JoseMSL's picture
Upload 5 files
5520989 verified
|
Raw
History Blame Contribute Delete
8.4 kB
metadata
title: MSL Internal API Joint
emoji: 🎻
colorFrom: purple
colorTo: pink
sdk: docker
app_port: 7860
pinned: false
license: other

bert-api-v8-joint/

Backend Python Flask que sirve el joint intent + slot filling model entregado por RMIT en Parts 5+6 (PDF Part5_Part6, mayo 2026). Arquitectura distinta a v6/v7-part6: en lugar de un único clasificador AutoModelForSequenceClassification, monta una clase custom JointIntentSlotModel(nn.Module) con dos heads sobre AutoModel — uno para intent, otro para BIO slot labels por token.

Origen: copiado de D:\XDev.Projects\MEHEARSAL-NLP-CONTROLLER-RMIT\Part_5_6\bert-api\bert-api-01 (versión D — defensiva/híbrida del análisis del doc 40 §3.2) + 4 modificaciones para HF Spaces Docker (ver §"Adaptaciones" más abajo).

Despliegue actual: HuggingFace Space MuseSceneLab/msl-internal-api-v8-intent (Docker SDK). Ver doc 40 §5.2.1 + §6 Fase A.1-A.7.

Nota sobre la convención de nombres: la carpeta local se llama bert-api-v8-joint/ (refleja la arquitectura técnica — joint intent + slot model). El Space en HF se llama msl-internal-api-v8-intent (refleja la convención MSL vN-{focus} por consistencia con msl-internal-api-v7-part6). El env var BERT_V8_INTENT_API_URL y el route /api/classify-bert-v8-intent siguen el nombre del Space.

Modelo HF: MuseSceneLab/part-5-6-model — 21 intents musicales (sin generic MUTE/SOLO/LOOP en el dataset, aunque INTENT_METADATA los conserva por compat) + slot filling BIO (O, B-instrument, I-instrument, B-section, B-bpm, B-bar, B-percent, B-style).

Nota sobre el frontmatter YAML del principio: lo leen los Spaces de HuggingFace para configurar el deploy (título, SDK, puerto). app_port: 7860 es crítico — sin él HF no sabe qué puerto exponer y el Space queda en "config error". En cualquier otro contexto (lectura local, repo de GitHub) el frontmatter se ignora o se renderiza como bloque inicial.

Despliegue futuro: AWS App Runner cuando se cumplan los disparadores de doc 33 §13.4.


Estructura

bert-api/
├── bert_api.py           Flask app. Carga modelo en arranque, expone /classify y /health
├── requirements.txt      flask, flask-cors, transformers, torch, huggingface_hub, python-dotenv
├── Dockerfile            Imagen para HF Spaces. Python 3.11-slim, expone 7860
├── .dockerignore         Excluye venv, __pycache__, README, etc. de la imagen
└── README.md             Este archivo

Endpoints

Método Path Body Devuelve
POST /classify { "utterance": "mute the guitar" } { intent_label, locale, target, params_json, confidence, model, slots }
GET /health { status, model, hf_model, num_intents, num_slots }

Diferencias del shape de respuesta vs v6/v7-part6

Campo v6/v7-part6 (single-task) v8-joint (este Space)
confidence 0-100 (percentage, round(c*100, 2)) 0-1 (fraction, round(c, 4)) — el frontend debe formatear como (c * 100).toFixed(2) antes de mostrar, y el mapConfidence() del proxy /api/classify-bert-joint/route.ts debe usar umbrales 0.80 / 0.50 (no 80 / 50)
model "DistilBERT" "DistilBERT-Joint-v6"
slots (no existe) { "guitar": "B-instrument", "4": "B-bar" } — diccionario palabra → BIO label. Vacío {} si no hay slots
/health extras (nada) hf_model, num_intents, num_slots

Variables de entorno

Var Default Para qué
HF_TOKEN (obligatorio) Auth para descargar el modelo privado de HF. En HF Spaces se configura como Secret del Space
BERT_MODEL_NAME MuseSceneLab/part-5-6-model Cambiar para forzar otro joint model. Solo modelos joint compatibles — un modelo single-task aquí rompería el model.load_state_dict() porque la clase JointIntentSlotModel espera dos heads (intent_head, slot_head) y un label_maps.json con id2intent + id2slot
PORT 7860 Puerto. Para gunicorn en el Dockerfile se hardcodea a 7860 en el flag --bind. Para Flask local (python bert_api.py) se lee de aquí

Servidor: gunicorn en producción, Flask dev en local

El Dockerfile lanza el backend con gunicorn (WSGI server productivo):

gunicorn --bind 0.0.0.0:7860 --workers 2 --preload --timeout 120 bert_api:app
  • --workers 2: 2 procesos paralelos (CPU Basic free de HF Spaces tiene 2 vCPU).
  • --preload: carga el modelo una vez antes de fork, los workers comparten memoria via COW. Sin esto, cada worker cargaría su copia y duplicaríamos memoria.
  • --timeout 120: si una inferencia se cuelga, mata el worker y arranca otro. Default 30s es demasiado bajo para casos límite con torch.

Para desarrollo local rápido (iteración sobre bert_api.py sin tener que reconstruir imagen), el bloque if __name__ == '__main__' con app.run() sigue funcionando — basta con python bert_api.py. Esto NO se ejecuta en Spaces porque gunicorn importa bert_api:app directamente, sin pasar por __main__.


Desarrollo local

cd bert-api
python -m venv venv
.\venv\Scripts\activate            # Windows PowerShell: .\venv\Scripts\Activate.ps1
pip install -r requirements.txt
$env:HF_TOKEN = "hf_..."           # tu token con permiso de lectura sobre el modelo
python bert_api.py

Levanta en http://localhost:7860. Probar con:

curl -X POST http://localhost:7860/classify -H "Content-Type: application/json" -d '{"utterance":"mute the guitar"}'

Nota: la primera ejecución descarga el modelo (500 MB) desde HF a la caché local (`/.cache/huggingface/`). Ejecuciones posteriores son instantáneas.


Despliegue como Space (proceso R4-R7 de doc 33)

  1. Crear Space en huggingface.co/new-space:

    • Owner: MuseSceneLab
    • Name: msl-internal-api-v8-intent
    • SDK: Docker (template Blank — usamos nuestro Dockerfile)
    • Hardware: CPU Basic (free)
    • Visibility: Public (el contenedor; los pesos del modelo siguen privados)
    • License: other (decisión doc 34 §D1 — IP de MSL)
  2. En el Space, ir a Settings → Repository secrets → añadir HF_TOKEN con el token mehearsal-read de Jose.

  3. Subir los 4 archivos vía Web UI (drag & drop en Files → Add file → Upload files): bert_api.py, Dockerfile, requirements.txt, README.md.

  4. HF construye la imagen (~3-5 min). El cold start del Space joint puede ser más lento que el de v6/v7-part6 porque snapshot_download() descarga el modelo entero la primera vez (en lugar del lazy load de AutoModelForSequenceClassification.from_pretrained()). Verificar logs en la UI del Space.

  5. URL pública: https://musescenelab-msl-internal-api-v8-intent.hf.space/classify.


Adaptaciones respecto al código fuente

Fuente: Part_5_6/bert-api/bert-api-01 del repo MEHEARSAL-NLP-CONTROLLER-RMIT (rama part_5_6) — versión D del análisis del doc 40 §3.2.

Cuatro diffs vs ese fuente:

  1. Import os al principio del archivo.
  2. HF_MODEL_NAME configurable vía env var (default MuseSceneLab/part-5-6-model).
  3. Porting de carga LOCAL → carga HF Hub: el fuente D carga el modelo desde nlp_v5/best_joint_model/ (directorio local relativo al script). Sustituido por snapshot_download(repo_id=HF_MODEL_NAME, repo_type="model") para que HF Spaces descargue del Hub. Patrón tomado de la versión C (Part_5_6/bert-api/bert_api.py).
  4. Puerto y debug en app.run(): puerto leído de env var PORT (default 7860, requisito de Spaces), debug=False para producción.

La lógica de JointIntentSlotModel, INTENT_METADATA (21 intents), extract_entities() con params_json computado por intent, el intent upgrade hack heredado de v5, y la extracción slot-first + regex fallback queda intacta. Esta es la "versión defensiva" (D) decidida en doc 40 §3.2.1 frente a la "versión limpia según PDF Part 6" (C).


Roadmap

  • Ahora: HF Spaces Docker (este folder = código fuente, sin cambios entre dev local y prod Space)
  • Futuro: migración a AWS App Runner. Ver doc 33 §13. El Dockerfile actual sirve igual sin cambios.