Spaces:
Running
Running
| import json | |
| def _inject(prompt: str, art: str, summ: str) -> str: | |
| return prompt.replace("{insert_article_here}", art).replace("{insert_summary_here}", summ) | |
| def openai_call(p, a, s, temp): | |
| from src.api_clients import openai_client | |
| from src.config import MAX_TOKENS | |
| safe_prompt = "SYSTEM INSTRUCTION: Respond ONLY with the five JSON objects, no markdown, no extra text.\n\n" + _inject(p, a, s) | |
| r = openai_client.chat.completions.create( | |
| model="gpt-4o-mini", | |
| messages=[{"role": "user", "content": safe_prompt}], | |
| max_tokens=MAX_TOKENS["OpenAI"], | |
| temperature=temp | |
| ) | |
| return r.choices[0].message.content, r.usage.total_tokens | |
| def deepseek_call(p, a, s, temp): | |
| from src.api_clients import deepseek_client | |
| from src.config import MAX_TOKENS | |
| safe_prompt = "SYSTEM INSTRUCTION: Respond ONLY with the five JSON objects, no markdown, no extra text.\n\n" + _inject(p, a, s) | |
| r = deepseek_client.chat.completions.create( | |
| model="deepseek-chat", | |
| messages=[{"role": "user", "content": safe_prompt}], | |
| max_tokens=MAX_TOKENS["DeepSeek"], | |
| temperature=temp | |
| ) | |
| return r.choices[0].message.content, r.usage.total_tokens | |
| def claude_call(p, a, s, temp): | |
| from src.api_clients import claude_client | |
| from src.config import MAX_TOKENS | |
| safe_prompt = "SYSTEM INSTRUCTION: Respond ONLY with the five JSON objects, no markdown, no extra text.\n\n" + _inject(p, a, s) | |
| r = claude_client.messages.create( | |
| model="claude-3-5-sonnet-20241022", | |
| messages=[{"role": "user", "content": safe_prompt}], | |
| max_tokens=MAX_TOKENS["Claude"], | |
| temperature=temp | |
| ) | |
| txt = r.content[0].text.strip() | |
| tot = getattr(r.usage, "input_tokens", 0) + getattr(r.usage, "output_tokens", 0) # Fixed: Claude uses input_tokens/output_tokens | |
| return txt, tot | |
| def split_json_objects(s: str): | |
| objs, depth, start = [], 0, None | |
| for i, ch in enumerate(s): | |
| if ch == "{": | |
| if depth == 0: start = i | |
| depth += 1 | |
| elif ch == "}": | |
| depth -= 1 | |
| if depth == 0 and start is not None: | |
| objs.append(s[start:i + 1]) | |
| return objs | |
| def parse(raw: str): | |
| out = {} | |
| for js in split_json_objects(raw): | |
| try: | |
| d = json.loads(js) | |
| except json.JSONDecodeError: | |
| continue | |
| m = str(d.get("metric", "")).lower().replace("-", "_") | |
| canonical = { | |
| "coverage": "coverage", | |
| "alignment": "alignment", | |
| "hallucination": "hallucination", | |
| "relevance": "relevance", | |
| "bias_toxicity": "bias_toxicity" | |
| }.get(m) | |
| if canonical: | |
| out[canonical] = d | |
| continue | |
| dl = {k.lower(): k for k in d} | |
| if "key_points" in dl: out["coverage"] = d | |
| elif "aspects" in dl: out["alignment"] = d | |
| elif "claims_checked" in dl: out["hallucination"] = d | |
| elif "article_theme" in dl: out["relevance"] = d | |
| elif ("bias_score" in dl) or ("biasscore" in dl): out["bias_toxicity"] = d | |
| return out | |
| def wavg(m, w): | |
| if all(v == 0 for v in w.values()): return 0.0 | |
| total = sum(w.values()) | |
| return sum(m.get(k, {}).get("overall_score", 0) * w[k] for k in w) / total | |
| def preset_vals(name): | |
| from src.config import PRESET | |
| return [PRESET[name][k] for k in ("coverage","alignment","hallucination","relevance","bias_toxicity")] |