Josedcape commited on
Commit
5ffde4c
verified
1 Parent(s): 3aed6db

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +59 -514
app.py CHANGED
@@ -1,858 +1,403 @@
1
  import streamlit as st
2
-
3
  import openai
4
-
5
  import os
6
-
7
  import tempfile
8
-
9
  from google.cloud import texttospeech
10
-
11
  from dotenv import load_dotenv
12
-
13
  from docx import Document
14
-
15
  import base64
16
-
17
  from streamlit_player import st_player
18
-
19
  import smtplib
20
-
21
  from email.mime.multipart import MIMEMultipart
22
-
23
  from email.mime.text import MIMEText
24
-
25
  from email.mime.application import MIMEApplication
26
 
27
-
28
-
29
  # Configuraci贸n de la interfaz
30
-
31
  st.set_page_config(page_title="SURVEY ASSISTANT", layout="wide")
32
 
33
-
34
-
35
  # Cargar variables de entorno
36
-
37
  load_dotenv()
38
-
39
  openai.api_key = os.getenv("OPENAI_API_KEY")
40
-
41
  os.environ["GOOGLE_APPLICATION_CREDENTIALS"] = "botidinamix-g.json"
42
 
43
-
44
-
45
  # Funci贸n para obtener respuesta de OpenAI con historial de conversaci贸n
46
-
47
  def obtener_respuesta(pregunta, historial, modelo="gpt-4", temperatura=0.5):
48
-
49
  mensajes = historial + [
50
-
51
  {"role": "user", "content": pregunta}
52
-
53
  ]
54
-
55
  response = openai.ChatCompletion.create(
56
-
57
  model=modelo,
58
-
59
  messages=mensajes,
60
-
61
  temperature=temperatura,
62
-
63
  max_tokens=300,
64
-
65
  )
66
-
67
  respuesta = response['choices'][0]['message']['content']
68
-
69
  return respuesta
70
 
71
-
72
-
73
  # Funci贸n para convertir texto a voz usando Google Cloud Text-to-Speech
74
-
75
  def text_to_speech(text):
76
-
77
  client = texttospeech.TextToSpeechClient()
78
-
79
  synthesis_input = texttospeech.SynthesisInput(text=text)
80
-
81
  voice = texttospeech.VoiceSelectionParams(language_code="es-ES", ssml_gender=texttospeech.SsmlVoiceGender.NEUTRAL)
82
-
83
  audio_config = texttospeech.AudioConfig(audio_encoding=texttospeech.AudioEncoding.MP3)
84
-
85
  response = client.synthesize_speech(input=synthesis_input, voice=voice, audio_config=audio_config)
86
-
87
  audio_path = tempfile.NamedTemporaryFile(delete=False, suffix=".mp3").name
88
-
89
  with open(audio_path, "wb") as out:
90
-
91
  out.write(response.audio_content)
92
-
93
  return audio_path
94
 
95
-
96
-
97
  # Funci贸n para reproducir un archivo de audio
98
-
99
  def reproducir_audio(file_path):
100
-
101
  audio_file = open(file_path, "rb")
102
-
103
  audio_data = audio_file.read()
104
-
105
  audio_base64 = base64.b64encode(audio_data).decode()
106
-
107
  audio_file.close()
108
 
109
-
110
-
111
- st.session_state.audio_base64 = audio_base64
112
-
113
- st.session_state.audio_playing = True
114
-
115
-
116
-
117
  st.markdown(
118
-
119
  f"""
120
-
121
- <audio id="audio" autoplay>
122
-
123
  <source src="data:audio/mp3;base64,{audio_base64}" type="audio/mp3">
124
-
125
  </audio>
126
-
127
  """,
128
-
129
  unsafe_allow_html=True
130
-
131
  )
132
 
133
-
134
-
135
- # Funci贸n para detener el audio
136
-
137
- def detener_audio():
138
-
139
- st.session_state.audio_playing = False
140
-
141
-
142
-
143
  # Funci贸n para manejar la encuesta din谩mica
144
-
145
  def encuesta_asistente():
146
-
147
  st.title("Asistente Boti Encuesta")
148
-
149
  st.write("Este asistente te guiar谩 a trav茅s de una serie de preguntas para ayudarte a configurar tu asistente virtual")
150
 
151
-
152
-
153
  # Logo de ayuda del asistente
154
-
155
  ayuda_logo = "https://img.freepik.com/premium-vector/minimal-ai-tech-robot-vector-illustration_589744-869.jpg"
156
-
157
  st.image(ayuda_logo, width=50)
158
 
159
-
160
-
161
  # Bot贸n de ayuda del asistente
162
-
163
  if st.button("Ayuda del asistente"):
164
-
165
  reproducir_audio("audios/instructivo.mp3")
166
 
167
-
168
-
169
  preguntas = [
170
-
171
  {
172
-
173
  "pregunta": "驴Cu谩l es tu nombre?",
174
-
175
  "tipo": "texto"
176
-
177
  },
178
-
179
  {
180
-
181
  "pregunta": "驴Qu茅 tipo de asistente virtual deseas?",
182
-
183
  "tipo": "multiple",
184
-
185
  "opciones": ["Asistente Personal", "Asistente de Negocios", "Asistente de Salud", "Asistente de Educaci贸n", "Otro"]
186
-
187
  },
188
-
189
  {
190
-
191
  "pregunta": "驴Qu茅 objetivo debe cumplir este asistente?",
192
-
193
  "tipo": "multiple",
194
-
195
  "opciones": ["Organizaci贸n Personal", "Mejora de Productividad", "Asistencia M茅dica", "Educaci贸n y Aprendizaje", "Otro"]
196
-
197
  },
198
-
199
  {
200
-
201
  "pregunta": "驴Cu谩les son las funciones que debe tener?",
202
-
203
  "tipo": "multiple",
204
-
205
  "opciones": ["Gesti贸n de Calendarios", "Recordatorios", "Consultas M茅dicas", "Ayuda con Tareas Escolares", "Otro"]
206
-
207
  },
208
-
209
  {
210
-
211
  "pregunta": "驴C贸mo te gustar铆a que este asistente te ayude en tus tareas diarias?",
212
-
213
  "tipo": "multiple",
214
-
215
  "opciones": ["Planificaci贸n de D铆a", "Recordatorios", "Consultas y Respuestas", "Apoyo Emocional", "Otro"]
216
-
217
  },
218
-
219
  {
220
-
221
  "pregunta": "驴Qu茅 interfaz deber铆a tener este asistente?",
222
-
223
  "tipo": "multiple",
224
-
225
  "opciones": ["Aplicaci贸n M贸vil", "Aplicaci贸n Web", "Asistente de Voz", "Chatbot en Redes Sociales", "Otro"]
226
-
227
  },
228
-
229
  {
230
-
231
  "pregunta": "驴Utilizar铆as el asistente para aumentar tu tiempo libre o para generar ingresos adicionales?",
232
-
233
  "tipo": "multiple",
234
-
235
  "opciones": ["Aumentar tiempo libre", "Generar ingresos adicionales"]
236
-
237
  },
238
-
239
  {
240
-
241
  "pregunta": "Por 煤ltimo, 驴qu茅 estilos y elementos visuales deber铆a tener?",
242
-
243
  "tipo": "multiple",
244
-
245
  "opciones": ["Estilo moderno con colores vivos", "Colores sobrios y cl谩sico", "Moderno, colores pastel o simples", "Moderno, elegante, simple, no importa el estilo", "Otro"]
246
-
247
  }
248
-
249
  ]
250
 
251
-
252
-
253
  if 'respuestas' not in st.session_state:
254
-
255
  st.session_state.respuestas = {}
256
-
257
  st.session_state.historial = [{"role": "system", "content": "Eres Boty, un asistente de la empresa Botidinamix AI para el desarrollo e implementaci贸n de asistentes virtuales automatizados. Te guiar谩s a trav茅s de dos o tres preguntas para ayudarte a orientar y configurar tu asistente virtual. Act煤as de manera muy amable, entusiasta y te diriges por el nombre a cada encuestado. Limita las preguntas adicionales a un m谩ximo de 3 preguntas espec铆ficas."}]
258
-
259
  st.session_state.pregunta_actual = 0
260
-
261
  st.session_state.preguntas_adicionales = []
262
-
263
  st.session_state.pregunta_adicional_actual = 0
264
-
265
  st.session_state.respuestas_adicionales = {}
266
-
267
  st.session_state.respuestas_adicionales_completadas = False
268
 
269
-
270
-
271
  # Validaci贸n de preguntas adicionales
272
-
273
  if st.session_state.preguntas_adicionales and not st.session_state.respuestas_adicionales_completadas:
274
-
275
  st.write("Por favor, para poder continuar con el cuestionario es necesario que responda todas las preguntas adicionales.")
276
-
277
  pregunta_adicional_actual = st.session_state.pregunta_adicional_actual
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
278
 
279
- pregunta_adicional = st.session_state.preguntas_adicionales[pregunta_adicional_actual]
280
-
281
- st.write(f"**Pregunta adicional {pregunta_adicional_actual + 1}:** {pregunta_adicional}")
282
-
283
-
284
-
285
- st.session_state.respuestas_adicionales[f'respuesta_adicional_1_{pregunta_adicional_actual}'] = st.text_input("Respuesta adicional 1:", key=f"respuesta_adicional_1_{pregunta_adicional_actual}")
286
-
287
- st.session_state.respuestas_adicionales[f'respuesta_adicional_2_{pregunta_adicional_actual}'] = st.text_input("Respuesta adicional 2:", key=f"respuesta_adicional_2_{pregunta_adicional_actual}")
288
-
289
- st.session_state.respuestas_adicionales[f'otras_observaciones_{pregunta_adicional_actual}'] = st.text_input("Otras observaciones:", key=f'otras_observaciones_{pregunta_adicional_actual}')
290
-
291
-
292
-
293
- if st.button("Enviar respuestas adicionales", key=f"btn_adicional_{pregunta_adicional_actual}"):
294
-
295
- with st.spinner('Procesando sus respuestas, por favor espere...'):
296
-
297
- st.session_state.respuestas[pregunta_adicional + " (Respuesta adicional 1)"] = st.session_state.respuestas_adicionales[f'respuesta_adicional_1_{pregunta_adicional_actual}']
298
-
299
- st.session_state.respuestas[pregunta_adicional + " (Respuesta adicional 2)"] = st.session_state.respuestas_adicionales[f'respuesta_adicional_2_{pregunta_adicional_actual}']
300
-
301
- st.session_state.respuestas[pregunta_adicional + " (Otras observaciones)"] = st.session_state.respuestas_adicionales[f'otras_observaciones_{pregunta_adicional_actual}']
302
-
303
-
304
-
305
- st.session_state.historial.append({"role": "user", "content": st.session_state.respuestas_adicionales[f'respuesta_adicional_1_{pregunta_adicional_actual}']})
306
-
307
- st.session_state.historial.append({"role": "user", "content": st.session_state.respuestas_adicionales[f'respuesta_adicional_2_{pregunta_adicional_actual}']})
308
-
309
- st.session_state.historial.append({"role": "user", "content": st.session_state.respuestas_adicionales[f'otras_observaciones_{pregunta_adicional_actual}']})
310
-
311
- st.session_state.historial.append({"role": "assistant", "content": st.session_state.respuesta_actual})
312
-
313
-
314
-
315
- st.session_state.pregunta_adicional_actual += 1
316
-
317
-
318
-
319
- if st.session_state.pregunta_adicional_actual == len(st.session_state.preguntas_adicionales):
320
-
321
- st.session_state.respuestas_adicionales_completadas = True
322
-
323
- st.session_state.preguntas_adicionales = []
324
-
325
-
326
-
327
- st.experimental_rerun()
328
-
329
  else:
330
-
331
  if st.session_state.pregunta_actual < len(preguntas):
332
-
333
  pregunta_actual = preguntas[st.session_state.pregunta_actual]
334
-
335
  st.write(f"**Pregunta:** {pregunta_actual['pregunta']}")
336
 
337
-
338
-
339
  if pregunta_actual["tipo"] == "texto":
340
-
341
  respuesta = st.text_input("Tu respuesta:", key=f"respuesta_{st.session_state.pregunta_actual}")
342
-
343
  elif pregunta_actual["tipo"] == "multiple":
344
-
345
  respuesta = st.selectbox("Selecciona una opci贸n:", pregunta_actual["opciones"], key=f"respuesta_{st.session_state.pregunta_actual}")
346
-
347
  if respuesta == "Otro":
348
-
349
  respuesta_otro = st.text_input("Por favor especifica:", key=f"respuesta_otro_{st.session_state.pregunta_actual}")
350
-
351
  if respuesta_otro:
352
-
353
  respuesta = respuesta_otro
354
 
355
-
356
-
357
  if st.button("Enviar respuesta", key=f"btn_{st.session_state.pregunta_actual}"):
358
-
359
  with st.spinner('Procesando su respuesta, por favor espere...'):
360
-
361
  st.session_state.respuestas[pregunta_actual['pregunta']] = respuesta
362
 
363
-
364
-
365
  # Obtener respuesta del asistente
366
-
367
  respuesta_asistente = obtener_respuesta(respuesta, st.session_state.historial)
368
-
369
  st.session_state.respuesta_actual = respuesta_asistente
370
 
371
-
372
-
373
  # Agregar la pregunta y respuesta actual al historial
374
-
375
  st.session_state.historial.append({"role": "user", "content": respuesta})
376
-
377
  st.session_state.historial.append({"role": "assistant", "content": respuesta_asistente})
378
 
379
-
380
-
381
  # Verificar si el asistente hace una pregunta adicional
382
-
383
  if "pregunta" in respuesta_asistente.lower() and len(st.session_state.preguntas_adicionales) < 3:
384
-
385
  st.session_state.preguntas_adicionales.append(respuesta_asistente)
386
-
387
  st.session_state.respuestas_adicionales_completadas = False
388
 
389
-
390
-
391
  # Convertir respuesta a audio
392
-
393
  audio_path = text_to_speech(respuesta_asistente)
394
-
395
  st.session_state.audio_path = audio_path
396
 
397
-
398
-
399
  st.session_state.pregunta_actual += 1
400
-
401
  st.experimental_rerun()
402
-
403
  else:
404
-
405
- # Mostrar resumen
406
-
407
  resumen = generar_resumen(st.session_state.respuestas)
408
-
409
- st.write("Resumen del asistente configurado:")
410
-
411
  st.write(resumen)
412
-
413
-
414
-
415
  st.write("Gracias por responder todas las preguntas. Haz clic en 'Registrar Encuesta' para finalizar y generar el archivo descargable.")
416
-
417
  if st.button("Registrar Encuesta"):
418
-
419
  st.session_state.encuesta_completada = True
420
-
421
- st.success("Encuesta completada exitosamente. NO OLVIDE DESCARGAR EL ARCHIVO AL FINALIZAR LA ENCUESTA. Haz clic en 'Obtener Resultado de la Encuesta' para descargar el archivo.")
422
-
423
-
424
 
425
  if 'respuesta_actual' in st.session_state:
426
-
427
  st.write("Respuesta del asistente:")
428
-
429
  st.write(st.session_state.respuesta_actual)
430
 
431
-
432
-
433
  audio_path = st.session_state.audio_path
434
-
435
  audio_file = open(audio_path, "rb")
436
-
437
  audio_data = audio_file.read()
438
-
439
  audio_base64 = base64.b64encode(audio_data).decode()
440
 
441
-
442
-
443
  st.markdown(
444
-
445
  f"""
446
-
447
  <audio autoplay>
448
-
449
  <source src="data:audio/mp3;base64,{audio_base64}" type="audio/mp3">
450
-
451
  </audio>
452
-
453
  """,
454
-
455
  unsafe_allow_html=True
456
-
457
  )
458
 
459
-
460
-
461
  if 'encuesta_completada' in st.session_state and st.session_state.encuesta_completada:
462
-
463
  st.markdown(
464
-
465
  """
466
-
467
  <style>
468
-
469
  .download-button {
470
-
471
  font-size: 20px !important;
472
-
473
  padding: 10px !important;
474
-
475
  background-color: #007bff !important;
476
-
477
  color: white !important;
478
-
479
  border: none !important;
480
-
481
  text-align: center !important;
482
-
483
  cursor: pointer !important;
484
-
485
  }
486
-
487
  </style>
488
-
489
  """,
490
-
491
  unsafe_allow_html=True
492
-
493
  )
494
-
495
  generar_documento()
496
 
497
-
498
-
499
  def generar_resumen(respuestas):
500
-
501
- resumen = "De acuerdo a sus respuestas, se ha configurado un asistente con las siguientes caracter铆sticas:\n\n"
502
-
503
  for pregunta, respuesta in respuestas.items():
504
-
505
- resumen += f"- {pregunta}: {respuesta}\n"
506
-
507
  return resumen
508
 
509
-
510
-
511
  def generar_documento():
512
-
513
  if 'respuestas' in st.session_state:
514
-
515
  respuestas = st.session_state.respuestas
516
 
517
-
518
-
519
  doc = Document()
520
-
521
  doc.add_heading('Respuestas de la Encuesta', 0)
522
 
523
-
524
-
525
  for pregunta, respuesta in respuestas.items():
526
-
527
  doc.add_heading(pregunta, level=1)
528
-
529
  doc.add_paragraph(respuesta)
530
 
531
-
532
-
533
  temp_file = tempfile.NamedTemporaryFile(delete=False, suffix=".docx")
534
-
535
  doc.save(temp_file.name)
536
 
537
-
538
-
539
  with open(temp_file.name, "rb") as file:
540
-
541
  st.download_button(
542
-
543
  label="Descargar Archivo",
544
-
545
  data=file,
546
-
547
  file_name="resultado_encuesta.docx",
548
-
549
  mime="application/vnd.openxmlformats-officedocument.wordprocessingml.document",
550
-
551
  key="btn_descargar_archivo"
552
-
553
  )
554
 
555
-
556
-
557
- enviar_correo(temp_file.name)
558
-
559
-
560
-
561
- def enviar_correo(archivo_path):
562
-
563
- remitente = "tucorreo@example.com"
564
-
565
  destinatario = "josedcape@gmail.com"
 
 
566
 
567
- asunto = "Resultado de la Encuesta de Asistente Virtual"
568
-
569
- cuerpo = "Adjunto encontrar谩 el archivo con el resultado de la encuesta para la configuraci贸n del asistente virtual."
570
-
571
-
572
-
573
- msg = MIMEMultipart()
574
-
575
- msg['From'] = remitente
576
-
577
- msg['To'] = destinatario
578
-
579
- msg['Subject'] = asunto
580
-
581
- msg.attach(MIMEText(cuerpo, 'plain'))
582
-
583
-
584
-
585
- with open(archivo_path, "rb") as attachment:
586
-
587
- part = MIMEApplication(attachment.read(), Name=os.path.basename(archivo_path))
588
-
589
- part['Content-Disposition'] = f'attachment; filename="{os.path.basename(archivo_path)}"'
590
-
591
- msg.attach(part)
592
-
593
-
594
-
595
- try:
596
-
597
- servidor = smtplib.SMTP('smtp.gmail.com', 587)
598
-
599
- servidor.starttls()
600
-
601
- servidor.login(remitente, "tu_contrase帽a")
602
-
603
- texto = msg.as_string()
604
-
605
- servidor.sendmail(remitente, destinatario, texto)
606
-
607
- servidor.quit()
608
-
609
- st.success("Correo enviado exitosamente.")
610
-
611
- except Exception as e:
612
-
613
- st.error(f"Error al enviar el correo: {e}")
614
 
 
615
 
 
 
 
 
 
 
 
616
 
617
  # Funci贸n para incrustar video en la p谩gina principal
618
-
619
  def incrustar_video_principal():
620
-
621
- video_url = "https://www.youtube.com/watch?v=example_video_url" # Reemplaza con el enlace correcto
622
-
623
- st_player(video_url, playing=True, volume=0)
624
-
625
-
626
-
627
- if st.session_state.audio_playing:
628
-
629
- st.markdown(
630
-
631
- f"""
632
-
633
- <audio id="audio" autoplay>
634
-
635
- <source src="data:audio/mp3;base64,{st.session_state.audio_base64}" type="audio/mp3">
636
-
637
- </audio>
638
-
639
- """,
640
-
641
- unsafe_allow_html=True
642
-
643
- )
644
-
645
-
646
-
647
- if st.button("Detener Audio", key="detener_audio", help="Haz clic para detener el audio", css_class="big-button"):
648
-
649
- detener_audio()
650
-
651
-
652
 
653
  # Estilos personalizados
654
-
655
  st.markdown(
656
-
657
  """
658
-
659
  <style>
660
-
661
  .sidebar .sidebar-content {
662
-
663
  background-color: #2C3E50;
664
-
665
  }
666
-
667
  .sidebar .sidebar-content .element-container {
668
-
669
  color: #ECF0F1;
670
-
671
  }
672
-
673
  .main {
674
-
675
  background-color: #000000;
676
-
677
  color: #ECF0F1;
678
-
679
  background-image: url('https://images6.alphacoders.com/774/thumb-1920-774373.jpg');
680
-
681
  background-size: cover;
682
-
683
  }
684
-
685
  h1, h2, h3, h4, h5, h6 {
686
-
687
  color: #FFFFFF;
688
-
689
  font-weight: bold;
690
-
691
  }
692
-
693
  .big-button, .stButton button {
694
-
695
  font-size: 20px !important;
696
-
697
  padding: 10px !important;
698
-
699
  background-color: #007bff !important;
700
-
701
  color: white !important;
702
-
703
  border: none !important;
704
-
705
  text-align: center !important;
706
-
707
  cursor: pointer !important;
708
-
709
  }
710
-
711
  .stTextInput input {
712
-
713
  color: black !important;
714
-
715
  background-color: white !important;
716
-
717
  }
718
-
719
  .nav-bar {
720
-
721
  background-color: #000000; /* Cambiado a negro */
722
-
723
  color: white;
724
-
725
  padding: 10px;
726
-
727
  text-align: center;
728
-
729
  font-size: 24px;
730
-
731
  font-weight: bold;
732
-
733
  }
734
-
735
  .nav-link {
736
-
737
  color: white;
738
-
739
  margin: 0 15px;
740
-
741
  text-decoration: none;
742
-
743
  cursor: pointer;
744
-
745
  }
746
-
747
  </style>
748
-
749
  """,
750
-
751
  unsafe_allow_html=True
752
-
753
  )
754
 
755
-
756
-
757
  # Funci贸n para la barra de navegaci贸n
758
-
759
  def barra_navegacion():
760
-
761
  st.markdown(
762
-
763
  """
764
-
765
  <div class="nav-bar">
766
-
767
- <a class="nav-link" href="?page=principal">""" + ("P谩gina Principal" if st.session_state.idioma == "Espa帽ol" else "Main Page") + """</a>
768
-
769
- <a class="nav-link" href="?page=asistente">""" + ("Asistente Boti" if st.session_state.idioma == "Espa帽ol" else "Boti Assistant") + """</a>
770
-
771
- <a class="nav-link" href="?page=video">""" + ("Ver Video" if st.session_state.idioma == "Espa帽ol" else "Watch Video") + """</a>
772
-
773
  </div>
774
-
775
  """,
776
-
777
  unsafe_allow_html=True
778
-
779
  )
780
 
781
-
782
-
783
  # Funci贸n para seleccionar idioma
784
-
785
  def seleccionar_idioma():
786
-
787
  idioma = st.sidebar.radio("Idioma", ("Espa帽ol", "English"))
788
-
789
  st.session_state.idioma = idioma
790
 
791
-
792
-
793
  # Funciones para las p谩ginas
794
-
795
  def pagina_principal():
796
-
797
  st.title("Bienvenido a Boti Asistente")
798
-
799
  st.write("Esta es la p谩gina principal de Boti Asistente, especializado en el desarrollo de bots para Botidinamix.")
800
-
801
  incrustar_video_principal()
802
-
803
  st.markdown("<h2 style='text-align: center; color: white;'>Para realizar su encuesta, haga clic en la barra superior</h2>", unsafe_allow_html=True)
804
 
805
-
806
-
807
  def pagina_asistente():
808
-
809
  encuesta_asistente()
810
 
811
-
812
-
813
- def pagina_video():
814
-
815
- st.title("Ver Video")
816
-
817
- st_player("https://www.youtube.com/watch?v=example_video_url") # Reemplaza con el enlace correcto
818
-
819
-
820
 
821
  # Funci贸n principal
822
-
823
  def main():
824
-
825
  if 'idioma' not in st.session_state:
826
-
827
  st.session_state.idioma = 'Espa帽ol'
828
-
829
 
830
-
831
  seleccionar_idioma()
832
-
833
  barra_navegacion()
834
-
835
 
836
-
837
  query_params = st.experimental_get_query_params()
838
-
839
  page = query_params.get("page", ["principal"])[0]
840
-
841
  if page == "principal":
842
-
843
  pagina_principal()
844
-
845
  elif page == "asistente":
846
-
847
  pagina_asistente()
848
-
849
  elif page == "video":
850
-
851
- pagina_video()
852
-
853
-
854
 
855
  if __name__ == "__main__":
856
-
857
  main()
858
-
 
1
  import streamlit as st
 
2
  import openai
 
3
  import os
 
4
  import tempfile
 
5
  from google.cloud import texttospeech
 
6
  from dotenv import load_dotenv
 
7
  from docx import Document
 
8
  import base64
 
9
  from streamlit_player import st_player
 
10
  import smtplib
 
11
  from email.mime.multipart import MIMEMultipart
 
12
  from email.mime.text import MIMEText
 
13
  from email.mime.application import MIMEApplication
14
 
 
 
15
  # Configuraci贸n de la interfaz
 
16
  st.set_page_config(page_title="SURVEY ASSISTANT", layout="wide")
17
 
 
 
18
  # Cargar variables de entorno
 
19
  load_dotenv()
 
20
  openai.api_key = os.getenv("OPENAI_API_KEY")
 
21
  os.environ["GOOGLE_APPLICATION_CREDENTIALS"] = "botidinamix-g.json"
22
 
 
 
23
  # Funci贸n para obtener respuesta de OpenAI con historial de conversaci贸n
 
24
  def obtener_respuesta(pregunta, historial, modelo="gpt-4", temperatura=0.5):
 
25
  mensajes = historial + [
 
26
  {"role": "user", "content": pregunta}
 
27
  ]
 
28
  response = openai.ChatCompletion.create(
 
29
  model=modelo,
 
30
  messages=mensajes,
 
31
  temperature=temperatura,
 
32
  max_tokens=300,
 
33
  )
 
34
  respuesta = response['choices'][0]['message']['content']
 
35
  return respuesta
36
 
 
 
37
  # Funci贸n para convertir texto a voz usando Google Cloud Text-to-Speech
 
38
  def text_to_speech(text):
 
39
  client = texttospeech.TextToSpeechClient()
 
40
  synthesis_input = texttospeech.SynthesisInput(text=text)
 
41
  voice = texttospeech.VoiceSelectionParams(language_code="es-ES", ssml_gender=texttospeech.SsmlVoiceGender.NEUTRAL)
 
42
  audio_config = texttospeech.AudioConfig(audio_encoding=texttospeech.AudioEncoding.MP3)
 
43
  response = client.synthesize_speech(input=synthesis_input, voice=voice, audio_config=audio_config)
 
44
  audio_path = tempfile.NamedTemporaryFile(delete=False, suffix=".mp3").name
 
45
  with open(audio_path, "wb") as out:
 
46
  out.write(response.audio_content)
 
47
  return audio_path
48
 
 
 
49
  # Funci贸n para reproducir un archivo de audio
 
50
  def reproducir_audio(file_path):
 
51
  audio_file = open(file_path, "rb")
 
52
  audio_data = audio_file.read()
 
53
  audio_base64 = base64.b64encode(audio_data).decode()
 
54
  audio_file.close()
55
 
 
 
 
 
 
 
 
 
56
  st.markdown(
 
57
  f"""
58
+ <audio autoplay>
 
 
59
  <source src="data:audio/mp3;base64,{audio_base64}" type="audio/mp3">
 
60
  </audio>
 
61
  """,
 
62
  unsafe_allow_html=True
 
63
  )
64
 
 
 
 
 
 
 
 
 
 
 
65
  # Funci贸n para manejar la encuesta din谩mica
 
66
  def encuesta_asistente():
 
67
  st.title("Asistente Boti Encuesta")
 
68
  st.write("Este asistente te guiar谩 a trav茅s de una serie de preguntas para ayudarte a configurar tu asistente virtual")
69
 
 
 
70
  # Logo de ayuda del asistente
 
71
  ayuda_logo = "https://img.freepik.com/premium-vector/minimal-ai-tech-robot-vector-illustration_589744-869.jpg"
 
72
  st.image(ayuda_logo, width=50)
73
 
 
 
74
  # Bot贸n de ayuda del asistente
 
75
  if st.button("Ayuda del asistente"):
 
76
  reproducir_audio("audios/instructivo.mp3")
77
 
 
 
78
  preguntas = [
 
79
  {
 
80
  "pregunta": "驴Cu谩l es tu nombre?",
 
81
  "tipo": "texto"
 
82
  },
 
83
  {
 
84
  "pregunta": "驴Qu茅 tipo de asistente virtual deseas?",
 
85
  "tipo": "multiple",
 
86
  "opciones": ["Asistente Personal", "Asistente de Negocios", "Asistente de Salud", "Asistente de Educaci贸n", "Otro"]
 
87
  },
 
88
  {
 
89
  "pregunta": "驴Qu茅 objetivo debe cumplir este asistente?",
 
90
  "tipo": "multiple",
 
91
  "opciones": ["Organizaci贸n Personal", "Mejora de Productividad", "Asistencia M茅dica", "Educaci贸n y Aprendizaje", "Otro"]
 
92
  },
 
93
  {
 
94
  "pregunta": "驴Cu谩les son las funciones que debe tener?",
 
95
  "tipo": "multiple",
 
96
  "opciones": ["Gesti贸n de Calendarios", "Recordatorios", "Consultas M茅dicas", "Ayuda con Tareas Escolares", "Otro"]
 
97
  },
 
98
  {
 
99
  "pregunta": "驴C贸mo te gustar铆a que este asistente te ayude en tus tareas diarias?",
 
100
  "tipo": "multiple",
 
101
  "opciones": ["Planificaci贸n de D铆a", "Recordatorios", "Consultas y Respuestas", "Apoyo Emocional", "Otro"]
 
102
  },
 
103
  {
 
104
  "pregunta": "驴Qu茅 interfaz deber铆a tener este asistente?",
 
105
  "tipo": "multiple",
 
106
  "opciones": ["Aplicaci贸n M贸vil", "Aplicaci贸n Web", "Asistente de Voz", "Chatbot en Redes Sociales", "Otro"]
 
107
  },
 
108
  {
 
109
  "pregunta": "驴Utilizar铆as el asistente para aumentar tu tiempo libre o para generar ingresos adicionales?",
 
110
  "tipo": "multiple",
 
111
  "opciones": ["Aumentar tiempo libre", "Generar ingresos adicionales"]
 
112
  },
 
113
  {
 
114
  "pregunta": "Por 煤ltimo, 驴qu茅 estilos y elementos visuales deber铆a tener?",
 
115
  "tipo": "multiple",
 
116
  "opciones": ["Estilo moderno con colores vivos", "Colores sobrios y cl谩sico", "Moderno, colores pastel o simples", "Moderno, elegante, simple, no importa el estilo", "Otro"]
 
117
  }
 
118
  ]
119
 
 
 
120
  if 'respuestas' not in st.session_state:
 
121
  st.session_state.respuestas = {}
 
122
  st.session_state.historial = [{"role": "system", "content": "Eres Boty, un asistente de la empresa Botidinamix AI para el desarrollo e implementaci贸n de asistentes virtuales automatizados. Te guiar谩s a trav茅s de dos o tres preguntas para ayudarte a orientar y configurar tu asistente virtual. Act煤as de manera muy amable, entusiasta y te diriges por el nombre a cada encuestado. Limita las preguntas adicionales a un m谩ximo de 3 preguntas espec铆ficas."}]
 
123
  st.session_state.pregunta_actual = 0
 
124
  st.session_state.preguntas_adicionales = []
 
125
  st.session_state.pregunta_adicional_actual = 0
 
126
  st.session_state.respuestas_adicionales = {}
 
127
  st.session_state.respuestas_adicionales_completadas = False
128
 
 
 
129
  # Validaci贸n de preguntas adicionales
 
130
  if st.session_state.preguntas_adicionales and not st.session_state.respuestas_adicionales_completadas:
 
131
  st.write("Por favor, para poder continuar con el cuestionario es necesario que responda todas las preguntas adicionales.")
 
132
  pregunta_adicional_actual = st.session_state.pregunta_adicional_actual
133
+ if pregunta_adicional_actual < len(st.session_state.preguntas_adicionales):
134
+ pregunta_adicional = st.session_state.preguntas_adicionales[pregunta_adicional_actual]
135
+ st.write(f"**Pregunta adicional {pregunta_adicional_actual + 1}:** {pregunta_adicional}")
136
+
137
+ st.session_state.respuestas_adicionales[f'respuesta_adicional_1_{pregunta_adicional_actual}'] = st.text_input("Respuesta adicional 1:", key=f"respuesta_adicional_1_{pregunta_adicional_actual}")
138
+ st.session_state.respuestas_adicionales[f'respuesta_adicional_2_{pregunta_adicional_actual}'] = st.text_input("Respuesta adicional 2:", key=f"respuesta_adicional_2_{pregunta_adicional_actual}")
139
+ st.session_state.respuestas_adicionales[f'otras_observaciones_{pregunta_adicional_actual}'] = st.text_input("Otras observaciones:", key=f'otras_observaciones_{pregunta_adicional_actual}')
140
+
141
+ if st.button("Enviar respuestas adicionales", key=f"btn_adicional_{pregunta_adicional_actual}"):
142
+ with st.spinner('Procesando sus respuestas, por favor espere...'):
143
+ st.session_state.respuestas[pregunta_adicional + " (Respuesta adicional 1)"] = st.session_state.respuestas_adicionales[f'respuesta_adicional_1_{pregunta_adicional_actual}']
144
+ st.session_state.respuestas[pregunta_adicional + " (Respuesta adicional 2)"] = st.session_state.respuestas_adicionales[f'respuesta_adicional_2_{pregunta_adicional_actual}']
145
+ st.session_state.respuestas[pregunta_adicional + " (Otras observaciones)"] = st.session_state.respuestas_adicionales[f'otras_observaciones_{pregunta_adicional_actual}']
146
+
147
+ st.session_state.historial.append({"role": "user", "content": st.session_state.respuestas_adicionales[f'respuesta_adicional_1_{pregunta_adicional_actual}']})
148
+ st.session_state.historial.append({"role": "user", "content": st.session_state.respuestas_adicionales[f'respuesta_adicional_2_{pregunta_adicional_actual}']})
149
+ st.session_state.historial.append({"role": "user", "content": st.session_state.respuestas_adicionales[f'otras_observaciones_{pregunta_adicional_actual}']})
150
+ st.session_state.historial.append({"role": "assistant", "content": st.session_state.respuesta_actual})
151
+
152
+ st.session_state.pregunta_adicional_actual += 1
153
+
154
+ if st.session_state.pregunta_adicional_actual == len(st.session_state.preguntas_adicionales):
155
+ st.session_state.respuestas_adicionales_completadas = True
156
+ st.session_state.preguntas_adicionales = []
157
 
158
+ st.experimental_rerun()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
159
  else:
 
160
  if st.session_state.pregunta_actual < len(preguntas):
 
161
  pregunta_actual = preguntas[st.session_state.pregunta_actual]
 
162
  st.write(f"**Pregunta:** {pregunta_actual['pregunta']}")
163
 
 
 
164
  if pregunta_actual["tipo"] == "texto":
 
165
  respuesta = st.text_input("Tu respuesta:", key=f"respuesta_{st.session_state.pregunta_actual}")
 
166
  elif pregunta_actual["tipo"] == "multiple":
 
167
  respuesta = st.selectbox("Selecciona una opci贸n:", pregunta_actual["opciones"], key=f"respuesta_{st.session_state.pregunta_actual}")
 
168
  if respuesta == "Otro":
 
169
  respuesta_otro = st.text_input("Por favor especifica:", key=f"respuesta_otro_{st.session_state.pregunta_actual}")
 
170
  if respuesta_otro:
 
171
  respuesta = respuesta_otro
172
 
 
 
173
  if st.button("Enviar respuesta", key=f"btn_{st.session_state.pregunta_actual}"):
 
174
  with st.spinner('Procesando su respuesta, por favor espere...'):
 
175
  st.session_state.respuestas[pregunta_actual['pregunta']] = respuesta
176
 
 
 
177
  # Obtener respuesta del asistente
 
178
  respuesta_asistente = obtener_respuesta(respuesta, st.session_state.historial)
 
179
  st.session_state.respuesta_actual = respuesta_asistente
180
 
 
 
181
  # Agregar la pregunta y respuesta actual al historial
 
182
  st.session_state.historial.append({"role": "user", "content": respuesta})
 
183
  st.session_state.historial.append({"role": "assistant", "content": respuesta_asistente})
184
 
 
 
185
  # Verificar si el asistente hace una pregunta adicional
 
186
  if "pregunta" in respuesta_asistente.lower() and len(st.session_state.preguntas_adicionales) < 3:
 
187
  st.session_state.preguntas_adicionales.append(respuesta_asistente)
 
188
  st.session_state.respuestas_adicionales_completadas = False
189
 
 
 
190
  # Convertir respuesta a audio
 
191
  audio_path = text_to_speech(respuesta_asistente)
 
192
  st.session_state.audio_path = audio_path
193
 
 
 
194
  st.session_state.pregunta_actual += 1
 
195
  st.experimental_rerun()
 
196
  else:
197
+ # Mostrar el resumen de la encuesta antes de registrar
198
+ st.write("NO OLVIDE DESCARGAR EL ARCHIVO AL FINALIZAR LA ENCUESTA")
199
+ st.write("A continuaci贸n, se muestra un resumen del asistente de acuerdo a sus respuestas:")
200
  resumen = generar_resumen(st.session_state.respuestas)
 
 
 
201
  st.write(resumen)
202
+
 
 
203
  st.write("Gracias por responder todas las preguntas. Haz clic en 'Registrar Encuesta' para finalizar y generar el archivo descargable.")
 
204
  if st.button("Registrar Encuesta"):
 
205
  st.session_state.encuesta_completada = True
206
+ enviar_correo(resumen)
207
+ st.success("Encuesta completada exitosamente. Haz clic en 'Obtener Resultado de la Encuesta' para descargar el archivo.")
 
 
208
 
209
  if 'respuesta_actual' in st.session_state:
 
210
  st.write("Respuesta del asistente:")
 
211
  st.write(st.session_state.respuesta_actual)
212
 
 
 
213
  audio_path = st.session_state.audio_path
 
214
  audio_file = open(audio_path, "rb")
 
215
  audio_data = audio_file.read()
 
216
  audio_base64 = base64.b64encode(audio_data).decode()
217
 
 
 
218
  st.markdown(
 
219
  f"""
 
220
  <audio autoplay>
 
221
  <source src="data:audio/mp3;base64,{audio_base64}" type="audio/mp3">
 
222
  </audio>
 
223
  """,
 
224
  unsafe_allow_html=True
 
225
  )
226
 
 
 
227
  if 'encuesta_completada' in st.session_state and st.session_state.encuesta_completada:
 
228
  st.markdown(
 
229
  """
 
230
  <style>
 
231
  .download-button {
 
232
  font-size: 20px !important;
 
233
  padding: 10px !important;
 
234
  background-color: #007bff !important;
 
235
  color: white !important;
 
236
  border: none !important;
 
237
  text-align: center !important;
 
238
  cursor: pointer !important;
 
239
  }
 
240
  </style>
 
241
  """,
 
242
  unsafe_allow_html=True
 
243
  )
 
244
  generar_documento()
245
 
 
 
246
  def generar_resumen(respuestas):
247
+ # Generar un resumen en formato de texto
248
+ resumen = "Este es el asistente configurado de acuerdo a sus respuestas:\n\n"
 
249
  for pregunta, respuesta in respuestas.items():
250
+ resumen += f"{pregunta}: {respuesta}\n"
 
 
251
  return resumen
252
 
 
 
253
  def generar_documento():
 
254
  if 'respuestas' in st.session_state:
 
255
  respuestas = st.session_state.respuestas
256
 
 
 
257
  doc = Document()
 
258
  doc.add_heading('Respuestas de la Encuesta', 0)
259
 
 
 
260
  for pregunta, respuesta in respuestas.items():
 
261
  doc.add_heading(pregunta, level=1)
 
262
  doc.add_paragraph(respuesta)
263
 
 
 
264
  temp_file = tempfile.NamedTemporaryFile(delete=False, suffix=".docx")
 
265
  doc.save(temp_file.name)
266
 
 
 
267
  with open(temp_file.name, "rb") as file:
 
268
  st.download_button(
 
269
  label="Descargar Archivo",
 
270
  data=file,
 
271
  file_name="resultado_encuesta.docx",
 
272
  mime="application/vnd.openxmlformats-officedocument.wordprocessingml.document",
 
273
  key="btn_descargar_archivo"
 
274
  )
275
 
276
+ def enviar_correo(resumen):
277
+ remitente = "tucorreo@gmail.com"
 
 
 
 
 
 
 
 
278
  destinatario = "josedcape@gmail.com"
279
+ asunto = "Resumen de la Encuesta"
280
+ cuerpo = resumen
281
 
282
+ mensaje = MIMEMultipart()
283
+ mensaje['From'] = remitente
284
+ mensaje['To'] = destinatario
285
+ mensaje['Subject'] = asunto
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
286
 
287
+ mensaje.attach(MIMEText(cuerpo, 'plain'))
288
 
289
+ # Iniciar la sesi贸n SMTP
290
+ servidor = smtplib.SMTP('smtp.gmail.com', 587)
291
+ servidor.starttls()
292
+ servidor.login(remitente, os.getenv("EMAIL_PASSWORD"))
293
+ texto = mensaje.as_string()
294
+ servidor.sendmail(remitente, destinatario, texto)
295
+ servidor.quit()
296
 
297
  # Funci贸n para incrustar video en la p谩gina principal
 
298
  def incrustar_video_principal():
299
+ video_url = "https://www.youtube.com/watch?v=uGzZe1LxVPk" # Reemplaza con el enlace correcto
300
+ st_player(video_url, playing=True, volume=100)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
301
 
302
  # Estilos personalizados
 
303
  st.markdown(
 
304
  """
 
305
  <style>
 
306
  .sidebar .sidebar-content {
 
307
  background-color: #2C3E50;
 
308
  }
 
309
  .sidebar .sidebar-content .element-container {
 
310
  color: #ECF0F1;
 
311
  }
 
312
  .main {
 
313
  background-color: #000000;
 
314
  color: #ECF0F1;
 
315
  background-image: url('https://images6.alphacoders.com/774/thumb-1920-774373.jpg');
 
316
  background-size: cover;
 
317
  }
 
318
  h1, h2, h3, h4, h5, h6 {
 
319
  color: #FFFFFF;
 
320
  font-weight: bold;
 
321
  }
 
322
  .big-button, .stButton button {
 
323
  font-size: 20px !important;
 
324
  padding: 10px !important;
 
325
  background-color: #007bff !important;
 
326
  color: white !important;
 
327
  border: none !important;
 
328
  text-align: center !important;
 
329
  cursor: pointer !important;
 
330
  }
 
331
  .stTextInput input {
 
332
  color: black !important;
 
333
  background-color: white !important;
 
334
  }
 
335
  .nav-bar {
 
336
  background-color: #000000; /* Cambiado a negro */
 
337
  color: white;
 
338
  padding: 10px;
 
339
  text-align: center;
 
340
  font-size: 24px;
 
341
  font-weight: bold;
 
342
  }
 
343
  .nav-link {
 
344
  color: white;
 
345
  margin: 0 15px;
 
346
  text-decoration: none;
 
347
  cursor: pointer;
 
348
  }
 
349
  </style>
 
350
  """,
 
351
  unsafe_allow_html=True
 
352
  )
353
 
 
 
354
  # Funci贸n para la barra de navegaci贸n
 
355
  def barra_navegacion():
 
356
  st.markdown(
 
357
  """
 
358
  <div class="nav-bar">
359
+ <a class="nav-link" href="?page=principal">P谩gina Principal</a>
360
+ <a class="nav-link" href="?page=asistente">Asistente Boti</a>
361
+ <a class="nav-link" href="?page=video">Ver Video</a>
 
 
 
 
362
  </div>
 
363
  """,
 
364
  unsafe_allow_html=True
 
365
  )
366
 
 
 
367
  # Funci贸n para seleccionar idioma
 
368
  def seleccionar_idioma():
 
369
  idioma = st.sidebar.radio("Idioma", ("Espa帽ol", "English"))
 
370
  st.session_state.idioma = idioma
371
 
 
 
372
  # Funciones para las p谩ginas
 
373
  def pagina_principal():
 
374
  st.title("Bienvenido a Boti Asistente")
 
375
  st.write("Esta es la p谩gina principal de Boti Asistente, especializado en el desarrollo de bots para Botidinamix.")
 
376
  incrustar_video_principal()
 
377
  st.markdown("<h2 style='text-align: center; color: white;'>Para realizar su encuesta, haga clic en la barra superior</h2>", unsafe_allow_html=True)
378
 
 
 
379
  def pagina_asistente():
 
380
  encuesta_asistente()
381
 
382
+ def pagina_ver_video():
383
+ incrustar_video_principal()
 
 
 
 
 
 
 
384
 
385
  # Funci贸n principal
 
386
  def main():
 
387
  if 'idioma' not in st.session_state:
 
388
  st.session_state.idioma = 'Espa帽ol'
 
389
 
 
390
  seleccionar_idioma()
 
391
  barra_navegacion()
 
392
 
 
393
  query_params = st.experimental_get_query_params()
 
394
  page = query_params.get("page", ["principal"])[0]
 
395
  if page == "principal":
 
396
  pagina_principal()
 
397
  elif page == "asistente":
 
398
  pagina_asistente()
 
399
  elif page == "video":
400
+ pagina_ver_video()
 
 
 
401
 
402
  if __name__ == "__main__":
 
403
  main()