-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathrender_silhouettes.py
More file actions
116 lines (93 loc) · 3.85 KB
/
Copy pathrender_silhouettes.py
File metadata and controls
116 lines (93 loc) · 3.85 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
#!/usr/bin/env python3
"""Render the silhouettes as readable Markdown.
Top 15: detailed profile (categories, divisions, top subjects).
The rest: short summary table.
"""
from __future__ import annotations
from datetime import date
from pathlib import Path
import yaml
CAT_LABELS = {
"social": "Social (old-age/disability/pension/health insurance)",
"civil": "Civil (contracts/companies/liability)",
"civil_famille": "Civil (family/succession/debt enforcement)",
"public": "Public/administrative/tax",
"penal": "Criminal",
"penal_federal": "Federal criminal (TPF)",
"other": "Other",
}
CAT_ORDER = ["social", "civil", "civil_famille", "public", "penal", "penal_federal", "other"]
def bar(n: int, total: int, width: int = 20) -> str:
if total == 0:
return ""
filled = int(round(n / total * width))
return "█" * filled + "░" * (width - filled)
def render_lawyer(lw: dict) -> str:
n = lw["n_hits"]
out = []
out.append(f"### {lw['name']} ({lw['kanton']}, {lw['partei']}) — {n} decisions\n")
cats = lw.get("by_category") or {}
if cats:
out.append("**Silhouette by legal matter**")
out.append("")
out.append("```")
for cat in CAT_ORDER:
if cat not in cats:
continue
c = cats[cat]
pct = c / n * 100
label = CAT_LABELS.get(cat, cat)
out.append(f" {label:<42} {bar(c, n)} {c:>3} ({pct:>4.1f}%)")
out.append("```")
out.append("")
subjects = lw.get("top_subjects") or []
if subjects:
out.append(f"**Top recurring subjects** (out of {lw.get('n_subjects_extracted', 0)} extracted)")
out.append("")
for s in subjects[:10]:
out.append(f"- {s['subject']} *(×{s['n']})*")
out.append("")
return "\n".join(out)
def main() -> int:
data = yaml.safe_load(Path("data/analysis/silhouettes.yaml").read_text())
lawyers = data["lawyers"]
generated_at = data.get("generated_at") or date.today().isoformat()
md = []
md.append("# LobbyLex — practice silhouettes")
md.append("")
md.append(f"*Generated on {generated_at} from {len(lawyers)} lawyers "
f"and {sum(l['n_hits'] for l in lawyers)} decisions (Phase 1: TF + TPF).*")
md.append("")
md.append("**Method**: zero LLM. The legal matter comes from the procedure code in the "
"decision_id (5A, 4A, 6B, 8C, 9C, I, U, K… per the TF/TFA nomenclature). "
"The subject comes from the `Objet` / `Gegenstand` / `Oggetto` field extracted by regex "
"over the first 5000 characters of each decision.")
md.append("")
top = [l for l in lawyers if l["n_hits"] >= 10]
rest = [l for l in lawyers if 0 < l["n_hits"] < 10]
zeros = [l for l in lawyers if l["n_hits"] == 0]
md.append(f"## Detailed profiles (≥ 10 decisions) — {len(top)} lawyers")
md.append("")
for lw in top:
md.append(render_lawyer(lw))
md.append(f"## Short profiles (1-9 decisions) — {len(rest)} lawyers")
md.append("")
md.append("| Lawyer | Canton | Party | n | Categories |")
md.append("|---|---|---|---|---|")
for lw in rest:
cats = lw.get("by_category") or {}
cat_str = ", ".join(f"{CAT_LABELS.get(c, c).split(' ')[0].lower()}={n}" for c, n in cats.items())
md.append(f"| {lw['name']} | {lw['kanton']} | {lw['partei']} | {lw['n_hits']} | {cat_str} |")
md.append("")
md.append(f"## No hit in Phase 1 — {len(zeros)} lawyers")
md.append("")
md.append("To re-test in Phase 2 (TAF/cantonal extension + DE post-fix pattern).")
md.append("")
md.append(", ".join(l["name"] for l in zeros))
md.append("")
out = Path("data/analysis/silhouettes.md")
out.write_text("\n".join(md))
print(f"→ {out}")
return 0
if __name__ == "__main__":
raise SystemExit(main())