Spaces:
Running
Running
File size: 10,524 Bytes
2c2f50d 2108de0 21a807d 2108de0 e0ecd33 e4f7e04 53a4ac5 e4f7e04 53a4ac5 e4f7e04 2108de0 088ccd5 53a4ac5 2108de0 53a4ac5 c52e98f 2108de0 a83f5b8 c52e98f 2108de0 e4f7e04 2108de0 a83f5b8 e4f7e04 2108de0 53a4ac5 2108de0 e4f7e04 2108de0 6f6776f 2108de0 6f6776f 6440885 bde368b 2108de0 21a807d 2108de0 01fb88d bde368b 2108de0 53a4ac5 2108de0 e4f7e04 2108de0 bde368b 01fb88d 2108de0 53a4ac5 2108de0 01fb88d 53a4ac5 01fb88d 2108de0 01fb88d bde368b 2108de0 53a4ac5 2108de0 21a807d 53a4ac5 2108de0 5d02f0a e0ecd33 2108de0 e0ecd33 2108de0 e0ecd33 53a4ac5 6f6776f bde368b 53a4ac5 bde368b e4f7e04 6f6776f 01fb88d 6f6776f 53a4ac5 01fb88d bde368b 53a4ac5 bde368b 01fb88d bde368b 53a4ac5 bde368b e0ecd33 53a4ac5 2108de0 21a807d 6f6776f 5d02f0a 6f6776f bde368b 2108de0 e4f7e04 2108de0 e4f7e04 2108de0 e4f7e04 2108de0 e4f7e04 2108de0 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 | # ==================== Interprete de manchas de Test de Rorschach =====================================
#
# (o\ | /o)
# \.\_/. /
# .--._/oo\_.--.
# \ VVVV/ \VVVV /
# \____/ \____/
# __________________________________________________________________________________________________________
# DIANA MILENA SOLER Psicologa Est Medicina U. Juan N Corpas JAIRO ALEXANDER ERASO MD U Nacional de Colombia
#
import streamlit as st
import google.generativeai as genai # Import Gemini
from docx import Document
import tempfile
import os
import re
import logging
import datetime
# Configurar logging para monitorear las llamadas al API
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s',
handlers=[
logging.StreamHandler()
]
)
logger = logging.getLogger("rorschach_gemini_app")
# Configuración mínima de Streamlit
st.set_page_config(
page_title="Interpretación Rorschach con Gemini",
page_icon="🧠",
)
# --- CONFIGURACIÓN Gemini ---
GEMINI_API_KEY = os.getenv("GEMINI_API_KEY")
if not GEMINI_API_KEY:
st.error("GEMINI_API_KEY no encontrada. Por favor configúrala en tus variables de entorno.")
logger.error("GEMINI_API_KEY no encontrada.")
st.stop()
try:
genai.configure(api_key=GEMINI_API_KEY)
logger.info("✅ Configuración de Gemini API realizada.")
except Exception as e:
error_msg = f"❌ Error al configurar Gemini API: {str(e)}"
logger.error(error_msg)
st.error(error_msg)
st.stop()
@st.cache_resource
def get_gemini_model():
logger.info("🔄 Cargando modelo Gemini...")
# Puedes cambiar a "gemini-pro" si lo prefieres, gemini-1.5-flash es más rápido y económico
return genai.GenerativeModel("gemini-2.5-flash-lite")
# Inicializar modelo Gemini
model = None
try:
model = get_gemini_model()
logger.info("✅ Modelo Gemini cargado correctamente (gemini-2.5-flash-lite)")
except Exception as e:
error_msg = f"❌ Error al inicializar modelo Gemini: {str(e)}"
logger.error(error_msg)
st.error(error_msg)
# st.stop() # Decidir si detener la app si el modelo no carga
# Formatear prompt para interpretación Rorschach con Gemini
def format_prompt_gemini(message):
system_prompt = """Eres un experto en interpretación del Test de Rorschach.
Analiza las respuestas del usuario a las láminas y proporciona una interpretación
psicológica detallada basada en el método de Exner.
Considera:
- Localización de las respuestas
- Determinantes (forma, color, movimiento)
- Contenido de las respuestas
- Originalidad/popularidad
- Funcionamiento cognitivo, afectivo e interpersonal
Al final describe una conclusion creativa en terminos sencillos de la personalidad del usuario
con recomendaciones generales.
"""
# Gemini prefiere una concatenación más directa o el uso de 'parts' para roles.
# Para una única llamada de generación de texto, concatenar es simple.
prompt = f"{system_prompt}\n\nInterpretación Rorschach para las siguientes respuestas del usuario:\n{message}"
logger.info(f"Prompt para Gemini generado con {len(prompt)} caracteres")
return prompt
# Generar respuesta desde Gemini
def generate_with_gemini(user_input_message):
if not model:
logger.error("❌ No hay modelo Gemini disponible para generar respuesta")
return "Error de conexión con el modelo Gemini. Por favor, inténtelo de nuevo más tarde."
try:
logger.info(f"🔄 Iniciando llamada al API de Gemini - {datetime.datetime.now()}")
generation_config = genai.types.GenerationConfig(
temperature=0.7, # Gemini usa un rango similar, 0.9 es bastante creativo
max_output_tokens=1024, # Aumentado un poco para asegurar respuestas completas
top_p=0.95,
# top_k es otro parámetro que podrías usar en Gemini
# repetition_penalty no es un parámetro directo en GenerationConfig
# do_sample es implícito si temperature > 0
# seed no es un parámetro directo de GenerationConfig para `generate_content`
)
formatted_prompt = format_prompt_gemini(user_input_message)
start_time = datetime.datetime.now()
# Llamada a Gemini
response = model.generate_content(
formatted_prompt,
generation_config=generation_config
)
end_time = datetime.datetime.now()
duration = (end_time - start_time).total_seconds()
logger.info(f"✅ Respuesta de Gemini generada en {duration:.2f} segundos")
# Acceder al texto de la respuesta
if response.parts:
output_text = response.text
else:
# Esto podría ocurrir si la respuesta fue bloqueada por filtros de seguridad
logger.warning(f"⚠️ Respuesta de Gemini vacía o bloqueada. Razón: {response.prompt_feedback}")
output_text = (
"No se pudo generar una respuesta. Esto podría deberse a filtros de seguridad "
f"o a un problema con la solicitud. Razón del feedback: {response.prompt_feedback}"
)
return output_text
except Exception as e:
error_msg = f"❌ Error en la generación con Gemini: {str(e)}"
logger.error(error_msg)
# Verificar si el error es por API key inválida (aunque ya se verifica al inicio)
if "API_KEY_INVALID" in str(e):
st.error("La clave API de Gemini es inválida o ha expirado. Verifica tu configuración.")
return f"Lo siento, ocurrió un error durante la interpretación con Gemini. Detalles: {str(e)}"
# Reemplazo de variables en documento Word
from docx.enum.text import WD_ALIGN_PARAGRAPH
def replace_variables_word(doc, variables):
for paragraph in doc.paragraphs:
for key, value in variables.items():
if f'<{key}>' in paragraph.text:
# Usar run para preservar formato si es posible, pero simple replace es más robusto para placeholder
# Si el placeholder está solo, paragraph.text es suficiente
# Si está entre otro texto, se necesita más cuidado con runs
new_text = paragraph.text.replace(f'<{key}>', str(value)) # Asegurar que value sea string
if paragraph.text != new_text: # Solo si hubo cambio
paragraph.text = new_text
paragraph.alignment = WD_ALIGN_PARAGRAPH.LEFT # Justificación
for table in doc.tables:
for row in table.rows:
for cell in row.cells:
for paragraph in cell.paragraphs:
for key, value in variables.items():
if f'<{key}>' in paragraph.text:
new_text = paragraph.text.replace(f'<{key}>', str(value))
if paragraph.text != new_text:
paragraph.text = new_text
paragraph.alignment = WD_ALIGN_PARAGRAPH.LEFT
# Generar documento Word con interpretación
def generate_word_document(interpretation):
try:
template_path = os.path.join('PLANTILLAS', 'PLANTILLA_INTERPRETACION.docx')
if not os.path.exists(template_path):
logger.warning(f"⚠️ No se encontró la plantilla en {template_path}")
st.warning(f"No se encontró la plantilla en {template_path}")
return None
doc = Document(template_path)
variables = {'INTERPRETACION': interpretation}
replace_variables_word(doc, variables)
with tempfile.NamedTemporaryFile(delete=False, suffix='.docx') as tmp:
doc.save(tmp.name)
logger.info(f"✅ Documento Word generado correctamente: {tmp.name}")
return tmp.name
except Exception as e:
error_msg = f"❌ Error al generar el documento: {str(e)}"
logger.error(error_msg)
st.error(error_msg)
return None
# Interfaz Streamlit
st.title("Interpretación del Test de Rorschach (con Gemini)")
logger.info("🚀 Aplicación (Gemini) iniciada")
entrada_usuario = st.text_area(
"Ingrese respuestas del Test de Rorschach:",
height=150,
placeholder="Ejemplo: Lámina I: Veo un murciélago sobre un noche estrellada..."
)
if st.button("Enviar Interpretación", type="primary"):
if not entrada_usuario:
st.warning("Por favor ingrese texto para interpretar")
elif not model: # Verificar si el modelo se cargó
st.error("El modelo de IA no está disponible. Por favor, revise la configuración y los logs.")
logger.error("Intento de generar interpretación sin modelo cargado.")
else:
logger.info(f"🔄 Procesando entrada de {len(entrada_usuario)} caracteres para Gemini")
with st.spinner("Generando interpretación con Gemini..."):
bot_response = generate_with_gemini(entrada_usuario) # Llamada a la nueva función
st.subheader("Interpretación (Gemini)")
st.markdown(bot_response) # Usar markdown para mejor formato si Gemini lo usa
if "No se pudo generar una respuesta" not in bot_response and "ocurrió un error" not in bot_response :
document_path = generate_word_document(bot_response)
if document_path:
with open(document_path, "rb") as file:
file_data = file.read()
st.download_button(
label="Descargar Interpretación",
data=file_data,
file_name="Interpretacion_Rorschach_Gemini.docx",
mime="application/vnd.openxmlformats-officedocument.wordprocessingml.document"
)
logger.info("📄 Botón de descarga (Gemini) mostrado al usuario")
# Clean up the temporary file
try:
os.remove(document_path)
logger.info(f"🧹 Archivo temporal {document_path} eliminado.")
except OSError as e_rm:
logger.error(f"⚠️ Error al eliminar archivo temporal {document_path}: {e_rm}")
else:
logger.error("❌ No se pudo generar el documento Word (Gemini)")
else:
logger.warning("⚠️ No se generó documento Word debido a error en la interpretación.")
# --- END OF FILE manchas_gemini.py --- |