|
import os |
|
import requests |
|
import json |
|
import re |
|
import gradio as gr |
|
from sentence_transformers import SentenceTransformer |
|
import numpy as np |
|
from sklearn.metrics.pairwise import cosine_similarity |
|
|
|
|
|
class MultilingualLlamaAgent: |
|
""" |
|
A multilingual chatbot powered by Llama hosted on Hugging Face with RAG capabilities. |
|
""" |
|
|
|
def __init__(self): |
|
"""Initialize the Hugging Face API client for Llama 3.2 and RAG components.""" |
|
print("Initializing Llama 3.2 multilingual agent with RAG...") |
|
|
|
|
|
self.model_id = os.environ.get('MODEL') |
|
self.api_token = os.environ.get("HF_TOKEN") |
|
self.api_url = f"https://api-inference.huggingface.co/models/{self.model_id}" |
|
|
|
|
|
self.max_new_tokens = 540 |
|
self.temperature = 0.7 |
|
self.top_p = 0.9 |
|
|
|
|
|
self.greeting_message = """Hola, entiendo que estás buscando información y asesoramiento. Estoy aquí para ayudarte. |
|
Para que esta conversación sea lo más cómoda para ti, ¿cómo prefieres que te llame o cuáles son tus pronombres?. Si prefieres mantener tu anonimato, puedes usar un nombre ficticio.""" |
|
|
|
|
|
self.embedding_model = SentenceTransformer( |
|
"paraphrase-multilingual-MiniLM-L12-v2" |
|
) |
|
self.knowledge_base = self.load_knowledge_base(os.environ.get('PROTOCOLO')) |
|
self.knowledge_embeddings = self.embed_knowledge_base() |
|
|
|
def load_knowledge_base(self, knowledge_base): |
|
"""Load the knowledge base from a provided string.""" |
|
try: |
|
|
|
chunks = [ |
|
chunk.strip() for chunk in self.knowledge_base.split("\n\n") if chunk.strip() |
|
] |
|
return chunks |
|
except Exception as e: |
|
print(f"Error processing knowledge base: {str(e)}") |
|
return [] |
|
|
|
def embed_knowledge_base(self): |
|
"""Create embeddings for the knowledge base chunks.""" |
|
if not self.knowledge_base: |
|
return [] |
|
return self.embedding_model.encode(self.knowledge_base) |
|
|
|
def retrieve_relevant_info(self, query, top_k=3, threshold=0.5): |
|
"""Retrieve the most relevant information from the knowledge base.""" |
|
if not self.knowledge_base or not self.knowledge_embeddings.size: |
|
return "" |
|
|
|
|
|
query_embedding = self.embedding_model.encode([query])[0] |
|
|
|
|
|
similarities = cosine_similarity([query_embedding], self.knowledge_embeddings)[ |
|
0 |
|
] |
|
|
|
|
|
relevant_indices = np.where(similarities > threshold)[0] |
|
if len(relevant_indices) == 0: |
|
return "" |
|
|
|
top_indices = relevant_indices[ |
|
np.argsort(-similarities[relevant_indices])[:top_k] |
|
] |
|
|
|
|
|
relevant_info = "\n\n".join([self.knowledge_base[i] for i in top_indices]) |
|
return relevant_info |
|
|
|
def extract_answer(self, response_or_json): |
|
try: |
|
|
|
if hasattr(response_or_json, "json"): |
|
data = response_or_json.json() |
|
elif isinstance(response_or_json, str): |
|
data = json.loads(response_or_json) |
|
else: |
|
data = response_or_json |
|
print("data-", data) |
|
|
|
|
|
generated_text = data[0]["generated_text"] |
|
pattern = r"<\|start_header_id\|>assistant<\|end_header_id\|>\s*(.*?)(?:<\|eot_id\|>|$)" |
|
match = re.search(pattern, generated_text, re.DOTALL) |
|
|
|
if match: |
|
return match.group(1).strip() |
|
else: |
|
return generated_text |
|
|
|
except Exception as e: |
|
return f"Error processing the input: {str(e)}" |
|
|
|
def generate_response(self, user_input: str) -> str: |
|
"""Generate a response using the Hugging Face Inference API and RAG.""" |
|
|
|
|
|
query = user_input.split("Usuario: ")[-1].split("\nAsistente:")[0].strip() |
|
|
|
|
|
relevant_info = self.retrieve_relevant_info(query) |
|
|
|
tono = os.environ.get('TONO') |
|
|
|
tono = f""" |
|
{tono} |
|
""" |
|
|
|
|
|
if relevant_info: |
|
system_context = f""" |
|
Eres un asistente a victimas de violencia laboral que sigue las siguientes instrucciones de tono al reponder las preguntas de los usuarios {tono} |
|
|
|
Información relevante para responder a la consulta del usuario: |
|
{relevant_info} |
|
|
|
Utiliza la información proporcionada para dar una respuesta más precisa y útil, pero siempre manteniendo el tono y enfoque adecuados. |
|
""" |
|
else: |
|
system_context = f""" |
|
Eres un asistente a victimas de violencia laboral que sigue las siguientes instrucciones de tono al reponder las preguntas de los usuarios {tono} |
|
""" |
|
|
|
prompt = f""" |
|
<|begin_of_text|><|start_header_id|>system<|end_header_id|> |
|
|
|
{system_context}<|eot_id|><|start_header_id|>user<|end_header_id|> |
|
|
|
{user_input}<|eot_id|><|start_header_id|>assistant<|end_header_id|> |
|
""" |
|
|
|
try: |
|
|
|
payload = { |
|
"inputs": prompt, |
|
"parameters": { |
|
"max_new_tokens": self.max_new_tokens, |
|
"temperature": self.temperature, |
|
"top_p": self.top_p, |
|
}, |
|
} |
|
|
|
|
|
headers = {"Authorization": f"Bearer {self.api_token}"} |
|
|
|
|
|
response = requests.post(self.api_url, headers=headers, json=payload) |
|
|
|
|
|
if response.status_code == 200: |
|
result = response.json() |
|
print("result-", result) |
|
return self.extract_answer(result) |
|
else: |
|
return f"Error: {response.status_code} - {response.text}" |
|
|
|
except Exception as e: |
|
return f"An error occurred: {str(e)}" |
|
|
|
|
|
def chat_with_agent(message, history): |
|
"""Handle user input and generate a response for the Gradio interface.""" |
|
if not agent.api_token: |
|
return history + [ |
|
[ |
|
message, |
|
"Error: Hugging Face API token is missing. Please set the HF_TOKEN environment variable.", |
|
] |
|
] |
|
|
|
|
|
full_context = "" |
|
for h in history: |
|
full_context += f"Usuario: {h[0]}\nAsistente: {h[1]}\n" |
|
|
|
full_context += f"Usuario: {message}\nAsistente:" |
|
|
|
response = agent.generate_response(full_context) |
|
|
|
|
|
return history + [[message, response]] |
|
|
|
|
|
|
|
agent = MultilingualLlamaAgent() |
|
|
|
|
|
with gr.Blocks() as demo: |
|
gr.Markdown(""" |
|
# 🤖 Chatbot basado en Llama para atencion a victimas de acoso laboral. |
|
|
|
## ¡Hola! |
|
|
|
Gracias por contactarnos. Entendemos que has pasado por una situación incómoda y estamos acá para ofrecerte un espacio seguro y confiable para que puedas compartir tu experiencia. |
|
|
|
Antes de empezar, queremos informarte que estás conversando con un chatbot con inteligencia artificial diseñado para ofrecerte información, recursos, apoyo y acompañamiento. Si en algún momento necesitas hablar con una persona real, te indicaremos cómo hacerlo. |
|
|
|
Además, queremos asegurarte que toda la información que compartas con nosotros será tratada con la máxima **confidencialidad**. Nadie más tendrá acceso a esta información sin tu consentimiento expreso en esta primera etapa. La información que proporciones se utilizará únicamente para entender mejor lo que te ocurrió y buscar las mejores soluciones para ti. También queremos que sepas que nos guiamos por principios de derechos humanos para que este espacio esté libre de prejuicios, sesgos y estereotipos. Creemos que todas las personas merecen ser tratadas con respeto e igualdad, independientemente de su género, orientación sexual, origen étnico, color de piel, religión o cualquier otra condición. No toleramos ninguna forma de discriminación. |
|
|
|
Aquí encontrarás información útil sobre la violencia laboral, tus derechos y los recursos disponibles para que puedas tomar las mejores decisiones de manera informada. |
|
""") |
|
|
|
with gr.Row(): |
|
with gr.Column(scale=2): |
|
chatbot = gr.Chatbot(height=500, value=[[None, agent.greeting_message]]) |
|
msg = gr.Textbox(placeholder="Escribe tu mensaje aquí...", show_label=False) |
|
|
|
with gr.Row(): |
|
submit_btn = gr.Button("Enviar") |
|
clear_btn = gr.Button("Limpiar chat") |
|
|
|
with gr.Column(scale=1): |
|
gr.Markdown(""" |
|
- Este chatbot esta entrenado sobre un modelo Llama. |
|
- Sigue protocolos creados para atencion a victimas de acoso laboral por expertos en la materia. |
|
""") |
|
|
|
|
|
submit_btn.click(chat_with_agent, [msg, chatbot], [chatbot]) |
|
msg.submit(chat_with_agent, [msg, chatbot], [chatbot]) |
|
clear_btn.click( |
|
lambda: [[None, agent.greeting_message]], None, chatbot, queue=False |
|
) |
|
submit_btn.click(lambda: "", None, msg, queue=False) |
|
msg.submit(lambda: "", None, msg, queue=False) |
|
|
|
|
|
if __name__ == "__main__": |
|
demo.launch(share=True) |