chore: regroupement des scripts de patch dans patches/
This commit is contained in:
@@ -0,0 +1,182 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
patch_facilitator_c1.py — Chantier C1 (Encoder structuré)
|
||||
=========================================================
|
||||
Patch strict de facilitator_v9.py :
|
||||
P1. Config : ajoute ENCODER_MODE (.env, défaut 'agent' — rien ne change
|
||||
tant que ENCODER_MODE=schema n'est pas posé).
|
||||
P2. Insère run_encoder_schema() avant la section FREE DESIGNER
|
||||
(même contrat de retour que run_encoder, fallback agent intégré).
|
||||
P3. Dispatch dans run_full_pipeline_pass (pipeline + révisions).
|
||||
P4. Dispatch dans le flux standard (fallback agent en mode express :
|
||||
le plan Narrator n'y est pas annoté SLIDE N — layout).
|
||||
|
||||
Usage (dossier du pipeline, single-line) :
|
||||
python3 patch_facilitator_c1.py
|
||||
Vérifie chaque ancre (présence + unicité), écrit facilitator_v9.py.bak,
|
||||
compile le résultat. Idempotent : refuse de patcher deux fois.
|
||||
"""
|
||||
|
||||
import py_compile
|
||||
import shutil
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
TARGET = Path("facilitator_v9.py")
|
||||
|
||||
FUNC = '''
|
||||
def run_encoder_schema(plan: str, layouts: dict, proj: "Project"):
|
||||
"""Encoder structuré (chantier C1) : chat/completions + json_schema
|
||||
strict Mistral, slide par slide. Même contrat de retour que
|
||||
run_encoder : (yaml_str, data, path, attempts) — attempts = nb de
|
||||
slides en échec. Fallback automatique sur l'Encoder agent si le
|
||||
module manque ou si aucune slide n'est encodée."""
|
||||
section("ÉTAPE 3 — THE ENCODER (structured outputs)")
|
||||
try:
|
||||
import encoder_schema as enc
|
||||
except ImportError as e:
|
||||
warn(f"encoder_schema.py indisponible ({e}) — bascule mode agent.")
|
||||
return run_encoder(AgentSession(ENCODER_ID), plan, layouts, proj)
|
||||
try:
|
||||
import schemas as sch
|
||||
for issue in (sch.verify_against_layouts(layouts) if layouts else []):
|
||||
warn(f"Schéma vs layouts_v2 : {issue}")
|
||||
except ImportError:
|
||||
warn("schemas.py absent — vérification de cohérence sautée.")
|
||||
info(f"Encodage slide par slide ({enc.DEFAULT_MODEL}, temp 0)...")
|
||||
data, usage, errors = enc.encode_plan(plan, API_KEY, progress=info)
|
||||
nb = len(data.get("slides", []))
|
||||
ok(f"{nb} slides encodées — tokens : {usage.get('total_tokens', 0)} "
|
||||
f"(prompt {usage.get('prompt_tokens', 0)} / "
|
||||
f"completion {usage.get('completion_tokens', 0)})")
|
||||
for e in errors:
|
||||
warn(e)
|
||||
if not nb:
|
||||
warn("Aucune slide encodée — bascule mode agent.")
|
||||
return run_encoder(AgentSession(ENCODER_ID), plan, layouts, proj)
|
||||
yaml_str = enc.to_yaml(data)
|
||||
is_valid, message, _ = validate_yaml(yaml_str, layouts)
|
||||
if is_valid:
|
||||
ok(f"YAML valide : {message}")
|
||||
else:
|
||||
warn(f"Validation : {message}")
|
||||
if errors:
|
||||
print("\\n [1] Continuer sans les slides en échec")
|
||||
print(" [2] Basculer sur l'Encoder agent (deck complet)")
|
||||
print(" [0] Abandonner")
|
||||
choix = ask("Votre choix :")
|
||||
if choix == "2":
|
||||
return run_encoder(AgentSession(ENCODER_ID), plan, layouts, proj)
|
||||
if choix == "0":
|
||||
return None, None, None, len(errors)
|
||||
path = save_text(yaml_str, proj.out("input", "yaml"))
|
||||
return yaml_str, data, path, len(errors)
|
||||
|
||||
'''
|
||||
|
||||
PATCHES = [
|
||||
# P1 — config
|
||||
(
|
||||
'ENCODER_ID = os.getenv("ENCODER_AGENT_ID")\n',
|
||||
'ENCODER_ID = os.getenv("ENCODER_AGENT_ID")\n'
|
||||
'ENCODER_MODE = os.getenv("ENCODER_MODE", "agent")'
|
||||
' # agent | schema (C1)\n',
|
||||
),
|
||||
# P3 — dispatch pipeline pass (révisions comprises)
|
||||
(
|
||||
' encoder = AgentSession(ENCODER_ID)\n'
|
||||
' yaml_str, yaml_data, yaml_path, tries = run_encoder(\n'
|
||||
' encoder, plan, layouts, proj, scope_encoder)\n',
|
||||
' if ENCODER_MODE == "schema":\n'
|
||||
' yaml_str, yaml_data, yaml_path, tries = '
|
||||
'run_encoder_schema(\n'
|
||||
' plan, layouts, proj)\n'
|
||||
' else:\n'
|
||||
' encoder = AgentSession(ENCODER_ID)\n'
|
||||
' yaml_str, yaml_data, yaml_path, tries = run_encoder(\n'
|
||||
' encoder, plan, layouts, proj, scope_encoder)\n',
|
||||
),
|
||||
# P4 — dispatch flux standard (express → agent)
|
||||
(
|
||||
' encoder = AgentSession(ENCODER_ID)\n'
|
||||
' yaml_str, yaml_data, yaml_path, tries = run_encoder(\n'
|
||||
' encoder, plan, layouts, proj)\n'
|
||||
' manifest.step("encoder", tentatives_correction=tries)\n'
|
||||
' if yaml_str is None:\n'
|
||||
' if express:\n',
|
||||
' if ENCODER_MODE == "schema" and not express:\n'
|
||||
' yaml_str, yaml_data, yaml_path, tries = '
|
||||
'run_encoder_schema(\n'
|
||||
' plan, layouts, proj)\n'
|
||||
' else:\n'
|
||||
' if ENCODER_MODE == "schema" and express:\n'
|
||||
' info("Mode express → Encoder agent '
|
||||
'(plan non annoté).")\n'
|
||||
' encoder = AgentSession(ENCODER_ID)\n'
|
||||
' yaml_str, yaml_data, yaml_path, tries = run_encoder(\n'
|
||||
' encoder, plan, layouts, proj)\n'
|
||||
' manifest.step("encoder", tentatives_correction=tries)\n'
|
||||
' if yaml_str is None:\n'
|
||||
' if express:\n',
|
||||
),
|
||||
]
|
||||
|
||||
MARKER = "run_encoder_schema"
|
||||
ANCHOR_SECTION = "# FLUX LIBRE — THE FREE DESIGNER"
|
||||
|
||||
|
||||
def fail(msg):
|
||||
print(" ! %s" % msg)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def main():
|
||||
if not TARGET.exists():
|
||||
fail("%s introuvable — lancer depuis le dossier du pipeline."
|
||||
% TARGET)
|
||||
for dep in ("schemas.py", "encoder_schema.py"):
|
||||
if not Path(dep).exists():
|
||||
fail("%s manquant à côté du facilitator." % dep)
|
||||
content = TARGET.read_text(encoding="utf-8")
|
||||
if MARKER in content:
|
||||
fail("Déjà patché (run_encoder_schema présent) — rien à faire.")
|
||||
|
||||
# Vérification de toutes les ancres AVANT toute écriture
|
||||
for i, (old, _) in enumerate(PATCHES, 1):
|
||||
n = content.count(old)
|
||||
if n == 0:
|
||||
fail("Ancre du patch %d introuvable — facilitator inattendu."
|
||||
% i)
|
||||
if n > 1:
|
||||
fail("Ancre du patch %d non unique (%d occurrences)." % (i, n))
|
||||
if content.count(ANCHOR_SECTION) != 1:
|
||||
fail("Ancre de section FREE DESIGNER introuvable ou non unique.")
|
||||
|
||||
shutil.copy2(TARGET, TARGET.with_suffix(".py.bak"))
|
||||
print(" + Sauvegarde : %s.bak" % TARGET)
|
||||
|
||||
for old, new in PATCHES:
|
||||
content = content.replace(old, new)
|
||||
|
||||
# P2 — insertion de la fonction avant le séparateur de la section
|
||||
lines = content.split("\n")
|
||||
idx = next(i for i, l in enumerate(lines) if ANCHOR_SECTION in l)
|
||||
ins = idx - 1 if lines[idx - 1].startswith("# ───") else idx
|
||||
lines[ins:ins] = FUNC.split("\n")
|
||||
content = "\n".join(lines)
|
||||
|
||||
TARGET.write_text(content, encoding="utf-8")
|
||||
print(" + 4 patchs appliqués.")
|
||||
try:
|
||||
py_compile.compile(str(TARGET), doraise=True)
|
||||
print(" + Compilation OK.")
|
||||
except py_compile.PyCompileError as e:
|
||||
shutil.copy2(TARGET.with_suffix(".py.bak"), TARGET)
|
||||
fail("Erreur de compilation — fichier restauré :\n%s" % e)
|
||||
print("\n Activer : ajouter ENCODER_MODE=schema dans .env")
|
||||
print(" Retour arrière : ENCODER_MODE=agent (ou supprimer la ligne).")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user