morphos / scripts /hub.py
Jose Salazar
Distribución del corpus RAG vía Hub privado y horneado de modelos
aa0d853
Raw
History Blame Contribute Delete
3.81 kB
"""Publicación y descarga de los artefactos RAG en repos privados del Hub.
Se usa la API de Python (`huggingface_hub`) y no el CLI `hf` a propósito: en la versión instalada
(1.16.1) el CLI arrastra una incompatibilidad typer/click que hace que `ctx.exit()` propague un
`click.exceptions.Exit(0)` como traceback y **devuelva código 1 aunque la operación haya ido
bien**. Eso es inservible dentro de un Makefile, donde un exit≠0 aborta la cadena.
Artefactos:
- índice (~70 MB): derivado de libros con licencia, contiene su texto troceado → repo PRIVADO.
- libros (~226 MB): los PDF originales → repo PRIVADO, sólo necesarios para reingerir.
Uso:
python scripts/hub.py publish-index
python scripts/hub.py fetch-index
python scripts/hub.py publish-books
"""
from __future__ import annotations
import argparse
import json
import sys
from pathlib import Path
from huggingface_hub import HfApi, snapshot_download
RAIZ = Path(__file__).resolve().parents[1]
DIR_INDICE = RAIZ / "instance" / "rag_index"
DIR_LIBROS = RAIZ / "books"
REPO_INDICE = "blackmistcode/morphos-rag-index"
REPO_LIBROS = "blackmistcode/morphos-books"
def _asegurar_repo(api: HfApi, repo_id: str) -> None:
"""Crea el repo si falta. `private=True` sólo aplica en la creación: si el repo ya existe
NO lo vuelve privado, así que se comprueba explícitamente y se aborta si es público."""
api.create_repo(repo_id=repo_id, repo_type="dataset", private=True, exist_ok=True)
if not api.dataset_info(repo_id).private:
sys.exit(
f"ABORTADO: {repo_id} es PÚBLICO. Contiene material con licencia; hazlo privado "
f"antes de subir nada."
)
def publicar_indice() -> None:
if not DIR_INDICE.exists():
sys.exit(f"ERROR: no existe {DIR_INDICE}. Ejecuta 'make ingest' primero.")
manifiesto = json.loads((DIR_INDICE / "manifest.json").read_text(encoding="utf-8"))
hash_corpus = manifiesto.get("hash_corpus", "desconocido")
api = HfApi()
_asegurar_repo(api, REPO_INDICE)
api.upload_folder(
repo_id=REPO_INDICE,
repo_type="dataset",
folder_path=str(DIR_INDICE),
commit_message=f"Índice RAG · corpus {hash_corpus} · {manifiesto.get('n_fragmentos')} fragmentos",
)
print(f"OK: índice publicado en {REPO_INDICE} (corpus {hash_corpus})")
def descargar_indice() -> None:
DIR_INDICE.mkdir(parents=True, exist_ok=True)
snapshot_download(
repo_id=REPO_INDICE,
repo_type="dataset",
local_dir=str(DIR_INDICE),
)
manifiesto = DIR_INDICE / "manifest.json"
if manifiesto.exists():
m = json.loads(manifiesto.read_text(encoding="utf-8"))
print(f"OK: índice descargado · corpus {m.get('hash_corpus')} · {m.get('n_fragmentos')} fragmentos")
else:
print("AVISO: descargado sin manifest.json; el índice puede estar incompleto.")
def publicar_libros() -> None:
pdfs = sorted(DIR_LIBROS.glob("*.pdf"))
if not pdfs:
sys.exit(f"ERROR: no hay PDFs en {DIR_LIBROS}.")
api = HfApi()
_asegurar_repo(api, REPO_LIBROS)
api.upload_folder(
repo_id=REPO_LIBROS,
repo_type="dataset",
folder_path=str(DIR_LIBROS),
allow_patterns=["*.pdf"],
commit_message=f"Corpus veterinario con licencia ({len(pdfs)} PDF)",
)
print(f"OK: {len(pdfs)} libros publicados en {REPO_LIBROS}")
def main() -> None:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("accion", choices=["publish-index", "fetch-index", "publish-books"])
args = parser.parse_args()
{
"publish-index": publicar_indice,
"fetch-index": descargar_indice,
"publish-books": publicar_libros,
}[args.accion]()
if __name__ == "__main__":
main()