estrela-rome-v2 / scripts /ai_runner.py
mrj-crom's picture
Upload folder using huggingface_hub
28d5f26 verified
Raw
History Blame Contribute Delete
5.64 kB
"""
AI RUNNER ÚNICO — executa receitas YAML de QUALQUER família de IA e produz
saída padronizada: output/ai_runs/<stamp>_<nome>/{resultados.json, ANALISE_IA.md, ledger.sha256}
python3 scripts/ai_runner.py --receita data/receitas_ia/llm_cego.yaml
python3 scripts/ai_runner.py --receita ... --dry # mostra passos sem rodar
Princípios: zero-mock (passos reais, saída hashada) · hardware no meta ·
falha de passo aborta a receita e registra no JSON.
"""
import argparse
import datetime
import hashlib
import json
import os
import platform
import subprocess
import sys
from pathlib import Path
ROOT = Path(__file__).resolve().parent.parent
SAIDA_RAIZ = ROOT / "output" / "ai_runs"
def sha256_file(p):
h = hashlib.sha256()
with open(p, "rb") as f:
for chunk in iter(lambda: f.read(1 << 20), b""):
h.update(chunk)
return h.hexdigest()
def deep_get(d, caminho):
cur = d
for parte in caminho.split("."):
if not isinstance(cur, dict):
return None
cur = cur.get(parte)
return cur
def main():
ap = argparse.ArgumentParser()
ap.add_argument("--receita", required=True)
ap.add_argument("--hardware", default=None,
help="cpu_local | gpu_vast (default: detecta pelo local do runner)")
ap.add_argument("--dry", action="store_true")
args = ap.parse_args()
try:
import yaml
except ImportError:
sys.exit("[ERRO] pip install pyyaml")
rec = yaml.safe_load(Path(args.receita).read_text(encoding="utf-8"))
stamp = datetime.datetime.now(datetime.timezone.utc).strftime("%Y%m%d_%H%M%S")
hardware = args.hardware or ("gpu_vast" if os.environ.get("VAST_INSTANCE") else "cpu_local")
run_dir = SAIDA_RAIZ / f"{stamp}_{rec['nome']}_{hardware}"
run_dir.mkdir(parents=True, exist_ok=True)
print("=" * 76)
print(f"🧪 RECEITA {rec['nome']} ({rec['familia']}) · hardware={hardware}")
print(f"Artefatos: {run_dir}")
print("=" * 76)
resultados = {
"receita": rec["nome"], "familia": rec["familia"],
"versao": str(rec.get("versao", "1")), "hardware": hardware,
"host_fingerprint": platform.node(),
"timestamp_utc": stamp, "passos": {}, "erro": None,
}
for passo in rec.get("passos", []):
pid = passo["id"]
cmd = " ".join(passo["cmd"].split())
print(f"\n──[{pid}] {passo.get('desc','')}\n $ {cmd}")
if args.dry:
continue
proc = subprocess.run(cmd, shell=True, cwd=ROOT,
capture_output=True, text=True, timeout=60 * 60 * 12)
(run_dir / f"{pid}.log").write_text(proc.stdout[-20000:] + "\n|ERR|\n" + proc.stderr[-5000:])
if proc.returncode != 0:
resultados["erro"] = f"passo {pid} falhou (rc={proc.returncode})"
print(f" ✗ ABORTADO — ver {run_dir}/{pid}.log")
break
saidas = {}
for glob_s in passo.get("saida_glob", []):
import glob as _g
hits = sorted(_g.glob(str(ROOT / glob_s)))
if hits:
mais_novo = max(hits, key=os.path.getmtime)
alvo = run_dir / Path(mais_novo).name
alvo.write_text(Path(mais_novo).read_text(encoding="utf-8"))
saidas[str(glob_s)] = {"arquivo": Path(mais_novo).name,
"sha256": sha256_file(mais_novo)[:16]}
try:
saidas["dados"] = json.loads(alvo.read_text(encoding="utf-8"))
except Exception:
pass
resultados["passos"][pid] = {"rc": 0, "saidas": saidas}
print(f" ✓ ok → coletado(s): {list(saidas) or 'nenhum'}")
# métricas-chave extraídas dos dados coletados
metricas = {}
for m in rec.get("metricas_chave", []):
for pid, info in resultados["passos"].items():
valor = deep_get(info.get("saidas", {}).get("dados", {}), m)
if valor is not None:
metricas[f"{pid}.{m}"] = valor
resultados["metricas"] = metricas
verdicto_tpl = rec.get("veredito_auto")
resultados["veredito_auto"] = verdicto_tpl if not args.dry else "(dry-run)"
(run_dir / "resultados.json").write_text(
json.dumps(resultados, indent=2, ensure_ascii=False), encoding="utf-8")
linhas_hash = [f"{sha256_file(run_dir / f)} {f}"
for f in ["resultados.json"] + sorted(
p.name for p in run_dir.glob("*.log"))]
chain = hashlib.sha256("\n".join(linhas_hash).encode()).hexdigest()
(run_dir / "ledger.sha256").write_text("\n".join(linhas_hash) + f"\n{chain} CHAIN_SHA256\n")
analise = [f"# ANALISE_IA — {rec['nome']} ({hardware}) `{stamp}`\n",
f"- Receita v{resultados['versao']} · chain `{chain[:16]}`",
f"- Métricas-chave: ```json\n{json.dumps(metricas, indent=2)}```",
f"- Erro: {resultados['erro'] or 'nenhum'}\n",
"| Passo | rc | Saídas hashadas |\n|---|---|---|"]
for pid, info in resultados["passos"].items():
analise.append(f"| {pid} | {info['rc']} | "
+ "; ".join(f"{k}:{v['sha256'][:8]}" for k, v in
info["saidas"].items() if k != "dados") + " |")
(run_dir / "ANALISE_IA.md").write_text("\n".join(analise), encoding="utf-8")
print("\n" + "=" * 76)
print(f"📊 MÉTRICAS: {json.dumps(metricas, ensure_ascii=False)}")
print(f"🔗 CHAIN: {chain[:16]}… · ANALISE_IA.md pronto em {run_dir}")
print("=" * 76)
if __name__ == "__main__":
main()