Claude commited on
Commit
c90271f
·
unverified ·
1 Parent(s): 1451885

Fix silent API error handling in chat

Browse files

Frontend now properly detects HTTP errors and displays meaningful
error messages instead of showing a stuck typing indicator. Backend
logs API key presence and request details for easier debugging.

https://claude.ai/code/session_015z3yZxNNfXF63JuQDuPbEG

Files changed (2) hide show
  1. app/main.py +12 -0
  2. static/app.js +31 -5
app/main.py CHANGED
@@ -80,7 +80,18 @@ def _detect_phase(reply: str, current_phase: int) -> int:
80
 
81
  @app.post("/api/chat", response_model=ChatResponse)
82
  async def api_chat(req: ChatRequest):
 
 
 
 
 
 
 
 
 
 
83
  try:
 
84
  rag_chunks = retrieve(req.message)
85
  system_prompt = build_system_prompt(req.mode, req.topic, req.phase, rag_chunks)
86
 
@@ -88,6 +99,7 @@ async def api_chat(req: ChatRequest):
88
  messages.append({"role": "user", "content": req.message})
89
 
90
  reply = await chat(system_prompt, messages)
 
91
  detected_phase = _detect_phase(reply, req.phase)
92
 
93
  return ChatResponse(reply=reply, phase=detected_phase)
 
80
 
81
  @app.post("/api/chat", response_model=ChatResponse)
82
  async def api_chat(req: ChatRequest):
83
+ import os
84
+ api_key = os.environ.get("OPENROUTER_API_KEY", "")
85
+ base_url = os.environ.get("LLM_BASE_URL", "")
86
+ model = os.environ.get("LLM_MODEL", "")
87
+ if not api_key:
88
+ logger.error("OPENROUTER_API_KEY is not set!")
89
+ return JSONResponse(status_code=500, content={"error": "Cle API non configuree (OPENROUTER_API_KEY manquant)"})
90
+ if not base_url:
91
+ logger.warning("LLM_BASE_URL is not set, will use OpenAI default")
92
+
93
  try:
94
+ logger.info(f"Chat request: mode={req.mode}, topic={req.topic[:50]}, phase={req.phase}, model={model}")
95
  rag_chunks = retrieve(req.message)
96
  system_prompt = build_system_prompt(req.mode, req.topic, req.phase, rag_chunks)
97
 
 
99
  messages.append({"role": "user", "content": req.message})
100
 
101
  reply = await chat(system_prompt, messages)
102
+ logger.info(f"LLM reply received ({len(reply)} chars)")
103
  detected_phase = _detect_phase(reply, req.phase)
104
 
105
  return ChatResponse(reply=reply, phase=detected_phase)
static/app.js CHANGED
@@ -255,9 +255,21 @@
255
  history: state.history.slice(0, -1) // send history before this message
256
  })
257
  })
258
- .then(function (res) { return res.json(); })
 
 
 
 
 
 
 
259
  .then(function (data) {
260
  setTyping(false);
 
 
 
 
 
261
  state.phase = data.phase;
262
  state.history.push({ role: "assistant", content: data.reply });
263
  state.timestamps.push(Date.now());
@@ -268,7 +280,8 @@
268
  })
269
  .catch(function (err) {
270
  setTyping(false);
271
- addMessage("assistant", "Erreur de connexion. Veuillez reessayer.");
 
272
  btnSend.disabled = false;
273
  });
274
  }
@@ -458,9 +471,21 @@
458
  history: []
459
  })
460
  })
461
- .then(function (res) { return res.json(); })
 
 
 
 
 
 
 
462
  .then(function (data) {
463
  setTyping(false);
 
 
 
 
 
464
  state.phase = data.phase;
465
  state.history.push({ role: "assistant", content: data.reply });
466
  state.timestamps.push(Date.now());
@@ -469,9 +494,10 @@
469
  btnSend.disabled = false;
470
  chatInput.focus();
471
  })
472
- .catch(function () {
473
  setTyping(false);
474
- addMessage("assistant", "Erreur de connexion. Veuillez reessayer.");
 
475
  btnSend.disabled = false;
476
  });
477
  }
 
255
  history: state.history.slice(0, -1) // send history before this message
256
  })
257
  })
258
+ .then(function (res) {
259
+ if (!res.ok) {
260
+ return res.json().then(function (err) {
261
+ throw new Error(err.error || "Erreur serveur " + res.status);
262
+ });
263
+ }
264
+ return res.json();
265
+ })
266
  .then(function (data) {
267
  setTyping(false);
268
+ if (!data.reply) {
269
+ addMessage("assistant", "Reponse vide du serveur. Verifiez la configuration API.");
270
+ btnSend.disabled = false;
271
+ return;
272
+ }
273
  state.phase = data.phase;
274
  state.history.push({ role: "assistant", content: data.reply });
275
  state.timestamps.push(Date.now());
 
280
  })
281
  .catch(function (err) {
282
  setTyping(false);
283
+ console.error("sendMessage error:", err);
284
+ addMessage("assistant", "Erreur: " + (err.message || "Connexion impossible. Veuillez reessayer."));
285
  btnSend.disabled = false;
286
  });
287
  }
 
471
  history: []
472
  })
473
  })
474
+ .then(function (res) {
475
+ if (!res.ok) {
476
+ return res.json().then(function (err) {
477
+ throw new Error(err.error || "Erreur serveur " + res.status);
478
+ });
479
+ }
480
+ return res.json();
481
+ })
482
  .then(function (data) {
483
  setTyping(false);
484
+ if (!data.reply) {
485
+ addMessage("assistant", "Reponse vide du serveur. Verifiez la configuration API.");
486
+ btnSend.disabled = false;
487
+ return;
488
+ }
489
  state.phase = data.phase;
490
  state.history.push({ role: "assistant", content: data.reply });
491
  state.timestamps.push(Date.now());
 
494
  btnSend.disabled = false;
495
  chatInput.focus();
496
  })
497
+ .catch(function (err) {
498
  setTyping(false);
499
+ console.error("startSession error:", err);
500
+ addMessage("assistant", "Erreur: " + (err.message || "Connexion impossible. Veuillez reessayer."));
501
  btnSend.disabled = false;
502
  });
503
  }