"""Claude API 기반 블로그 글 품질 리뷰 — 6기준 × 10점, 42/60 통과.""" import json import logging from typing import Any, Dict, Optional import anthropic from .config import ANTHROPIC_API_KEY, CLAUDE_MODEL from .db import get_template logger = logging.getLogger(__name__) PASS_THRESHOLD = 42 # 60점 만점 중 42점 이상이면 통과 (70%) _client: Optional[anthropic.Anthropic] = None def _get_client() -> anthropic.Anthropic: global _client if _client is None: _client = anthropic.Anthropic(api_key=ANTHROPIC_API_KEY) return _client def review_post(title: str, body: str) -> Dict[str, Any]: """블로그 글 품질 리뷰. Returns: { "scores": { "empathy": N, "click_appeal": N, "conversion": N, "seo": N, "format": N, "link_natural": N }, "total": N, "pass": bool, "feedback": str } """ template = get_template("quality_review") if not template: raise RuntimeError("quality_review 템플릿이 없습니다") prompt = template.format(title=title, body=body[:6000]) client = _get_client() resp = client.messages.create( model=CLAUDE_MODEL, max_tokens=2048, messages=[{"role": "user", "content": prompt}], ) raw = resp.content[0].text try: text = raw.strip() if text.startswith("```"): lines = text.split("\n") lines = [l for l in lines if not l.strip().startswith("```")] text = "\n".join(lines) result = json.loads(text) scores = result.get("scores", {}) total = sum(scores.values()) passed = total >= PASS_THRESHOLD return { "scores": scores, "total": total, "pass": passed, "feedback": result.get("feedback", ""), } except (json.JSONDecodeError, KeyError, TypeError) as e: logger.warning("Quality review JSON parse failed: %s", e) return { "scores": { "empathy": 0, "click_appeal": 0, "conversion": 0, "seo": 0, "format": 0, "link_natural": 0, }, "total": 0, "pass": False, "feedback": f"리뷰 파싱 실패. 원본 응답:\n{raw[:500]}", }