Initial MVP for QA asset backend

This commit is contained in:
2026-07-05 17:44:15 +08:00
commit 95b5e09fd4
71 changed files with 6546 additions and 0 deletions

View File

@@ -0,0 +1,49 @@
import json
from pathlib import Path
from typing import Any
import httpx
from app.config import get_settings
from app.services.mock_data_service import mock_ai_cleaning_result
from app.services.qa_parser import normalize_ai_item
from app.utils.json_validator import validate_ai_qa_items
PROMPT_PATH = Path(__file__).resolve().parents[1] / "prompts" / "qa_cleaning_prompt.md"
class AICleaner:
def __init__(self) -> None:
self.settings = get_settings()
def _prompt(self) -> str:
return PROMPT_PATH.read_text(encoding="utf-8")
async def clean_transcript(self, session_id: int, transcript: str) -> list[dict[str, Any]]:
if not self.settings.openai_configured:
return [normalize_ai_item(item) for item in mock_ai_cleaning_result(session_id)]
payload = {
"model": self.settings.model_name,
"messages": [
{"role": "system", "content": self._prompt()},
{
"role": "user",
"content": f"场次 ID: {session_id}\n\n以下是转写稿:\n{transcript}",
},
],
"temperature": 0.1,
}
base_url = (self.settings.openai_base_url or "https://api.openai.com/v1").rstrip("/")
headers = {"Authorization": f"Bearer {self.settings.openai_api_key}"}
async with httpx.AsyncClient(timeout=60) as client:
response = await client.post(f"{base_url}/chat/completions", headers=headers, json=payload)
response.raise_for_status()
content = response.json()["choices"][0]["message"]["content"]
try:
parsed = json.loads(content)
except json.JSONDecodeError as exc:
raise ValueError(f"AI 返回非法 JSON: {exc}") from exc
return [normalize_ai_item(item) for item in validate_ai_qa_items(parsed)]