Add QuickCreate heuristic fallback when AI unavailable
This commit is contained in:
parent
153eb728e2
commit
243e4375e0
18
RELEASE_NOTES_v2.2.64.md
Normal file
18
RELEASE_NOTES_v2.2.64.md
Normal file
@ -0,0 +1,18 @@
|
||||
# Release Notes v2.2.64
|
||||
|
||||
Dato: 18. marts 2026
|
||||
|
||||
## Fixes
|
||||
|
||||
- Forbedret QuickCreate robusthed når AI/LLM er utilgængelig.
|
||||
- Tilføjet lokal heuristisk fallback i `CaseAnalysisService`, så brugeren stadig får:
|
||||
- foreslået titel
|
||||
- foreslået prioritet
|
||||
- simple tags
|
||||
- kunde-match forsøg
|
||||
- Fjernet afhængighed af at Ollama altid svarer, så QuickCreate ikke længere ender i tom AI-unavailable flow ved midlertidige AI-fejl.
|
||||
|
||||
## Berørte filer
|
||||
|
||||
- `app/services/case_analysis_service.py`
|
||||
- `RELEASE_NOTES_v2.2.64.md`
|
||||
@ -67,12 +67,12 @@ class CaseAnalysisService:
|
||||
|
||||
return analysis
|
||||
else:
|
||||
logger.warning("⚠️ Ollama returned no result, using empty analysis")
|
||||
return self._empty_analysis(text)
|
||||
logger.warning("⚠️ Ollama returned no result, using heuristic fallback analysis")
|
||||
return await self._heuristic_fallback_analysis(text)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"❌ Case analysis failed: {e}", exc_info=True)
|
||||
return self._empty_analysis(text)
|
||||
return await self._heuristic_fallback_analysis(text)
|
||||
|
||||
def _build_analysis_prompt(self) -> str:
|
||||
"""Build Danish system prompt for case analysis"""
|
||||
@ -470,6 +470,73 @@ Returner JSON med suggested_title, suggested_description, priority, customer_hin
|
||||
confidence=0.0,
|
||||
ai_reasoning="AI unavailable - fill fields manually"
|
||||
)
|
||||
|
||||
async def _heuristic_fallback_analysis(self, text: str) -> QuickCreateAnalysis:
|
||||
"""Local fallback when AI service is unavailable."""
|
||||
cleaned_text = (text or "").strip()
|
||||
if not cleaned_text:
|
||||
return self._empty_analysis(text)
|
||||
|
||||
lowered = cleaned_text.lower()
|
||||
|
||||
# Priority heuristics based on urgency wording.
|
||||
urgent_terms = ["nede", "kritisk", "asap", "omgående", "straks", "akut", "haster"]
|
||||
high_terms = ["hurtigt", "vigtigt", "snarest", "prioriter"]
|
||||
low_terms = ["når i får tid", "ikke hastende", "lavprioriteret"]
|
||||
|
||||
if any(term in lowered for term in urgent_terms):
|
||||
priority = SagPriority.URGENT
|
||||
elif any(term in lowered for term in high_terms):
|
||||
priority = SagPriority.HIGH
|
||||
elif any(term in lowered for term in low_terms):
|
||||
priority = SagPriority.LOW
|
||||
else:
|
||||
priority = SagPriority.NORMAL
|
||||
|
||||
# Basic title heuristic: first non-empty line/sentence, clipped to 80 chars.
|
||||
first_line = cleaned_text.splitlines()[0].strip()
|
||||
first_sentence = re.split(r"[.!?]", first_line)[0].strip()
|
||||
title_source = first_sentence or first_line or cleaned_text
|
||||
title = title_source[:80].strip()
|
||||
if not title:
|
||||
title = "Ny sag"
|
||||
|
||||
# Lightweight keyword tags.
|
||||
keyword_tags = {
|
||||
"printer": "printer",
|
||||
"mail": "mail",
|
||||
"email": "mail",
|
||||
"vpn": "vpn",
|
||||
"net": "netværk",
|
||||
"wifi": "wifi",
|
||||
"server": "server",
|
||||
"laptop": "laptop",
|
||||
"adgang": "adgang",
|
||||
"onboarding": "onboarding",
|
||||
}
|
||||
suggested_tags: List[str] = []
|
||||
for key, tag in keyword_tags.items():
|
||||
if key in lowered and tag not in suggested_tags:
|
||||
suggested_tags.append(tag)
|
||||
|
||||
# Try simple customer matching from long words in text.
|
||||
candidate_hints = []
|
||||
for token in re.findall(r"[A-Za-z0-9ÆØÅæøå._-]{3,}", cleaned_text):
|
||||
if token.lower() in {"ring", "kunde", "sag", "skal", "have", "virker", "ikke"}:
|
||||
continue
|
||||
candidate_hints.append(token)
|
||||
customer_id, customer_name = await self._match_customer(candidate_hints[:8])
|
||||
|
||||
return QuickCreateAnalysis(
|
||||
suggested_title=title,
|
||||
suggested_description=cleaned_text,
|
||||
suggested_priority=priority,
|
||||
suggested_customer_id=customer_id,
|
||||
suggested_customer_name=customer_name,
|
||||
suggested_tags=suggested_tags,
|
||||
confidence=0.35,
|
||||
ai_reasoning="AI service unavailable - using local fallback suggestions"
|
||||
)
|
||||
|
||||
def _get_cached_analysis(self, text: str) -> Optional[QuickCreateAnalysis]:
|
||||
"""Get cached analysis if available and not expired"""
|
||||
|
||||
Loading…
Reference in New Issue
Block a user