JairoCesar commited on
Commit
2108de0
·
verified ·
1 Parent(s): d1f9ca2

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +127 -66
app.py CHANGED
@@ -1,5 +1,7 @@
 
 
1
  import streamlit as st
2
- from huggingface_hub import InferenceClient
3
  from docx import Document
4
  import tempfile
5
  import os
@@ -15,36 +17,53 @@ logging.basicConfig(
15
  logging.StreamHandler()
16
  ]
17
  )
18
- logger = logging.getLogger("rorschach_app")
19
 
20
  # Configuración mínima de Streamlit
21
  st.set_page_config(
22
- page_title="Interpretación Rorschach",
23
  page_icon="🧠",
24
  )
25
 
26
- # Usar tu token de Hugging Face
27
- hf_token = os.getenv("HF_TOKEN") # O reemplázalo directamente: hf_token = "tu_token_aquí"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
28
 
29
- # Inicializar cliente de Hugging Face
30
- client = None
31
  try:
32
- client = InferenceClient(
33
- model="mistralai/Mistral-7B-Instruct-v0.3",
34
- token=hf_token
35
- )
36
- logger.info("✅ Conexión con modelo Mixtral-8x7B establecida correctamente")
37
  except Exception as e:
38
- error_msg = f"❌ Error al inicializar cliente de Hugging Face: {str(e)}"
39
  logger.error(error_msg)
40
  st.error(error_msg)
 
41
 
42
- # Formatear prompt para interpretación Rorschach
43
- def format_prompt(message):
44
- system_prompt = """Eres un experto en interpretación del Test de Rorschach.
45
- Analiza las respuestas del usuario a las láminas y proporciona una interpretación
46
  psicológica detallada basada en el método de Exner.
47
-
48
  Considera:
49
  - Localización de las respuestas
50
  - Determinantes (forma, color, movimiento)
@@ -54,63 +73,91 @@ def format_prompt(message):
54
  Al final describe una conclusion creativa en terminos sencillos de la personalidad del usuario
55
  con recomendaciones generales.
56
  """
57
-
58
- prompt = f"<s>[INST] {system_prompt} [/INST] Entendido. [INST] Interpretación Rorschach: {message} [/INST]"
59
- logger.info(f"Prompt generado con {len(prompt)} caracteres")
 
 
60
  return prompt
61
 
62
- # Generar respuesta desde Hugging Face (modo no streaming)
63
- def generate(prompt):
64
- if not client:
65
- logger.error("❌ No hay cliente disponible para generar respuesta")
66
- return "Error de conexión con el modelo. Por favor, inténtelo de nuevo más tarde."
67
 
68
  try:
69
- logger.info(f"🔄 Iniciando llamada al API de Hugging Face - {datetime.datetime.now()}")
70
 
71
- generate_kwargs = dict(
72
- temperature=0.9,
73
- max_new_tokens=800,
74
  top_p=0.95,
75
- repetition_penalty=1.1,
76
- do_sample=True,
77
- seed=42,
 
78
  )
79
 
80
- formatted_prompt = format_prompt(prompt)
81
  start_time = datetime.datetime.now()
82
 
83
- # Llamada sin streaming
84
- output = client.text_generation(formatted_prompt, **generate_kwargs)
 
 
 
85
 
86
  end_time = datetime.datetime.now()
87
  duration = (end_time - start_time).total_seconds()
88
 
89
- logger.info(f"✅ Respuesta generada en {duration:.2f} segundos")
90
- return output
 
 
 
 
 
 
 
 
 
 
 
91
 
92
  except Exception as e:
93
- error_msg = f"❌ Error en la generación: {str(e)}"
94
  logger.error(error_msg)
95
- return f"Lo siento, ocurrió un error durante la interpretación. Detalles: {str(e)}"
 
 
 
96
 
97
  # Reemplazo de variables en documento Word
98
- from docx.enum.text import WD_ALIGN_PARAGRAPH # Asegúrate de importar esto arriba
99
 
100
  def replace_variables_word(doc, variables):
101
  for paragraph in doc.paragraphs:
102
  for key, value in variables.items():
103
  if f'<{key}>' in paragraph.text:
104
- paragraph.text = re.sub(f'<{key}>', value, paragraph.text)
105
- paragraph.alignment = WD_ALIGN_PARAGRAPH.LEFT # Justificación completa
 
 
 
 
 
106
  for table in doc.tables:
107
  for row in table.rows:
108
  for cell in row.cells:
109
  for paragraph in cell.paragraphs:
110
  for key, value in variables.items():
111
  if f'<{key}>' in paragraph.text:
112
- paragraph.text = re.sub(f'<{key}>', value, paragraph.text)
113
- paragraph.alignment = WD_ALIGN_PARAGRAPH.LEFT
 
 
 
114
 
115
  # Generar documento Word con interpretación
116
  def generate_word_document(interpretation):
@@ -138,8 +185,8 @@ def generate_word_document(interpretation):
138
  return None
139
 
140
  # Interfaz Streamlit
141
- st.title("Interpretación del Test de Rorschach")
142
- logger.info("🚀 Aplicación iniciada")
143
 
144
  entrada_usuario = st.text_area(
145
  "Ingrese respuestas del Test de Rorschach:",
@@ -147,27 +194,41 @@ entrada_usuario = st.text_area(
147
  placeholder="Ejemplo: Lámina I: Veo un murciélago sobre un noche estrellada..."
148
  )
149
 
150
- if st.button("Enviar", type="primary"):
151
  if not entrada_usuario:
152
  st.warning("Por favor ingrese texto para interpretar")
 
 
 
153
  else:
154
- logger.info(f"🔄 Procesando entrada de {len(entrada_usuario)} caracteres")
155
- with st.spinner("Generando interpretación..."):
156
- bot_response = generate(entrada_usuario)
157
- st.subheader("Interpretación")
158
- st.write(bot_response)
159
-
160
- document_path = generate_word_document(bot_response)
161
- if document_path:
162
- with open(document_path, "rb") as file:
163
- file_data = file.read()
164
- st.download_button(
165
- label="Descargar Interpretación",
166
- data=file_data,
167
- file_name="Interpretacion_Rorschach.docx",
168
- mime="application/vnd.openxmlformats-officedocument.wordprocessingml.document"
169
- )
170
- logger.info("📄 Botón de descarga mostrado al usuario")
 
 
 
 
 
 
 
 
 
 
171
  else:
172
- logger.error(" No se pudo generar el documento Word")
173
 
 
 
1
+ # --- START OF FILE manchas_gemini.py ---
2
+
3
  import streamlit as st
4
+ import google.generativeai as genai # Import Gemini
5
  from docx import Document
6
  import tempfile
7
  import os
 
17
  logging.StreamHandler()
18
  ]
19
  )
20
+ logger = logging.getLogger("rorschach_gemini_app")
21
 
22
  # Configuración mínima de Streamlit
23
  st.set_page_config(
24
+ page_title="Interpretación Rorschach con Gemini",
25
  page_icon="🧠",
26
  )
27
 
28
+ # --- CONFIGURACIÓN Gemini ---
29
+ GEMINI_API_KEY = os.getenv("GEMINI_API_KEY")
30
+ if not GEMINI_API_KEY:
31
+ st.error("GEMINI_API_KEY no encontrada. Por favor configúrala en tus variables de entorno.")
32
+ logger.error("GEMINI_API_KEY no encontrada.")
33
+ st.stop()
34
+
35
+ try:
36
+ genai.configure(api_key=GEMINI_API_KEY)
37
+ logger.info("✅ Configuración de Gemini API realizada.")
38
+ except Exception as e:
39
+ error_msg = f"❌ Error al configurar Gemini API: {str(e)}"
40
+ logger.error(error_msg)
41
+ st.error(error_msg)
42
+ st.stop()
43
+
44
+ @st.cache_resource
45
+ def get_gemini_model():
46
+ logger.info("🔄 Cargando modelo Gemini...")
47
+ # Puedes cambiar a "gemini-pro" si lo prefieres, gemini-1.5-flash es más rápido y económico
48
+ return genai.GenerativeModel("gemini-1.5-flash-latest")
49
 
50
+ # Inicializar modelo Gemini
51
+ model = None
52
  try:
53
+ model = get_gemini_model()
54
+ logger.info("✅ Modelo Gemini cargado correctamente (gemini-1.5-flash-latest)")
 
 
 
55
  except Exception as e:
56
+ error_msg = f"❌ Error al inicializar modelo Gemini: {str(e)}"
57
  logger.error(error_msg)
58
  st.error(error_msg)
59
+ # st.stop() # Decidir si detener la app si el modelo no carga
60
 
61
+ # Formatear prompt para interpretación Rorschach con Gemini
62
+ def format_prompt_gemini(message):
63
+ system_prompt = """Eres un experto en interpretación del Test de Rorschach.
64
+ Analiza las respuestas del usuario a las láminas y proporciona una interpretación
65
  psicológica detallada basada en el método de Exner.
66
+
67
  Considera:
68
  - Localización de las respuestas
69
  - Determinantes (forma, color, movimiento)
 
73
  Al final describe una conclusion creativa en terminos sencillos de la personalidad del usuario
74
  con recomendaciones generales.
75
  """
76
+
77
+ # Gemini prefiere una concatenación más directa o el uso de 'parts' para roles.
78
+ # Para una única llamada de generación de texto, concatenar es simple.
79
+ prompt = f"{system_prompt}\n\nInterpretación Rorschach para las siguientes respuestas del usuario:\n{message}"
80
+ logger.info(f"Prompt para Gemini generado con {len(prompt)} caracteres")
81
  return prompt
82
 
83
+ # Generar respuesta desde Gemini
84
+ def generate_with_gemini(user_input_message):
85
+ if not model:
86
+ logger.error("❌ No hay modelo Gemini disponible para generar respuesta")
87
+ return "Error de conexión con el modelo Gemini. Por favor, inténtelo de nuevo más tarde."
88
 
89
  try:
90
+ logger.info(f"🔄 Iniciando llamada al API de Gemini - {datetime.datetime.now()}")
91
 
92
+ generation_config = genai.types.GenerationConfig(
93
+ temperature=0.7, # Gemini usa un rango similar, 0.9 es bastante creativo
94
+ max_output_tokens=1024, # Aumentado un poco para asegurar respuestas completas
95
  top_p=0.95,
96
+ # top_k es otro parámetro que podrías usar en Gemini
97
+ # repetition_penalty no es un parámetro directo en GenerationConfig
98
+ # do_sample es implícito si temperature > 0
99
+ # seed no es un parámetro directo de GenerationConfig para `generate_content`
100
  )
101
 
102
+ formatted_prompt = format_prompt_gemini(user_input_message)
103
  start_time = datetime.datetime.now()
104
 
105
+ # Llamada a Gemini
106
+ response = model.generate_content(
107
+ formatted_prompt,
108
+ generation_config=generation_config
109
+ )
110
 
111
  end_time = datetime.datetime.now()
112
  duration = (end_time - start_time).total_seconds()
113
 
114
+ logger.info(f"✅ Respuesta de Gemini generada en {duration:.2f} segundos")
115
+
116
+ # Acceder al texto de la respuesta
117
+ if response.parts:
118
+ output_text = response.text
119
+ else:
120
+ # Esto podría ocurrir si la respuesta fue bloqueada por filtros de seguridad
121
+ logger.warning(f"⚠️ Respuesta de Gemini vacía o bloqueada. Razón: {response.prompt_feedback}")
122
+ output_text = (
123
+ "No se pudo generar una respuesta. Esto podría deberse a filtros de seguridad "
124
+ f"o a un problema con la solicitud. Razón del feedback: {response.prompt_feedback}"
125
+ )
126
+ return output_text
127
 
128
  except Exception as e:
129
+ error_msg = f"❌ Error en la generación con Gemini: {str(e)}"
130
  logger.error(error_msg)
131
+ # Verificar si el error es por API key inválida (aunque ya se verifica al inicio)
132
+ if "API_KEY_INVALID" in str(e):
133
+ st.error("La clave API de Gemini es inválida o ha expirado. Verifica tu configuración.")
134
+ return f"Lo siento, ocurrió un error durante la interpretación con Gemini. Detalles: {str(e)}"
135
 
136
  # Reemplazo de variables en documento Word
137
+ from docx.enum.text import WD_ALIGN_PARAGRAPH
138
 
139
  def replace_variables_word(doc, variables):
140
  for paragraph in doc.paragraphs:
141
  for key, value in variables.items():
142
  if f'<{key}>' in paragraph.text:
143
+ # Usar run para preservar formato si es posible, pero simple replace es más robusto para placeholder
144
+ # Si el placeholder está solo, paragraph.text es suficiente
145
+ # Si está entre otro texto, se necesita más cuidado con runs
146
+ new_text = paragraph.text.replace(f'<{key}>', str(value)) # Asegurar que value sea string
147
+ if paragraph.text != new_text: # Solo si hubo cambio
148
+ paragraph.text = new_text
149
+ paragraph.alignment = WD_ALIGN_PARAGRAPH.LEFT # Justificación
150
  for table in doc.tables:
151
  for row in table.rows:
152
  for cell in row.cells:
153
  for paragraph in cell.paragraphs:
154
  for key, value in variables.items():
155
  if f'<{key}>' in paragraph.text:
156
+ new_text = paragraph.text.replace(f'<{key}>', str(value))
157
+ if paragraph.text != new_text:
158
+ paragraph.text = new_text
159
+ paragraph.alignment = WD_ALIGN_PARAGRAPH.LEFT
160
+
161
 
162
  # Generar documento Word con interpretación
163
  def generate_word_document(interpretation):
 
185
  return None
186
 
187
  # Interfaz Streamlit
188
+ st.title("Interpretación del Test de Rorschach (con Gemini)")
189
+ logger.info("🚀 Aplicación (Gemini) iniciada")
190
 
191
  entrada_usuario = st.text_area(
192
  "Ingrese respuestas del Test de Rorschach:",
 
194
  placeholder="Ejemplo: Lámina I: Veo un murciélago sobre un noche estrellada..."
195
  )
196
 
197
+ if st.button("Enviar Interpretación", type="primary"):
198
  if not entrada_usuario:
199
  st.warning("Por favor ingrese texto para interpretar")
200
+ elif not model: # Verificar si el modelo se cargó
201
+ st.error("El modelo de IA no está disponible. Por favor, revise la configuración y los logs.")
202
+ logger.error("Intento de generar interpretación sin modelo cargado.")
203
  else:
204
+ logger.info(f"🔄 Procesando entrada de {len(entrada_usuario)} caracteres para Gemini")
205
+ with st.spinner("Generando interpretación con Gemini..."):
206
+ bot_response = generate_with_gemini(entrada_usuario) # Llamada a la nueva función
207
+ st.subheader("Interpretación (Gemini)")
208
+ st.markdown(bot_response) # Usar markdown para mejor formato si Gemini lo usa
209
+
210
+ if "No se pudo generar una respuesta" not in bot_response and "ocurrió un error" not in bot_response :
211
+ document_path = generate_word_document(bot_response)
212
+ if document_path:
213
+ with open(document_path, "rb") as file:
214
+ file_data = file.read()
215
+ st.download_button(
216
+ label="Descargar Interpretación",
217
+ data=file_data,
218
+ file_name="Interpretacion_Rorschach_Gemini.docx",
219
+ mime="application/vnd.openxmlformats-officedocument.wordprocessingml.document"
220
+ )
221
+ logger.info("📄 Botón de descarga (Gemini) mostrado al usuario")
222
+ # Clean up the temporary file
223
+ try:
224
+ os.remove(document_path)
225
+ logger.info(f"🧹 Archivo temporal {document_path} eliminado.")
226
+ except OSError as e_rm:
227
+ logger.error(f"⚠️ Error al eliminar archivo temporal {document_path}: {e_rm}")
228
+
229
+ else:
230
+ logger.error("❌ No se pudo generar el documento Word (Gemini)")
231
  else:
232
+ logger.warning("⚠️ No se generó documento Word debido a error en la interpretación.")
233
 
234
+ # --- END OF FILE manchas_gemini.py ---