feat: expose LLM error reason in /api/ask response and UI
- Add llm_error field to AskResponse so users know why AI summarisation was skipped - Show orange warning banner in frontend when LLM is not configured or call fails - Update AskEndpoint tests to assert llm_error presence
This commit is contained in:
@@ -53,6 +53,7 @@
|
|||||||
</form>
|
</form>
|
||||||
<template x-if="askAnswer">
|
<template x-if="askAnswer">
|
||||||
<div class="ask-result">
|
<div class="ask-result">
|
||||||
|
<div x-show="askLlmError" class="ask-error" x-text="askLlmError"></div>
|
||||||
<div class="ask-answer" x-html="askAnswerHtml"></div>
|
<div class="ask-answer" x-html="askAnswerHtml"></div>
|
||||||
<template x-if="askEvents.length">
|
<template x-if="askEvents.length">
|
||||||
<div class="ask-events">
|
<div class="ask-events">
|
||||||
@@ -245,6 +246,7 @@
|
|||||||
askAnswerHtml: '',
|
askAnswerHtml: '',
|
||||||
askEvents: [],
|
askEvents: [],
|
||||||
askLlmUsed: false,
|
askLlmUsed: false,
|
||||||
|
askLlmError: '',
|
||||||
|
|
||||||
async initApp() {
|
async initApp() {
|
||||||
await this.initAuth();
|
await this.initAuth();
|
||||||
@@ -501,6 +503,7 @@
|
|||||||
this.askAnswerHtml = this._mdToHtml(body.answer);
|
this.askAnswerHtml = this._mdToHtml(body.answer);
|
||||||
this.askEvents = body.events || [];
|
this.askEvents = body.events || [];
|
||||||
this.askLlmUsed = body.llm_used;
|
this.askLlmUsed = body.llm_used;
|
||||||
|
this.askLlmError = body.llm_error || '';
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
this.askAnswer = 'Sorry, something went wrong: ' + (err.message || 'Unknown error');
|
this.askAnswer = 'Sorry, something went wrong: ' + (err.message || 'Unknown error');
|
||||||
this.askAnswerHtml = this.askAnswer;
|
this.askAnswerHtml = this.askAnswer;
|
||||||
@@ -515,6 +518,7 @@
|
|||||||
this.askAnswerHtml = '';
|
this.askAnswerHtml = '';
|
||||||
this.askEvents = [];
|
this.askEvents = [];
|
||||||
this.askLlmUsed = false;
|
this.askLlmUsed = false;
|
||||||
|
this.askLlmError = '';
|
||||||
},
|
},
|
||||||
|
|
||||||
_mdToHtml(text) {
|
_mdToHtml(text) {
|
||||||
|
|||||||
@@ -418,6 +418,16 @@ input {
|
|||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ask-error {
|
||||||
|
background: rgba(249, 115, 22, 0.1);
|
||||||
|
border: 1px solid rgba(249, 115, 22, 0.3);
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 10px 14px;
|
||||||
|
color: #fdba74;
|
||||||
|
font-size: 14px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
.ask-events {
|
.ask-events {
|
||||||
margin-bottom: 14px;
|
margin-bottom: 14px;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -92,3 +92,4 @@ class AskResponse(BaseModel):
|
|||||||
events: list[AskEventRef]
|
events: list[AskEventRef]
|
||||||
query_info: dict
|
query_info: dict
|
||||||
llm_used: bool
|
llm_used: bool
|
||||||
|
llm_error: str | None = None
|
||||||
|
|||||||
@@ -272,16 +272,21 @@ async def ask_question(body: AskRequest, user: dict = Depends(require_auth)):
|
|||||||
events=[],
|
events=[],
|
||||||
query_info={"entity": entity, "start": start, "end": end, "event_count": 0},
|
query_info={"entity": entity, "start": start, "end": end, "event_count": 0},
|
||||||
llm_used=False,
|
llm_used=False,
|
||||||
|
llm_error="LLM not used — no events found." if not LLM_API_KEY else None,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Try LLM summarisation
|
# Try LLM summarisation
|
||||||
answer = ""
|
answer = ""
|
||||||
llm_used = False
|
llm_used = False
|
||||||
if LLM_API_KEY:
|
llm_error = None
|
||||||
|
if not LLM_API_KEY:
|
||||||
|
llm_error = "LLM_API_KEY is not configured. Set it in your .env to enable AI narrative summarisation."
|
||||||
|
else:
|
||||||
try:
|
try:
|
||||||
answer = await _call_llm(question, events)
|
answer = await _call_llm(question, events)
|
||||||
llm_used = True
|
llm_used = True
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
|
llm_error = f"LLM call failed: {exc}"
|
||||||
logger.warning("LLM call failed, falling back to structured summary", error=str(exc))
|
logger.warning("LLM call failed, falling back to structured summary", error=str(exc))
|
||||||
|
|
||||||
# Fallback: structured summary if LLM unavailable or failed
|
# Fallback: structured summary if LLM unavailable or failed
|
||||||
@@ -315,4 +320,5 @@ async def ask_question(body: AskRequest, user: dict = Depends(require_auth)):
|
|||||||
"mongo_query": json.dumps(query, default=str),
|
"mongo_query": json.dumps(query, default=str),
|
||||||
},
|
},
|
||||||
llm_used=llm_used,
|
llm_used=llm_used,
|
||||||
|
llm_error=llm_error,
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user