50 lines
1.8 KiB
Python
50 lines
1.8 KiB
Python
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)]
|
|
|