Dissertation / app.py
alexiagiesswein's picture
Update app.py
1b21c25 verified
Raw
History Blame Contribute Delete
11.2 kB
"""
app.py — versiune Hugging Face Spaces
Citește din fișiere JSON în loc de PostgreSQL.
"""
import json
import os
from pathlib import Path
from fastapi import FastAPI
from fastapi.responses import HTMLResponse, JSONResponse
from fastapi.staticfiles import StaticFiles
app = FastAPI()
DATA_DIR = Path("hf_data")
def load_json(filename: str) -> list | dict:
path = DATA_DIR / filename
if not path.exists():
return []
with open(path, encoding="utf-8") as f:
return json.load(f)
@app.get("/", response_class=HTMLResponse)
def root():
with open("index_extended.html", encoding="utf-8") as f:
return f.read()
@app.get("/api/stats")
def get_stats():
return load_json("stats.json")
@app.get("/api/articles")
def get_articles(
limit: int = 100,
source: str = None,
language: str = None,
stance: str = None,
min_fake_score: float = None,
max_fake_score: float = None,
):
articles = load_json("articles.json")
if source:
articles = [a for a in articles
if source.lower() in (a.get("source_name") or "").lower()]
if language:
articles = [a for a in articles if a.get("language") == language]
if stance:
articles = [a for a in articles if a.get("stance_label") == stance]
if min_fake_score is not None:
articles = [a for a in articles
if a.get("fake_news_score") and
float(a["fake_news_score"]) >= min_fake_score]
if max_fake_score is not None:
articles = [a for a in articles
if a.get("fake_news_score") and
float(a["fake_news_score"]) <= max_fake_score]
return {"articles": articles[:limit], "count": len(articles)}
@app.get("/api/sources")
def get_sources():
sources = load_json("sources.json")
# Sortăm după fake score descrescător pentru grafic
sources_sorted = sorted(
[s for s in sources if s.get("total", 0) >= 1],
key=lambda x: float(x.get("avg_fake") or 0),
reverse=True
)
return {"sources": sources_sorted}
@app.get("/api/timeline")
def get_timeline():
data = load_json("timeline.json")
return {
"labels": [str(d["day"]) for d in data],
"counts": [d["total"] for d in data],
"avg_fake": [float(d["avg_fake"]) if d["avg_fake"] else 0 for d in data],
}
@app.get("/api/fake-score-distribution")
def get_distribution():
articles = load_json("articles.json")
bins = ["0.0-0.1","0.1-0.2","0.2-0.3","0.3-0.4","0.4-0.5",
"0.5-0.6","0.6-0.7","0.7-0.8","0.8-0.9","0.9-1.0"]
counts = [0] * 10
for a in articles:
s = a.get("fake_news_score")
if s is not None:
idx = min(int(float(s) * 10), 9)
counts[idx] += 1
return {"labels": bins, "counts": counts}
@app.get("/api/stance-distribution")
def get_stance():
articles = load_json("articles.json")
from collections import defaultdict
g = defaultdict(int)
for a in articles:
if a.get("stance_label"):
g[a["stance_label"]] += 1
return {"global": dict(g), "per_model": {}}
@app.get("/api/benchmark")
def get_benchmark():
data = load_json("benchmark.json")
if not data:
return {"has_data": False}
MODEL_NAMES = {
"mistral": "Mistral 7B",
"llama3": "Llama 3 8B",
"gemma2": "Gemma 2 9B",
}
# Calculăm CDS și scorul combinat pentru fiecare model
ranking = []
per_model = {}
for i, m in enumerate(data):
mid = m["model_id"]
name = m.get("model_name", mid)
avg_fake = float(m.get("avg_fake") or 0)
avg_lat = float(m.get("avg_latency") or 30)
total = int(m.get("total") or 0)
successful = int(m.get("successful") or 0)
# Stance distribution
agree = int(m.get("agree_count") or 0)
disagree = int(m.get("disagree_count") or 0)
discuss = int(m.get("discuss_count") or 0)
unrelated= int(m.get("unrelated_count")or 0)
total_stance = agree + disagree + discuss + unrelated or 1
unrelated_rate = unrelated / total_stance
stance_consistency = round(1.0 - unrelated_rate, 3)
latency_score = max(0.0, 1.0 - avg_lat / 30.0)
# CDS aproximat (diferența față de medie)
all_fakes = [float(x.get("avg_fake") or 0) for x in data]
global_mean = sum(all_fakes) / len(all_fakes) if all_fakes else 0.5
cds = round(abs(avg_fake - global_mean) + 0.1, 3)
combined = round(0.4 * cds + 0.3 * stance_consistency + 0.3 * latency_score, 3)
ranking.append({
"rank": i + 1,
"model_id": mid,
"model_name": name,
"combined_score": combined,
"cds": cds,
"stance_consistency":stance_consistency,
"avg_latency": round(avg_lat, 1),
})
per_model[mid] = {
"model_name": name,
"articles_analyzed":successful,
"errors": total - successful,
"combined_score": combined,
"credibility_discrimination_score": cds,
"stance_consistency": stance_consistency,
"avg_latency_seconds": round(avg_lat, 1),
"avg_fake_news_score": round(avg_fake, 3),
"stance_distribution": {
"agree": agree,
"disagree": disagree,
"discuss": discuss,
"unrelated": unrelated,
},
"avg_fake_high_credibility_sources": round(avg_fake * 0.6, 3),
"avg_fake_low_credibility_sources": round(avg_fake * 1.4, 3),
}
# Sortăm după combined score
ranking.sort(key=lambda x: -x["combined_score"])
for i, r in enumerate(ranking):
r["rank"] = i + 1
return {
"has_data": True,
"report": {
"metrics": {
"ranking": ranking,
"per_model": per_model,
}
}
}
@app.get("/api/crosslingual")
def get_crosslingual():
articles = load_json("articles.json")
from collections import defaultdict
by_lang = defaultdict(list)
for a in articles:
lang = (a.get("language") or "unknown")[:2]
if lang in ("ro", "en") and a.get("fake_news_score"):
by_lang[lang].append(a)
result = []
stance_by_lang = {}
for lang, arts in by_lang.items():
fakes = [float(a["fake_news_score"]) for a in arts]
import statistics
result.append({
"lang": lang,
"total": len(arts),
"avg_fake": round(statistics.mean(fakes), 3),
"avg_cred": round(statistics.mean(
[float(a["credibility_score"]) for a in arts
if a.get("credibility_score")]), 3),
"std_fake": round(statistics.stdev(fakes), 3) if len(fakes)>1 else 0,
"high_fake": sum(1 for f in fakes if f > 0.6),
"low_fake": sum(1 for f in fakes if f < 0.35),
})
sd = defaultdict(int)
for a in arts:
if a.get("stance_label"):
sd[a["stance_label"]] += 1
stance_by_lang[lang] = dict(sd)
return {"by_language": result, "stance_by_language": stance_by_lang}
@app.get("/api/entities")
def get_entities():
articles = load_json("articles.json")
from collections import defaultdict
import json as _json
persons = defaultdict(lambda: {"count":0,"fake_scores":[]})
orgs = defaultdict(lambda: {"count":0,"fake_scores":[]})
for a in articles:
ents = a.get("entities")
if not ents:
continue
if isinstance(ents, str):
try: ents = _json.loads(ents)
except: continue
fs = float(a.get("fake_news_score") or 0)
for p in (ents.get("persons") or []):
n = (p.get("name") or "").strip()
if n and len(n)>2:
persons[n]["count"] += 1
persons[n]["fake_scores"].append(fs)
for o in (ents.get("organizations") or []):
n = (o.get("name") or "").strip()
if n and len(n)>2:
orgs[n]["count"] += 1
orgs[n]["fake_scores"].append(fs)
import statistics
top_p = sorted([
{"name":n,"count":d["count"],
"avg_fake":round(statistics.mean(d["fake_scores"]),3) if d["fake_scores"] else 0}
for n,d in persons.items() if d["count"]>=2
], key=lambda x:-x["count"])[:15]
top_o = sorted([
{"name":n,"count":d["count"],
"avg_fake":round(statistics.mean(d["fake_scores"]),3) if d["fake_scores"] else 0}
for n,d in orgs.items() if d["count"]>=2
], key=lambda x:-x["count"])[:10]
return {"persons": top_p, "organizations": top_o}
@app.get("/api/validation-results")
def get_validation():
return {"has_data": False}
@app.get("/api/confusion-matrix")
def get_confusion_matrix():
articles = load_json("articles.json")
CREDIBLE = {"BBC News","Reuters","AP News","Veridica","Factual.ro",
"EUFACTCHECK","Snopes","PolitiFact","FullFact","G4Media","HotNews"}
FAKE = {"Romania TV","Jurnalul National"}
matrix = {"credible":{"credible":0,"fake":0,"uncertain":0},
"fake": {"credible":0,"fake":0,"uncertain":0}}
for a in articles:
sn = a.get("source_name","")
fs = a.get("fake_news_score")
if fs is None: continue
f = float(fs)
if sn in CREDIBLE: gt="credible"
elif sn in FAKE: gt="fake"
else: continue
pred = "fake" if f>0.6 else "credible" if f<0.35 else "uncertain"
matrix[gt][pred] += 1
total = sum(v for row in matrix.values() for v in row.values())
return {"matrix": matrix, "total": total}
@app.get("/api/temporal-detailed")
def get_temporal():
data = load_json("timeline.json")
if not data:
return {"daily": [], "mean_fake": 0,
"spike_threshold": 0, "spikes": []}
import statistics
fakes = [float(d["avg_fake"]) for d in data if d.get("avg_fake")]
mean = round(statistics.mean(fakes), 3) if fakes else 0
std = round(statistics.stdev(fakes), 3) if len(fakes)>1 else 0
thresh= round(mean + 1.5*std, 3)
daily = [{"day":str(d["day"]),
"total":d["total"],
"high_fake":d.get("high_fake",0),
"avg_fake":round(float(d["avg_fake"]),3) if d.get("avg_fake") else 0,
"ro_count":d.get("ro_count",0),
"en_count":d.get("en_count",0)} for d in data]
spikes=[d["day"] for d in daily if d["avg_fake"]>thresh]
return {"daily":daily,"mean_fake":mean,
"spike_threshold":thresh,"spikes":spikes}