Summary-Evaluator / src /utils.py
navaneethkrishnan's picture
Upload utils.py
915a441 verified
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")]