RayMelius Claude Sonnet 4.6 commited on
Commit
abeb532
Β·
1 Parent(s): 0dfc2b9

Fix AI Analyst: align model default, actionable provider-not-enabled error

Browse files

- dashboard.py: change HF_MODEL default from Qwen2.5-3B to Qwen2.5-7B-Instruct-1M
(matches docker-compose ai_analyst service)
- Detect 400 model_not_supported / provider errors and return a clear message
with link to huggingface.co/settings/inference-providers
- /ai/debug: add "fix" field with provider setup instructions when 400 occurs
- docker-compose: add HF_TOKEN + HF_MODEL env vars to dashboard service
- index.html: error insights shown in red; status header turns red on error

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

dashboard/dashboard.py CHANGED
@@ -28,7 +28,7 @@ FRONTEND_URL = os.getenv("FRONTEND_URL", "")
28
 
29
  # ── AI Analyst (inline LLM for on-demand generation) ───────────────────────────
30
  HF_TOKEN = os.getenv("HF_TOKEN", "")
31
- HF_MODEL = os.getenv("HF_MODEL", "Qwen/Qwen2.5-3B-Instruct")
32
  HF_URL = "https://router.huggingface.co/v1/chat/completions"
33
  OLLAMA_HOST = os.getenv("OLLAMA_HOST", "")
34
  OLLAMA_MODEL = os.getenv("OLLAMA_MODEL", "llama3.1:8b")
@@ -119,6 +119,13 @@ def _call_llm(prompt):
119
  time.sleep(wait)
120
  else:
121
  print(f"[Dashboard/LLM] HF error body: {r.text[:400]}")
 
 
 
 
 
 
 
122
  return None, f"HF HTTP {r.status_code}: {r.text[:120]}"
123
  except requests.exceptions.Timeout:
124
  print(f"[Dashboard/LLM] HF timeout (attempt {attempt+1})")
@@ -607,7 +614,13 @@ def ai_debug():
607
  result["http_status"] = r.status_code
608
  result["response_body"] = r.text[:500]
609
  try:
610
- result["response_json"] = r.json()
 
 
 
 
 
 
611
  except Exception:
612
  pass
613
  except Exception as e:
 
28
 
29
  # ── AI Analyst (inline LLM for on-demand generation) ───────────────────────────
30
  HF_TOKEN = os.getenv("HF_TOKEN", "")
31
+ HF_MODEL = os.getenv("HF_MODEL", "Qwen/Qwen2.5-7B-Instruct-1M")
32
  HF_URL = "https://router.huggingface.co/v1/chat/completions"
33
  OLLAMA_HOST = os.getenv("OLLAMA_HOST", "")
34
  OLLAMA_MODEL = os.getenv("OLLAMA_MODEL", "llama3.1:8b")
 
119
  time.sleep(wait)
120
  else:
121
  print(f"[Dashboard/LLM] HF error body: {r.text[:400]}")
122
+ try:
123
+ err_code = r.json().get("error", {}).get("code", "")
124
+ except Exception:
125
+ err_code = ""
126
+ if err_code == "model_not_supported" or "provider" in r.text.lower():
127
+ return None, ("HF providers not enabled. Go to huggingface.co/settings/inference-providers "
128
+ "and enable at least one provider (e.g. Cerebras, Groq, or HF Inference).")
129
  return None, f"HF HTTP {r.status_code}: {r.text[:120]}"
130
  except requests.exceptions.Timeout:
131
  print(f"[Dashboard/LLM] HF timeout (attempt {attempt+1})")
 
614
  result["http_status"] = r.status_code
615
  result["response_body"] = r.text[:500]
616
  try:
617
+ rj = r.json()
618
+ result["response_json"] = rj
619
+ err_code = rj.get("error", {}).get("code", "")
620
+ if err_code == "model_not_supported" or "provider" in r.text.lower():
621
+ result["fix"] = ("Enable inference providers at: "
622
+ "https://huggingface.co/settings/inference-providers "
623
+ "Enable at least one free provider: Cerebras, Groq, SambaNova, or HF Inference.")
624
  except Exception:
625
  pass
626
  except Exception as e:
dashboard/templates/index.html CHANGED
@@ -467,7 +467,10 @@
467
  const ph = document.getElementById("ai-placeholder");
468
  if (ph) ph.remove();
469
  const div = document.createElement("div");
 
 
470
  div.className = "insight-card insight-new";
 
471
  const t = new Date(insight.timestamp * 1000).toLocaleTimeString();
472
  div.innerHTML = `<div class="insight-time">${t}</div><div>${insight.text}</div>`;
473
  list.prepend(div);
@@ -1128,8 +1131,11 @@
1128
  eventSource.addEventListener("ai_insight", (e) => {
1129
  const insight = JSON.parse(e.data);
1130
  addInsight(insight);
1131
- document.getElementById("ai-status").textContent =
1132
- "Last update: " + new Date().toLocaleTimeString();
 
 
 
1133
  const btn = document.getElementById("ai-generate-btn");
1134
  if (btn._tick) { clearInterval(btn._tick); btn._tick = null; }
1135
  btn.disabled = false;
 
467
  const ph = document.getElementById("ai-placeholder");
468
  if (ph) ph.remove();
469
  const div = document.createElement("div");
470
+ const isErr = insight.source === "error" || insight.source === "config"
471
+ || (insight.text || "").startsWith("⚠️");
472
  div.className = "insight-card insight-new";
473
+ if (isErr) div.style.cssText = "border-left-color:#e53935; background:#fff5f5;";
474
  const t = new Date(insight.timestamp * 1000).toLocaleTimeString();
475
  div.innerHTML = `<div class="insight-time">${t}</div><div>${insight.text}</div>`;
476
  list.prepend(div);
 
1131
  eventSource.addEventListener("ai_insight", (e) => {
1132
  const insight = JSON.parse(e.data);
1133
  addInsight(insight);
1134
+ const isErr = insight.source === "error" || insight.source === "config"
1135
+ || (insight.text || "").startsWith("⚠️");
1136
+ const statusEl = document.getElementById("ai-status");
1137
+ statusEl.textContent = isErr ? "error β€” see below" : "Last update: " + new Date().toLocaleTimeString();
1138
+ statusEl.style.color = isErr ? "#e53935" : "#999";
1139
  const btn = document.getElementById("ai-generate-btn");
1140
  if (btn._tick) { clearInterval(btn._tick); btn._tick = null; }
1141
  btn.disabled = false;
docker-compose.yml CHANGED
@@ -179,6 +179,8 @@ services:
179
  environment:
180
  - MATCHER_URL=http://matcher:6000
181
  - FRONTEND_URL=http://localhost:5000
 
 
182
 
183
  volumes:
184
  matcher_data: # Persists SQLite database across container restarts
 
179
  environment:
180
  - MATCHER_URL=http://matcher:6000
181
  - FRONTEND_URL=http://localhost:5000
182
+ - HF_TOKEN=${HF_TOKEN:-}
183
+ - HF_MODEL=${HF_MODEL:-Qwen/Qwen2.5-7B-Instruct-1M}
184
 
185
  volumes:
186
  matcher_data: # Persists SQLite database across container restarts