# ics.py import re import yaml import pandas as pd import unicodedata import textwrap PAIR_RE = re.compile(r"```yaml[^\n]*\n(.*?)```", re.S | re.I) def _normalize_unicode(text: str) -> str: return unicodedata.normalize("NFKC", text) def _pairs_dataframe(md: str) -> pd.DataFrame: rows = [] for raw in PAIR_RE.findall(md): bloc = yaml.safe_load(raw) if isinstance(bloc, dict) and "pair" in bloc: rows.append(bloc["pair"]) return pd.DataFrame(rows) def _fill(segment: str, pair: dict) -> str: segment = _normalize_unicode(segment) for k, v in pair.items(): val = f"{v:.2f}" if isinstance(v, (int, float)) else str(v) segment = re.sub( rf"{{{{\s*{re.escape(k)}\s*}}}}", val, segment, flags=re.I, ) segment = re.sub( r"ICS\s*=\s*[-+]?\d+(?:\.\d+)?", f"ICS = {pair['ics']:.2f}", segment, count=1, ) return segment def _segments(md: str): blocs = list(PAIR_RE.finditer(md)) for i, match in enumerate(blocs): pair = yaml.safe_load(match.group(1))["pair"] start = match.end() end = blocs[i + 1].start() if i + 1 < len(blocs) else len(md) segment = md[start:end] yield pair, segment def _pivot(df: pd.DataFrame) -> str: out = [] for min_, g in df.groupby("minerai"): out += [f"## {min_}", "| Composant | ICS | Faisabilité technique | Délai d'implémentation | Impact économique |", "| :-- | :--: | :--: | :--: | :--: |"] for _, r in g.sort_values("ics", ascending=False).iterrows(): out += [f"| {r.composant} | {r.ics:.2f} | {r.f_tech:.2f} | " f"{r.delai:.2f} | {r.cout:.2f} |"] out.append("") return "\n".join(out) def _synth(df: pd.DataFrame) -> str: lignes = ["| Composant | Minerai | ICS |", "| :-- | :-- | :--: |"] for _, r in df.sort_values("ics", ascending=False).iterrows(): lignes.append(f"| {r.composant} | {r.minerai} | {r.ics:.2f} |") return "\n".join(lignes) def build_dynamic_sections(md_raw: str) -> str: md_raw = _normalize_unicode(md_raw) df = _pairs_dataframe(md_raw) if df.empty: return md_raw couples = ["# Criticité par couple Composant -> Minerai"] for pair, seg in _segments(md_raw): if pair: couples.append(_fill(seg, pair)) couples_md = "\n".join(couples) pivot_md = _pivot(df) synth_md = _synth(df) md = re.sub(r"#\s+Criticité par couple.*", couples_md, md_raw, flags=re.S | re.I) md = re.sub(r".*?", f"\n{pivot_md}\n", md, flags=re.S) md = re.sub(r".*?", f"\n{synth_md}\n", md, flags=re.S) return textwrap.dedent(md)