a548266461
- Add backend/ai/utils.py — parse_classification, parse_suggestions, strip_code_fences shared by all AI providers; removes duplicated private functions from anthropic_provider.py and openai_provider.py - Add backend/deps/utils.py — get_client_ip, parse_uuid request-parsing helpers; removes local _ip() variants from admin.py, auth.py, shares.py, folders.py - Add backend/storage/exceptions.py — canonical CloudConnectionError definition; all routers and backends import from here instead of redefining - Move validate_password_strength to backend/services/auth.py; removes duplicated _validate_password_strength from admin.py and auth.py Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
52 lines
1.6 KiB
Python
52 lines
1.6 KiB
Python
"""Shared AI response parsing utilities — used by all provider implementations."""
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
import re
|
|
|
|
from ai.base import ClassificationResult
|
|
|
|
|
|
def strip_code_fences(text: str) -> str:
|
|
"""Remove markdown code fences (```json ... ```) from *text*."""
|
|
text = re.sub(r"```(?:json)?\s*", "", text)
|
|
text = re.sub(r"```", "", text)
|
|
return text.strip()
|
|
|
|
|
|
def parse_classification(raw: str) -> ClassificationResult:
|
|
"""Parse a classification JSON response into a ClassificationResult.
|
|
|
|
Tolerates markdown code fences and extracts the first JSON object found.
|
|
Returns an empty ClassificationResult on any parse failure.
|
|
"""
|
|
raw = strip_code_fences(raw)
|
|
match = re.search(r"\{.*\}", raw, re.DOTALL)
|
|
if match:
|
|
try:
|
|
data = json.loads(match.group())
|
|
return ClassificationResult(
|
|
topics=data.get("assigned_topics", []),
|
|
suggested_new_topics=data.get("new_topic_suggestions", []),
|
|
reasoning=data.get("reasoning", ""),
|
|
)
|
|
except json.JSONDecodeError:
|
|
pass
|
|
return ClassificationResult()
|
|
|
|
|
|
def parse_suggestions(raw: str) -> list[str]:
|
|
"""Parse a topic-suggestion JSON response into a list of topic name strings.
|
|
|
|
Tolerates markdown code fences. Returns an empty list on parse failure.
|
|
"""
|
|
raw = strip_code_fences(raw)
|
|
match = re.search(r"\{.*\}", raw, re.DOTALL)
|
|
if match:
|
|
try:
|
|
data = json.loads(match.group())
|
|
return data.get("suggested_topics", [])
|
|
except json.JSONDecodeError:
|
|
pass
|
|
return []
|