finagents-demo / scripts /eval_demo.py
ghostof0days's picture
Deploy FinAgents demo
ab13359 verified
Raw
History Blame Contribute Delete
3.4 kB
import json
import os
from pathlib import Path
from typing import Dict, Iterable, List, Tuple
def _read_jsonl(path: Path) -> List[Dict[str, str]]:
rows: List[Dict[str, str]] = []
with path.open("r", encoding="utf-8") as f:
for line in f:
line = line.strip()
if not line:
continue
rows.append(json.loads(line))
return rows
def _normalize(s: str) -> str:
return " ".join((s or "").strip().lower().split())
def _token_f1(pred: str, gold: str) -> float:
"""
Lightweight similarity: token-level F1 (good enough for Buffett-style free text).
"""
p = _normalize(pred).split()
g = _normalize(gold).split()
if not p and not g:
return 1.0
if not p or not g:
return 0.0
from collections import Counter
pc = Counter(p)
gc = Counter(g)
common = pc & gc
tp = sum(common.values())
precision = tp / max(1, len(p))
recall = tp / max(1, len(g))
if precision + recall == 0:
return 0.0
return 2 * precision * recall / (precision + recall)
def _exact_match(pred: str, gold: str) -> float:
return 1.0 if _normalize(pred) == _normalize(gold) else 0.0
def _iter_examples(rows: List[Dict[str, str]]) -> Iterable[Tuple[str, str]]:
for obj in rows:
# each line is a single-key dict: {prompt: answer}
if not obj:
continue
[(prompt, answer)] = list(obj.items())
yield prompt, answer
def main():
"""
Evaluate adapter vs base on the bundled example sets.
Requirements:
- GPU recommended
- HF_TOKEN set if BASE is gated (Llama 3.1)
Usage:
HF_TOKEN=... python scripts/eval_demo.py
"""
# Import after env is set.
import extract
root = Path(__file__).resolve().parents[1]
exdir = root / "example_data"
# Map example file -> adapter key (matches app.py hidden "Model" input)
suites = [
("buffett_example.jsonl", "buffett", _token_f1),
("buffett_ma_example.jsonl", "buffett_ma", _token_f1),
("ner_example.jsonl", "ner", _exact_match),
("xbrl_term_example.jsonl", "xbrl_term", _exact_match),
]
# Allow small/quick eval
limit = int(os.getenv("EVAL_LIMIT", "25"))
print(f"Base model: {extract.BASE_MODEL_ID}")
print(f"Limit per suite: {limit}")
print("")
for filename, adapter_key, metric in suites:
path = exdir / filename
if not path.exists():
print(f"[skip] missing {filename}")
continue
rows = _read_jsonl(path)
examples = list(_iter_examples(rows))[:limit]
base_scores: List[float] = []
ft_scores: List[float] = []
for prompt, gold in examples:
base = extract._generate(prompt, adapter_key=None, max_new_tokens=220)
ft = extract._generate(prompt, adapter_key=adapter_key, max_new_tokens=220)
base_scores.append(metric(base, gold))
ft_scores.append(metric(ft, gold))
base_avg = sum(base_scores) / max(1, len(base_scores))
ft_avg = sum(ft_scores) / max(1, len(ft_scores))
print(f"{filename} (adapter={adapter_key})")
print(f" base avg: {base_avg:.3f}")
print(f" ft avg: {ft_avg:.3f}")
print(f" delta : {ft_avg - base_avg:+.3f}")
print("")
if __name__ == "__main__":
main()