Evidence-grounded LLM verdicts (date context, think-block-safe JSON parsing, source status)
Browse files- src/streamlit_app.py +22 -3
src/streamlit_app.py
CHANGED
|
@@ -1,4 +1,5 @@
|
|
| 1 |
import os
|
|
|
|
| 2 |
import json
|
| 3 |
import time
|
| 4 |
import requests
|
|
@@ -452,6 +453,8 @@ def parse_llm_json(raw):
|
|
| 452 |
if not raw:
|
| 453 |
return None
|
| 454 |
text = raw.strip()
|
|
|
|
|
|
|
| 455 |
if text.startswith("```"):
|
| 456 |
text = text.strip("`")
|
| 457 |
if text.startswith("json"):
|
|
@@ -475,6 +478,12 @@ SYSTEM_PROMPT = (
|
|
| 475 |
"app. You will receive a piece of content, two AI classifier verdicts with confidence "
|
| 476 |
"scores, and web search evidence. Your job is to decide how truthful the content is. "
|
| 477 |
"You are the final judge: your verdict overrides the classifier verdicts.\n"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 478 |
'Respond ONLY with a valid JSON object in this exact shape:\n'
|
| 479 |
'{"verdict": "REAL" or "FAKE" or "UNKNOWN", "confidence": <integer 0-100>, '
|
| 480 |
'"explanation": "<2-3 plain-language sentences>", '
|
|
@@ -492,13 +501,19 @@ def synthesize_verdict(content, model_results, evidence):
|
|
| 492 |
if not GROQ_AVAILABLE:
|
| 493 |
return None
|
| 494 |
payload = {
|
|
|
|
| 495 |
"content": content,
|
| 496 |
"classifier_verdicts": {k: v for k, v in model_results.items() if v},
|
| 497 |
"web_evidence": [
|
| 498 |
-
{
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 499 |
],
|
| 500 |
}
|
| 501 |
-
prompt = json.dumps(payload, ensure_ascii=False)[:
|
| 502 |
for model in GROQ_MODELS:
|
| 503 |
try:
|
| 504 |
response = GROQ_CLIENT.chat.completions.create(
|
|
@@ -508,7 +523,7 @@ def synthesize_verdict(content, model_results, evidence):
|
|
| 508 |
{"role": "user", "content": prompt},
|
| 509 |
],
|
| 510 |
temperature=0.2,
|
| 511 |
-
max_tokens=
|
| 512 |
response_format={"type": "json_object"},
|
| 513 |
)
|
| 514 |
data = parse_llm_json(response.choices[0].message.content)
|
|
@@ -628,6 +643,10 @@ def process_analysis(user_input, input_method, clf_political, clf_general):
|
|
| 628 |
|
| 629 |
st.write("π Checking claims across the web...")
|
| 630 |
result = run_analysis(text_to_analyze, clf_political, clf_general)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 631 |
|
| 632 |
analysis_time = time.time() - start_time
|
| 633 |
status.update(label="β
Analysis ready!", state="complete")
|
|
|
|
| 1 |
import os
|
| 2 |
+
import re
|
| 3 |
import json
|
| 4 |
import time
|
| 5 |
import requests
|
|
|
|
| 453 |
if not raw:
|
| 454 |
return None
|
| 455 |
text = raw.strip()
|
| 456 |
+
if "<think>" in text:
|
| 457 |
+
text = re.sub(r"<think>.*?</think>", "", text, flags=re.DOTALL).strip()
|
| 458 |
if text.startswith("```"):
|
| 459 |
text = text.strip("`")
|
| 460 |
if text.startswith("json"):
|
|
|
|
| 478 |
"app. You will receive a piece of content, two AI classifier verdicts with confidence "
|
| 479 |
"scores, and web search evidence. Your job is to decide how truthful the content is. "
|
| 480 |
"You are the final judge: your verdict overrides the classifier verdicts.\n"
|
| 481 |
+
"CRITICAL: The web evidence you are given is the ground truth. Base your verdict "
|
| 482 |
+
"primarily on it: if the evidence supports the claim, choose REAL; if it contradicts "
|
| 483 |
+
"the claim, choose FAKE; if no evidence was provided or it is genuinely insufficient, "
|
| 484 |
+
"choose UNKNOWN. You must never claim that evidence does not exist online β you can "
|
| 485 |
+
"only judge the evidence you were provided.\n"
|
| 486 |
+
"Pay attention to the current date you are given: events in the past are not future events.\n"
|
| 487 |
'Respond ONLY with a valid JSON object in this exact shape:\n'
|
| 488 |
'{"verdict": "REAL" or "FAKE" or "UNKNOWN", "confidence": <integer 0-100>, '
|
| 489 |
'"explanation": "<2-3 plain-language sentences>", '
|
|
|
|
| 501 |
if not GROQ_AVAILABLE:
|
| 502 |
return None
|
| 503 |
payload = {
|
| 504 |
+
"current_date": datetime.now().strftime("%B %d, %Y"),
|
| 505 |
"content": content,
|
| 506 |
"classifier_verdicts": {k: v for k, v in model_results.items() if v},
|
| 507 |
"web_evidence": [
|
| 508 |
+
{
|
| 509 |
+
"title": s["title"],
|
| 510 |
+
"url": s["url"],
|
| 511 |
+
"content": s["content"][:250],
|
| 512 |
+
}
|
| 513 |
+
for s in evidence
|
| 514 |
],
|
| 515 |
}
|
| 516 |
+
prompt = json.dumps(payload, ensure_ascii=False)[:7000]
|
| 517 |
for model in GROQ_MODELS:
|
| 518 |
try:
|
| 519 |
response = GROQ_CLIENT.chat.completions.create(
|
|
|
|
| 523 |
{"role": "user", "content": prompt},
|
| 524 |
],
|
| 525 |
temperature=0.2,
|
| 526 |
+
max_tokens=1100,
|
| 527 |
response_format={"type": "json_object"},
|
| 528 |
)
|
| 529 |
data = parse_llm_json(response.choices[0].message.content)
|
|
|
|
| 643 |
|
| 644 |
st.write("π Checking claims across the web...")
|
| 645 |
result = run_analysis(text_to_analyze, clf_political, clf_general)
|
| 646 |
+
if result.get("evidence"):
|
| 647 |
+
st.write(f"π Found {len(result['evidence'])} relevant sources")
|
| 648 |
+
else:
|
| 649 |
+
st.write("βΉοΈ No web results found β analysis based on AI review")
|
| 650 |
|
| 651 |
analysis_time = time.time() - start_time
|
| 652 |
status.update(label="β
Analysis ready!", state="complete")
|