"""MatrixAI model — try it here. Generated by MatrixAI as a template. It is yours: edit it freely. This app only READS what the package carries. It does not create repositories, upload files or ask for tokens. """ import json import subprocess import sys from pathlib import Path import gradio as gr AQUI = Path(__file__).resolve().parent def _junto_a_mi(nombre): """Busca en ESTA carpeta y en la de arriba. Dentro del paquete esta plantilla vive en `space/` y los artefactos están un nivel por encima. Publicado como Space, Hugging Face exige `app.py` en la RAÍZ y los artefactos acaban a su lado. Buscar en los dos sitios hace que el mismo fichero valga para los dos casos, en vez de tener dos versiones que acabarían divergiendo. """ for base in (AQUI, AQUI.parent): candidato = base / nombre if candidato.is_file(): return candidato return AQUI / nombre # Lo que el paquete YA trae. Si falta, se dice: una app que finge predecir # sobre un paquete incompleto es peor que una que explica qué falta. SPEC = _junto_a_mi("inference_spec.json") PREDICT = _junto_a_mi("predict.py") PAQUETE = PREDICT.parent # Un Space gratuito es CPU con tope de tiempo: probar el modelo cabe, # reproducirlo entero puede no caber. Se dice ARRIBA, no cuando ya se ha # agotado el tiempo. LIMITES = ( "This Space runs on free CPU with a time limit. Trying the model fits; " "rebuilding its dataset and training again may not. For that, download " "the package and run `matrixai verify . --retrain` on your own machine." ) def _campos(): if not SPEC.is_file(): return [] try: spec = json.loads(SPEC.read_text(encoding="utf-8")) except (OSError, ValueError): return [] entradas = spec.get("inputs") or spec.get("input_fields") or [] return [str(c.get("name") or c) for c in entradas if c] def verificar(): """El resultado de `matrixai verify`, DENTRO del Space. AUDITORÍA EXTERNA (2026-08-20) [BLOQUEANTE de cierre del C4]: la plantilla solo ejecutaba `predict.py`. El criterio de cierre del C4 pide que el Space **enseñe el resultado del C2**, y sin eso el Space invita a probar un modelo sin decir si el paquete está íntegro — que es justo lo contrario de para lo que existe una ficha ejecutable. Se ejecuta el `verify` del paquete y se enseña **su informe tal cual**: aquí no se interpreta nada. Si matrixai no está instalado en el Space, se dice — un botón que falla en silencio se lee como que no hay nada que comprobar. """ try: salida = subprocess.run( [sys.executable, "-m", "matrixai", "verify", str(PAQUETE)], capture_output=True, text=True, timeout=120, cwd=str(PAQUETE)) except FileNotFoundError: return ("matrixai is not installed in this Space, so integrity cannot " "be checked here. Run `matrixai verify .` after downloading.") except subprocess.TimeoutExpired: return "Verification took too long for a free CPU Space. " + LIMITES informe = (salida.stdout or "").strip() or (salida.stderr or "").strip() # Los tres códigos NO se colapsan, igual que en el CLI: 0 cuadra, # 2 alguien lo tocó, 3 no se pudo comprobar. veredicto = {0: "PASS — nothing failed", 2: "FAIL — something does not match what the package declares", 3: "NOT FULLY CHECKED — some stage could not be compared"}.get( salida.returncode, f"exit code {salida.returncode}") return f"{veredicto}\n\n{informe}" def predecir(*valores): if not PREDICT.is_file(): return "This package does not carry predict.py, so it cannot run here." campos = _campos() entrada = {n: v for n, v in zip(campos, valores)} try: salida = subprocess.run( [sys.executable, str(PREDICT), "--json", json.dumps(entrada)], capture_output=True, text=True, timeout=60, cwd=str(PAQUETE)) except subprocess.TimeoutExpired: return "It took too long for a free CPU Space. " + LIMITES if salida.returncode != 0: return f"predict.py failed:\n{salida.stderr[:2000]}" return salida.stdout.strip() or "(no output)" CAMPOS = _campos() with gr.Blocks() as demo: gr.Markdown("# Try this model") gr.Markdown(LIMITES) # LA INTEGRIDAD, ARRIBA Y ANTES DE PROBAR NADA. Un Space que invita a # predecir sin decir si el paquete cuadra convierte una ficha # ejecutable en una demo. gr.Markdown("## Is this package intact?") salida_verify = gr.Textbox(label="matrixai verify", lines=12) gr.Button("Verify this package").click(verificar, inputs=None, outputs=salida_verify) gr.Markdown("## Try it") if CAMPOS: entradas = [gr.Textbox(label=n) for n in CAMPOS] salida = gr.Textbox(label="Prediction") gr.Button("Predict").click(predecir, inputs=entradas, outputs=salida) else: gr.Markdown( "This package does not declare its input fields " "(`inference_spec.json` is missing or unreadable), so the form " "cannot be built. The model file is still here to download." ) if __name__ == "__main__": demo.launch()