refactor(backend): extract shared helper modules per architecture rules
- 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>
This commit is contained in:
@@ -0,0 +1,51 @@
|
||||
"""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 []
|
||||
Reference in New Issue
Block a user