Josedcape commited on
Commit
9d76a92
·
verified ·
1 Parent(s): 9b22f7b

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +742 -260
app.py CHANGED
@@ -1,43 +1,54 @@
1
- import streamlit as st
 
2
  import openai
3
  from dotenv import load_dotenv
 
4
  import nltk
5
- import os
6
- import tempfile
7
  from nltk.tokenize import word_tokenize
8
  from nltk.corpus import stopwords
9
  from nltk.stem import SnowballStemmer
10
- import PyPDF2
11
- import time
 
 
12
  from google.cloud import texttospeech
13
- from streamlit_webrtc import webrtc_streamer, WebRtcMode, AudioProcessorBase
14
- from Historial.historial_chat import cargar_historial, guardar_historial
15
- from agent_functions import menu_df, tomar_pedido_agente, procesar_orden_agente, generar_pdf_orden, obtener_respuesta, generar_mensaje_automatico
16
 
17
- # Configuración de NLTK
18
- nltk.download('punkt')
19
- nltk.download('stopwords')
20
 
21
- # Cargar la clave API desde el archivo .env
22
  load_dotenv()
 
 
23
  os.environ["GOOGLE_APPLICATION_CREDENTIALS"] = "botidinamix-g.json"
24
- openai.api_key = os.getenv("OPENAI_API_KEY")
25
 
26
- # Función para extraer texto del PDF
 
 
 
 
 
 
 
 
27
  def extraer_texto_pdf(archivo):
28
  texto = ""
29
  if archivo:
30
  with tempfile.NamedTemporaryFile(delete=False) as temp_file:
31
  temp_file.write(archivo.read())
32
  temp_file_path = temp_file.name
33
- with open(temp_file_path, 'rb') as file:
34
- reader = PyPDF2.PdfReader(file)
35
- for page in range(len(reader.pages)):
36
- texto += reader.pages[page].extract_text()
37
- os.unlink(temp_file_path)
 
 
 
 
38
  return texto
39
 
40
- # Función para preprocesar texto
41
  def preprocesar_texto(texto):
42
  tokens = word_tokenize(texto, language='spanish')
43
  tokens = [word.lower() for word in tokens if word.isalpha()]
@@ -47,260 +58,731 @@ def preprocesar_texto(texto):
47
  tokens = [stemmer.stem(word) for word in tokens]
48
  return " ".join(tokens)
49
 
50
- # Clase para procesar audio
51
- class AudioProcessor(AudioProcessorBase):
52
- def __init__(self):
53
- self.audio_bytes = b''
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
54
 
55
- def recv(self, frame):
56
- self.audio_bytes += frame.to_ndarray().tobytes()
57
- return frame
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
58
 
59
- # Main App
60
  def main():
61
- # --- Diseño general ---
62
- st.set_page_config(page_title="Asistente Virtual", page_icon="🤖")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
63
 
64
- # --- Estilos CSS personalizados ---
 
 
 
 
 
 
 
 
 
65
  st.markdown(
66
  """
67
  <style>
68
- body {
69
- background: rgb(241,241,234);
70
- background: radial-gradient(circle, rgba(241,241,234,1) 4%, rgba(255,127,8,1) 36%, rgba(235,255,8,1) 94%, rgba(0,0,255,1) 99%);
71
- }
72
- h1, h2, h3, h4, h5, h6 {
73
- color: green !important;
74
- font-weight: bold !important;
75
- }
76
- .stChatFloatingInputContainer {
77
- background-color: rgba(255, 255, 255, 0.8);
78
- border-radius: 10px;
79
- }
80
- .stTextInput > div > div > input {
81
- color: #333;
82
- }
83
- [data-testid="stChatMessage"] {
84
- background-color: black !important;
85
- color: gold !important;
86
- border-radius: 10px;
87
- }
88
- [data-testid="stChatMessage"] p {
89
- color: gold !important;
90
- }
91
- ::-webkit-scrollbar {
92
- width: 16px;
93
- }
94
- ::-webkit-scrollbar-thumb {
95
- background-color: #FFD700;
96
- border-radius: 10px;
97
- }
98
- .st-spinner > div {
99
- border-top-color: transparent;
100
- border-right-color: transparent;
101
- animation: spin 1s linear infinite;
102
- }
103
- @keyframes spin {
104
- from { transform: rotate(0deg); }
105
- to { transform: rotate(360deg); }
106
- }
107
  </style>
 
 
 
 
 
 
108
  """,
109
- unsafe_allow_html=True,
110
  )
111
 
112
- # --- Barra lateral ---
113
- with st.sidebar:
114
- st.image("hamburguesa napolitana.jpg")
115
- st.title("🤖 RESTAURANTE SAZON BURGER 🍔✨-BOTIDINAMIX AI")
116
- st.markdown("---")
117
-
118
- # Opciones de navegación
119
- pagina = st.selectbox("Selecciona una página", ["Chat", "Subir PDF", "Agentes"])
120
-
121
- # --- Página principal ---
122
- if pagina == "Chat":
123
- mostrar_chat()
124
- elif pagina == "Subir PDF":
125
- mostrar_subir_pdf()
126
- elif pagina == "Agentes":
127
- mostrar_agentes()
128
-
129
- def mostrar_chat():
130
- # --- Botones de historial ---
131
- if st.button("Buscar Historial"):
132
- st.session_state.mostrar_historial = True
133
- if st.button("Borrar Historial"):
134
- st.session_state.mensajes = []
135
- st.session_state.mostrar_historial = False
136
- st.success("Historial borrado correctamente")
137
-
138
- # --- Chatbot ---
139
- if 'mensajes' not in st.session_state:
140
- st.session_state.mensajes = cargar_historial()
141
-
142
- for mensaje in st.session_state.mensajes:
143
- with st.chat_message(mensaje["role"]):
144
- st.markdown(mensaje["content"])
145
-
146
- # Función para manejar la entrada de audio
147
- def on_audio(audio_bytes):
148
- with st.spinner("Transcribiendo..."):
149
- transcript = openai.Audio.transcribe("whisper-1", audio_bytes)
150
- pregunta_usuario = transcript["text"]
151
- st.session_state.mensajes.append({"role": "user", "content": pregunta_usuario, "timestamp": time.time()})
152
- with st.chat_message("user"):
153
- st.markdown(pregunta_usuario)
154
-
155
- st.subheader("🎤 Captura de voz")
156
- st.info("Haz clic en el micrófono y comienza a hablar. Tu pregunta se transcribirá automáticamente.")
157
- with st.container():
158
- if st.button("Grabar 🎙️"):
159
- st.session_state.run_webrtc = True
160
- if st.session_state.get("run_webrtc", False):
161
- webrtc_ctx = webrtc_streamer(
162
- key="example",
163
- mode=WebRtcMode.SENDONLY,
164
- audio_receiver_size=256,
165
- rtc_configuration={
166
- "iceServers": [{"urls": ["stun:stun.l.google.com:19302"]}]
167
- },
168
- media_stream_constraints={"audio": True},
169
- audio_processor_factory=AudioProcessor,
170
- )
171
-
172
- if webrtc_ctx.audio_receiver:
173
- audio_frames = webrtc_ctx.audio_receiver.get_frames(timeout=1)
174
- for audio_frame in audio_frames:
175
- audio_bytes = audio_frame.to_ndarray().tobytes()
176
- on_audio(audio_bytes)
177
-
178
- st.markdown("---")
179
- st.subheader("📄 Subir PDF")
180
- st.info("Sube un archivo PDF y el asistente responderá en función de su contenido.")
181
- archivo_pdf = st.file_uploader("Selecciona un archivo PDF", type=["pdf"])
182
-
183
- texto_extraido = ""
184
- if archivo_pdf:
185
- texto_extraido = extraer_texto_pdf(archivo_pdf)
186
- st.success("Texto extraído del PDF exitosamente.")
187
- st.text_area("Texto extraído", value=texto_extraido, height=200)
188
-
189
- if not texto_extraido:
190
- texto_extraido = st.text_area("Texto extraído", height=200)
191
-
192
- texto_preprocesado = preprocesar_texto(texto_extraido)
193
-
194
- # --- Opciones de entrada de usuario ---
195
- st.markdown("---")
196
- pregunta_usuario = st.text_input("Escribe tu pregunta:")
197
- if st.button("Enviar"):
198
- if pregunta_usuario:
199
- st.session_state.mensajes.append({"role": "user", "content": pregunta_usuario, "timestamp": time.time()})
200
- with st.chat_message("user"):
201
- st.markdown(pregunta_usuario)
202
-
203
- with st.spinner("Generando respuesta..."):
204
- respuesta, audio_path = obtener_respuesta(pregunta_usuario, texto_preprocesado, modelo="gpt-4", temperatura=0.5)
205
- st.session_state.mensajes.append({"role": "assistant", "content": respuesta, "timestamp": time.time()})
206
- with st.chat_message("assistant"):
207
- st.markdown(respuesta)
208
- st.audio(audio_path, format="audio/mp3", start_time=0)
209
-
210
- guardar_historial(st.session_state.mensajes)
211
- else:
212
- st.warning("Por favor, ingresa una pregunta antes de enviar.")
213
 
214
- def mostrar_subir_pdf():
215
- st.subheader("📄 Subir PDF")
216
- st.info("Sube un archivo PDF y el asistente responderá en función de su contenido.")
217
- archivo_pdf = st.file_uploader("Selecciona un archivo PDF", type=["pdf"])
218
 
219
- texto_extraido = ""
 
 
 
 
 
 
 
 
 
 
 
 
220
  if archivo_pdf:
221
- texto_extraido = extraer_texto_pdf(archivo_pdf)
222
- st.success("Texto extraído del PDF exitosamente.")
223
- st.text_area("Texto extraído", value=texto_extraido, height=200)
224
-
225
- if not texto_extraido:
226
- texto_extraido = st.text_area("Texto extraído", height=200)
227
-
228
- texto_preprocesado = preprocesar_texto(texto_extraido)
229
-
230
- # --- Opciones de entrada de usuario ---
231
- st.markdown("---")
232
- pregunta_usuario = st.text_input("Escribe tu pregunta:")
233
- if st.button("Enviar"):
234
- if pregunta_usuario:
235
- st.session_state.mensajes.append({"role": "user", "content": pregunta_usuario, "timestamp": time.time()})
236
- with st.chat_message("user"):
237
- st.markdown(pregunta_usuario)
238
-
239
- with st.spinner("Generando respuesta..."):
240
- respuesta, audio_path = obtener_respuesta(pregunta_usuario, texto_preprocesado, modelo="gpt-4", temperatura=0.5)
241
- st.session_state.mensajes.append({"role": "assistant", "content": respuesta, "timestamp": time.time()})
242
- with st.chat_message("assistant"):
243
- st.markdown(respuesta)
244
- st.audio(audio_path, format="audio/mp3", start_time=0)
245
-
246
- guardar_historial(st.session_state.mensajes)
247
- else:
248
- st.warning("Por favor, ingresa una pregunta antes de enviar.")
249
-
250
- def mostrar_agentes():
251
- st.subheader("📋 Menú y Pedidos")
252
- st.success("Menú cargado exitosamente. Listo para tomar pedidos.")
253
- st.write(menu_df)
254
-
255
- # Captura de pedido
256
- st.markdown("Selecciona los items del menú:")
257
- items_seleccionados = st.multiselect("Items", menu_df['item'].tolist())
258
-
259
- if st.button("Tomar Pedido"):
260
- if items_seleccionados:
261
- pedido_usuario = ','.join(items_seleccionados)
262
- confirmados = tomar_pedido_agente(pedido_usuario)
263
- st.info(f"Pedido confirmado: {confirmados}")
264
-
265
- total = procesar_orden_agente(','.join(confirmados))
266
- st.success(f"Total del pedido: ${total}")
267
-
268
- # Generar PDF de la orden
269
- order_details = {item: {'price': menu_df[menu_df['item'] == item]['price'].values[0]} for item in confirmados}
270
- pdf_path = generar_pdf_orden(order_details)
271
- st.markdown(f"[Descargar PDF de la Orden]({pdf_path})", unsafe_allow_html=True)
272
-
273
- # Generar mensaje automático
274
- mensaje_automatico = generar_mensaje_automatico(confirmados)
275
- st.session_state.mensajes_agente.append({"role": "assistant", "content": mensaje_automatico, "timestamp": time.time()})
276
- with st.chat_message("assistant"):
277
- st.markdown(mensaje_automatico)
278
-
279
- # --- Chat para Agentes ---
280
- st.subheader("Chat con Agentes")
281
- if 'mensajes_agente' not in st.session_state:
282
- st.session_state.mensajes_agente = []
283
-
284
- for mensaje in st.session_state.mensajes_agente:
285
- with st.chat_message(mensaje["role"]):
286
- st.markdown(mensaje["content"])
287
-
288
- agente_pregunta = st.text_input("Escribe tu pregunta para el agente:")
289
- if st.button("Enviar al Agente"):
290
- if agente_pregunta:
291
- st.session_state.mensajes_agente.append({"role": "user", "content": agente_pregunta, "timestamp": time.time()})
292
- with st.chat_message("user"):
293
- st.markdown(agente_pregunta)
294
-
295
- # Procesar la respuesta del agente
296
- with st.spinner("El agente está respondiendo..."):
297
- respuesta_agente, audio_path = obtener_respuesta(agente_pregunta, '', modelo="gpt-4", temperatura=0.5)
298
- st.session_state.mensajes_agente.append({"role": "assistant", "content": respuesta_agente, "timestamp": time.time()})
299
- with st.chat_message("assistant"):
300
- st.markdown(respuesta_agente)
301
- st.audio(audio_path, format="audio/mp3", start_time=0)
302
- else:
303
- st.warning("Por favor, ingresa una pregunta antes de enviar.")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
304
 
305
  if __name__ == "__main__":
306
  main()
 
1
+ import os
2
+ import tempfile
3
  import openai
4
  from dotenv import load_dotenv
5
+ import PyPDF2
6
  import nltk
 
 
7
  from nltk.tokenize import word_tokenize
8
  from nltk.corpus import stopwords
9
  from nltk.stem import SnowballStemmer
10
+ import pandas as pd
11
+ from fpdf import FPDF
12
+ import streamlit as st
13
+ import requests
14
  from google.cloud import texttospeech
15
+ import base64
 
 
16
 
17
+ nltk.download('punkt', quiet=True)
18
+ nltk.download('stopwords', quiet=True)
 
19
 
20
+ # Cargar las claves API desde el archivo .env
21
  load_dotenv()
22
+ openai_api_key = os.getenv("OPENAI_API_KEY")
23
+ brevo_api_key = os.getenv("BREVO_API_KEY")
24
  os.environ["GOOGLE_APPLICATION_CREDENTIALS"] = "botidinamix-g.json"
 
25
 
26
+ # Verifica que las claves API están configuradas
27
+ if not openai_api_key:
28
+ st.error("No API key provided for OpenAI. Please set your API key in the .env file.")
29
+ else:
30
+ openai.api_key = openai_api_key
31
+
32
+ if not brevo_api_key:
33
+ st.error("No API key provided for Brevo. Please set your API key in the .env file.")
34
+
35
  def extraer_texto_pdf(archivo):
36
  texto = ""
37
  if archivo:
38
  with tempfile.NamedTemporaryFile(delete=False) as temp_file:
39
  temp_file.write(archivo.read())
40
  temp_file_path = temp_file.name
41
+ try:
42
+ with open(temp_file_path, 'rb') as file:
43
+ reader = PyPDF2.PdfReader(file)
44
+ for page in range(len(reader.pages)):
45
+ texto += reader.pages[page].extract_text()
46
+ except Exception as e:
47
+ st.error(f"Error al extraer texto del PDF: {e}")
48
+ finally:
49
+ os.unlink(temp_file_path)
50
  return texto
51
 
 
52
  def preprocesar_texto(texto):
53
  tokens = word_tokenize(texto, language='spanish')
54
  tokens = [word.lower() for word in tokens if word.isalpha()]
 
58
  tokens = [stemmer.stem(word) for word in tokens]
59
  return " ".join(tokens)
60
 
61
+ def obtener_respuesta(pregunta, texto_preprocesado, modelo, temperatura=0.5, assistant_id=""):
62
+ try:
63
+ response = openai.ChatCompletion.create(
64
+ model=modelo,
65
+ messages=[
66
+ {"role": "system", "content": "Actua como Galatea la asistente de la clinica Odontologica OMARDENT y resuelve las inquietudes"},
67
+ {"role": "user", "content": f"{pregunta}\n\nContexto: {texto_preprocesado}"}
68
+ ],
69
+ temperature=temperatura
70
+ )
71
+ respuesta = response.choices[0].message['content'].strip()
72
+
73
+ # Configura la solicitud de síntesis de voz
74
+ client = texttospeech.TextToSpeechClient()
75
+ input_text = texttospeech.SynthesisInput(text=respuesta)
76
+ voice = texttospeech.VoiceSelectionParams(
77
+ language_code="es-ES", ssml_gender=texttospeech.SsmlVoiceGender.FEMALE
78
+ )
79
+ audio_config = texttospeech.AudioConfig(
80
+ audio_encoding=texttospeech.AudioEncoding.MP3
81
+ )
82
+
83
+ # Realiza la solicitud de síntesis de voz
84
+ response = client.synthesize_speech(
85
+ input=input_text, voice=voice, audio_config=audio_config
86
+ )
87
+
88
+ # Reproduce el audio en Streamlit
89
+ st.audio(response.audio_content, format="audio/mp3")
90
+ return respuesta
91
+
92
+ except openai.OpenAIError as e:
93
+ st.error(f"Error al comunicarse con OpenAI: {e}")
94
+ return "Lo siento, no puedo procesar tu solicitud en este momento."
95
+
96
+ except Exception as e:
97
+ st.error(f"Error al generar la respuesta y el audio: {e}")
98
+ return "Lo siento, ocurrió un error al procesar tu solicitud."
99
+
100
+ def guardar_en_txt(nombre_archivo, datos):
101
+ carpeta = "datos_guardados"
102
+ os.makedirs(carpeta, exist_ok=True)
103
+ ruta_archivo = os.path.join(carpeta, nombre_archivo)
104
+ try:
105
+ with open(ruta_archivo, 'a', encoding='utf-8') as archivo: # Append mode
106
+ archivo.write(datos + "\n")
107
+ except Exception as e:
108
+ st.error(f"Error al guardar datos en el archivo: {e}")
109
+ return ruta_archivo
110
+
111
+ def cargar_desde_txt(nombre_archivo):
112
+ carpeta = "datos_guardados"
113
+ ruta_archivo = os.path.join(carpeta, nombre_archivo)
114
+ try:
115
+ if os.path.exists(ruta_archivo):
116
+ with open(ruta_archivo, 'r', encoding='utf-8') as archivo:
117
+ return archivo.read()
118
+ else:
119
+ st.warning("Archivo no encontrado.")
120
+ return ""
121
+ except Exception as e:
122
+ st.error(f"Error al cargar datos desde el archivo: {e}")
123
+ return ""
124
+
125
+ def listar_archivos_txt():
126
+ carpeta = "datos_guardados"
127
+ try:
128
+ if not os.path.exists(carpeta):
129
+ return []
130
+ archivos = [f for f in os.listdir(carpeta) if f.endswith('.txt')]
131
+ archivos_ordenados = sorted(archivos, key=lambda x: os.path.getctime(os.path.join(carpeta, x)), reverse=True)
132
+ return archivos_ordenados
133
+ except Exception as e:
134
+ st.error(f"Error al listar archivos: {e}")
135
+ return []
136
+
137
+ def generar_pdf(dataframe, titulo, filename):
138
+ pdf = FPDF()
139
+ pdf.add_page()
140
+ pdf.set_font("Arial", size=12)
141
+ pdf.cell(200, 10, txt=titulo, ln=True, align='C')
142
+
143
+ for i, row in dataframe.iterrows():
144
+ row_text = ", ".join(f"{col}: {val}" for col, val in row.items())
145
+ pdf.cell(200, 10, txt=row_text, ln=True)
146
+
147
+ try:
148
+ with tempfile.NamedTemporaryFile(delete=False, suffix='.pdf') as tmp_file:
149
+ pdf.output(tmp_file.name)
150
+ return tmp_file.name
151
+ except Exception as e:
152
+ st.error(f"Error al generar PDF: {e}")
153
+ return None
154
+
155
+ def enviar_correo(destinatario, asunto, contenido):
156
+ url = "https://api.brevo.com/v3/smtp/email"
157
+ headers = {
158
+ "accept": "application/json",
159
+ "api-key": brevo_api_key,
160
+ "content-type": "application/json"
161
+ }
162
+ payload = {
163
+ "sender": {"email": "tu_correo@dominio.com"},
164
+ "to": [{"email": destinatario}],
165
+ "subject": asunto,
166
+ "htmlContent": contenido
167
+ }
168
+ try:
169
+ response = requests.post(url, json=payload, headers=headers)
170
+ if response.status_code == 201:
171
+ st.success(f"Correo enviado a {destinatario}")
172
+ else:
173
+ st.error(f"Error al enviar el correo: {response.text}")
174
+ except Exception as e:
175
+ st.error(f"Error al enviar el correo: {e}")
176
+
177
+ def enviar_whatsapp(numero, mensaje):
178
+ url = "https://api.brevo.com/v3/whatsapp/send"
179
+ headers = {
180
+ "accept": "application/json",
181
+ "api-key": brevo_api_key,
182
+ "content-type": "application/json"
183
+ }
184
+ payload = {
185
+ "recipient": {"number": numero},
186
+ "sender": {"number": "tu_numero_whatsapp"},
187
+ "content": mensaje
188
+ }
189
+ try:
190
+ response = requests.post(url, json=payload, headers=headers)
191
+ if response.status_code == 201:
192
+ st.success(f"Mensaje de WhatsApp enviado a {numero}")
193
+ else:
194
+ st.error(f"Error al enviar el mensaje de WhatsApp: {response.text}")
195
+ except Exception as e:
196
+ st.error(f"Error al enviar el mensaje de WhatsApp: {e}")
197
+
198
+ def flujo_laboratorio():
199
+ st.title("🦷 Gestión de Trabajos de Laboratorio")
200
+
201
+ if 'laboratorio' not in st.session_state:
202
+ st.session_state.laboratorio = []
203
+
204
+ with st.form("laboratorio_form"):
205
+ tipo_trabajo = st.selectbox("Tipo de trabajo:", [
206
+ "Protesis total", "Protesis removible metal-acrilico", "Parcialita acrilico",
207
+ "Placa de blanqueamiento", "Placa de bruxismo", "Corona de acrilico",
208
+ "Corona en zirconio", "Protesis flexible", "Acker flexible"
209
+ ])
210
+ doctor = st.selectbox("Doctor que requiere el trabajo:", ["Dr. Jose Daniel C", "Dr. Jose Omar C"])
211
+ fecha_entrega = st.date_input("Fecha de entrega:")
212
+ fecha_envio = st.date_input("Fecha de envío:")
213
+ laboratorio = st.selectbox("Laboratorio dental:", ["Ernesto Correa lab", "Formando Sonrisas"])
214
+ nombre_paciente = st.text_input("Nombre paciente:")
215
+ observaciones = st.text_input("Observaciones:")
216
+ numero_orden = st.text_input("Número de orden:")
217
+ cantidad = st.number_input("Cantidad:", min_value=1, step=1)
218
+
219
+ submitted = st.form_submit_button("Registrar Trabajo")
220
+
221
+ if submitted:
222
+ trabajo = {
223
+ "tipo_trabajo": tipo_trabajo,
224
+ "doctor": doctor,
225
+ "fecha_entrega": str(fecha_entrega),
226
+ "fecha_envio": str(fecha_envio),
227
+ "laboratorio": laboratorio,
228
+ "nombre_paciente": nombre_paciente,
229
+ "observaciones": observaciones,
230
+ "numero_orden": numero_orden,
231
+ "cantidad": cantidad,
232
+ "estado": "pendiente"
233
+ }
234
+ st.session_state.laboratorio.append(trabajo)
235
+ datos_guardados = mostrar_datos_como_texto([trabajo]) # Append only the new entry
236
+ guardar_en_txt('trabajos_laboratorio.txt', datos_guardados)
237
+ st.success("Trabajo registrado con éxito.")
238
+
239
+ if st.session_state.laboratorio:
240
+ st.write("### Trabajos Registrados")
241
+ df_trabajos = pd.DataFrame(st.session_state.laboratorio)
242
+ st.write(df_trabajos)
243
+
244
+ pdf_file = generar_pdf(df_trabajos, "Registro de Trabajos de Laboratorio", "trabajos_laboratorio.pdf")
245
+ st.download_button(
246
+ label="📥 Descargar PDF",
247
+ data=open(pdf_file, 'rb').read(),
248
+ file_name="trabajos_laboratorio.pdf",
249
+ mime="application/pdf"
250
+ )
251
+
252
+ def flujo_insumos():
253
+ st.title("📦 Gestión de Insumos")
254
+
255
+ if 'insumos' not in st.session_state:
256
+ st.session_state.insumos = []
257
+
258
+ with st.form("insumos_form"):
259
+ insumo_nombre = st.text_input("Nombre del Insumo:")
260
+ insumo_cantidad = st.number_input("Cantidad Faltante:", min_value=0, step=1)
261
+ submitted = st.form_submit_button("Agregar Insumo")
262
+
263
+ if submitted and insumo_nombre:
264
+ insumo = {"nombre": insumo_nombre, "cantidad": insumo_cantidad}
265
+ st.session_state.insumos.append(insumo)
266
+ datos_guardados = mostrar_datos_como_texto([insumo]) # Append only the new entry
267
+ guardar_en_txt('insumos.txt', datos_guardados)
268
+ st.success(f"Insumo '{insumo_nombre}' agregado con éxito.")
269
+
270
+ if st.session_state.insumos:
271
+ st.write("### Insumos Registrados")
272
+ insumos_df = pd.DataFrame(st.session_state.insumos)
273
+ st.write(insumos_df)
274
+
275
+ pdf_file = generar_pdf(insumos_df, "Registro de Insumos Faltantes", "insumos.pdf")
276
+ st.download_button(
277
+ label="📥 Descargar PDF",
278
+ data=open(pdf_file, 'rb').read(),
279
+ file_name="insumos_faltantes.pdf",
280
+ mime="application/pdf"
281
+ )
282
+
283
+ def buscar_datos_guardados():
284
+ st.title("🔍 Buscar Datos Guardados")
285
+
286
+ carpeta = "datos_guardados"
287
+ if not os.path.exists(carpeta):
288
+ st.info("No se encontraron archivos de datos guardados.")
289
+ return
290
+
291
+ archivos = listar_archivos_txt()
292
+
293
+ if archivos:
294
+ archivo_seleccionado = st.selectbox("Selecciona un archivo para ver:", archivos)
295
+
296
+ if archivo_seleccionado:
297
+ datos = cargar_desde_txt(archivo_seleccionado)
298
+ if datos:
299
+ st.write(f"### Datos del archivo {archivo_seleccionado}")
300
+ st.text_area("Datos", datos, height=300)
301
+
302
+ # Link to download the file
303
+ try:
304
+ with open(os.path.join(carpeta, archivo_seleccionado), 'rb') as file:
305
+ st.download_button(
306
+ label="📥 Descargar Archivo TXT",
307
+ data=file,
308
+ file_name=archivo_seleccionado,
309
+ mime="text/plain"
310
+ )
311
+ except Exception as e:
312
+ st.error(f"Error al preparar la descarga: {e}")
313
+
314
+ # Enviar el archivo seleccionado por correo
315
+ if st.button("Enviar por correo"):
316
+ contenido = f"Datos del archivo {archivo_seleccionado}:\n\n{datos}"
317
+ enviar_correo("josedcape@gmail.com", f"Datos del archivo {archivo_seleccionado}", contenido)
318
+
319
+ # Enviar el archivo seleccionado por WhatsApp
320
+ if st.button("Enviar por WhatsApp"):
321
+ mensaje = f"Datos del archivo {archivo_seleccionado}:\n\n{datos}"
322
+ enviar_whatsapp("3114329322", mensaje)
323
+
324
+ else:
325
+ st.warning(f"No se encontraron datos en el archivo {archivo_seleccionado}")
326
+ else:
327
+ st.info("No se encontraron archivos de datos guardados.")
328
+
329
+ def generar_notificaciones_pendientes():
330
+ if 'laboratorio' not in st.session_state or not st.session_state.laboratorio:
331
+ st.info("No hay trabajos pendientes.")
332
+ return
333
+
334
+ pendientes = [trabajo for trabajo in st.session_state.laboratorio if trabajo["estado"] == "pendiente"]
335
+ if pendientes:
336
+ st.write("### Notificaciones de Trabajos Pendientes")
337
+ for trabajo in pendientes:
338
+ st.info(f"Pendiente: {trabajo['tipo_trabajo']} - {trabajo['numero_orden']} para {trabajo['doctor']}. Enviado a {trabajo['laboratorio']} el {trabajo['fecha_envio']}.")
339
+
340
+ def mostrar_datos_como_texto(datos):
341
+ texto = ""
342
+ if isinstance(datos, dict):
343
+ for key, value in datos.items():
344
+ texto += f"{key}: {value}\n"
345
+ elif isinstance(datos, list):
346
+ for item in datos:
347
+ if isinstance(item, dict):
348
+ for key, value in item.items():
349
+ texto += f"{key}: {value}\n"
350
+ texto += "\n"
351
+ else:
352
+ texto += f"{item}\n"
353
+ return texto
354
 
355
+ def flujo_presupuestos():
356
+ st.title("💰 Asistente de Presupuestos")
357
+ st.markdown("Hola Dr. cuénteme en que puedo ayudarle?")
358
+
359
+ lista_precios = {
360
+ "Restauraciones en resina de una superficie": 75000,
361
+ "Restauraciones en resina de dos superficies": 95000,
362
+ "Restauraciones en resina de tres o más superficies": 120000,
363
+ "Restauración en resina cervical": 60000,
364
+ "Coronas metal-porcelana": 750000,
365
+ "Provisional": 80000,
366
+ "Profilaxis simple": 75000,
367
+ "Profilaxis completa": 90000,
368
+ "Corona en zirconio": 980000,
369
+ "Blanqueamiento dental láser por sesión": 150000,
370
+ "Blanqueamiento dental casero": 330000,
371
+ "Blanqueamiento mixto": 430000,
372
+ "Prótesis parcial acrílico hasta 6 dientes": 530000,
373
+ "Prótesis parcial acrílico de más de 6 dientes": 580000,
374
+ "Prótesis flexible hasta 6 dientes": 800000,
375
+ "Prótesis flexible de más de 6 dientes": 900000,
376
+ "Prótesis total de alto impacto": 650000,
377
+ "Acker flexible hasta 2 dientes": 480000,
378
+ "Exodoncia por diente": 85000,
379
+ "Exodoncia cordal": 130000,
380
+ "Endodoncia con dientes terminados en 6": 580000,
381
+ "Endodoncia de un conducto": 380000,
382
+ "Endodoncia de premolares superiores": 480000,
383
+ }
384
+
385
+ if 'presupuesto' not in st.session_state:
386
+ st.session_state['presupuesto'] = []
387
+
388
+ with st.form("presupuesto_form"):
389
+ tratamiento = st.selectbox("Selecciona el tratamiento", list(lista_precios.keys()))
390
+ cantidad = st.number_input("Cantidad", min_value=1, step=1)
391
+ agregar = st.form_submit_button("Agregar al Presupuesto")
392
+
393
+ if agregar:
394
+ precio_total = lista_precios[tratamiento] * cantidad
395
+ st.session_state['presupuesto'].append({"tratamiento": tratamiento, "cantidad": cantidad, "precio_total": precio_total})
396
+ st.success(f"Agregado: {cantidad} {tratamiento} - Total: {precio_total} COP")
397
+
398
+ if st.session_state['presupuesto']:
399
+ st.write("### Servicios Seleccionados")
400
+ total_presupuesto = sum(item['precio_total'] for item in st.session_state['presupuesto'])
401
+ for item in st.session_state['presupuesto']:
402
+ st.write(f"{item['cantidad']} x {item['tratamiento']} - {item['precio_total']} COP")
403
+ st.write(f"**Total: {total_presupuesto} COP**")
404
+
405
+ if st.button("Copiar Presupuesto al Asistente"):
406
+ servicios = "\n".join([f"{item['cantidad']} x {item['tratamiento']} - {item['precio_total']} COP" for item in st.session_state['presupuesto']])
407
+ total = f"**Total: {total_presupuesto} COP**"
408
+ st.session_state['presupuesto_texto'] = f"{servicios}\n{total}"
409
+ st.success("Presupuesto copiado al asistente de chat.")
410
+ st.session_state['mostrar_chat'] = True
411
+
412
+ if st.session_state['mostrar_chat']:
413
+ st.markdown("### Chat con Asistente")
414
+ pregunta_usuario = st.text_input("Escribe tu pregunta aquí:", value=st.session_state.get('presupuesto_texto', ''))
415
+ if st.button("Enviar Pregunta"):
416
+ manejar_pregunta_usuario(pregunta_usuario)
417
+
418
+ def flujo_radiografias():
419
+ st.title("📸 Registro de Radiografías")
420
+
421
+ if 'radiografias' not in st.session_state:
422
+ st.session_state.radiografias = []
423
+
424
+ with st.form("radiografias_form"):
425
+ nombre_paciente = st.text_input("Nombre del Paciente:")
426
+ tipo_radiografia = st.selectbox("Tipo de Radiografía:", ["Periapical", "Panorámica", "Cefalométrica"])
427
+ fecha_realizacion = st.date_input("Fecha de Realización:")
428
+ observaciones = st.text_area("Observaciones:")
429
+
430
+ submitted = st.form_submit_button("Registrar Radiografía")
431
+
432
+ if submitted:
433
+ radiografia = {
434
+ "nombre_paciente": nombre_paciente,
435
+ "tipo_radiografia": tipo_radiografia,
436
+ "fecha_realizacion": str(fecha_realizacion),
437
+ "observaciones": observaciones
438
+ }
439
+ st.session_state.radiografias.append(radiografia)
440
+ datos_guardados = mostrar_datos_como_texto([radiografia])
441
+ guardar_en_txt('radiografias.txt', datos_guardados)
442
+ st.success("Radiografía registrada con éxito.")
443
+
444
+ if st.session_state.radiografias:
445
+ st.write("### Radiografías Registradas")
446
+ df_radiografias = pd.DataFrame(st.session_state.radiografias)
447
+ st.write(df_radiografias)
448
+
449
+ pdf_file = generar_pdf(df_radiografias, "Registro de Radiografías", "radiografias.pdf")
450
+ st.download_button(
451
+ label="📥 Descargar PDF",
452
+ data=open(pdf_file, 'rb').read(),
453
+ file_name="radiografias.pdf",
454
+ mime="application/pdf"
455
+ )
456
+
457
+ def mostrar_recomendaciones():
458
+ st.title("⭐ Recomendaciones")
459
+ st.write("Aquí puedes encontrar recomendaciones y consejos útiles.")
460
 
 
461
  def main():
462
+ st.set_page_config(page_title="Galatea OMARDENT", layout="wide")
463
+
464
+ # Inicializar el estado de la sesión
465
+ if 'modelo' not in st.session_state:
466
+ st.session_state['modelo'] = "gpt-3.5-turbo"
467
+ if 'temperatura' not in st.session_state:
468
+ st.session_state['temperatura'] = 0.5
469
+ if 'mensajes_chat' not in st.session_state:
470
+ st.session_state['mensajes_chat'] = []
471
+ if 'transcripcion_voz' not in st.session_state:
472
+ st.session_state['transcripcion_voz'] = ""
473
+ if 'imagen_asistente' not in st.session_state:
474
+ st.session_state['imagen_asistente'] = None
475
+ if 'video_estado' not in st.session_state:
476
+ st.session_state['video_estado'] = 'paused'
477
+ if 'assistant_id' not in st.session_state:
478
+ st.session_state['assistant_id'] = 'asst_4ZYvBvf4IUVQPjnugSZGLdV2'
479
+ if 'presupuesto_texto' not in st.session_state:
480
+ st.session_state['presupuesto_texto'] = ''
481
+ if 'mostrar_chat' not in st.session_state:
482
+ st.session_state['mostrar_chat'] = False
483
+ if 'memoria' not in st.session_state:
484
+ st.session_state['memoria'] = {}
485
+
486
+ # Barra lateral
487
+ ruta_logo = os.path.join("assets", "Logo Omardent.png")
488
+ if os.path.exists(ruta_logo):
489
+ st.sidebar.image(ruta_logo, use_column_width=True)
490
+ else:
491
+ st.sidebar.warning(f"Error: No se pudo encontrar la imagen en la ruta: {ruta_logo}")
492
+
493
+ st.sidebar.title("🤖 Galatea OMARDENT")
494
+ st.sidebar.markdown("---")
495
+ st.sidebar.subheader("🧠 Configuración del Modelo")
496
+ st.session_state['modelo'] = st.sidebar.selectbox(
497
+ "Selecciona el modelo:",
498
+ ["gpt-3.5-turbo", "gpt-4", "gpt-4-32k", "gpt-4o"],
499
+ index=0,
500
+ key='modelo_selectbox', # Clave única
501
+ help="Elige el modelo de lenguaje de OpenAI que prefieras."
502
+ )
503
+ st.sidebar.markdown("---")
504
+ st.session_state['temperatura'] = st.sidebar.slider(
505
+ "🌡️ Temperatura",
506
+ min_value=0.0, max_value=1.0,
507
+ value=st.session_state['temperatura'],
508
+ step=0.1,
509
+ key='temperatura_slider' # Clave única
510
+ )
511
+ assistant_id = st.sidebar.text_input("Assistant ID", key="assistant_id", help="Introduce el Assistant ID del playground de OpenAI")
512
+
513
+ st.sidebar.markdown("---")
514
+ st.sidebar.subheader("🌟 Navegación")
515
+ lateral_page = st.sidebar.radio("Ir a", ["Página Principal", "Gestión de Trabajos", "Gestión de Insumos", "Registro de Radiografías", "Buscar Datos", "Notificaciones", "Recomendaciones", "Asistente de Presupuestos", "Comunicación", "Asistente de Agendamiento"])
516
+
517
+ top_page = st.selectbox("Navegación Superior", ["Página Principal", "Galatea-Asistente"])
518
+
519
+ if top_page == "Galatea-Asistente":
520
+ mostrar_galatea_asistente()
521
+ else:
522
+ if lateral_page == "Página Principal":
523
+ mostrar_pagina_principal()
524
+ elif lateral_page == "Gestión de Trabajos":
525
+ flujo_laboratorio()
526
+ elif lateral_page == "Gestión de Insumos":
527
+ flujo_insumos()
528
+ elif lateral_page == "Registro de Radiografías":
529
+ flujo_radiografias()
530
+ elif lateral_page == "Buscar Datos":
531
+ buscar_datos_guardados()
532
+ elif lateral_page == "Notificaciones":
533
+ generar_notificaciones_pendientes()
534
+ elif lateral_page == "Recomendaciones":
535
+ mostrar_recomendaciones()
536
+ elif lateral_page == "Asistente de Presupuestos":
537
+ flujo_presupuestos()
538
+ elif lateral_page == "Comunicación":
539
+ st.write("Página de Comunicación") # Implementar según sea necesario
540
+ elif lateral_page == "Asistente de Agendamiento":
541
+ st.write("Página de Agendamiento") # Implementar según sea necesario
542
+
543
+ def mostrar_pagina_principal():
544
+ st.title("VIRTUAL OMARDENT AI-BOTIDINAMIX")
545
+ st.markdown(
546
+ f"""
547
+ <style>
548
+ #video-container {{
549
+ position: relative;
550
+ width: 100%;
551
+ padding-bottom: 56.25%;
552
+ background-color: lightblue;
553
+ overflow: hidden;
554
+ }}
555
+ #background-video {{
556
+ position: absolute;
557
+ top: 0;
558
+ left: 0;
559
+ width: 100%;
560
+ height: 100%;
561
+ }}
562
+ </style>
563
+ <div id="video-container">
564
+ <video id="background-video" autoplay loop muted playsinline>
565
+ <source src="https://cdn.leonardo.ai/users/645c3d5c-ca1b-4ce8-aefa-a091494e0d09/generations/0c4f0fe7-5937-4644-b984-bdbd95018990/0c4f0fe7-5937-4644-b984-bdbd95018990.mp4" type="video/mp4">
566
+ </video>
567
+ </div>
568
+ """,
569
+ unsafe_allow_html=True
570
+ )
571
+
572
+ archivo_pdf = st.file_uploader("📂 Cargar PDF", type='pdf', key='chat_pdf')
573
 
574
+ col1, col2 = st.columns([3, 1])
575
+ with col1:
576
+ pregunta_usuario = st.text_input("Pregunta:", key='unique_chat_input_key', value=st.session_state['transcripcion_voz'])
577
+ with col2:
578
+ capturar_voz()
579
+
580
+ if pregunta_usuario:
581
+ manejar_pregunta_usuario(pregunta_usuario, archivo_pdf)
582
+
583
+ def mostrar_galatea_asistente():
584
  st.markdown(
585
  """
586
  <style>
587
+ #video-container {
588
+ position: relative;
589
+ width: 100%;
590
+ height: 40vh;
591
+ background-color: lightblue;
592
+ overflow: hidden;
593
+ display: flex;
594
+ justify-content: center;
595
+ align-items: center;
596
+ }
597
+ #background-video {
598
+ width: 100%;
599
+ height: auto;
600
+ }
601
+ #chat-container {
602
+ margin-top: 20px;
603
+ width: 100%;
604
+ display: flex;
605
+ flex-direction: column;
606
+ justify-content: center;
607
+ align-items: center;
608
+ }
609
+ .chat-message {
610
+ background: rgba(255, 255, 255, 0.8);
611
+ border-radius: 10px;
612
+ padding: 10px;
613
+ margin-bottom: 10px;
614
+ max-width: 70%;
615
+ }
616
+ .chat-message.user {
617
+ align-self: flex-start;
618
+ }
619
+ .chat-message.assistant {
620
+ align-self: flex-end;
621
+ background: rgba(0, 123, 255, 0.8);
622
+ color: white;
623
+ }
 
 
624
  </style>
625
+ <div id="video-container">
626
+ <video id="background-video" autoplay loop muted playsinline>
627
+ <source src="https://cdn.pika.art/v1/081128be-944b-4999-9c2e-16f61d7e7a83/lip_sync.mp4" type="video/mp4">
628
+ </video>
629
+ </div>
630
+ <div id="chat-container">
631
  """,
632
+ unsafe_allow_html=True
633
  )
634
 
635
+ for mensaje in st.session_state['mensajes_chat']:
636
+ clase = "user" if mensaje["role"] == "user" else "assistant"
637
+ st.markdown(f'<div class="chat-message {clase}">{mensaje["content"]}</div>', unsafe_allow_html=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
638
 
639
+ pregunta_usuario = st.text_input("Escribe tu pregunta aquí:", key='unique_chat_input_key', value=st.session_state['transcripcion_voz'])
640
+ if st.button("Enviar Pregunta"):
641
+ manejar_pregunta_usuario(pregunta_usuario)
 
642
 
643
+ st.markdown("</div>", unsafe_allow_html=True)
644
+
645
+ if st.session_state['imagen_asistente']:
646
+ st.image(st.session_state['imagen_asistente'], use_column_width=True)
647
+ else:
648
+ st.warning("No se ha cargado ninguna imagen. Por favor, carga una imagen en la página principal.")
649
+
650
+ def manejar_pregunta_usuario(pregunta_usuario, archivo_pdf=None):
651
+ st.session_state['mensajes_chat'].append({"role": "user", "content": pregunta_usuario})
652
+ with st.chat_message("user"):
653
+ st.markdown(pregunta_usuario)
654
+
655
+ texto_preprocesado = ""
656
  if archivo_pdf:
657
+ texto_pdf = extraer_texto_pdf(archivo_pdf)
658
+ texto_preprocesado = preprocesar_texto(texto_pdf)
659
+ else:
660
+ with open("assets/instrucciones.pdf", "rb") as file:
661
+ texto_pdf = extraer_texto_pdf(file)
662
+ texto_preprocesado = preprocesar_texto(texto_pdf)
663
+
664
+ # Obtener respuesta del modelo usando Assistant ID si está presente
665
+ assistant_id = st.session_state.get('assistant_id', '')
666
+ if assistant_id:
667
+ prompt = f"{texto_preprocesado}\n\n{pregunta_usuario}"
668
+ response = openai.ChatCompletion.create(
669
+ model=st.session_state['modelo'],
670
+ messages=[
671
+ {"role": "system", "content": "You are a helpful assistant."},
672
+ {"role": "user", "content": prompt}
673
+ ],
674
+ temperature=st.session_state['temperatura'],
675
+ user=assistant_id
676
+ )
677
+ respuesta = response.choices[0].message['content'].strip()
678
+ else:
679
+ respuesta = obtener_respuesta(
680
+ pregunta_usuario,
681
+ texto_preprocesado,
682
+ st.session_state['modelo'],
683
+ st.session_state['temperatura'],
684
+ assistant_id
685
+ )
686
+
687
+ st.session_state['mensajes_chat'].append({"role": "assistant", "content": respuesta})
688
+ with st.chat_message("assistant"):
689
+ st.markdown(respuesta)
690
+
691
+ # Convertir la respuesta en voz
692
+ client = texttospeech.TextToSpeechClient()
693
+ synthesis_input = texttospeech.SynthesisInput(text=respuesta)
694
+ voice = texttospeech.VoiceSelectionParams(language_code="es-ES", ssml_gender=texttospeech.SsmlVoiceGender.FEMALE)
695
+ audio_config = texttospeech.AudioConfig(audio_encoding=texttospeech.AudioEncoding.MP3)
696
+ response = client.synthesize_speech(input=synthesis_input, voice=voice, audio_config=audio_config)
697
+
698
+ with tempfile.NamedTemporaryFile(delete=False, suffix=".mp3") as tmp_file:
699
+ tmp_file.write(response.audio_content)
700
+ audio_file_path = tmp_file.name
701
+
702
+ # Incrustar el audio en la página y reproducirlo automáticamente
703
+ audio_html = f"""
704
+ <audio id="response-audio" src="data:audio/mp3;base64,{base64.b64encode(response.audio_content).decode()}" autoplay></audio>
705
+ <script>
706
+ document.getElementById('response-audio').onended = function() {{
707
+ document.getElementById('background-video').pause();
708
+ }};
709
+ </script>
710
+ """
711
+ st.markdown(audio_html, unsafe_allow_html=True)
712
+
713
+ # Reproducir el video solo cuando el chat está activo
714
+ st.session_state['video_estado'] = 'playing'
715
+ st.markdown(f"<script>document.getElementById('background-video').play();</script>", unsafe_allow_html=True)
716
+
717
+ # Almacenar la información importante en la memoria
718
+ if "nombre" in pregunta_usuario.lower() or "teléfono" in pregunta_usuario.lower():
719
+ st.session_state['memoria']['última_interacción'] = pregunta_usuario
720
+ guardar_en_txt('memoria_asistente.txt', f"Última interacción: {pregunta_usuario}")
721
+
722
+ def capturar_voz():
723
+ st.markdown(
724
+ """
725
+ <style>
726
+ .assistant-button {
727
+ display: flex;
728
+ align-items: center;
729
+ justify-content: center;
730
+ background-color: #4CAF50;
731
+ color: white;
732
+ padding: 10px;
733
+ border: none;
734
+ border-radius: 5px;
735
+ cursor: pointer;
736
+ font-size: 16px;
737
+ margin-top: 10px;
738
+ }
739
+ .assistant-button img {
740
+ margin-right: 10px;
741
+ }
742
+ </style>
743
+ <button class="assistant-button" onclick="startRecording()">
744
+ <img src='https://img2.gratispng.com/20180808/cxq/kisspng-robotics-science-computer-icons-robot-technology-robo-to-logo-svg-png-icon-free-download-45527-5b6baa46a5e322.4713113715337825986795.jpg' alt='icon' width='20' height='20'/>
745
+ Capturar Voz
746
+ </button>
747
+ <script>
748
+ function startRecording() {
749
+ const recognition = new (window.SpeechRecognition || window.webkitSpeechRecognition)();
750
+ recognition.lang = 'es-ES';
751
+ recognition.interimResults = false;
752
+ recognition.maxAlternatives = 1;
753
+ recognition.start();
754
+ recognition.onresult = (event) => {
755
+ const lastResult = event.results.length - 1;
756
+ const text = event.results[lastResult][0].transcript;
757
+ const customEvent = new CustomEvent('audioTranscription', { detail: text });
758
+ document.dispatchEvent(customEvent);
759
+ };
760
+ recognition.onspeechend = () => {
761
+ recognition.stop();
762
+ };
763
+ recognition.onerror = (event) => {
764
+ console.error(event.error);
765
+ };
766
+ }
767
+ document.addEventListener('audioTranscription', (event) => {
768
+ const transcription = event.detail;
769
+ document.querySelector("input[name='unique_chat_input_key']").value = transcription;
770
+ // También puedes actualizar el estado de Streamlit aquí si es necesario
771
+ fetch('/process_audio', {
772
+ method: 'POST',
773
+ headers: {
774
+ 'Content-Type': 'application/json'
775
+ },
776
+ body: JSON.stringify({ transcription })
777
+ }).then(response => response.json())
778
+ .then(data => {
779
+ // Manejo de la respuesta de Flask si es necesario
780
+ });
781
+ });
782
+ </script>
783
+ """,
784
+ unsafe_allow_html=True
785
+ )
786
 
787
  if __name__ == "__main__":
788
  main()