Spaces:
Sleeping
Sleeping
import gradio as gr | |
import pickle | |
import os | |
from transformers import AutoTokenizer, AutoModel, pipeline | |
import torch | |
import faiss | |
import numpy as np | |
from spaces import GPU # IMPORTANTE para ZeroGPU | |
# Token para modelos privados si se requiere | |
hf_token = os.getenv("HF_KEY") | |
# Cargar índice FAISS y los chunks | |
if os.path.exists("index.pkl"): | |
with open("index.pkl", "rb") as f: | |
index, chunks = pickle.load(f) | |
else: | |
raise FileNotFoundError("No se encontró el archivo 'index.pkl'.") | |
# Modelo de embeddings | |
model_id = "jinaai/jina-embeddings-v2-base-es" | |
tokenizer = AutoTokenizer.from_pretrained(model_id) | |
model = AutoModel.from_pretrained(model_id) | |
def generar_embedding(texto): | |
inputs = tokenizer(texto, return_tensors="pt", padding=True, truncation=True) | |
with torch.no_grad(): | |
outputs = model(**inputs) | |
last_hidden = outputs.last_hidden_state | |
mask = inputs["attention_mask"].unsqueeze(-1).expand(last_hidden.size()).float() | |
summed = torch.sum(last_hidden * mask, 1) | |
counted = torch.clamp(mask.sum(1), min=1e-9) | |
mean_pooled = summed / counted | |
return mean_pooled.numpy() | |
# LLM para generar respuesta final | |
llm = pipeline( | |
"text-generation", | |
model="meta-llama/Llama-3.2-3B-Instruct", | |
token=hf_token, | |
trust_remote_code=True | |
) | |
# DECORADOR para que ZeroGPU ejecute esta función en CPU/GPU remota | |
def responder(pregunta): | |
if not pregunta: | |
return "Por favor ingresa una pregunta." | |
pregunta_embedding = generar_embedding(pregunta) | |
distances, indices = index.search(pregunta_embedding.reshape(1, -1), k=20) | |
result_chunks = [chunks[i] for i in indices[0]] | |
palabras_clave = pregunta.lower().split() | |
filtrados = [c for c in result_chunks if any(p in c.lower() for p in palabras_clave)] | |
contexto_final = "\n\n".join(filtrados[:3]) if filtrados else "\n\n".join(result_chunks[:3]) | |
prompt = f""" | |
Actúa como un asesor legal colombiano, especializado en el Código de Tránsito, Código de Policía y Código Penal. | |
Analiza el siguiente contexto legal y responde la pregunta de forma clara, completa y profesional. | |
Instrucciones: | |
- Usa un lenguaje formal y preciso. | |
- Fundamenta tu respuesta solo en el contexto proporcionado. | |
- Cita artículos, normas o sanciones si están presentes en el texto. | |
- Finaliza con una recomendación preventiva si aplica. | |
- Si no encuentras información suficiente, responde: | |
**"No encontré información suficiente en la ley para responder a esta pregunta."** | |
- No inventes información ni cites leyes que no estén en el contexto. | |
CONTEXTO LEGAL: | |
{contexto_final} | |
PREGUNTA: | |
{pregunta} | |
RESPUESTA: | |
""" | |
resultado = llm( | |
prompt, | |
max_new_tokens=350, | |
temperature=0.4, | |
top_p=0.9, | |
repetition_penalty=1.2 | |
)[0]["generated_text"] | |
if "RESPUESTA:" in resultado: | |
solo_respuesta = resultado.split("RESPUESTA:")[-1].strip() | |
else: | |
solo_respuesta = resultado.strip() | |
return solo_respuesta | |
# Interfaz de usuario con Gradio | |
demo = gr.Interface( | |
fn=responder, | |
inputs=gr.Textbox(label="Escribe tu pregunta"), | |
outputs=gr.Textbox(label="Respuesta generada"), | |
title="Asistente Legal Colombiano", | |
description="Consulta el Código de Tránsito, Código de Policía y Código Penal colombiano." | |
) | |
if __name__ == "__main__": | |
demo.launch() |