AIdeaText commited on
Commit
3fa2803
·
verified ·
1 Parent(s): df333ac

Upload claude_recommendations.py

Browse files
modules/studentact/claude_recommendations.py CHANGED
@@ -1,266 +1,347 @@
1
- # modules/studentact/claude_recommendations.py
2
- import os
3
- import anthropic
4
- import streamlit as st
5
- import logging
6
- import time
7
- import json
8
- from datetime import datetime, timezone
9
-
10
- # Local imports
11
- from ..utils.widget_utils import generate_unique_key
12
- from ..database.current_situation_mongo_db import store_current_situation_result
13
-
14
- logger = logging.getLogger(__name__)
15
-
16
- # Define text types
17
- TEXT_TYPES = {
18
- 'es': {
19
- 'academic_article': 'artículo académico',
20
- 'university_work': 'trabajo universitario',
21
- 'general_communication': 'comunicación general'
22
- },
23
- 'en': {
24
- 'academic_article': 'academic article',
25
- 'university_work': 'university work',
26
- 'general_communication': 'general communication'
27
- },
28
- 'fr': {
29
- 'academic_article': 'article académique',
30
- 'university_work': 'travail universitaire',
31
- 'general_communication': 'communication générale'
32
- }
33
- }
34
-
35
- # Cache for recommendations to avoid redundant API calls
36
- recommendation_cache = {}
37
-
38
- def get_recommendation_cache_key(text, metrics, text_type, lang_code):
39
- """
40
- Generate a cache key for recommendations.
41
- """
42
- # Create a simple hash based on text content and metrics
43
- text_hash = hash(text[:1000]) # Only use first 1000 chars for hashing
44
- metrics_hash = hash(json.dumps(metrics, sort_keys=True))
45
- return f"{text_hash}_{metrics_hash}_{text_type}_{lang_code}"
46
-
47
- def format_metrics_for_claude(metrics, lang_code, text_type):
48
- """
49
- Format metrics in a way that's readable for Claude
50
- """
51
- formatted_metrics = {}
52
- for key, value in metrics.items():
53
- if isinstance(value, (int, float)):
54
- formatted_metrics[key] = round(value, 2)
55
- else:
56
- formatted_metrics[key] = value
57
-
58
- # Add context about what type of text this is
59
- text_type_label = TEXT_TYPES.get(lang_code, {}).get(text_type, text_type)
60
- formatted_metrics['text_type'] = text_type_label
61
-
62
- return formatted_metrics
63
-
64
- def generate_claude_recommendations(text, metrics, text_type, lang_code):
65
- """
66
- Generate personalized recommendations using Claude API.
67
- """
68
- try:
69
- api_key = os.environ.get("ANTHROPIC_API_KEY")
70
- if not api_key:
71
- logger.error("Claude API key not found in environment variables")
72
- return get_fallback_recommendations(lang_code)
73
-
74
- # Check cache first
75
- cache_key = get_recommendation_cache_key(text, metrics, text_type, lang_code)
76
- if cache_key in recommendation_cache:
77
- logger.info("Using cached recommendations")
78
- return recommendation_cache[cache_key]
79
-
80
- # Format metrics for Claude
81
- formatted_metrics = format_metrics_for_claude(metrics, lang_code, text_type)
82
-
83
- # Determine language for prompt
84
- if lang_code == 'es':
85
- system_prompt = """Eres un asistente especializado en análisis de textos académicos y comunicación escrita.
86
- Tu tarea es analizar el texto del usuario y proporcionar recomendaciones personalizadas.
87
- Usa un tono constructivo y específico. Sé claro y directo con tus sugerencias.
88
- """
89
- user_prompt = f"""Por favor, analiza este texto de tipo '{formatted_metrics['text_type']}'
90
- y proporciona recomendaciones personalizadas para mejorarlo.
91
-
92
- MÉTRICAS DE ANÁLISIS:
93
- {json.dumps(formatted_metrics, indent=2, ensure_ascii=False)}
94
-
95
- TEXTO A ANALIZAR:
96
- {text[:2000]} # Limitamos el texto para evitar exceder tokens
97
-
98
- Proporciona tu análisis con el siguiente formato:
99
- 1. Un resumen breve (2-3 frases) del análisis general
100
- 2. 3-4 recomendaciones específicas y accionables (cada una de 1-2 frases)
101
- 3. Un ejemplo concreto de mejora tomado del propio texto del usuario
102
- 4. Una sugerencia sobre qué herramienta de AIdeaText usar (Análisis Morfosintáctico, Análisis Semántico o Análisis del Discurso)
103
-
104
- Tu respuesta debe ser concisa y no exceder los 300 palabras."""
105
- else:
106
- # Default to English
107
- system_prompt = """You are an assistant specialized in analyzing academic texts and written communication.
108
- Your task is to analyze the user's text and provide personalized recommendations.
109
- Use a constructive and specific tone. Be clear and direct with your suggestions.
110
- """
111
- user_prompt = f"""Please analyze this text of type '{formatted_metrics['text_type']}'
112
- and provide personalized recommendations to improve it.
113
-
114
- ANALYSIS METRICS:
115
- {json.dumps(formatted_metrics, indent=2, ensure_ascii=False)}
116
-
117
- TEXT TO ANALYZE:
118
- {text[:2000]} # Limiting text to avoid exceeding tokens
119
-
120
- Provide your analysis with the following format:
121
- 1. A brief summary (2-3 sentences) of the general analysis
122
- 2. 3-4 specific and actionable recommendations (each 1-2 sentences)
123
- 3. A concrete example of improvement taken from the user's own text
124
- 4. A suggestion about which AIdeaText tool to use (Morphosyntactic Analysis, Semantic Analysis or Discourse Analysis)
125
-
126
- Your response should be concise and not exceed 300 words."""
127
-
128
- # Initialize Claude client
129
- client = anthropic.Anthropic(api_key=api_key)
130
-
131
- # Call Claude API
132
- start_time = time.time()
133
- response = client.messages.create(
134
- model="claude-3-5-sonnet-20241022",
135
- max_tokens=1024,
136
- temperature=0.7,
137
- system=system_prompt,
138
- messages=[
139
- {"role": "user", "content": user_prompt}
140
- ]
141
- )
142
- logger.info(f"Claude API call completed in {time.time() - start_time:.2f} seconds")
143
-
144
- # Extract recommendations
145
- recommendations = response.content[0].text
146
-
147
- # Cache the result
148
- recommendation_cache[cache_key] = recommendations
149
-
150
- return recommendations
151
- except Exception as e:
152
- logger.error(f"Error generating recommendations with Claude: {str(e)}")
153
- return get_fallback_recommendations(lang_code)
154
-
155
- def get_fallback_recommendations(lang_code):
156
- """
157
- Return fallback recommendations if Claude API fails
158
- """
159
- if lang_code == 'es':
160
- return """
161
- **Análisis General**
162
- Tu texto presenta una estructura básica adecuada, pero hay áreas que pueden mejorarse para mayor claridad y cohesión.
163
-
164
- **Recomendaciones**:
165
- - Intenta variar tu vocabulario para evitar repeticiones innecesarias
166
- - Considera revisar la longitud de tus oraciones para mantener un mejor ritmo
167
- - Asegúrate de establecer conexiones claras entre las ideas principales
168
- - Revisa la consistencia en el uso de tiempos verbales
169
-
170
- **Herramienta recomendada**:
171
- Te sugerimos utilizar el Análisis Morfosintáctico para identificar patrones en tu estructura de oraciones.
172
- """
173
- else:
174
- return """
175
- **General Analysis**
176
- Your text presents an adequate basic structure, but there are areas that can be improved for better clarity and cohesion.
177
-
178
- **Recommendations**:
179
- - Try to vary your vocabulary to avoid unnecessary repetition
180
- - Consider reviewing the length of your sentences to maintain a better rhythm
181
- - Make sure to establish clear connections between main ideas
182
- - Check consistency in the use of verb tenses
183
-
184
- **Recommended tool**:
185
- We suggest using Morphosyntactic Analysis to identify patterns in your sentence structure.
186
- """
187
-
188
-
189
- #######################################
190
-
191
- def store_recommendations(username, text, metrics, text_type, recommendations):
192
- """
193
- Store the recommendations in the database
194
- """
195
- try:
196
- # Importar la función de almacenamiento de recomendaciones
197
- from ..database.claude_recommendations_mongo_db import store_claude_recommendation
198
-
199
- # Guardar usando la nueva función especializada
200
- result = store_claude_recommendation(
201
- username=username,
202
- text=text,
203
- metrics=metrics,
204
- text_type=text_type,
205
- recommendations=recommendations
206
- )
207
-
208
- logger.info(f"Recommendations stored successfully: {result}")
209
- return result
210
- except Exception as e:
211
- logger.error(f"Error storing recommendations: {str(e)}")
212
- return False
213
-
214
-
215
- ##########################################
216
- ##########################################
217
- def display_personalized_recommendations(text, metrics, text_type, lang_code, t):
218
- """
219
- Display personalized recommendations based on text analysis
220
- """
221
- try:
222
- # Generate recommendations
223
- recommendations = generate_claude_recommendations(text, metrics, text_type, lang_code)
224
-
225
- # Format and display recommendations in a nice container
226
- st.markdown("### 📝 " + t.get('recommendations_title', 'Personalized Recommendations'))
227
-
228
- with st.container():
229
- st.markdown(f"""
230
- <div style="padding: 20px; border-radius: 10px;
231
- background-color: #f8f9fa; margin-bottom: 20px;">
232
- {recommendations}
233
- </div>
234
- """, unsafe_allow_html=True)
235
-
236
- # Add prompt to use assistant
237
- st.info("💡 **" + t.get('assistant_prompt', 'For further improvement:') + "** " +
238
- 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.'))
239
-
240
- # Add save button
241
- col1, col2, col3 = st.columns([1,1,1])
242
- with col2:
243
- if st.button(
244
- t.get('save_button', 'Save Analysis'),
245
- key=generate_unique_key("claude_recommendations", "save"),
246
- type="primary",
247
- use_container_width=True
248
- ):
249
- if 'username' in st.session_state:
250
- success = store_recommendations(
251
- st.session_state.username,
252
- text,
253
- metrics,
254
- text_type,
255
- recommendations
256
- )
257
- if success:
258
- st.success(t.get('save_success', 'Analysis saved successfully'))
259
- else:
260
- st.error(t.get('save_error', 'Error saving analysis'))
261
- else:
262
- st.error(t.get('login_required', 'Please log in to save analysis'))
263
-
264
- except Exception as e:
265
- logger.error(f"Error displaying recommendations: {str(e)}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
266
  st.error(t.get('recommendations_error', 'Error generating recommendations. Please try again later.'))
 
1
+ # modules/studentact/claude_recommendations.py
2
+ import os
3
+ import anthropic
4
+ import streamlit as st
5
+ import logging
6
+ import time
7
+ import json
8
+ from datetime import datetime, timezone
9
+
10
+ # Local imports
11
+ from ..utils.widget_utils import generate_unique_key
12
+ from ..database.current_situation_mongo_db import store_current_situation_result
13
+
14
+ logger = logging.getLogger(__name__)
15
+
16
+ # Define text types
17
+ TEXT_TYPES = {
18
+ 'es': {
19
+ 'academic_article': 'artículo académico',
20
+ 'university_work': 'trabajo universitario',
21
+ 'general_communication': 'comunicación general'
22
+ },
23
+ 'en': {
24
+ 'academic_article': 'academic article',
25
+ 'university_work': 'university work',
26
+ 'general_communication': 'general communication'
27
+ },
28
+ 'fr': {
29
+ 'academic_article': 'article académique',
30
+ 'university_work': 'travail universitaire',
31
+ 'general_communication': 'communication générale'
32
+ },
33
+ 'pt': {
34
+ 'academic_article': 'artigo acadêmico',
35
+ 'university_work': 'trabalho universitário',
36
+ 'general_communication': 'comunicação geral'
37
+ }
38
+ }
39
+
40
+ # Cache for recommendations to avoid redundant API calls
41
+ recommendation_cache = {}
42
+
43
+ def get_recommendation_cache_key(text, metrics, text_type, lang_code):
44
+ """
45
+ Generate a cache key for recommendations.
46
+ """
47
+ # Create a simple hash based on text content and metrics
48
+ text_hash = hash(text[:1000]) # Only use first 1000 chars for hashing
49
+ metrics_hash = hash(json.dumps(metrics, sort_keys=True))
50
+ return f"{text_hash}_{metrics_hash}_{text_type}_{lang_code}"
51
+
52
+ def format_metrics_for_claude(metrics, lang_code, text_type):
53
+ """
54
+ Format metrics in a way that's readable for Claude
55
+ """
56
+ formatted_metrics = {}
57
+ for key, value in metrics.items():
58
+ if isinstance(value, (int, float)):
59
+ formatted_metrics[key] = round(value, 2)
60
+ else:
61
+ formatted_metrics[key] = value
62
+
63
+ # Add context about what type of text this is
64
+ text_type_label = TEXT_TYPES.get(lang_code, {}).get(text_type, text_type)
65
+ formatted_metrics['text_type'] = text_type_label
66
+
67
+ return formatted_metrics
68
+
69
+ def generate_claude_recommendations(text, metrics, text_type, lang_code):
70
+ """
71
+ Generate personalized recommendations using Claude API.
72
+ """
73
+ try:
74
+ api_key = os.environ.get("ANTHROPIC_API_KEY")
75
+ if not api_key:
76
+ logger.error("Claude API key not found in environment variables")
77
+ return get_fallback_recommendations(lang_code)
78
+
79
+ # Check cache first
80
+ cache_key = get_recommendation_cache_key(text, metrics, text_type, lang_code)
81
+ if cache_key in recommendation_cache:
82
+ logger.info("Using cached recommendations")
83
+ return recommendation_cache[cache_key]
84
+
85
+ # Format metrics for Claude
86
+ formatted_metrics = format_metrics_for_claude(metrics, lang_code, text_type)
87
+
88
+ # Determine language for prompt
89
+ if lang_code == 'es':
90
+ system_prompt = """Eres un asistente especializado en análisis de textos académicos y comunicación escrita.
91
+ Tu tarea es analizar el texto del usuario y proporcionar recomendaciones personalizadas.
92
+ Usa un tono constructivo y específico. Sé claro y directo con tus sugerencias.
93
+ """
94
+ user_prompt = f"""Por favor, analiza este texto de tipo '{formatted_metrics['text_type']}'
95
+ y proporciona recomendaciones personalizadas para mejorarlo.
96
+
97
+ MÉTRICAS DE ANÁLISIS:
98
+ {json.dumps(formatted_metrics, indent=2, ensure_ascii=False)}
99
+
100
+ TEXTO A ANALIZAR:
101
+ {text[:2000]} # Limitamos el texto para evitar exceder tokens
102
+
103
+ Proporciona tu análisis con el siguiente formato:
104
+ 1. Un resumen breve (2-3 frases) del análisis general
105
+ 2. 3-4 recomendaciones específicas y accionables (cada una de 1-2 frases)
106
+ 3. Un ejemplo concreto de mejora tomado del propio texto del usuario
107
+ 4. Una sugerencia sobre qué herramienta de AIdeaText usar (Análisis Morfosintáctico, Análisis Semántico o Análisis del Discurso)
108
+
109
+ Tu respuesta debe ser concisa y no exceder los 300 palabras."""
110
+
111
+ elif lang_code == 'fr':
112
+ system_prompt = """Vous êtes un assistant spécialisé dans l'analyse de textes académiques et de communication écrite.
113
+ Votre tâche est d'analyser le texte de l'utilisateur et de fournir des recommandations personnalisées.
114
+ Utilisez un ton constructif et spécifique. Soyez clair et direct dans vos suggestions.
115
+ """
116
+ user_prompt = f"""Veuillez analyser ce texte de type '{formatted_metrics['text_type']}'
117
+ et fournir des recommandations personnalisées pour l'améliorer.
118
+
119
+ MÉTRIQUES D'ANALYSE:
120
+ {json.dumps(formatted_metrics, indent=2, ensure_ascii=False)}
121
+
122
+ TEXTE À ANALYSER:
123
+ {text[:2000]}
124
+
125
+ Fournissez votre analyse avec le format suivant:
126
+ 1. Un résumé bref (2-3 phrases) de l'analyse générale
127
+ 2. 3-4 recommandations spécifiques et réalisables (chacune de 1-2 phrases)
128
+ 3. Un exemple concret d'amélioration tiré du texte même de l'utilisateur
129
+ 4. Une suggestion sur quel outil AIdeaText utiliser (Analyse Morphosyntaxique, Analyse Sémantique ou Analyse du Discours)
130
+
131
+ Votre réponse doit être concise et ne pas dépasser 300 mots."""
132
+
133
+ elif lang_code == 'pt':
134
+ system_prompt = """Você é um assistente especializado na análise de textos acadêmicos e comunicação escrita.
135
+ Sua tarefa é analisar o texto do usuário e fornecer recomendações personalizadas.
136
+ Use um tom construtivo e específico. Seja claro e direto com suas sugestões.
137
+ """
138
+ user_prompt = f"""Por favor, analise este texto do tipo '{formatted_metrics['text_type']}'
139
+ e forneça recomendações personalizadas para melhorá-lo.
140
+
141
+ MÉTRICAS DE ANÁLISE:
142
+ {json.dumps(formatted_metrics, indent=2, ensure_ascii=False)}
143
+
144
+ TEXTO PARA ANALISAR:
145
+ {text[:2000]}
146
+
147
+ Forneça sua análise com o seguinte formato:
148
+ 1. Um breve resumo (2-3 frases) da análise geral
149
+ 2. 3-4 recomendações específicas e acionáveis (cada uma com 1-2 frases)
150
+ 3. Um exemplo concreto de melhoria retirado do próprio texto do usuário
151
+ 4. Uma sugestão sobre qual ferramenta do AIdeaText usar (Análise Morfossintática, Análise Semântica ou Análise do Discurso)
152
+
153
+ Sua resposta deve ser concisa e não exceder 300 palavras."""
154
+
155
+ else:
156
+ # Default to English
157
+ system_prompt = """You are an assistant specialized in analyzing academic texts and written communication.
158
+ Your task is to analyze the user's text and provide personalized recommendations.
159
+ Use a constructive and specific tone. Be clear and direct with your suggestions.
160
+ """
161
+ user_prompt = f"""Please analyze this text of type '{formatted_metrics['text_type']}'
162
+ and provide personalized recommendations to improve it.
163
+
164
+ ANALYSIS METRICS:
165
+ {json.dumps(formatted_metrics, indent=2, ensure_ascii=False)}
166
+
167
+ TEXT TO ANALYZE:
168
+ {text[:2000]} # Limiting text to avoid exceeding tokens
169
+
170
+ Provide your analysis with the following format:
171
+ 1. A brief summary (2-3 sentences) of the general analysis
172
+ 2. 3-4 specific and actionable recommendations (each 1-2 sentences)
173
+ 3. A concrete example of improvement taken from the user's own text
174
+ 4. A suggestion about which AIdeaText tool to use (Morphosyntactic Analysis, Semantic Analysis or Discourse Analysis)
175
+
176
+ Your response should be concise and not exceed 300 words."""
177
+
178
+ # Initialize Claude client
179
+ client = anthropic.Anthropic(api_key=api_key)
180
+
181
+ # Call Claude API
182
+ start_time = time.time()
183
+ response = client.messages.create(
184
+ model="claude-3-5-sonnet-20241022",
185
+ max_tokens=1024,
186
+ temperature=0.7,
187
+ system=system_prompt,
188
+ messages=[
189
+ {"role": "user", "content": user_prompt}
190
+ ]
191
+ )
192
+ logger.info(f"Claude API call completed in {time.time() - start_time:.2f} seconds")
193
+
194
+ # Extract recommendations
195
+ recommendations = response.content[0].text
196
+
197
+ # Cache the result
198
+ recommendation_cache[cache_key] = recommendations
199
+
200
+ return recommendations
201
+ except Exception as e:
202
+ logger.error(f"Error generating recommendations with Claude: {str(e)}")
203
+ return get_fallback_recommendations(lang_code)
204
+
205
+ ##################################################################################
206
+ ##################################################################################
207
+ def get_fallback_recommendations(lang_code):
208
+ """
209
+ Return fallback recommendations if Claude API fails
210
+ """
211
+ if lang_code == 'es':
212
+ return """
213
+ **Análisis General**
214
+ Tu texto presenta una estructura básica adecuada, pero hay áreas que pueden mejorarse para mayor claridad y cohesión.
215
+ **Recomendaciones**:
216
+ - Intenta variar tu vocabulario para evitar repeticiones innecesarias
217
+ - Considera revisar la longitud de tus oraciones para mantener un mejor ritmo
218
+ - Asegúrate de establecer conexiones claras entre las ideas principales
219
+ - Revisa la consistencia en el uso de tiempos verbales
220
+ **Herramienta recomendada**:
221
+ Te sugerimos utilizar el Análisis Morfosintáctico para identificar patrones en tu estructura de oraciones.
222
+ """
223
+
224
+ elif lang_code == 'fr':
225
+ return """
226
+ **Analyse Générale**
227
+ 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.
228
+
229
+ **Recommandations**:
230
+ - Essayez de varier votre vocabulaire pour éviter les répétitions inutiles
231
+ - Envisagez de revoir la longueur de vos phrases pour maintenir un meilleur rythme
232
+ - Assurez-vous d'établir des liens clairs entre les idées principales
233
+ - Vérifiez la cohérence dans l'utilisation des temps verbaux
234
+
235
+ **Outil recommandé**:
236
+ Nous vous suggérons d'utiliser l'Analyse Morphosyntaxique pour identifier les modèles dans la structure de vos phrases.
237
+ """
238
+
239
+ elif lang_code == 'pt':
240
+ return """
241
+ **Análise Geral**
242
+ Seu texto apresenta uma estrutura básica adequada, mas há áreas que podem ser melhoradas para maior clareza e coesão.
243
+
244
+ **Recomendações**:
245
+ - Tente variar seu vocabulário para evitar repetições desnecessárias
246
+ - Considere revisar o comprimento de suas frases para manter um melhor ritmo
247
+ - Certifique-se de estabelecer conexões claras entre as ideias principais
248
+ - Revise a consistência no uso dos tempos verbais
249
+
250
+ **Ferramenta recomendada**:
251
+ Sugerimos utilizar a Análise Morfossintática para identificar padrões na sua estrutura de frases.
252
+ """
253
+
254
+ else:
255
+ return """
256
+ **General Analysis**
257
+ Your text presents an adequate basic structure, but there are areas that can be improved for better clarity and cohesion.
258
+
259
+ **Recommendations**:
260
+ - Try to vary your vocabulary to avoid unnecessary repetition
261
+ - Consider reviewing the length of your sentences to maintain a better rhythm
262
+ - Make sure to establish clear connections between main ideas
263
+ - Check consistency in the use of verb tenses
264
+
265
+ **Recommended tool**:
266
+ We suggest using Morphosyntactic Analysis to identify patterns in your sentence structure.
267
+ """
268
+
269
+
270
+ #######################################
271
+ #######################################
272
+ def store_recommendations(username, text, metrics, text_type, recommendations):
273
+ """
274
+ Store the recommendations in the database
275
+ """
276
+ try:
277
+ # Importar la función de almacenamiento de recomendaciones
278
+ from ..database.claude_recommendations_mongo_db import store_claude_recommendation
279
+
280
+ # Guardar usando la nueva función especializada
281
+ result = store_claude_recommendation(
282
+ username=username,
283
+ text=text,
284
+ metrics=metrics,
285
+ text_type=text_type,
286
+ recommendations=recommendations
287
+ )
288
+
289
+ logger.info(f"Recommendations stored successfully: {result}")
290
+ return result
291
+ except Exception as e:
292
+ logger.error(f"Error storing recommendations: {str(e)}")
293
+ return False
294
+
295
+
296
+ ##########################################
297
+ ##########################################
298
+ def display_personalized_recommendations(text, metrics, text_type, lang_code, t):
299
+ """
300
+ Display personalized recommendations based on text analysis
301
+ """
302
+ try:
303
+ # Generate recommendations
304
+ recommendations = generate_claude_recommendations(text, metrics, text_type, lang_code)
305
+
306
+ # Format and display recommendations in a nice container
307
+ st.markdown("### 📝 " + t.get('recommendations_title', 'Personalized Recommendations'))
308
+
309
+ with st.container():
310
+ st.markdown(f"""
311
+ <div style="padding: 20px; border-radius: 10px;
312
+ background-color: #f8f9fa; margin-bottom: 20px;">
313
+ {recommendations}
314
+ </div>
315
+ """, unsafe_allow_html=True)
316
+
317
+ # Add prompt to use assistant
318
+ st.info("💡 **" + t.get('assistant_prompt', 'For further improvement:') + "** " +
319
+ 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.'))
320
+
321
+ # Add save button
322
+ col1, col2, col3 = st.columns([1,1,1])
323
+ with col2:
324
+ if st.button(
325
+ t.get('save_button', 'Save Analysis'),
326
+ key=generate_unique_key("claude_recommendations", "save"),
327
+ type="primary",
328
+ use_container_width=True
329
+ ):
330
+ if 'username' in st.session_state:
331
+ success = store_recommendations(
332
+ st.session_state.username,
333
+ text,
334
+ metrics,
335
+ text_type,
336
+ recommendations
337
+ )
338
+ if success:
339
+ st.success(t.get('save_success', 'Analysis saved successfully'))
340
+ else:
341
+ st.error(t.get('save_error', 'Error saving analysis'))
342
+ else:
343
+ st.error(t.get('login_required', 'Please log in to save analysis'))
344
+
345
+ except Exception as e:
346
+ logger.error(f"Error displaying recommendations: {str(e)}")
347
  st.error(t.get('recommendations_error', 'Error generating recommendations. Please try again later.'))