Spaces:
Running
Running
| """ | |
| Este archivo se encarga de generar el texto que el chatbot mostrará al usuario | |
| basado en su estado emocional, recomendaciones y eventos anteriores. Se usa la | |
| Inference API de HuggingFace como generador principal, con plantilla de respaldo. | |
| """ | |
| import requests as http_requests | |
| from config import GROQ_TOKEN, GROQ_TEXT_MODEL, GROQ_CHAT_URL | |
| def construir_respuesta_manual( | |
| emocion_dominante: str, | |
| modo_recomendacion: str, | |
| recomendaciones: list[dict], | |
| emocion_previa: dict | None, | |
| pelicula_transicion: dict | None, | |
| ) -> str: | |
| """ | |
| Construye la respuesta que el chatbot da en base al estado emocional del usuario | |
| Args: | |
| - emocion_dominante: El estado emocional actual del usuario (e.g. "alegria", "tristeza"). | |
| - modo_recomendacion: El modo de recomendacion basado en la emocion | |
| - recomendaciones: Lista de peliculas recomendadas para el usuario. | |
| - emocion_previa: El estado emocional anterior del usuario, si existe. | |
| - pelicula_transicion: La pelicula vista entre el estado emocional anterior y el actual | |
| Returns: | |
| - Un texto que el chatbot puede mostrar al usuario explicando su estado emocional, el modo de recomendacion, y mencionando alguna pelicula recomendada. | |
| """ | |
| # Primero se construye la parte explicativa del estado y modo de recomendacion. | |
| if modo_recomendacion == "diferente": | |
| mode_text = "Como estas en un estado positivo, te propongo explorar peliculas distintas a tu historial." | |
| else: | |
| mode_text = "Como estas en un estado negativo, te propongo peliculas similares a tu historial para mantener una zona conocida." | |
| # Una vez explicado el modo se menciona la pelicula con mejor puntuacion de las recomendaciones | |
| if recomendaciones: | |
| top_title = recomendaciones[0].get("title", "una pelicula") | |
| reco_text = f"Primera sugerencia: {top_title}." | |
| else: | |
| reco_text = "No encontre recomendaciones para ese estado emocional en este momento." | |
| # Se construye la parte de transicion de una emocion a otra | |
| if not emocion_previa: | |
| transition_text = "Este es tu primer punto de referencia emocional para analizar transiciones futuras." | |
| else: | |
| prev_emotion = emocion_previa.get("emotion", "neutral") # Si no se encuentra la emocion previa, se asume neutral para la explicacion. | |
| if prev_emotion == emocion_dominante: | |
| transition_text = f"Tu estado se mantiene en {emocion_dominante}." # Si la emocion previa es igual a la actual, se explica que no hay transicion. | |
| else: | |
| transition_text = f"Detecto una transicion de {prev_emotion} a {emocion_dominante}." # Si hay una emocion previa diferente a la actual, se explica la transicion. | |
| if pelicula_transicion: | |
| movie_title = pelicula_transicion.get("title") or pelicula_transicion.get("movie_id", "pelicula marcada") | |
| transition_text += f" Ultima pelicula vista entre ambos estados: {movie_title}." | |
| return f"Estado actual: {emocion_dominante}. {mode_text} {reco_text} {transition_text}" | |
| def _construir_prompt( | |
| emocion_dominante: str, | |
| modo_recomendacion: str, | |
| recomendaciones: list[dict], | |
| emocion_previa: dict | None, | |
| pelicula_transicion: dict | None, | |
| ) -> str: | |
| """ | |
| Funcion que construye el prompt para la generacion de texto con Ollama. | |
| Se le da contexto sobre el estado emocional actual, el modo de recomendacion, las recomendaciones, la emocion previa y la pelicula de transicion para que genere una respuesta empatica y explicativa. | |
| Args: | |
| - emocion_dominante: El estado emocional actual del usuario. | |
| - modo_recomendacion: El modo de recomendacion basado en la emocion. | |
| - recomendaciones: Lista de peliculas recomendadas para el usuario. | |
| - emocion_previa: El estado emocional anterior del usuario, si existe. | |
| - pelicula_transicion: La pelicula vista entre el estado emocional anterior y el actual. | |
| Returns: | |
| - Un prompt de texto que se le puede pasar a Ollama para generar una respuesta. | |
| """ | |
| titulos_peliculas_top = [str(row.get("title", "")).strip() for row in recomendaciones[:3] if row.get("title")] | |
| titulos_peliculas_top_text = ", ".join(titulos_peliculas_top) if titulos_peliculas_top else "sin recomendaciones" | |
| prev_emotion = emocion_previa.get("emotion") if emocion_previa else "ninguna" | |
| titulo_pelicula_transicion = "" | |
| if pelicula_transicion: | |
| titulo_pelicula_transicion = str(pelicula_transicion.get("title") or pelicula_transicion.get("movie_id") or "").strip() | |
| return ( | |
| "Eres un asistente de recomendaciones de peliculas. " | |
| "Redacta una respuesta breve en espanol (maximo 3 frases), clara y empatica. " | |
| "Incluye estado emocional actual, explicacion de por que el modo de recomendacion es ese, " | |
| "y menciona una pelicula sugerida si existe. " | |
| f"Estado actual: {emocion_dominante}. " | |
| f"Modo: {modo_recomendacion}. " | |
| f"Emocion anterior: {prev_emotion}. " | |
| f"Peliculas sugeridas: {titulos_peliculas_top_text}. " | |
| f"Pelicula asociada a transicion: {titulo_pelicula_transicion or 'ninguna'}." | |
| ) | |
| def generar_texto_chatbot( | |
| emocion_dominante: str, | |
| modo_recomendacion: str, | |
| recomendaciones: list[dict], | |
| emocion_previa: dict | None, | |
| pelicula_transicion: dict | None, | |
| ) -> tuple[str, str]: | |
| """ | |
| Funcion que genera el texto final a mostrar. Intenta usar Ollama en primera instancia, | |
| si falla utiliza la plantilla contruida en construir_respuesta_manual(). | |
| Args: | |
| - emocion_dominante: El estado emocional actual del usuario. | |
| - modo_recomendacion: El modo de recomendacion basado en la emocion. | |
| - recomendaciones: Lista de peliculas recomendadas para el usuario. | |
| - emocion_previa: El estado emocional anterior del usuario, si existe. | |
| - pelicula_transicion: La pelicula vista entre el estado emocional anterior y el actual. | |
| Returns: | |
| - Un tuple con el texto generado y la fuente del texto ("ollama" o "template-fallback"). | |
| """ | |
| respuesta_manual = construir_respuesta_manual( | |
| emocion_dominante=emocion_dominante, | |
| modo_recomendacion=modo_recomendacion, | |
| recomendaciones=recomendaciones, | |
| emocion_previa=emocion_previa, | |
| pelicula_transicion=pelicula_transicion, | |
| ) | |
| try: | |
| prompt = _construir_prompt( | |
| emocion_dominante=emocion_dominante, | |
| modo_recomendacion=modo_recomendacion, | |
| recomendaciones=recomendaciones, | |
| emocion_previa=emocion_previa, | |
| pelicula_transicion=pelicula_transicion, | |
| ) | |
| url = GROQ_CHAT_URL | |
| headers = { | |
| "Authorization": f"Bearer {GROQ_TOKEN}", | |
| "Content-Type": "application/json", | |
| } | |
| payload = { | |
| "model": GROQ_TEXT_MODEL, | |
| "messages": [{"role": "user", "content": prompt}], | |
| "max_tokens": 120, | |
| "temperature": 0.7, | |
| "top_p": 0.9, | |
| } | |
| res = http_requests.post(url, headers=headers, json=payload, timeout=20) | |
| res.raise_for_status() | |
| data = res.json() | |
| generated = str(data["choices"][0]["message"]["content"]).strip() if data.get("choices") else "" | |
| if generated: | |
| return generated, "groq" | |
| print("Aviso: Groq devolvio respuesta vacia. Se usa plantilla.") | |
| except Exception as exc: | |
| print(f"Aviso: fallo generando texto con Groq ({exc}). Se usa plantilla.") | |
| return respuesta_manual, "template-fallback" | |