| 2702 | self.available = bool(api_key) |
| 2703 | |
| 2704 | def analyze(self, doc_id: str, registry_entry: Optional[dict], new_items: list) -> dict: |
| 2705 | if not self.available or not new_items: |
| 2706 | return {"is_update": False, "confidence": 0.0, "reasoning": "LLM not configured"} |
| 2707 | current = (registry_entry or {}).get("current", {}) |
| 2708 | prompt = ( |
| 2709 | f'You are a regulatory document version analyst.\n\n' |
| 2710 | f'Current entry for "{doc_id}": title={current.get("title","N/A")}, ' |
| 2711 | f'version={current.get("version","N/A")}, status={current.get("status","N/A")}, ' |
| 2712 | f'published={current.get("published_date","N/A")}\n\n' |
| 2713 | f'New search results:\n{json.dumps(new_items[:5], ensure_ascii=False)}\n\n' |
| 2714 | f'Is this a genuine NEW VERSION or UPDATE? Consider: newer date, same document ' |
| 2715 | f'type, Draft->Final transition, revision.\n' |
| 2716 | f'JSON only: {{"is_update":bool,"confidence":0.0-1.0,' |
| 2717 | f'"new_version":"YYYY-MM or null","new_url":"url or null","reasoning":"brief"}}' |
| 2718 | ) |
| 2719 | try: |
| 2720 | resp = requests.post( |
| 2721 | f"{self.base_url}/chat/completions", |
| 2722 | headers={"Authorization": f"Bearer {self.api_key}", |
| 2723 | "Content-Type": "application/json"}, |
| 2724 | json={"model": self.model, |
| 2725 | "messages": [{"role": "user", "content": prompt}], |
| 2726 | "temperature": 0.1, |
| 2727 | "response_format": {"type": "json_object"}}, |
| 2728 | timeout=30, |
| 2729 | ) |
| 2730 | resp.raise_for_status() |
| 2731 | return json.loads(resp.json()["choices"][0]["message"]["content"]) |
| 2732 | except Exception as e: |
| 2733 | return {"is_update": False, "confidence": 0.0, "reasoning": f"LLM error: {e}"} |
| 2734 | |
| 2735 | |
| 2736 | # --------------------------------------------------------------------------- |