Token Classification
spaCy
Spanish
named-entity-recognition
spanish
music
digital-humanities
historical-text
bert
Eval Results (legacy)
Instructions to use LexiMusUSAL/LexiMus-BETO-per-v1 with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- spaCy
How to use LexiMusUSAL/LexiMus-BETO-per-v1 with spaCy:
!pip install https://huggingface.co/LexiMusUSAL/LexiMus-BETO-per-v1/resolve/main/LexiMus-BETO-per-v1-any-py3-none-any.whl # Using spacy.load(). import spacy nlp = spacy.load("LexiMus-BETO-per-v1") # Importing as module. import LexiMus-BETO-per-v1 nlp = LexiMus-BETO-per-v1.load() - Notebooks
- Google Colab
- Kaggle
| #!/usr/bin/env python3 | |
| # -*- coding: utf-8 -*- | |
| """ | |
| cargar_modelo.py | |
| ──────────────── | |
| Ejemplo de uso completo de LexiMus-BETO-per-v1. | |
| Carga el modelo NER transformer + Entity Ruler desde CSV y aplica | |
| la inferencia sobre textos de prensa musical española histórica. | |
| Requisitos: | |
| pip install spacy>=3.8,<3.9 spacy-transformers | |
| Uso: | |
| python cargar_modelo.py | |
| python cargar_modelo.py --texto "Anoche actuó la Orquesta Nacional" | |
| python cargar_modelo.py --archivo mis_textos.txt | |
| """ | |
| import csv | |
| import argparse | |
| from pathlib import Path | |
| import spacy | |
| # ── Configuración ────────────────────────────────────────────────────────────── | |
| ETIQUETAS = {"COMPOSITOR", "INTERPRETE", "CANTANTE", "AGRUPACION"} | |
| COLORES_TERMINAL = { | |
| "COMPOSITOR": "\033[94m", # azul | |
| "INTERPRETE": "\033[93m", # amarillo | |
| "CANTANTE": "\033[92m", # verde | |
| "AGRUPACION": "\033[91m", # rojo | |
| "RESET": "\033[0m", | |
| } | |
| EJEMPLOS = [ | |
| "El maestro Arbós dirigió anoche la Orquesta Sinfónica de Madrid interpretando la Sinfonía en re menor de Beethoven.", | |
| "La soprano Conchita Supervía cosechó grandes ovaciones en el Teatro Real junto al tenor Miguel Fleta.", | |
| "El Cuarteto Francés, formado por los profesores Francés, Outumuro, Del Campo y Fontova, ofreció una sesión de música de cámara.", | |
| "Wagner ocupa un lugar central en el programa de la temporada, con la colaboración del Orfeón Pamplonés.", | |
| "Falla presentó su nuevo ballet ante un público entregado; la coreografía corrió a cargo de la compañía de Diaghilev.", | |
| ] | |
| # ── Funciones ────────────────────────────────────────────────────────────────── | |
| def cargar_patrones_csv(ruta_csv: Path) -> list: | |
| """Lee el CSV del Entity Ruler y devuelve lista de patrones spaCy.""" | |
| patrones = [] | |
| vistos = set() | |
| with open(ruta_csv, encoding="utf-8") as f: | |
| reader = csv.DictReader(f) | |
| for fila in reader: | |
| etq = fila["etiqueta"] | |
| if etq not in ETIQUETAS: | |
| continue | |
| textos_patron = {fila["texto"].strip()} | |
| if fila.get("variante_limpia", "").strip(): | |
| textos_patron.add(fila["variante_limpia"].strip()) | |
| notas = fila.get("notas", "") | |
| if "Apodo:" in notas: | |
| apodo = notas.split("Apodo:")[-1].split("|")[0].strip() | |
| if apodo: | |
| textos_patron.add(apodo) | |
| for t in textos_patron: | |
| if not t or len(t) < 2: | |
| continue | |
| clave = (t.lower(), etq) | |
| if clave in vistos: | |
| continue | |
| vistos.add(clave) | |
| patrones.append({"label": etq, "pattern": t}) | |
| return patrones | |
| def cargar_leximus(ruta_modelo: str | Path, ruta_csv: str | Path) -> spacy.language.Language: | |
| """ | |
| Carga el modelo LexiMus con Entity Ruler integrado. | |
| Args: | |
| ruta_modelo: Ruta al directorio del modelo spaCy (model-best/). | |
| ruta_csv: Ruta al archivo entidades_ner_leximus.csv. | |
| Returns: | |
| nlp: Pipeline spaCy listo para inferencia. | |
| """ | |
| ruta_modelo = Path(ruta_modelo) | |
| ruta_csv = Path(ruta_csv) | |
| if not ruta_modelo.exists(): | |
| raise FileNotFoundError(f"Modelo no encontrado: {ruta_modelo}") | |
| if not ruta_csv.exists(): | |
| raise FileNotFoundError(f"CSV de patrones no encontrado: {ruta_csv}") | |
| print(f"Cargando modelo desde {ruta_modelo}...") | |
| nlp = spacy.load(ruta_modelo) | |
| # Eliminar Entity Ruler previo (puede tener patrones desactualizados) | |
| if "entity_ruler" in nlp.component_names: | |
| nlp.remove_pipe("entity_ruler") | |
| patrones = cargar_patrones_csv(ruta_csv) | |
| ruler = nlp.add_pipe("entity_ruler", last=True, config={"overwrite_ents": False}) | |
| ruler.add_patterns(patrones) | |
| print(f"Sistema listo: NER transformer + Entity Ruler ({len(ruler)} patrones)") | |
| return nlp | |
| def analizar_texto(nlp: spacy.language.Language, texto: str, color: bool = True) -> list: | |
| """ | |
| Analiza un texto y devuelve las entidades musicales detectadas. | |
| Args: | |
| nlp: Pipeline cargado con cargar_leximus(). | |
| texto: Texto a analizar. | |
| color: Si True, imprime con colores ANSI en terminal. | |
| Returns: | |
| Lista de dicts con keys: texto, etiqueta, inicio, fin. | |
| """ | |
| doc = nlp(texto) | |
| entidades = [ | |
| {"texto": e.text, "etiqueta": e.label_, "inicio": e.start_char, "fin": e.end_char} | |
| for e in doc.ents if e.label_ in ETIQUETAS | |
| ] | |
| if color: | |
| print(f"\nTexto: {texto[:100]}{'...' if len(texto) > 100 else ''}") | |
| if entidades: | |
| for e in entidades: | |
| c = COLORES_TERMINAL.get(e["etiqueta"], "") | |
| r = COLORES_TERMINAL["RESET"] | |
| print(f" {c}[{e['etiqueta']}]{r} {e['texto']}") | |
| else: | |
| print(" (sin entidades detectadas)") | |
| return entidades | |
| def analizar_archivo(nlp: spacy.language.Language, ruta: str) -> None: | |
| """Analiza cada línea no vacía de un archivo de texto.""" | |
| ruta = Path(ruta) | |
| lineas = [l.strip() for l in ruta.read_text(encoding="utf-8").splitlines() if l.strip()] | |
| print(f"\nAnalizando {len(lineas)} textos de {ruta.name}...") | |
| total_ents = 0 | |
| for linea in lineas: | |
| ents = analizar_texto(nlp, linea) | |
| total_ents += len(ents) | |
| print(f"\nTotal: {total_ents} entidades detectadas en {len(lineas)} textos.") | |
| # ── Main ─────────────────────────────────────────────────────────────────────── | |
| def main(): | |
| parser = argparse.ArgumentParser(description="LexiMus NER - inferencia sobre texto musical español") | |
| parser.add_argument("--modelo", default=".", help="Ruta al directorio del modelo (por defecto: directorio actual)") | |
| parser.add_argument("--csv", default="entidades_ner_leximus.csv", help="Ruta al CSV del Entity Ruler") | |
| parser.add_argument("--texto", help="Texto a analizar directamente") | |
| parser.add_argument("--archivo", help="Archivo .txt con un texto por línea") | |
| args = parser.parse_args() | |
| nlp = cargar_leximus(args.modelo, args.csv) | |
| if args.texto: | |
| analizar_texto(nlp, args.texto) | |
| elif args.archivo: | |
| analizar_archivo(nlp, args.archivo) | |
| else: | |
| # Ejecutar ejemplos por defecto | |
| print("\n── Ejemplos de inferencia ─────────────────────────────────────────") | |
| for ejemplo in EJEMPLOS: | |
| analizar_texto(nlp, ejemplo) | |
| if __name__ == "__main__": | |
| main() | |