#!/usr/bin/env python3 """54_publicar_v050.py — Publicação da v0.5.0 no HF (UM ÚNICO upload_folder organizado — o HF bloqueia envios parciais em sequência e em curto espaço de tempo; uma única operação atômica evita o bloqueio). Token: EXCLUSIVAMENTE via variável de ambiente HF_TOKEN (nunca escrito em arquivo). Após o upload: verificação + APAGAMENTO dos estados de treino remanescentes (nenhum deve existir) + relatório. """ import os, sys ARQUIVOS_EXCLUIR_DIRS = {"target", ".cargo", "__pycache__", ".git"} ARQUIVOS_EXCLUIR_NOME = {"shard_treino.jsonl", "shard_validacao.jsonl"} # checkpoints/estados NUNCA publicados (regeneráveis via scripts 51/40) SUFIxOS_ESTADO = (".pt", ".pth", ".ckpt", ".safetensors", ".bin", ".npz", ".msgpack") NOMES_ESTADO = {"gerador_conceitos.json", "tokenizador_conceitos.json"} def coletar(pasta): arquivos = {} for raiz, dirs, fs in os.walk(pasta): dirs[:] = [d for d in dirs if d not in ARQUIVOS_EXCLUIR_DIRS] for f in fs: if f in ARQUIVOS_EXCLUIR_NOME or f in NOMES_ESTADO: continue if f.endswith(SUFIxOS_ESTADO): continue if f.endswith(".so") or f == ".gitignore": continue caminho = os.path.join(raiz, f) rel = os.path.relpath(caminho, pasta) arquivos[rel] = caminho return arquivos def main(): from huggingface_hub import HfApi token = os.environ.get("HF_TOKEN") if not token: print("ERRO: HF_TOKEN ausente"); sys.exit(1) api = HfApi(token=token) repo = "PowerMachine/khtst-rust" pasta = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) arquivos = coletar(pasta) print(f"publicando {len(arquivos)} arquivos em {repo} (upload ÚNICO)") total_mb = sum(os.path.getsize(p) for p in arquivos.values()) / 1e6 print(f"tamanho total: {total_mb:.1f} MB") # verificação final: o VALOR EXATO do token não pode estar em nenhum # arquivo (menções TEXTUAIS a "HF_TOKEN" como conceito são legítimas) token_bytes = token.encode() for rel, p in arquivos.items(): try: with open(p, "rb") as f: if token_bytes in f.read(): print(f"ERRO: token encontrado em {rel}"); sys.exit(1) except OSError: pass print("varredura de token: limpo") # UM ÚNICO upload_folder (atómico) api.upload_folder( repo_id=repo, repo_type="model", folder_path=pasta, ignore_patterns=[ "target/*", ".cargo/*", "__pycache__/*", "*.so", ".gitignore", "dados/shard_*.jsonl", "resultados/gerador_conceitos.json", "resultados/tokenizador_conceitos.json", "*.pt", "*.ckpt", "*.safetensors", "*.bin", "*.npz", ], commit_message="v0.5.0: suíte SOM-4D + suíte JEPA (12) + tecnologia Pensamento + telemetria Theil–Sen — 29/29 gates verdes (provas r-18..r-22)", ) print("upload concluído") # verificação pós-upload files = api.list_repo_files(repo_id=repo, repo_type="model") print(f"repo agora tem {len(files)} arquivos") estados = [f for f in files if f.endswith(SUFIxOS_ESTADO) or f.split("/")[-1] in NOMES_ESTADO] print(f"estados de treino no repo: {len(estados)} {estados if estados else '(limpo)'}") # garante que os novos módulos estão lá for chave in ("src/som4d.rs", "src/jepa.rs", "src/pensamento.rs", "src/rng.rs", "docs/memorias/r-22-resultados-telemetria-v050.md", "scripts/53_suite_v050.py"): print(f" {'OK ' if chave in files else 'FALTA'} {chave}") print("PUBLICACAO_OK") if __name__ == "__main__": main()