arreglo de ui y busquedas

This commit is contained in:
jlimolina 2025-11-21 04:42:02 +01:00
parent cb8f69fb93
commit fc06566928
15 changed files with 1115 additions and 435 deletions

View file

@ -1,16 +1,12 @@
# embeddings_worker.py
# Worker de embeddings para TRADUCCIONES:
# - Lee traducciones con status='done' y sin embedding para un modelo concreto
# - Calcula embedding (Sentence-Transformers) sobre titulo_trad + resumen_trad
# - Guarda en traduccion_embeddings (traduccion_id, model, dim, embedding)
import os
import time
import logging
from typing import List
import numpy as np
import psycopg2
import psycopg2.extras
from psycopg2.extras import execute_values
from sentence_transformers import SentenceTransformer
import torch
@ -28,20 +24,20 @@ DB = dict(
# ---------- Parámetros de worker ----------
# Modelo por defecto: multilingüe, bueno para muchas lenguas
EMB_MODEL = os.environ.get(
EMB_MODEL = os.environ.get(
"EMB_MODEL",
"sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2",
"sentence-transformers/paraphrase-multilingual-mpnet-base-v2",
)
EMB_BATCH = int(os.environ.get("EMB_BATCH", "128"))
EMB_BATCH = int(os.environ.get("EMB_BATCH", "128"))
SLEEP_IDLE = float(os.environ.get("EMB_SLEEP_IDLE", "5.0"))
# Filtrado por idiomas destino (coma-separado). Por defecto sólo 'es'
EMB_LANGS = [s.strip() for s in os.environ.get("EMB_LANGS", "es").split(",") if s.strip()]
EMB_LANGS = [s.strip() for s in os.environ.get("EMB_LANGS", "es").split(",") if s.strip()]
# DEVICE_ENV: 'auto' | 'cpu' | 'cuda'
DEVICE_ENV = os.environ.get("DEVICE", "auto").lower()
# Límite por iteración (para no tragar toda la tabla de golpe)
EMB_LIMIT = int(os.environ.get("EMB_LIMIT", "1000"))
EMB_LIMIT = int(os.environ.get("EMB_LIMIT", "1000"))
# ---------- Utilidades ----------
@ -65,8 +61,13 @@ def ensure_schema(conn):
);
"""
)
cur.execute("CREATE INDEX IF NOT EXISTS idx_tr_emb_model ON traduccion_embeddings(model);")
cur.execute("CREATE INDEX IF NOT EXISTS idx_tr_emb_trid ON traduccion_embeddings(traduccion_id);")
# Alineado con init-db/08-embeddings.sql
cur.execute(
"CREATE INDEX IF NOT EXISTS idx_tr_emb_model ON traduccion_embeddings(model);"
)
cur.execute(
"CREATE INDEX IF NOT EXISTS idx_tr_emb_traduccion_id ON traduccion_embeddings(traduccion_id);"
)
conn.commit()
@ -104,7 +105,7 @@ def texts_from_rows(rows: List[psycopg2.extras.DictRow]) -> List[str]:
Compone el texto a vectorizar por cada traducción:
'titulo_trad' + '\n' + 'resumen_trad'. Si alguno falta, usa lo disponible.
"""
texts = []
texts: List[str] = []
for r in rows:
title = (r["titulo_trad"] or "").strip()
body = (r["resumen_trad"] or "").strip()
@ -117,24 +118,37 @@ def texts_from_rows(rows: List[psycopg2.extras.DictRow]) -> List[str]:
def upsert_embeddings(conn, rows, embs: np.ndarray, model_name: str):
"""
Inserta/actualiza embeddings por traducción.
Inserta/actualiza embeddings por traducción en lote (batch insert).
"""
if embs.size == 0 or not rows:
return
dim = int(embs.shape[1])
# Preparamos los datos para execute_values
data = [
(
int(r["traduccion_id"]),
model_name,
dim,
[float(x) for x in e],
)
for r, e in zip(rows, embs)
]
with conn.cursor() as cur:
for r, e in zip(rows, embs):
cur.execute(
"""
INSERT INTO traduccion_embeddings (traduccion_id, model, dim, embedding)
VALUES (%s, %s, %s, %s)
ON CONFLICT (traduccion_id, model) DO UPDATE
SET embedding = EXCLUDED.embedding,
dim = EXCLUDED.dim,
created_at = NOW()
execute_values(
cur,
"""
INSERT INTO traduccion_embeddings (traduccion_id, model, dim, embedding)
VALUES %s
ON CONFLICT (traduccion_id, model) DO UPDATE
SET embedding = EXCLUDED.embedding,
dim = EXCLUDED.dim,
created_at = NOW()
""",
(int(r["traduccion_id"]), model_name, dim, list(map(float, e))),
)
data,
)
conn.commit()