"""Genera wiki/figures/.md da raw/immagini.json. Nessun riassunto: ogni campo del catalogo viene riportato. Uso: python scripts/gen_figures.py (rigenera tutto; le note sono derivate, non si modificano a mano).""" import json from pathlib import Path root = Path(__file__).resolve().parent.parent cat = json.loads((root / "raw/immagini.json").read_text(encoding="utf8")) out = root / "wiki/figures" out.mkdir(parents=True, exist_ok=True) # --- pagine della wiki che usano ciascuna figura (link [[fig-...]] o embed del file), per la navigazione inversa --- import re as _re0 _file2id = {pn["file"][:-4]: f["id"] for k in ("figures",) for f in cat[k] for pn in f["panels"]} _file2id.update({pn["file"][:-4]: f["id"] for f in cat.get("riassunto", {}).get("figures", []) for pn in f["panels"]}) used_by = {} for _p in sorted((root / "wiki").rglob("*.md")): if "figures" in _p.parts or _p.name in ("figure-indice.md", "bibliografia.md"): continue _t = _p.read_text(encoding="utf8").split("---", 2)[-1] _ids = set(_re0.findall(r"\[\[((?:ris-)?fig-[\w-]+)", _t)) _ids |= {_file2id[h] for h in _re0.findall(r"!\[\[immagini/([0-9a-f]{64})", _t) if h in _file2id} for _i in _ids: used_by.setdefault(_i, set()).add(_p.stem) def usage(fid): pages = sorted(used_by.get(fid, ())) return ["## Pagine che la usano", " · ".join(f"[[{x}]]" for x in pages) if pages else "nessuna", ""] def q(s): return json.dumps(str(s), ensure_ascii=False) def lst(xs): return "[" + ", ".join(q(x) for x in xs) + "]" for f in cat["figures"]: loc, qual = f["location"], f["quality"] f["label"] = f.get("label") or f["id"] # figure senza numero stampato v = qual.get("verification") or {} tesi_loc = f"§{loc['section']} r.{loc['md_line']}" fm = [ "---", f"title: {q(' - '.join(x for x in (f['label'], f.get('title') or f.get('caption_printed')) if x))}", "type: figure", f"id: {f['id']}", f"tipo: {f['type']}", f"capitolo: {q(loc['chapter'])}", f"sezione: {q(loc['section'])}", f"tesi_loc: {q(tesi_loc)}", f"composti: {lst(f.get('compounds', []))}", f"concetti: {lst(f.get('concepts', []))}", f"keywords: {lst(f.get('keywords', []))}", f"confidence: {qual['confidence']}", f"flags: {lst(qual.get('flags', []))}", f"verifica: {v.get('verdict', 'n/d')}", "derivata: true", "---", "", ] body = [f"# {f['label']}", ""] body += [f"**Didascalia stampata (testo della tesi):** {f.get('caption_printed') or 'n/d'}", ""] cap = f", didascalia r.{loc['caption_md_line']}" if loc.get("caption_md_line") else "" body += [f"_Posizione: tesi.md {tesi_loc} (sezione {loc['section']} {loc['section_title']}){cap}_", ""] if "caption_mismatch" in qual.get("flags", []): body += ["> ⚠ Flag `caption_mismatch`: la didascalia stampata qui sopra è quella attribuita dal catalogo e potrebbe non descrivere l'immagine (vedi «Didascalia generata» e «Da verificare»).", ""] body += ["> Sotto: contenuto generato guardando l'immagine, non verificato una per una.", ""] body += [f"**Didascalia generata:** {f['caption']}", ""] for p in f["panels"]: body += [p["embed"], ""] body += [f"- Pannello: {p['panel'] or 'unico'} · file `{p['file']}` · {p['width']}×{p['height']} · confidence {p['confidence']}"] body += [f"- Descrizione: {p['description']}"] body += ["- Testo visibile: " + (" · ".join(p["visible_text"]) or "n/d")] if p.get("quality_flags"): body += ["- Flag: " + ", ".join(p["quality_flags"])] body += [""] if f.get("text_context"): body += ["## Contesto nel testo", f["text_context"], ""] if f.get("cited_in_md_lines"): body += ["Citata in tesi.md alle righe: " + ", ".join(map(str, f["cited_in_md_lines"])), ""] if qual.get("review_notes"): body += ["## Da verificare", qual["review_notes"], ""] if v.get("issues"): body += ["Esito revisione indipendente: " + "; ".join(v["issues"]), ""] body += usage(f["id"]) body += ["## Collegamenti", "- [[tesi]]", ""] (out / f"{f['id']}.md").write_text("\n".join(fm + body), encoding="utf8") # --- figure del riassunto di tesi (chiave "riassunto" di immagini.json): note ris-fig-NN.md --- ris = cat.get("riassunto", {}).get("figures", []) for f in ris: qual = f["quality"] fm = [ "---", f"title: {q(' - '.join(x for x in (f['label'], f.get('title')) if x))}", "type: figure", f"id: {f['id']}", f"tipo: {f['type']}", 'documento: "riassunto"', f"tesi_loc: {q('riassunto r.' + str(f['location']['md_line']))}", f"composti: {lst(f.get('compounds', []))}", f"concetti: {lst(f.get('concepts', []))}", f"keywords: {lst(f.get('keywords', []))}", f"confidence: {qual['confidence']}", f"flags: {lst(qual.get('flags', []))}", "derivata: true", "---", "", ] loc = f["location"] body = [f"# {f['label']} (riassunto di tesi)", ""] body += [f"**Didascalia stampata (testo del riassunto):** {f['caption_printed']}", ""] body += [f"_Posizione: riassunto_tesi.md r.{loc['md_line']}, didascalia r.{loc['caption_md_line']}_", ""] body += ["> Sotto: contenuto generato guardando l'immagine, non verificato una per una.", ""] body += [f"**Didascalia generata:** {f['caption']}", ""] for p in f["panels"]: body += [p["embed"], ""] body += [f"- Pannello: {p['panel'] or 'unico'} · file `{p['file']}` · {p['width']}×{p['height']} · confidence {p['confidence']}"] body += [f"- Descrizione: {p['description']}"] body += ["- Testo visibile: " + (" · ".join(p["visible_text"]) or "n/d")] if p.get("quality_flags"): body += ["- Flag: " + ", ".join(p["quality_flags"])] body += [""] if f.get("text_context"): body += ["## Contesto nel testo", f["text_context"], ""] if f.get("cited_in_md_lines"): body += ["Citata in riassunto_tesi.md alle righe: " + ", ".join(map(str, f["cited_in_md_lines"])), ""] if f.get("thesis_equivalents"): body += ["## Corrispondenze nella tesi"] body += [f"- [[{e['id']}]] — {e['relation']} (verifica: {e['verified']})" for e in f["thesis_equivalents"]] + [""] if qual.get("review_notes"): body += ["## Da verificare", qual["review_notes"], ""] body += usage(f["id"]) body += ["## Collegamenti", "- [[riassunto-tesi]] · [[riassunto-vs-tesi]]", ""] (out / f"{f['id']}.md").write_text("\n".join(fm + body), encoding="utf8") print(f"{len(cat['figures'])} note in {out}") print(f"{len(ris)} note del riassunto in {out}") # --- wiki/figure-indice.md: indice derivato (sezione -> figure) --- import re as _re def _clean(s): return _re.sub(r"<[^>]+>", "", s or "").strip() idx = ["---", "title: Indice delle figure", "type: overview", "tags: [figure, indice, navigazione]", "created: 2026-10-15", "updated: 2026-10-15", 'tesi_loc: "r.73-1301 (didascalie)"', "derivata: true", "status: draft", "---", "", "# Indice delle figure", "", f"Le {len(cat['figures'])} figure del catalogo raggruppate per sezione della tesi, più le {len(cat.get('riassunto', {}).get('figures', []))} del riassunto di tesi in fondo (generata da `raw/immagini.json`: non modificare a mano). " "Ogni voce rimanda alla nota della figura; ⚠ = figura con flag o note di revisione. Matrice campioni × tecniche: [[campioni]]; tabelle: [[tabelle-indice]].", ""] by_sec = {} for f in cat["figures"]: by_sec.setdefault(f["location"]["section"], []).append(f) for s in cat["sections"]: figs = by_sec.get(s["number"], []) if not figs: continue idx += [f"## §{s['number']} {_clean(s['title'])}"] for f in figs: warn = " ⚠" if (f["quality"].get("flags") or f["quality"].get("review_notes")) else "" if f["number"]: idx.append(f"- [[{f['id']}|Fig. {f['number']}]] — {_clean(f['title'])} _({f['type']})_{warn}") else: idx.append(f"- [[{f['id']}|schema]] — {_clean(f['caption'])} _({f['type']})_{warn}") idx.append("") if ris: idx += ["## Riassunto di tesi", ""] for f in ris: warn = " ⚠" if (f["quality"].get("flags") or f["quality"].get("review_notes")) else "" idx.append(f"- [[{f['id']}|Fig. {f['number']}]] — {_clean(f['title'])} _({f['type']})_{warn}") idx.append("") idx += ["## Collegamenti", "- [[index]] · [[tesi]] · [[campioni]] · [[tabelle-indice]]", ""] (root / "wiki/figure-indice.md").write_text("\n".join(idx), encoding="utf8") print("figure-indice.md generato")