Josedcape commited on
Commit
17f0253
·
verified ·
1 Parent(s): ee78a4d

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +57 -500
app.py CHANGED
@@ -1,422 +1,29 @@
1
- import os
2
- import time
3
- from openai import OpenAI
4
  import streamlit as st
5
- from dotenv import load_dotenv
6
- import requests
7
- import base64
8
- from pathlib import Path
9
- import io
10
- import json
11
 
12
- # Configuración inicial de Streamlit con tema futurista
13
- st.set_page_config(
14
- page_title="🚀 Galatea AI - OMARDENT",
15
- layout="wide",
16
- page_icon="🦷",
17
- initial_sidebar_state="expanded"
18
- )
19
-
20
- # Cargar claves desde el archivo .env
21
- load_dotenv()
22
-
23
- # Inicializar cliente OpenAI moderno
24
- client = OpenAI(
25
- api_key=os.getenv("OPENAI_API_KEY")
26
- )
27
-
28
- # Descargar el sonido de notificación si no existe
29
- url_sonido = "http://sonidosmp3gratis.com/sounds/000217388_prev.mp3"
30
- if not os.path.exists("notificacion.mp3"):
31
- response = requests.get(url_sonido)
32
- with open("notificacion.mp3", "wb") as f:
33
- f.write(response.content)
34
-
35
- # Función para obtener respuesta y síntesis de voz usando OpenAI TTS moderno
36
- def obtener_respuesta_openai(pregunta, modelo="gpt-4o-mini", voz="nova", temperatura=0.5):
37
- """
38
- Obtiene respuesta del chat y genera audio con OpenAI TTS
39
- """
40
- try:
41
- print(f"🤖 Procesando pregunta: {pregunta[:50]}...")
42
- contexto = """
43
- Actúas como Galatea, la auxiliar de odontología capacitada de la clínica odontológica Omardent.
44
- Tu tarea es enviar respuestas precisas y directas, sin agregar o inventar información. Solo responde lo solicitado de manera breve y profesional.
45
- En la clínica atienden dos doctores: el Dr. Omar y el Dr. José Daniel.
46
- La clínica tiene únicamente dos consultorios.
47
- Además, trabaja una auxiliar llamada Ade.
48
- Nunca debes decir "buenos días" o "buenas tardes". Mantén un tono cordial en todo momento.
49
- """
50
- # Obtener respuesta del chat usando la nueva API
51
- print(f"💬 Generando respuesta con {modelo}...")
52
- chat_response = client.chat.completions.create(
53
- model=modelo,
54
- messages=[
55
- {"role": "system", "content": contexto},
56
- {"role": "user", "content": pregunta}
57
- ],
58
- temperature=temperatura
59
- )
60
- respuesta = chat_response.choices[0].message.content.strip()
61
- print(f"✅ Respuesta generada: {respuesta[:50]}...")
62
- # Generar audio con OpenAI TTS
63
- print(f"🎵 Generando audio con voz {voz}...")
64
- audio_response = client.audio.speech.create(
65
- model="tts-1", # Modelo TTS más rápido
66
- voice=voz, # Voz seleccionada por el usuario
67
- input=respuesta,
68
- response_format="mp3",
69
- speed=1.0 # Velocidad normal para claridad
70
- )
71
- # Convertir audio a base64 para Streamlit
72
- audio_bytes = audio_response.content
73
- audio_base64 = base64.b64encode(audio_bytes).decode('utf-8')
74
- print(f"✅ Audio generado exitosamente - Tamaño: {len(audio_base64)} caracteres")
75
- return respuesta, audio_base64
76
- except Exception as e:
77
- print(f"❌ Error al procesar la solicitud: {e}")
78
- return f"Error al procesar la solicitud: {e}", None
79
-
80
- # Función avanzada para mejorar prompts usando OpenAI
81
- def enhance_prompt_with_ai(prompt):
82
- """
83
- Mejora el prompt del usuario usando IA avanzada para obtener mejores respuestas
84
- """
85
- try:
86
- print(f"🔄 Mejorando prompt: {prompt[:50]}...")
87
- enhanced_response = client.chat.completions.create(
88
- model="gpt-4o-mini",
89
- messages=[
90
- {
91
- "role": "system",
92
- "content": """Eres un experto en optimización de prompts para asistentes dentales.
93
- Tu tarea es mejorar las preguntas de los usuarios para que sean más específicas, claras y efectivas.
94
- REGLAS:
95
- 1. Mantén el contexto odontológico de la clínica Omardent
96
- 2. Haz la pregunta más específica y detallada
97
- 3. Agrega contexto relevante si es necesario
98
- 4. Mantén un tono profesional pero amigable
99
- 5. Si la pregunta es muy general, hazla más específica
100
- 6. Incluye detalles que ayuden a dar una respuesta más precisa
101
- EJEMPLOS:
102
- - "¿Cuánto cuesta?" → "¿Cuál es el costo aproximado de una limpieza dental en la clínica Omardent?"
103
- - "Tengo dolor" → "Tengo dolor en una muela del lado derecho, ¿qué podría ser y cuándo debería agendar una cita?"
104
- - "Horarios" → "¿Cuáles son los horarios de atención de la clínica Omardent y cómo puedo agendar una cita?"
105
- Devuelve SOLO la pregunta mejorada, sin explicaciones adicionales."""
106
- },
107
- {"role": "user", "content": f"Mejora esta pregunta: {prompt}"}
108
- ],
109
- temperature=0.3,
110
- max_tokens=200
111
- )
112
- improved_prompt = enhanced_response.choices[0].message.content.strip()
113
- print(f"✅ Prompt mejorado: {improved_prompt[:50]}...")
114
- return improved_prompt
115
- except Exception as e:
116
- print(f"❌ Error mejorando prompt: {e}")
117
- return prompt # Devolver el prompt original si falla
118
-
119
- # Función para generar sugerencias de preguntas
120
- def generate_smart_suggestions():
121
- """
122
- Genera sugerencias inteligentes de preguntas usando OpenAI
123
- """
124
- try:
125
- suggestions_response = client.chat.completions.create(
126
- model="gpt-4o-mini",
127
- messages=[
128
- {
129
- "role": "system",
130
- "content": """Genera 5 preguntas frecuentes que los pacientes podrían hacer a un asistente dental de la clínica Omardent.
131
- Las preguntas deben ser variadas: horarios, servicios, costos, cuidados, emergencias.
132
- Devuelve solo las preguntas, una por línea, sin numeración."""
133
- }
134
- ],
135
- temperature=0.7,
136
- max_tokens=300
137
- )
138
- suggestions = suggestions_response.choices[0].message.content.strip().split('\n')
139
- return [s.strip() for s in suggestions if s.strip()]
140
- except Exception as e:
141
- print(f"Error generando sugerencias: {e}")
142
- return [
143
- "¿Cuáles son los horarios de atención de la clínica?",
144
- "¿Qué servicios odontológicos ofrecen?",
145
- "¿Cómo puedo agendar una cita de emergencia?",
146
- "¿Cuánto cuesta una limpieza dental?",
147
- "¿Qué cuidados debo tener después de una extracción?"
148
- ]
149
-
150
- # Interfaz de usuario
151
  def mostrar_galatea_asistente():
152
- # CSS Futurista con Animaciones Avanzadas
153
- st.markdown(
154
- """
155
- <style>
156
- @import url('https://fonts.googleapis.com/css2?family=Orbitron:wght@400;700;900&family=Exo+2:wght@300;400;600&display=swap');
157
- /* Variables CSS para tema futurista */
158
- :root {
159
- --primary-cyan: #00ffff;
160
- --primary-blue: #0066ff;
161
- --dark-bg: #0a0a0a;
162
- --card-bg: #1a1a2e;
163
- --accent-purple: #8b5cf6;
164
- --accent-pink: #ec4899;
165
- --text-light: #e2e8f0;
166
- --glow-cyan: 0 0 20px #00ffff;
167
- --glow-purple: 0 0 20px #8b5cf6;
168
- }
169
- /* Fondo principal futurista */
170
- .stApp {
171
- background: linear-gradient(135deg, #0a0a0a 0%, #1a1a2e 50%, #16213e 100%);
172
- color: var(--text-light);
173
- font-family: 'Exo 2', sans-serif;
174
- }
175
- /* Animaciones de partículas en el fondo */
176
- .stApp::before {
177
- content: '';
178
- position: fixed;
179
- top: 0;
180
- left: 0;
181
- width: 100%;
182
- height: 100%;
183
- background-image:
184
- radial-gradient(2px 2px at 20px 30px, var(--primary-cyan), transparent),
185
- radial-gradient(2px 2px at 40px 70px, var(--accent-purple), transparent),
186
- radial-gradient(1px 1px at 90px 40px, var(--primary-blue), transparent),
187
- radial-gradient(1px 1px at 130px 80px, var(--accent-pink), transparent);
188
- background-repeat: repeat;
189
- background-size: 200px 200px;
190
- animation: particleFloat 20s linear infinite;
191
- opacity: 0.1;
192
- z-index: -1;
193
- }
194
- @keyframes particleFloat {
195
- 0% { transform: translateY(0px) translateX(0px); }
196
- 33% { transform: translateY(-20px) translateX(10px); }
197
- 66% { transform: translateY(-10px) translateX(-10px); }
198
- 100% { transform: translateY(0px) translateX(0px); }
199
- }
200
- /* Botones futuristas con efectos de glow */
201
- .stButton>button {
202
- background: linear-gradient(135deg, var(--primary-cyan), var(--primary-blue));
203
- color: var(--dark-bg);
204
- border: none;
205
- border-radius: 25px;
206
- padding: 0.75rem 1.5rem;
207
- font-weight: 600;
208
- font-family: 'Orbitron', monospace;
209
- text-transform: uppercase;
210
- letter-spacing: 1px;
211
- transition: all 0.3s ease;
212
- box-shadow: var(--glow-cyan);
213
- position: relative;
214
- overflow: hidden;
215
- }
216
- .stButton>button::before {
217
- content: '';
218
- position: absolute;
219
- top: 0;
220
- left: -100%;
221
- width: 100%;
222
- height: 100%;
223
- background: linear-gradient(90deg, transparent, rgba(255,255,255,0.3), transparent);
224
- transition: left 0.5s;
225
- }
226
- .stButton>button:hover {
227
- transform: translateY(-3px) scale(1.05);
228
- box-shadow: var(--glow-cyan), 0 10px 25px rgba(0,255,255,0.3);
229
- background: linear-gradient(135deg, var(--accent-purple), var(--accent-pink));
230
- }
231
- .stButton>button:hover::before {
232
- left: 100%;
233
- }
234
- /* Inputs futuristas */
235
- .stTextInput>div>div>input {
236
- background: rgba(26, 26, 46, 0.8);
237
- border: 2px solid var(--primary-cyan);
238
- border-radius: 15px;
239
- color: var(--text-light);
240
- font-family: 'Exo 2', sans-serif;
241
- padding: 0.75rem;
242
- transition: all 0.3s ease;
243
- backdrop-filter: blur(10px);
244
- }
245
- .stTextInput>div>div>input:focus {
246
- border-color: var(--accent-purple);
247
- box-shadow: var(--glow-purple);
248
- transform: scale(1.02);
249
- }
250
- /* Selectboxes futuristas */
251
- .stSelectbox>div>div>select {
252
- background: rgba(26, 26, 46, 0.8);
253
- border: 2px solid var(--primary-cyan);
254
- border-radius: 15px;
255
- color: var(--text-light);
256
- font-family: 'Exo 2', sans-serif;
257
- padding: 0.5rem;
258
- backdrop-filter: blur(10px);
259
- }
260
- /* Slider futurista */
261
- .stSlider>div>div>div>div {
262
- background: linear-gradient(90deg, var(--primary-cyan), var(--accent-purple));
263
- border-radius: 10px;
264
- }
265
- /* Cards con efecto glassmorphism */
266
- .futuristic-card {
267
- background: rgba(26, 26, 46, 0.3);
268
- backdrop-filter: blur(15px);
269
- border: 1px solid rgba(0, 255, 255, 0.3);
270
- border-radius: 20px;
271
- padding: 2rem;
272
- margin: 1rem 0;
273
- box-shadow: 0 8px 32px rgba(0, 255, 255, 0.1);
274
- transition: all 0.3s ease;
275
- position: relative;
276
- overflow: hidden;
277
- }
278
- .futuristic-card::before {
279
- content: '';
280
- position: absolute;
281
- top: 0;
282
- left: 0;
283
- right: 0;
284
- height: 2px;
285
- background: linear-gradient(90deg, var(--primary-cyan), var(--accent-purple), var(--accent-pink));
286
- animation: borderGlow 3s ease-in-out infinite alternate;
287
- }
288
- @keyframes borderGlow {
289
- 0% { opacity: 0.5; }
290
- 100% { opacity: 1; }
291
- }
292
- .futuristic-card:hover {
293
- transform: translateY(-5px);
294
- box-shadow: 0 15px 40px rgba(0, 255, 255, 0.2);
295
- border-color: var(--accent-purple);
296
- }
297
- /* Texto con efecto de glow */
298
- .glow-text {
299
- color: var(--primary-cyan);
300
- text-shadow: 0 0 10px var(--primary-cyan);
301
- font-family: 'Orbitron', monospace;
302
- font-weight: 700;
303
- }
304
- /* Animación de typing */
305
- .typing-animation {
306
- overflow: hidden;
307
- border-right: 3px solid var(--primary-cyan);
308
- white-space: nowrap;
309
- animation: typing 3s steps(40, end), blink-caret 0.75s step-end infinite;
310
- }
311
- @keyframes typing {
312
- from { width: 0; }
313
- to { width: 100%; }
314
- }
315
- @keyframes blink-caret {
316
- from, to { border-color: transparent; }
317
- 50% { border-color: var(--primary-cyan); }
318
- }
319
- /* Sidebar futurista */
320
- .css-1d391kg {
321
- background: rgba(10, 10, 10, 0.9);
322
- backdrop-filter: blur(15px);
323
- }
324
- /* Audio player futurista */
325
- audio {
326
- background: rgba(26, 26, 46, 0.8);
327
- border-radius: 15px;
328
- border: 2px solid var(--primary-cyan);
329
- backdrop-filter: blur(10px);
330
- }
331
- /* Spinner personalizado */
332
- .stSpinner > div {
333
- border-top-color: var(--primary-cyan) !important;
334
- border-right-color: var(--accent-purple) !important;
335
- }
336
- /* Efectos de hover para elementos interactivos */
337
- .interactive-element {
338
- transition: all 0.3s ease;
339
- cursor: pointer;
340
- }
341
- .interactive-element:hover {
342
- transform: scale(1.05);
343
- filter: brightness(1.2);
344
- }
345
- /* Animación de pulso para elementos importantes */
346
- .pulse-glow {
347
- animation: pulseGlow 2s ease-in-out infinite alternate;
348
- }
349
- @keyframes pulseGlow {
350
- 0% { box-shadow: 0 0 5px var(--primary-cyan); }
351
- 100% { box-shadow: 0 0 20px var(--primary-cyan), 0 0 30px var(--primary-cyan); }
352
- }
353
- /* Scrollbar personalizada */
354
- ::-webkit-scrollbar {
355
- width: 8px;
356
- }
357
- ::-webkit-scrollbar-track {
358
- background: var(--dark-bg);
359
- }
360
- ::-webkit-scrollbar-thumb {
361
- background: linear-gradient(var(--primary-cyan), var(--accent-purple));
362
- border-radius: 4px;
363
- }
364
- ::-webkit-scrollbar-thumb:hover {
365
- background: linear-gradient(var(--accent-purple), var(--accent-pink));
366
- }
367
- </style>
368
- """,
369
- unsafe_allow_html=True
370
- )
371
-
372
- # Header futurista con animaciones
373
- st.markdown(
374
- """
375
- <div class="futuristic-card pulse-glow" style="text-align: center; margin-bottom: 2rem;">
376
- <h1 class="glow-text typing-animation" style="font-size: 3rem; margin: 0;">
377
- 🚀 GALATEA AI
378
- </h1>
379
- <h2 style="color: var(--accent-purple); font-family: 'Orbitron', monospace; margin: 0.5rem 0;">
380
- CLÍNICA ODONTOLÓGICA OMARDENT
381
- </h2>
382
- <div style="display: flex; justify-content: center; align-items: center; gap: 1rem; margin-top: 1rem;">
383
- <span style="color: var(--primary-cyan); font-weight: 600;">🤖 OpenAI GPT-4o-mini</span>
384
- <span style="color: var(--accent-pink);">•</span>
385
- <span style="color: var(--primary-cyan); font-weight: 600;">🎵 OpenAI TTS</span>
386
- <span style="color: var(--accent-pink);">•</span>
387
- <span style="color: var(--primary-cyan); font-weight: 600;">⚡ Tiempo Real</span>
388
- </div>
389
- <div style="margin-top: 1rem; padding: 0.5rem; background: rgba(0,255,255,0.1); border-radius: 10px; border: 1px solid var(--primary-cyan);">
390
- <span style="color: var(--text-light); font-size: 0.9rem;">
391
- 🌟 Asistente Dental Inteligente con Síntesis de Voz Avanzada
392
- </span>
393
- </div>
394
- </div>
395
- """,
396
- unsafe_allow_html=True
397
- )
398
 
399
  # Configuración en columnas
400
  col1, col2 = st.columns([2, 1])
401
  with col1:
402
- # Inicializar el estado de la pregunta si no existe
403
- if 'pregunta' not in st.session_state:
404
- st.session_state.pregunta = ""
405
  pregunta = st.text_input(
406
  "💬 Escribe tu pregunta para Galatea:",
407
  value=st.session_state.pregunta,
408
- placeholder="Ejemplo: ¿Cuáles son los horarios de atención?"
 
409
  )
 
 
410
  with col2:
411
  st.markdown("### 🎛️ Configuración")
412
- # Selector de voz
413
  voz_seleccionada = st.selectbox(
414
  "🎤 Voz OpenAI:",
415
  ["nova", "alloy", "echo", "fable", "onyx", "shimmer"],
416
  index=0,
417
  help="Nova: Femenina joven | Alloy: Neutral | Echo: Masculina"
418
  )
419
- # Selector de modelo
420
  modelo_seleccionado = st.selectbox(
421
  "🤖 Modelo:",
422
  ["gpt-4o-mini", "gpt-3.5-turbo", "gpt-4"],
@@ -427,67 +34,27 @@ def mostrar_galatea_asistente():
427
  col_btn1, col_btn2, col_btn3 = st.columns(3)
428
  with col_btn1:
429
  if st.button("✨ Mejorar Prompt", use_container_width=True):
430
- if pregunta:
431
  with st.spinner("🔄 Mejorando pregunta..."):
432
- pregunta_mejorada = enhance_prompt_with_ai(pregunta)
433
  st.session_state.pregunta = pregunta_mejorada
434
- st.rerun() # Streamlit moderno
 
 
 
435
  with col_btn2:
436
- respuesta_inmediata = st.button("🚀 Respuesta Inmediata", use_container_width=True)
 
 
 
 
 
437
  with col_btn3:
438
  st.markdown("### ⏱️ Temporizador")
439
  intervalo = st.slider("Segundos:", 5, 60, 10)
440
 
441
- # Función para procesar respuesta
442
- def procesar_respuesta():
443
- if st.session_state.pregunta:
444
- with st.spinner("🤖 Generando respuesta y audio con OpenAI TTS..."):
445
- respuesta, audio_base64 = obtener_respuesta_openai(
446
- st.session_state.pregunta,
447
- modelo=modelo_seleccionado,
448
- voz=voz_seleccionada
449
- )
450
- # Mostrar respuesta
451
- st.markdown("---")
452
- st.markdown(
453
- f"""
454
- <div class="success-box">
455
- <h3>🤖 Galatea responde:</h3>
456
- <p style="font-size: 1.1em; line-height: 1.6;">{respuesta}</p>
457
- </div>
458
- """,
459
- unsafe_allow_html=True
460
- )
461
- if audio_base64:
462
- st.markdown("### 🎵 Audio generado con OpenAI TTS:")
463
- st.markdown(
464
- f"""
465
- <div style="background: #f0f8ff; padding: 1rem; border-radius: 10px; margin: 1rem 0;">
466
- <audio autoplay controls style="width: 100%;">
467
- <source src="data:audio/mp3;base64,{audio_base64}" type="audio/mp3">
468
- Tu navegador no soporta el elemento de audio.
469
- </audio>
470
- <p style="margin-top: 0.5rem; font-size: 0.9em; color: #666;">
471
- 🎤 Voz: <strong>{voz_seleccionada}</strong> |
472
- 🤖 Modelo: <strong>{modelo_seleccionado}</strong>
473
- </p>
474
- </div>
475
- """, unsafe_allow_html=True)
476
- else:
477
- st.error("❌ No se pudo generar el audio")
478
- else:
479
- st.warning("⚠️ Por favor, escribe una pregunta primero.")
480
-
481
- # Respuesta inmediata
482
- if respuesta_inmediata:
483
- procesar_respuesta()
484
-
485
- # Temporizador
486
  if st.button("⏱️ Iniciar Temporizador", use_container_width=True):
487
- if not st.session_state.pregunta:
488
- st.warning("⚠️ Por favor, escribe una pregunta primero.")
489
- else:
490
- # Placeholder para el reloj
491
  reloj_placeholder = st.empty()
492
  for i in range(intervalo, 0, -1):
493
  reloj_placeholder.markdown(
@@ -509,53 +76,43 @@ def mostrar_galatea_asistente():
509
  """,
510
  unsafe_allow_html=True
511
  )
512
- # Procesar respuesta después del temporizador
513
  procesar_respuesta()
 
 
514
 
515
- # Información adicional en la barra lateral
516
- with st.sidebar:
517
- st.markdown("### 📋 Información de la Clínica")
518
- st.markdown("""
519
- **🏥 Clínica Omardent**
520
- - 👨‍⚕️ Dr. Omar
521
- - 👨‍⚕️ Dr. José Daniel
522
- - 👩‍⚕️ Auxiliar Ade
523
- - 🏢 2 Consultorios disponibles
524
- """)
525
- st.markdown("### 🎤 Voces Disponibles")
526
- voces_info = {
527
- "nova": "👩 Femenina joven y clara",
528
- "alloy": "🤖 Neutral y versátil",
529
- "echo": "👨 Masculina profesional",
530
- "fable": "🎭 Acento británico",
531
- "onyx": "👨 Masculina profunda",
532
- "shimmer": "👩 Femenina suave"
533
- }
534
- for voz, descripcion in voces_info.items():
535
- st.markdown(f"**{voz}**: {descripcion}")
536
- st.markdown("### 💡 Ejemplos de Preguntas")
537
- ejemplos = [
538
- "¿Cuáles son los horarios de atención?",
539
- "¿Qué servicios ofrece la clínica?",
540
- "¿Cómo puedo agendar una cita?",
541
- "¿Cuánto cuesta una limpieza dental?",
542
- "¿Qué debo hacer después de una extracción?"
543
- ]
544
- for ejemplo in ejemplos:
545
- if st.button(f"📝 {ejemplo}", key=f"ejemplo_{hash(ejemplo)}", use_container_width=True):
546
- st.session_state.pregunta = ejemplo
547
- st.rerun()
548
  st.markdown("---")
549
- st.markdown("### ⚙️ Tecnología")
550
- st.markdown("""
551
- - 🤖 **OpenAI GPT-4o-mini** para respuestas
552
- - 🎵 **OpenAI TTS** para síntesis de voz
553
- - **Streamlit** para la interfaz
554
- - 🔊 **Audio de alta calidad** en tiempo real
555
- """)
556
-
557
- def main():
558
- mostrar_galatea_asistente()
559
-
560
- if __name__ == "__main__":
561
- main()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  import streamlit as st
 
 
 
 
 
 
2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3
  def mostrar_galatea_asistente():
4
+ # Inicializar el estado de la pregunta si no existe
5
+ if 'pregunta' not in st.session_state:
6
+ st.session_state.pregunta = ""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7
 
8
  # Configuración en columnas
9
  col1, col2 = st.columns([2, 1])
10
  with col1:
 
 
 
11
  pregunta = st.text_input(
12
  "💬 Escribe tu pregunta para Galatea:",
13
  value=st.session_state.pregunta,
14
+ placeholder="Ejemplo: ¿Cuáles son los horarios de atención?",
15
+ key="pregunta_input"
16
  )
17
+ st.session_state.pregunta = pregunta # Actualizar el estado con la pregunta actual
18
+
19
  with col2:
20
  st.markdown("### 🎛️ Configuración")
 
21
  voz_seleccionada = st.selectbox(
22
  "🎤 Voz OpenAI:",
23
  ["nova", "alloy", "echo", "fable", "onyx", "shimmer"],
24
  index=0,
25
  help="Nova: Femenina joven | Alloy: Neutral | Echo: Masculina"
26
  )
 
27
  modelo_seleccionado = st.selectbox(
28
  "🤖 Modelo:",
29
  ["gpt-4o-mini", "gpt-3.5-turbo", "gpt-4"],
 
34
  col_btn1, col_btn2, col_btn3 = st.columns(3)
35
  with col_btn1:
36
  if st.button("✨ Mejorar Prompt", use_container_width=True):
37
+ if st.session_state.pregunta:
38
  with st.spinner("🔄 Mejorando pregunta..."):
39
+ pregunta_mejorada = enhance_prompt_with_ai(st.session_state.pregunta)
40
  st.session_state.pregunta = pregunta_mejorada
41
+ st.rerun()
42
+ else:
43
+ st.warning("⚠️ Por favor, escribe una pregunta primero.")
44
+
45
  with col_btn2:
46
+ if st.button("🚀 Respuesta Inmediata", use_container_width=True):
47
+ if st.session_state.pregunta:
48
+ procesar_respuesta()
49
+ else:
50
+ st.warning("⚠️ Por favor, escribe una pregunta primero.")
51
+
52
  with col_btn3:
53
  st.markdown("### ⏱️ Temporizador")
54
  intervalo = st.slider("Segundos:", 5, 60, 10)
55
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
56
  if st.button("⏱️ Iniciar Temporizador", use_container_width=True):
57
+ if st.session_state.pregunta:
 
 
 
58
  reloj_placeholder = st.empty()
59
  for i in range(intervalo, 0, -1):
60
  reloj_placeholder.markdown(
 
76
  """,
77
  unsafe_allow_html=True
78
  )
 
79
  procesar_respuesta()
80
+ else:
81
+ st.warning("⚠️ Por favor, escribe una pregunta primero.")
82
 
83
+ def procesar_respuesta():
84
+ if st.session_state.pregunta:
85
+ with st.spinner("🤖 Generando respuesta y audio con OpenAI TTS..."):
86
+ respuesta, audio_base64 = obtener_respuesta_openai(
87
+ st.session_state.pregunta,
88
+ modelo=modelo_seleccionado,
89
+ voz=voz_seleccionada
90
+ )
91
+ # Mostrar respuesta
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
92
  st.markdown("---")
93
+ st.markdown(
94
+ f"""
95
+ <div class="success-box">
96
+ <h3>🤖 Galatea responde:</h3>
97
+ <p style="font-size: 1.1em; line-height: 1.6;">{respuesta}</p>
98
+ </div>
99
+ """,
100
+ unsafe_allow_html=True
101
+ )
102
+ if audio_base64:
103
+ st.markdown("### 🎵 Audio generado con OpenAI TTS:")
104
+ st.markdown(
105
+ f"""
106
+ <div style="background: #f0f8ff; padding: 1rem; border-radius: 10px; margin: 1rem 0;">
107
+ <audio autoplay controls style="width: 100%;">
108
+ <source src="data:audio/mp3;base64,{audio_base64}" type="audio/mp3">
109
+ Tu navegador no soporta el elemento de audio.
110
+ </audio>
111
+ <p style="margin-top: 0.5rem; font-size: 0.9em; color: #666;">
112
+ 🎤 Voz: <strong>{voz_seleccionada}</strong> |
113
+ 🤖 Modelo: <strong>{modelo_seleccionado}</strong>
114
+ </p>
115
+ </div>
116
+ """, unsafe_allow_html=True)
117
+ else:
118
+ st.error("❌ No se pudo generar el audio")