|
|
| import os
|
| import anthropic
|
| import streamlit as st
|
| import logging
|
| import time
|
| import json
|
| from datetime import datetime, timezone
|
|
|
|
|
| from ..utils.widget_utils import generate_unique_key
|
| from ..database.current_situation_mongo_db import store_current_situation_result
|
|
|
| logger = logging.getLogger(__name__)
|
|
|
|
|
| TEXT_TYPES = {
|
| 'es': {
|
| 'academic_article': 'artículo académico',
|
| 'university_work': 'trabajo universitario',
|
| 'general_communication': 'comunicación general'
|
| },
|
| 'en': {
|
| 'academic_article': 'academic article',
|
| 'university_work': 'university work',
|
| 'general_communication': 'general communication'
|
| },
|
| 'fr': {
|
| 'academic_article': 'article académique',
|
| 'university_work': 'travail universitaire',
|
| 'general_communication': 'communication générale'
|
| },
|
| 'pt': {
|
| 'academic_article': 'artigo acadêmico',
|
| 'university_work': 'trabalho universitário',
|
| 'general_communication': 'comunicação geral'
|
| }
|
| }
|
|
|
|
|
| recommendation_cache = {}
|
|
|
| def get_recommendation_cache_key(text, metrics, text_type, lang_code):
|
| """
|
| Generate a cache key for recommendations.
|
| """
|
|
|
| text_hash = hash(text[:1000])
|
| metrics_hash = hash(json.dumps(metrics, sort_keys=True))
|
| return f"{text_hash}_{metrics_hash}_{text_type}_{lang_code}"
|
|
|
| def format_metrics_for_claude(metrics, lang_code, text_type):
|
| """
|
| Format metrics in a way that's readable for Claude
|
| """
|
| formatted_metrics = {}
|
| for key, value in metrics.items():
|
| if isinstance(value, (int, float)):
|
| formatted_metrics[key] = round(value, 2)
|
| else:
|
| formatted_metrics[key] = value
|
|
|
|
|
| text_type_label = TEXT_TYPES.get(lang_code, {}).get(text_type, text_type)
|
| formatted_metrics['text_type'] = text_type_label
|
|
|
| return formatted_metrics
|
|
|
| def generate_claude_recommendations(text, metrics, text_type, lang_code):
|
| """
|
| Generate personalized recommendations using Claude API.
|
| """
|
| 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_recommendations(lang_code)
|
|
|
|
|
| cache_key = get_recommendation_cache_key(text, metrics, text_type, lang_code)
|
| if cache_key in recommendation_cache:
|
| logger.info("Using cached recommendations")
|
| return recommendation_cache[cache_key]
|
|
|
|
|
| formatted_metrics = format_metrics_for_claude(metrics, lang_code, text_type)
|
|
|
|
|
| if lang_code == 'es':
|
| system_prompt = """Eres un asistente especializado en análisis de textos académicos y comunicación escrita.
|
| Tu tarea es analizar el texto del usuario y proporcionar recomendaciones personalizadas.
|
| Usa un tono constructivo y específico. Sé claro y directo con tus sugerencias.
|
| """
|
| user_prompt = f"""Por favor, analiza este texto de tipo '{formatted_metrics['text_type']}'
|
| y proporciona recomendaciones personalizadas para mejorarlo.
|
|
|
| MÉTRICAS DE ANÁLISIS:
|
| {json.dumps(formatted_metrics, indent=2, ensure_ascii=False)}
|
|
|
| TEXTO A ANALIZAR:
|
| {text[:2000]} # Limitamos el texto para evitar exceder tokens
|
|
|
| Proporciona tu análisis con el siguiente formato:
|
| 1. Un resumen breve (2-3 frases) del análisis general
|
| 2. 3-4 recomendaciones específicas y accionables (cada una de 1-2 frases)
|
| 3. Un ejemplo concreto de mejora tomado del propio texto del usuario
|
| 4. Una sugerencia sobre qué herramienta de AIdeaText usar (Análisis Morfosintáctico, Análisis Semántico o Análisis del Discurso)
|
|
|
| Tu respuesta debe ser concisa y no exceder los 300 palabras."""
|
|
|
| elif lang_code == 'fr':
|
| system_prompt = """Vous êtes un assistant spécialisé dans l'analyse de textes académiques et de communication écrite.
|
| Votre tâche est d'analyser le texte de l'utilisateur et de fournir des recommandations personnalisées.
|
| Utilisez un ton constructif et spécifique. Soyez clair et direct dans vos suggestions.
|
| """
|
| user_prompt = f"""Veuillez analyser ce texte de type '{formatted_metrics['text_type']}'
|
| et fournir des recommandations personnalisées pour l'améliorer.
|
|
|
| MÉTRIQUES D'ANALYSE:
|
| {json.dumps(formatted_metrics, indent=2, ensure_ascii=False)}
|
|
|
| TEXTE À ANALYSER:
|
| {text[:2000]}
|
|
|
| Fournissez votre analyse avec le format suivant:
|
| 1. Un résumé bref (2-3 phrases) de l'analyse générale
|
| 2. 3-4 recommandations spécifiques et réalisables (chacune de 1-2 phrases)
|
| 3. Un exemple concret d'amélioration tiré du texte même de l'utilisateur
|
| 4. Une suggestion sur quel outil AIdeaText utiliser (Analyse Morphosyntaxique, Analyse Sémantique ou Analyse du Discours)
|
|
|
| Votre réponse doit être concise et ne pas dépasser 300 mots."""
|
|
|
| elif lang_code == 'pt':
|
| system_prompt = """Você é um assistente especializado na análise de textos acadêmicos e comunicação escrita.
|
| Sua tarefa é analisar o texto do usuário e fornecer recomendações personalizadas.
|
| Use um tom construtivo e específico. Seja claro e direto com suas sugestões.
|
| """
|
| user_prompt = f"""Por favor, analise este texto do tipo '{formatted_metrics['text_type']}'
|
| e forneça recomendações personalizadas para melhorá-lo.
|
|
|
| MÉTRICAS DE ANÁLISE:
|
| {json.dumps(formatted_metrics, indent=2, ensure_ascii=False)}
|
|
|
| TEXTO PARA ANALISAR:
|
| {text[:2000]}
|
|
|
| Forneça sua análise com o seguinte formato:
|
| 1. Um breve resumo (2-3 frases) da análise geral
|
| 2. 3-4 recomendações específicas e acionáveis (cada uma com 1-2 frases)
|
| 3. Um exemplo concreto de melhoria retirado do próprio texto do usuário
|
| 4. Uma sugestão sobre qual ferramenta do AIdeaText usar (Análise Morfossintática, Análise Semântica ou Análise do Discurso)
|
|
|
| Sua resposta deve ser concisa e não exceder 300 palavras."""
|
|
|
| else:
|
|
|
| system_prompt = """You are an assistant specialized in analyzing academic texts and written communication.
|
| Your task is to analyze the user's text and provide personalized recommendations.
|
| Use a constructive and specific tone. Be clear and direct with your suggestions.
|
| """
|
| user_prompt = f"""Please analyze this text of type '{formatted_metrics['text_type']}'
|
| and provide personalized recommendations to improve it.
|
|
|
| ANALYSIS METRICS:
|
| {json.dumps(formatted_metrics, indent=2, ensure_ascii=False)}
|
|
|
| TEXT TO ANALYZE:
|
| {text[:2000]} # Limiting text to avoid exceeding tokens
|
|
|
| Provide your analysis with the following format:
|
| 1. A brief summary (2-3 sentences) of the general analysis
|
| 2. 3-4 specific and actionable recommendations (each 1-2 sentences)
|
| 3. A concrete example of improvement taken from the user's own text
|
| 4. A suggestion about which AIdeaText tool to use (Morphosyntactic Analysis, Semantic Analysis or Discourse Analysis)
|
|
|
| Your response should be concise and not exceed 300 words."""
|
|
|
|
|
| client = anthropic.Anthropic(api_key=api_key)
|
|
|
|
|
| start_time = time.time()
|
| response = client.messages.create(
|
| model="claude-3-5-sonnet-20241022",
|
| 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")
|
|
|
|
|
| recommendations = response.content[0].text
|
|
|
|
|
| recommendation_cache[cache_key] = recommendations
|
|
|
| return recommendations
|
| except Exception as e:
|
| logger.error(f"Error generating recommendations with Claude: {str(e)}")
|
| return get_fallback_recommendations(lang_code)
|
|
|
|
|
|
|
| def get_fallback_recommendations(lang_code):
|
| """
|
| Return fallback recommendations if Claude API fails
|
| """
|
| if lang_code == 'es':
|
| return """
|
| **Análisis General**
|
| Tu texto presenta una estructura básica adecuada, pero hay áreas que pueden mejorarse para mayor claridad y cohesión.
|
| **Recomendaciones**:
|
| - Intenta variar tu vocabulario para evitar repeticiones innecesarias
|
| - Considera revisar la longitud de tus oraciones para mantener un mejor ritmo
|
| - Asegúrate de establecer conexiones claras entre las ideas principales
|
| - Revisa la consistencia en el uso de tiempos verbales
|
| **Herramienta recomendada**:
|
| Te sugerimos utilizar el Análisis Morfosintáctico para identificar patrones en tu estructura de oraciones.
|
| """
|
|
|
| elif lang_code == 'fr':
|
| return """
|
| **Analyse Générale**
|
| Votre texte présente une structure de base adéquate, mais certains aspects pourraient être améliorés pour plus de clarté et de cohésion.
|
|
|
| **Recommandations**:
|
| - Essayez de varier votre vocabulaire pour éviter les répétitions inutiles
|
| - Envisagez de revoir la longueur de vos phrases pour maintenir un meilleur rythme
|
| - Assurez-vous d'établir des liens clairs entre les idées principales
|
| - Vérifiez la cohérence dans l'utilisation des temps verbaux
|
|
|
| **Outil recommandé**:
|
| Nous vous suggérons d'utiliser l'Analyse Morphosyntaxique pour identifier les modèles dans la structure de vos phrases.
|
| """
|
|
|
| elif lang_code == 'pt':
|
| return """
|
| **Análise Geral**
|
| Seu texto apresenta uma estrutura básica adequada, mas há áreas que podem ser melhoradas para maior clareza e coesão.
|
|
|
| **Recomendações**:
|
| - Tente variar seu vocabulário para evitar repetições desnecessárias
|
| - Considere revisar o comprimento de suas frases para manter um melhor ritmo
|
| - Certifique-se de estabelecer conexões claras entre as ideias principais
|
| - Revise a consistência no uso dos tempos verbais
|
|
|
| **Ferramenta recomendada**:
|
| Sugerimos utilizar a Análise Morfossintática para identificar padrões na sua estrutura de frases.
|
| """
|
|
|
| else:
|
| return """
|
| **General Analysis**
|
| Your text presents an adequate basic structure, but there are areas that can be improved for better clarity and cohesion.
|
|
|
| **Recommendations**:
|
| - Try to vary your vocabulary to avoid unnecessary repetition
|
| - Consider reviewing the length of your sentences to maintain a better rhythm
|
| - Make sure to establish clear connections between main ideas
|
| - Check consistency in the use of verb tenses
|
|
|
| **Recommended tool**:
|
| We suggest using Morphosyntactic Analysis to identify patterns in your sentence structure.
|
| """
|
|
|
|
|
|
|
|
|
| def store_recommendations(username, text, metrics, text_type, recommendations):
|
| """
|
| Store the recommendations in the database
|
| """
|
| try:
|
|
|
| from ..database.claude_recommendations_mongo_db import store_claude_recommendation
|
|
|
|
|
| result = store_claude_recommendation(
|
| username=username,
|
| text=text,
|
| metrics=metrics,
|
| text_type=text_type,
|
| recommendations=recommendations
|
| )
|
|
|
| logger.info(f"Recommendations stored successfully: {result}")
|
| return result
|
| except Exception as e:
|
| logger.error(f"Error storing recommendations: {str(e)}")
|
| return False
|
|
|
|
|
|
|
|
|
| def display_personalized_recommendations(text, metrics, text_type, lang_code, t):
|
| """
|
| Display personalized recommendations based on text analysis
|
| """
|
| try:
|
|
|
| recommendations = generate_claude_recommendations(text, metrics, text_type, lang_code)
|
|
|
|
|
| st.markdown("### 📝 " + t.get('recommendations_title', 'Personalized Recommendations'))
|
|
|
| with st.container():
|
| st.markdown(f"""
|
| <div style="padding: 20px; border-radius: 10px;
|
| background-color: #f8f9fa; margin-bottom: 20px;">
|
| {recommendations}
|
| </div>
|
| """, unsafe_allow_html=True)
|
|
|
|
|
| st.info("💡 **" + t.get('assistant_prompt', 'For further improvement:') + "** " +
|
| t.get('assistant_message', 'Open the virtual assistant (powered by Claude AI) in the upper left corner by clicking the arrow next to the logo.'))
|
|
|
|
|
| col1, col2, col3 = st.columns([1,1,1])
|
| with col2:
|
| if st.button(
|
| t.get('save_button', 'Save Analysis'),
|
| key=generate_unique_key("claude_recommendations", "save"),
|
| type="primary",
|
| use_container_width=True
|
| ):
|
| if 'username' in st.session_state:
|
| success = store_recommendations(
|
| st.session_state.username,
|
| text,
|
| metrics,
|
| text_type,
|
| recommendations
|
| )
|
| if success:
|
| st.success(t.get('save_success', 'Analysis saved successfully'))
|
| else:
|
| st.error(t.get('save_error', 'Error saving analysis'))
|
| else:
|
| st.error(t.get('login_required', 'Please log in to save analysis'))
|
|
|
| except Exception as e:
|
| logger.error(f"Error displaying recommendations: {str(e)}")
|
| st.error(t.get('recommendations_error', 'Error generating recommendations. Please try again later.')) |