|
|
|
import os
|
|
import anthropic
|
|
import streamlit as st
|
|
import time
|
|
import json
|
|
import base64
|
|
import logging
|
|
|
|
from datetime import datetime, timezone
|
|
from io import BytesIO
|
|
|
|
|
|
from ..utils.widget_utils import generate_unique_key
|
|
from ..database.chat_mongo_db import store_chat_history
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
conversation_cache = {}
|
|
|
|
def get_conversation_cache_key(text, metrics, graph_data, lang_code):
|
|
"""
|
|
Generate a cache key for conversations based on analysis data.
|
|
"""
|
|
text_hash = hash(text[:1000])
|
|
metrics_hash = hash(json.dumps(metrics, sort_keys=True))
|
|
graph_hash = hash(graph_data[:100]) if graph_data else 0
|
|
return f"{text_hash}_{metrics_hash}_{graph_hash}_{lang_code}"
|
|
|
|
def format_semantic_context(text, metrics, graph_data, lang_code):
|
|
"""
|
|
Format the semantic analysis data for Claude's context.
|
|
"""
|
|
formatted_data = {
|
|
'text_sample': text[:2000],
|
|
'key_concepts': metrics.get('key_concepts', []),
|
|
'concept_centrality': metrics.get('concept_centrality', {}),
|
|
'graph_description': "Network graph available" if graph_data else "No graph available",
|
|
'language': lang_code
|
|
}
|
|
|
|
return json.dumps(formatted_data, indent=2, ensure_ascii=False)
|
|
|
|
def initiate_semantic_conversation(text, metrics, graph_data, lang_code):
|
|
"""
|
|
Start a conversation with Claude about semantic analysis results.
|
|
"""
|
|
try:
|
|
api_key = os.environ.get("ANTHROPIC_API_KEY")
|
|
if not api_key:
|
|
logger.error("Claude API key not found in environment variables")
|
|
return get_fallback_response(lang_code)
|
|
|
|
|
|
cache_key = get_conversation_cache_key(text, metrics, graph_data, lang_code)
|
|
if cache_key in conversation_cache:
|
|
logger.info("Using cached conversation starter")
|
|
return conversation_cache[cache_key]
|
|
|
|
|
|
context = format_semantic_context(text, metrics, graph_data, lang_code)
|
|
|
|
|
|
if lang_code == 'es':
|
|
system_prompt = """Eres un asistente especializado en análisis semántico de textos.
|
|
El usuario ha analizado un texto y quiere discutir los resultados contigo.
|
|
Estos son los datos del análisis:
|
|
- Fragmento del texto analizado
|
|
- Lista de conceptos clave identificados
|
|
- Medidas de centralidad de los conceptos
|
|
- Un grafo de relaciones conceptuales (si está disponible)
|
|
|
|
Tu rol es:
|
|
1. Demostrar comprensión del análisis mostrado
|
|
2. Hacer preguntas relevantes sobre los resultados
|
|
3. Ayudar al usuario a interpretar los hallazgos
|
|
4. Sugerir posibles direcciones para profundizar el análisis
|
|
|
|
Usa un tono profesional pero accesible. Sé conciso pero claro.
|
|
"""
|
|
user_prompt = f"""Aquí están los resultados del análisis semántico:
|
|
|
|
{context}
|
|
|
|
Por favor:
|
|
1. Haz un breve resumen de lo que notas en los resultados
|
|
2. Formula 2-3 preguntas interesantes que podríamos explorar sobre estos datos
|
|
3. Sugiere un aspecto del análisis que podría profundizarse
|
|
|
|
Mantén tu respuesta bajo 250 palabras."""
|
|
|
|
elif lang_code == 'fr':
|
|
system_prompt = """Vous êtes un assistant spécialisé dans l'analyse sémantique de textes.
|
|
L'utilisateur a analysé un texte et souhaite discuter des résultats avec vous.
|
|
Voici les données d'analyse:
|
|
- Extrait du texte analysé
|
|
- Liste des concepts clés identifiés
|
|
- Mesures de centralité des concepts
|
|
- Un graphique des relations conceptuelles (si disponible)
|
|
|
|
Votre rôle est:
|
|
1. Démontrer une compréhension de l'analyse présentée
|
|
2. Poser des questions pertinentes sur les résultats
|
|
3. Aider l'utilisateur à interpréter les résultats
|
|
4. Proposer des pistes pour approfondir l'analyse
|
|
|
|
Utilisez un ton professionnel mais accessible. Soyez concis mais clair.
|
|
"""
|
|
user_prompt = f"""Voici les résultats de l'analyse sémantique:
|
|
|
|
{context}
|
|
|
|
Veuillez:
|
|
1. Faire un bref résumé de ce que vous remarquez dans les résultats
|
|
2. Formuler 2-3 questions intéressantes que nous pourrions explorer
|
|
3. Suggérer un aspect de l'analyse qui pourrait être approfondi
|
|
|
|
Limitez votre réponse à 250 mots."""
|
|
|
|
elif lang_code == 'pt':
|
|
system_prompt = """Você é um assistente especializado em análise semântica de textos.
|
|
O usuário analisou um texto e quer discutir os resultados com você.
|
|
Aqui estão os dados da análise:
|
|
- Trecho do texto analisado
|
|
- Lista de conceitos-chave identificados
|
|
- Medidas de centralidade dos conceitos
|
|
- Um grafo de relações conceituais (se disponível)
|
|
|
|
Seu papel é:
|
|
1. Demonstrar compreensão da análise apresentada
|
|
2. Fazer perguntas relevantes sobre os resultados
|
|
3. Ajudar o usuário a interpretar os achados
|
|
4. Sugerir possíveis direções para aprofundar a análise
|
|
|
|
Use um tom profissional mas acessível. Seja conciso mas claro.
|
|
"""
|
|
user_prompt = f"""Aqui estão os resultados da análise semântica:
|
|
|
|
{context}
|
|
|
|
Por favor:
|
|
1. Faça um breve resumo do que você nota nos resultados
|
|
2. Formule 2-3 perguntas interessantes que poderíamos explorar
|
|
3. Sugira um aspecto da análise que poderia ser aprofundado
|
|
|
|
Mantenha sua resposta em até 250 palavras."""
|
|
|
|
else:
|
|
system_prompt = """You are an assistant specialized in semantic text analysis.
|
|
The user has analyzed a text and wants to discuss the results with you.
|
|
Here is the analysis data:
|
|
- Sample of the analyzed text
|
|
- List of identified key concepts
|
|
- Concept centrality measures
|
|
- A concept relationship graph (if available)
|
|
|
|
Your role is to:
|
|
1. Demonstrate understanding of the shown analysis
|
|
2. Ask relevant questions about the results
|
|
3. Help the user interpret the findings
|
|
4. Suggest possible directions to deepen the analysis
|
|
|
|
Use a professional but accessible tone. Be concise but clear.
|
|
"""
|
|
user_prompt = f"""Here are the semantic analysis results:
|
|
|
|
{context}
|
|
|
|
Please:
|
|
1. Give a brief summary of what you notice in the results
|
|
2. Formulate 2-3 interesting questions we could explore
|
|
3. Suggest one aspect of the analysis that could be deepened
|
|
|
|
Keep your response under 250 words."""
|
|
|
|
|
|
client = anthropic.Anthropic(api_key=api_key)
|
|
|
|
|
|
start_time = time.time()
|
|
response = client.messages.create(
|
|
model="claude-3-sonnet-20240229",
|
|
max_tokens=1024,
|
|
temperature=0.7,
|
|
system=system_prompt,
|
|
messages=[
|
|
{"role": "user", "content": user_prompt}
|
|
]
|
|
)
|
|
logger.info(f"Claude API call completed in {time.time() - start_time:.2f} seconds")
|
|
|
|
|
|
initial_response = response.content[0].text
|
|
|
|
|
|
conversation_cache[cache_key] = initial_response
|
|
|
|
return initial_response
|
|
|
|
except Exception as e:
|
|
logger.error(f"Error initiating semantic conversation: {str(e)}")
|
|
return get_fallback_response(lang_code)
|
|
|
|
def continue_conversation(conversation_history, new_message, lang_code):
|
|
"""
|
|
Continue an existing conversation about semantic analysis.
|
|
"""
|
|
try:
|
|
api_key = os.environ.get("ANTHROPIC_API_KEY")
|
|
if not api_key:
|
|
logger.error("Claude API key not found in environment variables")
|
|
return get_fallback_response(lang_code)
|
|
|
|
|
|
messages = []
|
|
for msg in conversation_history:
|
|
messages.append({
|
|
"role": "user" if msg["sender"] == "user" else "assistant",
|
|
"content": msg["message"]
|
|
})
|
|
|
|
|
|
messages.append({"role": "user", "content": new_message})
|
|
|
|
|
|
if lang_code == 'es':
|
|
system_prompt = """Continúa la conversación sobre el análisis semántico.
|
|
Sé conciso pero útil. Responde en español."""
|
|
elif lang_code == 'fr':
|
|
system_prompt = """Continuez la conversation sur l'analyse sémantique.
|
|
Soyez concis mais utile. Répondez en français."""
|
|
elif lang_code == 'pt':
|
|
system_prompt = """Continue a conversa sobre a análise semântica.
|
|
Seja conciso mas útil. Responda em português."""
|
|
else:
|
|
system_prompt = """Continue the conversation about semantic analysis.
|
|
Be concise but helpful. Respond in English."""
|
|
|
|
|
|
client = anthropic.Anthropic(api_key=api_key)
|
|
|
|
|
|
response = client.messages.create(
|
|
model="claude-3-sonnet-20240229",
|
|
max_tokens=1024,
|
|
temperature=0.7,
|
|
system=system_prompt,
|
|
messages=messages
|
|
)
|
|
|
|
return response.content[0].text
|
|
|
|
except Exception as e:
|
|
logger.error(f"Error continuing semantic conversation: {str(e)}")
|
|
return get_fallback_response(lang_code)
|
|
|
|
def get_fallback_response(lang_code):
|
|
"""
|
|
Return fallback response if Claude API fails.
|
|
"""
|
|
if lang_code == 'es':
|
|
return """Parece que hay un problema técnico. Por favor intenta de nuevo más tarde.
|
|
|
|
Mientras tanto, aquí hay algunas preguntas que podrías considerar sobre tu análisis:
|
|
1. ¿Qué conceptos tienen la mayor centralidad y por qué podría ser?
|
|
2. ¿Hay conexiones inesperadas entre conceptos en tu grafo?
|
|
3. ¿Cómo podrías profundizar en las relaciones entre los conceptos clave?"""
|
|
|
|
elif lang_code == 'fr':
|
|
return """Il semble y avoir un problème technique. Veuillez réessayer plus tard.
|
|
|
|
En attendant, voici quelques questions que vous pourriez considérer:
|
|
1. Quels concepts ont la plus grande centralité et pourquoi?
|
|
2. Y a-t-il des connexions inattendues entre les concepts?
|
|
3. Comment pourriez-vous approfondir les relations entre les concepts clés?"""
|
|
|
|
elif lang_code == 'pt':
|
|
return """Parece haver um problema técnico. Por favor, tente novamente mais tarde.
|
|
|
|
Enquanto isso, aqui estão algumas perguntas que você poderia considerar:
|
|
1. Quais conceitos têm maior centralidade e por que isso pode ocorrer?
|
|
2. Há conexões inesperadas entre conceitos no seu grafo?
|
|
3. Como você poderia aprofundar as relações entre os conceitos-chave?"""
|
|
|
|
else:
|
|
return """There seems to be a technical issue. Please try again later.
|
|
|
|
Meanwhile, here are some questions you might consider about your analysis:
|
|
1. Which concepts have the highest centrality and why might that be?
|
|
2. Are there unexpected connections between concepts in your graph?
|
|
3. How could you explore the relationships between key concepts further?"""
|
|
|
|
def store_conversation(username, text, metrics, graph_data, conversation):
|
|
try:
|
|
result = store_chat_history(
|
|
username=username,
|
|
messages=conversation,
|
|
analysis_type='semantic_analysis',
|
|
metadata={
|
|
'text_sample': text[:500],
|
|
'key_concepts': metrics.get('key_concepts', []),
|
|
'graph_available': bool(graph_data)
|
|
}
|
|
)
|
|
logger.info(f"Conversación semántica guardada: {result}")
|
|
return result
|
|
except Exception as e:
|
|
logger.error(f"Error almacenando conversación semántica: {str(e)}")
|
|
return False
|
|
|
|
def display_semantic_chat(text, metrics, graph_data, lang_code, t):
|
|
"""
|
|
Display the chat interface for semantic analysis discussion.
|
|
"""
|
|
try:
|
|
|
|
if 'semantic_chat' not in st.session_state:
|
|
st.session_state.semantic_chat = {
|
|
'history': [],
|
|
'initialized': False
|
|
}
|
|
|
|
|
|
chat_container = st.container()
|
|
|
|
|
|
if not st.session_state.semantic_chat['initialized']:
|
|
with st.spinner(t.get('initializing_chat', 'Initializing conversation...')):
|
|
initial_response = initiate_semantic_conversation(
|
|
text, metrics, graph_data, lang_code
|
|
)
|
|
|
|
st.session_state.semantic_chat['history'].append({
|
|
"sender": "assistant",
|
|
"message": initial_response
|
|
})
|
|
st.session_state.semantic_chat['initialized'] = True
|
|
|
|
|
|
if 'username' in st.session_state:
|
|
store_conversation(
|
|
st.session_state.username,
|
|
text,
|
|
metrics,
|
|
graph_data,
|
|
st.session_state.semantic_chat['history']
|
|
)
|
|
|
|
|
|
with chat_container:
|
|
st.markdown("### 💬 " + t.get('semantic_discussion', 'Semantic Analysis Discussion'))
|
|
|
|
for msg in st.session_state.semantic_chat['history']:
|
|
if msg["sender"] == "user":
|
|
st.chat_message("user").write(msg["message"])
|
|
else:
|
|
st.chat_message("assistant").write(msg["message"])
|
|
|
|
|
|
user_input = st.chat_input(
|
|
t.get('chat_input_placeholder', 'Ask about your semantic analysis...')
|
|
)
|
|
|
|
if user_input:
|
|
|
|
st.session_state.semantic_chat['history'].append({
|
|
"sender": "user",
|
|
"message": user_input
|
|
})
|
|
|
|
|
|
with chat_container:
|
|
st.chat_message("user").write(user_input)
|
|
with st.spinner(t.get('assistant_thinking', 'Assistant is thinking...')):
|
|
|
|
assistant_response = continue_conversation(
|
|
st.session_state.semantic_chat['history'],
|
|
user_input,
|
|
lang_code
|
|
)
|
|
|
|
|
|
st.session_state.semantic_chat['history'].append({
|
|
"sender": "assistant",
|
|
"message": assistant_response
|
|
})
|
|
|
|
|
|
st.chat_message("assistant").write(assistant_response)
|
|
|
|
|
|
if 'username' in st.session_state:
|
|
store_conversation(
|
|
st.session_state.username,
|
|
text,
|
|
metrics,
|
|
graph_data,
|
|
st.session_state.semantic_chat['history']
|
|
)
|
|
|
|
except Exception as e:
|
|
logger.error(f"Error displaying semantic chat: {str(e)}")
|
|
st.error(t.get('chat_error', 'Error in chat interface. Please try again.')) |