File size: 6,995 Bytes
094b8e7
 
7eea4b4
094b8e7
7eea4b4
 
 
094b8e7
96a4177
ebc1354
96a4177
 
e829bfc
96a4177
 
 
 
 
 
 
05db690
 
094b8e7
 
 
96a4177
094b8e7
 
 
05db690
 
7eea4b4
96a4177
05db690
96a4177
 
05db690
96a4177
 
094b8e7
 
05db690
 
 
094b8e7
05db690
094b8e7
05db690
 
094b8e7
 
05db690
094b8e7
96a4177
 
 
094b8e7
 
7eea4b4
 
 
 
ebc1354
 
96a4177
ebc1354
7eea4b4
 
 
 
 
 
 
 
 
96a4177
 
 
 
 
 
 
 
 
 
 
094b8e7
 
 
96a4177
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
094b8e7
 
05db690
094b8e7
 
 
 
 
 
 
05db690
96a4177
05db690
96a4177
05db690
 
 
 
96a4177
 
 
 
ebc1354
96a4177
ebc1354
 
7eea4b4
 
 
 
ebc1354
 
7eea4b4
96a4177
 
ebc1354
96a4177
ebc1354
 
96a4177
 
ebc1354
 
 
 
7eea4b4
ebc1354
96a4177
05db690
 
96a4177
 
 
05db690
 
094b8e7
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""Publica o AURORA v7 no HuggingFace de modo ORGANIZADO e COMPLETO:

  README.md (model card v7 COM GRÁFICOS DE DESEMPENHO) · LICENSE · configs/ ·
  src/aurora/ · scripts/ · docs/matematica/ (provas 00–18) · tests/ · evidências
  de treino/avaliação/comparação · estados/fase-v7/ (pesos finais + meta SHA-256)

REGRAS DO HUB (escopo v5): publicação em UM ÚNICO COMMIT COMPLETO —
`upload_folder` com `delete_patterns=["*"]` substitui ATOMICAMENTE todo o
conteúdo do repo (arquivos antigos somem no MESMO commit; nunca há uploads
parciais em sequência curta — o Hub bloqueia esse padrão).

SEGURANÇA: token EXCLUSIVAMENTE da variável HF_TOKEN — nunca gravado em
arquivo, log ou repo. A publicação NUNCA inclui: cache_dados, telemetria_out,
estados_local, stage_publicar, arquivos com o token.

Verificações de porta do Agente Engenheiro (pré-publicação):
  • nenhum segredo no stage (regex hf_[A-Za-z0-9]{30,});
  • nenhum resíduo proibido (bugwatch, estados_hf, __pycache__, .pt).

Uso:  HF_TOKEN=... python3 06_publicar_hf.py [--repo PowerMachine/aurora-multimodal-ptbr]
"""
import argparse
import os
import re
import shutil
import sys

RAIZ = "/home/z/my-project/aurora"
STAGE = "/home/z/my-project/aurora/stage_publicar"
PASTA_ESTADO = "estados/fase-v7"   # ÚNICO estado publicado (pesos finais)
IGNORAR_DIRS = {"__pycache__", "cache_dados", "telemetria_out",
                "cache_hub_tmp", ".git", "build", "estados_local",
                "estados_local_teste", "stage_publicar", "hf_stage",
                "download", "upload"}
IGNORAR_EXT = (".pt", ".pyc", ".pt.tmp")
PADRAO_TOKEN = re.compile(r"hf_[A-Za-z0-9]{30,}")
RESIDUOS_PROIBIDOS = ("bugwatch", "estados_hf")


def preparar_stage() -> int:
    if os.path.exists(STAGE):
        shutil.rmtree(STAGE)
    n = 0
    for raiz, dirs, arquivos in os.walk(RAIZ):
        dirs[:] = [d for d in dirs if d not in IGNORAR_DIRS]
        rel = os.path.relpath(raiz, RAIZ)
        alvo_raiz = os.path.join(STAGE, rel) if rel != "." else STAGE
        os.makedirs(alvo_raiz, exist_ok=True)
        for a in arquivos:
            if a.endswith(IGNORAR_EXT) or a.startswith("."):
                continue
            if any(r in a.lower() for r in RESIDUOS_PROIBIDOS):
                print(f"  porta do Agente: arquivo proibido ignorado: {a}")
                continue
            shutil.copy2(os.path.join(raiz, a), os.path.join(alvo_raiz, a))
            n += 1
    # evidências de treino/avaliação (artefatos de 1ª classe, v7)
    for nome in ("avaliacao_v7.json", "resumo_treino_v7.json",
                 "relatorio_agente_engenheiro.json",
                 "comparacao_treino_v7.json", "test_aurora_v6_pos_treino.txt"):
        fonte = os.path.join(RAIZ, "telemetria_out", nome)
        if os.path.exists(fonte):
            shutil.copy2(fonte, os.path.join(STAGE, nome))
            n += 1
    # v7 — GRÁFICOS DE DESEMPENHO (publicados APENAS no card HF — README.md)
    dir_graf = os.path.join(RAIZ, "graficos")
    if os.path.isdir(dir_graf):
        os.makedirs(os.path.join(STAGE, "graficos"), exist_ok=True)
        for a in sorted(os.listdir(dir_graf)):
            if a.endswith(".png"):
                shutil.copy2(os.path.join(dir_graf, a),
                             os.path.join(STAGE, "graficos", a))
                n += 1
    # ÚNICO estado (pesos finais) via GestorCheckpoints (doc 16 §8)
    sys.path.insert(0, os.path.join(RAIZ, "src"))
    from aurora.dados.checkpoints import GestorCheckpoints
    from aurora.config import Config
    gestor = GestorCheckpoints(dir_local=Config().checkpoints.dir_local,
                               pasta_publicacao=PASTA_ESTADO)
    if gestor.preparar_para_publicacao(STAGE):
        n += 2
        print(f"estado final incluído: {PASTA_ESTADO}/modelo.safetensors")
    else:
        print("AVISO: sem checkpoint local — publicando só código/docs")
    return n


def auditoria_segredos() -> list[str]:
    suspeitos = []
    for raiz, dirs, arquivos in os.walk(STAGE):
        for a in arquivos:
            if not a.endswith((".json", ".md", ".py", ".txt", ".yaml", ".yml")):
                continue
            caminho = os.path.join(raiz, a)
            try:
                with open(caminho, encoding="utf-8", errors="ignore") as f:
                    if PADRAO_TOKEN.search(f.read()):
                        suspeitos.append(caminho)
            except Exception:
                pass
    return suspeitos


def main():
    ap = argparse.ArgumentParser()
    ap.add_argument("--repo", default="PowerMachine/aurora-multimodal-ptbr")
    args = ap.parse_args()

    token = os.environ.get("HF_TOKEN")
    if not token:
        print("ERRO: defina HF_TOKEN no ambiente (nunca em arquivo).")
        sys.exit(1)

    n = preparar_stage()
    print(f"stage: {n} arquivos (sem caches/segredos/resíduos)")

    suspeitos = auditoria_segredos()
    if suspeitos:
        print("ERRO: possíveis segredos detectados:", suspeitos)
        sys.exit(1)

    from huggingface_hub import HfApi
    api = HfApi(token=token)
    api.create_repo(args.repo, repo_type="model", exist_ok=True, private=False)

    # PUBLICAÇÃO ÚNICA E COMPLETA: delete_patterns=["*"] remove no MESMO commit
    # qualquer arquivo antigo — nada de uploads parciais em sequência
    api.upload_folder(
        folder_path=STAGE, repo_id=args.repo, repo_type="model",
        commit_message="AURORA v7 — RETREINO OBSERVADO: estados antigos apagados; "
                       "treino do zero com monitor de RAM integral (Agente Engenheiro); "
                       "métricas de tests/test_aurora_v6.py comparadas com o treino "
                       "anterior; gráficos de desempenho publicados no card",
        delete_patterns=["*"],
        allow_patterns=["*.py", "*.md", "*.json", "*.yaml", "*.yml",
                        "*.txt", "*.png", "*.safetensors", "LICENSE*"])
    print("✓ PUBLICAÇÃO ÚNICA COMPLETA (1 commit; antigos removidos "
          "atomicamente)")

    # verificação final: resíduos proibidos não podem existir no repo
    arquivos = api.list_repo_files(args.repo, repo_type="model")
    restos = [f for f in arquivos
              if any(r in f.lower() for r in RESIDUOS_PROIBIDOS)
              or "__pycache__" in f or f.endswith(".pt")]
    if restos:
        print("ERRO: resíduos no repo:", restos)
        sys.exit(1)
    parciais = [f for f in arquivos if f.startswith("estados/")
                and "fase-v7" not in f]
    print(f"✓ verificação: {len(arquivos)} arquivos no repo; "
          f"resíduos=0; estados parciais={len(parciais)} (0 esperado)")

    print(f"REPO: https://huggingface.co/{args.repo}")
    print("Higienização: unset HF_TOKEN && python3 -m pip show huggingface_hub "
          ">/dev/null && python3 -c 'from huggingface_hub import HfApi; "
          "HfApi().logout()'")


if __name__ == "__main__":
    main()