SafeVixAI/SafeVixAI-Dataset-Hub
SafeVixAI Dataset Hub π‘οΈ The Intelligence Layer for the SafeVixAI platform β IIT Madras Road Safety Hackathon 2026 This repository hosts all datasets, pre-trained models, notebooks, and reproducible data acquisition scripts that power the SafeVixAI application. It is designed to be cloned directly into Google Colab or any research environment. Main Application Repo: SafeVixAI/SafeVixAI β‘ Quickstart (Google Colab) # Clone the entire intelligence layer !gitβ¦ See the full description on the dataset page: https://huggingface.co/datasets/SafeVixAI/SafeVixAI-Dataset-Hub.
1147
1#!/usr/bin/env python32"""3Batch upgrade AST stubs to LLM docs with email alerts on failure.4Usage: python scripts/batch_upgrade_wiki.py [--limit N] [--delay SECS]5"""6import os, sys, re, json, time, smtplib7from pathlib import Path8from email.mime.text import MIMEText9from urllib.request import Request, urlopen10from urllib.error import HTTPError11 12ROOT = Path(__file__).resolve().parent.parent.parent13WIKI_CONTENT = ROOT / "docs" / "wiki" / "content"14 15# ββ Email Alert βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ16def send_alert_email(subject, error_details, file_name, provider_errors):17 """Send email alert when wiki generation fails persistently."""18 smtp_user = os.environ.get("ALERT_EMAIL", "")19 smtp_pass = os.environ.get("ALERT_EMAIL_PASSWORD", "")20 alert_to = os.environ.get("ALERT_EMAIL_TO", smtp_user)21 22 if not smtp_user or not smtp_pass:23 print(" [ALERT] No email configured (set ALERT_EMAIL + ALERT_EMAIL_PASSWORD)")24 print(f" [ALERT] Issue: {subject}")25 print(f" [ALERT] Details: {error_details}")26 _print_solutions(provider_errors)27 return28 29 body = f"""SafeVixAI Wiki Manager β Alert30 31ISSUE: {subject}32FILE: {file_name}33TIME: {time.strftime('%Y-%m-%d %H:%M:%S')}34 35DETAILS:36{error_details}37 38PROVIDER ERRORS:39{chr(10).join(f' - {p}: {e}' for p, e in provider_errors.items())}40 413 WAYS TO FIX THIS:42 431. RATE LIMIT EXHAUSTED44 β Wait 1 hour and re-run: python scripts/batch_upgrade_wiki.py --limit 20 --delay 545 β Or switch to a different provider by updating OPENROUTER_API_KEY or MISTRAL_API_KEY46 472. API KEY EXPIRED/INVALID48 β Check your keys at: https://openrouter.ai/keys | https://console.mistral.ai/api-keys49 β Update chatbot_service/.env with fresh keys50 β Add keys as GitHub Secrets for CI: Settings β Secrets β OPENROUTER_API_KEY51 523. SERVICE OUTAGE53 β Check status: https://status.openrouter.ai | https://status.mistral.ai54 β The {len(provider_errors)} failed files will stay as AST stubs (still functional)55 β Re-run later: python scripts/wiki_manager.py update56"""57 msg = MIMEText(body)58 msg["Subject"] = f"[SafeVixAI] {subject}"59 msg["From"] = smtp_user60 msg["To"] = alert_to61 62 try:63 with smtplib.SMTP("smtp.gmail.com", 587) as s:64 s.starttls()65 s.login(smtp_user, smtp_pass)66 s.send_message(msg)67 print(f" [ALERT] Email sent to {alert_to}")68 except Exception as e:69 print(f" [ALERT] Email failed: {e}")70 _print_solutions(provider_errors)71 72def _print_solutions(provider_errors):73 print("\n === 3 WAYS TO FIX ===")74 print(" 1. Rate limit β wait 1hr, re-run with --delay 5")75 print(" 2. Key expired β refresh at openrouter.ai/keys or console.mistral.ai")76 print(" 3. Service down β check status pages, re-run later")77 print()78 79# ββ LLM Calls βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ80def call_llm(prompt, or_key, ms_key, gk_key):81 """Try OpenRouter β Mistral β Gemini with per-provider error tracking."""82 errors = {}83 providers = [84 ("openrouter", or_key, "https://openrouter.ai/api/v1/chat/completions",85 {"model": "google/gemini-2.0-flash-lite-001", "messages": [{"role": "user", "content": prompt}], "max_tokens": 4096, "temperature": 0.3}),86 ("mistral", ms_key, "https://api.mistral.ai/v1/chat/completions",87 {"model": "mistral-small-latest", "messages": [{"role": "user", "content": prompt}], "max_tokens": 4096, "temperature": 0.3}),88 ]89 for name, key, url, payload in providers:90 if not key:91 continue92 for attempt in range(2): # 2 retries per provider93 try:94 body = json.dumps(payload).encode("utf-8")95 headers = {"Content-Type": "application/json", "Authorization": f"Bearer {key}"}96 req = Request(url, data=body, headers=headers)97 resp = urlopen(req, timeout=60)98 data = json.loads(resp.read().decode("utf-8"))99 result = data["choices"][0]["message"]["content"]100 if result and len(result) > 100:101 if len(result) > 8000:102 result = result[:8000].rsplit("\n", 1)[0] + "\n"103 return result, name, errors104 except HTTPError as e:105 errors[name] = f"HTTP {e.code} (attempt {attempt+1})"106 if e.code == 429:107 time.sleep((attempt + 1) * 5)108 else:109 break110 except Exception as e:111 errors[name] = str(e)112 break113 114 # Try Gemini direct as last resort115 if gk_key:116 try:117 gurl = f"https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash-lite:generateContent?key={gk_key}"118 body = json.dumps({"contents": [{"parts": [{"text": prompt}]}], "generationConfig": {"maxOutputTokens": 4096, "temperature": 0.3}}).encode()119 req = Request(gurl, data=body, headers={"Content-Type": "application/json"})120 resp = urlopen(req, timeout=60)121 data = json.loads(resp.read().decode("utf-8"))122 result = data["candidates"][0]["content"]["parts"][0]["text"]123 if result and len(result) > 100:124 if len(result) > 8000:125 result = result[:8000].rsplit("\n", 1)[0] + "\n"126 return result, "gemini", errors127 except HTTPError as e:128 errors["gemini"] = f"HTTP {e.code}"129 except Exception as e:130 errors["gemini"] = str(e)131 132 return None, None, errors133 134# ββ Prompt ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ135def build_prompt(name, ext, section, path, code):136 return f"""Technical documentation writer for SafeVixAI (AI road safety platform, IIT Madras Hackathon 2026).137 138Generate a comprehensive wiki page in Markdown for this module.139 140Module: `{name}{ext}` | Section: {section} | File: `{path}`141Platform: 9 LLM providers, Supabase Auth, Next.js, FastAPI, LocalHashEmbeddingFunction (SHA-256)142 143```{ext.lstrip('.')}144{code}145```146 147Generate these sections:1481. # Title1492. ## Overview (what it does, 2-3 sentences)1503. ## Architecture (where it fits)1514. ## Key Classes/Functions (table: name | params | return | description)1525. ## Dependencies (imports)1536. ## Configuration (env vars, constants)1547. ## Usage Examples (real code)1558. ## Error Handling1569. ## Related Modules157 158Rules: Use actual names from code. No TODOs. Be specific. Output ONLY markdown."""159 160# ββ Main ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ161def main():162 limit = 127163 delay = 3164 args = sys.argv[1:]165 for i, arg in enumerate(args):166 if arg == "--limit" and i + 1 < len(args): limit = int(args[i+1])167 if arg == "--delay" and i + 1 < len(args): delay = int(args[i+1])168 169 or_key = os.environ.get("OPENROUTER_API_KEY", "")170 ms_key = os.environ.get("MISTRAL_API_KEY", "")171 gk_key = os.environ.get("GOOGLE_API_KEY", "")172 173 if not or_key and not ms_key and not gk_key:174 print("ERROR: No LLM API keys found")175 sys.exit(1)176 177 active = [n for n, k in [("OpenRouter", or_key), ("Mistral", ms_key), ("Gemini", gk_key)] if k]178 print(f"Providers: {' β '.join(active)}", flush=True)179 180 # Find stubs181 stubs = []182 for f in sorted(WIKI_CONTENT.rglob("*.md")):183 text = f.read_text(encoding="utf-8")184 if "Auto-generated:" not in text:185 continue186 src_match = re.search(r'Source: `(.+?)`', text)187 if not src_match:188 continue189 spath = src_match.group(1).replace("\\", "/")190 if (ROOT / spath).exists():191 stubs.append((f, spath))192 193 total = min(len(stubs), limit)194 print(f"Stubs: {len(stubs)} found, processing {total} (delay: {delay}s)", flush=True)195 print("=" * 50, flush=True)196 197 success, fail, consecutive_fails = 0, 0, 0198 all_errors = {}199 200 for i, (wiki_path, spath) in enumerate(stubs[:total]):201 ext = "." + spath.rsplit(".", 1)[-1]202 name = spath.rsplit("/", 1)[-1].rsplit(".", 1)[0]203 section = str(wiki_path.parent.relative_to(WIKI_CONTENT))204 205 try:206 src = (ROOT / spath).read_text(encoding="utf-8", errors="ignore")207 lines = src.split("\n")208 if len(lines) > 150:209 src = "\n".join(lines[:150]) + f"\n# ... ({len(lines)} total lines)"210 except Exception:211 print(f"[{i+1}/{total}] SKIP {name} (unreadable)", flush=True)212 continue213 214 print(f"[{i+1}/{total}] {name}{ext} ...", end=" ", flush=True)215 216 prompt = build_prompt(name, ext, section, spath, src)217 result, provider, errors = call_llm(prompt, or_key, ms_key, gk_key)218 219 if result:220 wiki_path.write_text(result, encoding="utf-8")221 success += 1222 consecutive_fails = 0223 print(f"OK ({len(result)} chars via {provider})", flush=True)224 else:225 fail += 1226 consecutive_fails += 1227 all_errors[name] = errors228 print(f"FAILED {errors}", flush=True)229 230 if consecutive_fails >= 5:231 print(f"\n5 consecutive failures β stopping early.", flush=True)232 send_alert_email(233 "Wiki generation stopped β 5 consecutive LLM failures",234 f"Failed at file #{i+1}: {name}{ext}\n{success} succeeded before failure.",235 name + ext, errors236 )237 break238 239 time.sleep(delay)240 241 print("=" * 50, flush=True)242 remaining = len(stubs) - success - fail243 print(f"Results: {success} upgraded | {fail} failed | {remaining} remaining", flush=True)244 245 if fail > 0 and consecutive_fails < 5:246 send_alert_email(247 f"Wiki generation completed with {fail} failures",248 f"{success} upgraded, {fail} failed out of {total} attempted.",249 "multiple files", all_errors.get(list(all_errors.keys())[-1], {}) if all_errors else {}250 )251 252 # Clean up test script if it exists253 test_script = ROOT / "scripts" / "test_llm.py"254 if test_script.exists():255 test_script.unlink()256 257if __name__ == "__main__":258 main()259 