Files
joke/crawler/ai_service.py
T
bwstudio ceed63fcb0 fix: resolve 10 code review issues
High priority:
- Fix concurrent race condition for view_count/like_count (atomic update)
- Add route request ID tracking to prevent race conditions
- Filter get_joke by status=approved (no pending content leak)
- Add error feedback for like button

Performance:
- Optimize random joke query (avoid full table sort)
- Limit page_size max to 100 (DoS prevention)

Medium:
- Add localStorage quota error handling
- Handle empty AI response gracefully
- Fix generate content title extraction

Low:
- Add rejected_jokes to stats API
- Update dashboard to show rejected count
2026-06-02 20:35:08 +08:00

71 lines
2.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""LLM 处理:调用 NVIDIA NIMOpenAI 兼容 API)进行笑话提取、改写和分类。"""
import json
import os
from openai import OpenAI
class AiService:
def __init__(self, api_base: str, api_key: str, model_name: str, temperature: float = 0.7, max_tokens: int = 2048):
self.client = OpenAI(base_url=api_base, api_key=api_key)
self.model = model_name
self.temperature = temperature
self.max_tokens = max_tokens
def extract_jokes(self, page_content: str, known_types: list[str], known_crowds: list[str]) -> list[dict]:
"""从页面内容中提取笑话,返回结构化数据。"""
from crawler.prompts import EXTRACTION_SYSTEM_PROMPT, EXTRACTION_USER_PROMPT
user_prompt = EXTRACTION_USER_PROMPT.format(
page_content=page_content[:8000],
known_types=", ".join(known_types),
known_crowds=", ".join(known_crowds),
)
response = self.client.chat.completions.create(
model=self.model,
messages=[
{"role": "system", "content": EXTRACTION_SYSTEM_PROMPT},
{"role": "user", "content": user_prompt},
],
temperature=self.temperature,
max_tokens=self.max_tokens,
)
raw = response.choices[0].message.content
return self._parse_json(raw)
def rewrite_joke(self, content: str) -> str:
"""润色单条笑话内容。"""
from crawler.prompts import REWRITE_SYSTEM_PROMPT, REWRITE_USER_PROMPT
response = self.client.chat.completions.create(
model=self.model,
messages=[
{"role": "system", "content": REWRITE_SYSTEM_PROMPT},
{"role": "user", "content": REWRITE_USER_PROMPT.format(content=content)},
],
temperature=0.8,
max_tokens=500,
)
return response.choices[0].message.content.strip()
def _parse_json(self, raw: str) -> list[dict]:
"""安全解析 LLM 返回的 JSON。"""
try:
data = json.loads(raw)
if isinstance(data, dict):
jokes = data.get("jokes") or data.get("items") or [data]
else:
jokes = data
return [j for j in jokes if isinstance(j, dict) and j.get("content")]
except json.JSONDecodeError:
# 尝试提取 markdown 代码块
if "```json" in raw:
raw = raw.split("```json")[1].split("```")[0]
elif "```" in raw:
raw = raw.split("```")[1].split("```")[0]
try:
return json.loads(raw.strip())
except Exception:
return []