Josedcape commited on
Commit
de37b56
·
verified ·
1 Parent(s): fa9ba9d

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +137 -429
app.py CHANGED
@@ -1,6 +1,7 @@
1
  import os
2
  import tempfile
3
  import openai
 
4
  from dotenv import load_dotenv
5
  import PyPDF2
6
  import nltk
@@ -12,6 +13,13 @@ from fpdf import FPDF
12
  import streamlit as st
13
  import requests
14
  from google.cloud import texttospeech
 
 
 
 
 
 
 
15
 
16
  nltk.download('punkt', quiet=True)
17
  nltk.download('stopwords', quiet=True)
@@ -31,438 +39,26 @@ else:
31
  if not brevo_api_key:
32
  st.error("No API key provided for Brevo. Please set your API key in the .env file.")
33
 
34
- def extraer_texto_pdf(archivo):
35
- texto = ""
36
- if archivo:
37
- with tempfile.NamedTemporaryFile(delete=False) as temp_file:
38
- temp_file.write(archivo.read())
39
- temp_file_path = temp_file.name
40
- try:
41
- with open(temp_file_path, 'rb') as file:
42
- reader = PyPDF2.PdfReader(file)
43
- for page in range(len(reader.pages)):
44
- texto += reader.pages[page].extract_text()
45
- except Exception as e:
46
- st.error(f"Error al extraer texto del PDF: {e}")
47
- finally:
48
- os.unlink(temp_file_path)
49
- return texto
50
-
51
- def preprocesar_texto(texto):
52
- tokens = word_tokenize(texto, language='spanish')
53
- tokens = [word.lower() for word in tokens if word.isalpha()]
54
- stopwords_es = set(stopwords.words('spanish'))
55
- tokens = [word for word in tokens if word not in stopwords_es]
56
- stemmer = SnowballStemmer('spanish')
57
- tokens = [stemmer.stem(word) for word in tokens]
58
- return " ".join(tokens)
59
-
60
- def obtener_respuesta(pregunta, texto_preprocesado, modelo, temperatura=0.5, assistant_id=""):
61
- try:
62
- response = openai.ChatCompletion.create(
63
- model=modelo,
64
- messages=[
65
- {"role": "system", "content": "Actua como Galatea la asistente de la clinica Odontologica OMARDENT y resuelve las inquietudes"},
66
- {"role": "user", "content": f"{pregunta}\n\nContexto: {texto_preprocesado}"}
67
- ],
68
- temperature=temperatura
69
- )
70
- respuesta = response.choices[0].message['content'].strip()
71
-
72
- # Configura la solicitud de síntesis de voz
73
- client = texttospeech.TextToSpeechClient()
74
- input_text = texttospeech.SynthesisInput(text=respuesta)
75
- voice = texttospeech.VoiceSelectionParams(
76
- language_code="es-ES", ssml_gender=texttospeech.SsmlVoiceGender.FEMALE
77
- )
78
- audio_config = texttospeech.AudioConfig(
79
- audio_encoding=texttospeech.AudioEncoding.MP3
80
- )
81
-
82
- # Realiza la solicitud de síntesis de voz
83
- response = client.synthesize_speech(
84
- input=input_text, voice=voice, audio_config=audio_config
85
- )
86
 
87
- # Reproduce el audio en Streamlit
88
- st.audio(response.audio_content, format="audio/mp3")
89
- return respuesta
90
-
91
- except openai.OpenAIError as e:
92
- st.error(f"Error al comunicarse con OpenAI: {e}")
93
- return "Lo siento, no puedo procesar tu solicitud en este momento."
94
-
95
- except Exception as e:
96
- st.error(f"Error al generar la respuesta y el audio: {e}")
97
- return "Lo siento, ocurrió un error al procesar tu solicitud."
98
-
99
- def guardar_en_txt(nombre_archivo, datos):
100
- carpeta = "datos_guardados"
101
- os.makedirs(carpeta, existo_ok=True)
102
- ruta_archivo = os.path.join(carpeta, nombre_archivo)
103
- try:
104
- with open(ruta_archivo, 'a', encoding='utf-8') as archivo: # Append mode
105
- archivo.write(datos + "\n")
106
- except Exception as e:
107
- st.error(f"Error al guardar datos en el archivo: {e}")
108
- return ruta_archivo
109
-
110
- def cargar_desde_txt(nombre_archivo):
111
- carpeta = "datos_guardados"
112
- ruta_archivo = os.path.join(carpeta, nombre_archivo)
113
- try:
114
- if os.path.exists(ruta_archivo):
115
- with open(ruta_archivo, 'r', encoding='utf-8') as archivo:
116
- return archivo.read()
117
- else:
118
- st.warning("Archivo no encontrado.")
119
- return ""
120
- except Exception as e:
121
- st.error(f"Error al cargar datos desde el archivo: {e}")
122
- return ""
123
-
124
- def listar_archivos_txt():
125
- carpeta = "datos_guardados"
126
- try:
127
- if not os.path.exists(carpeta):
128
- return []
129
- archivos = [f for f in os.listdir(carpeta) if f.endswith('.txt')]
130
- archivos_ordenados = sorted(archivos, key=lambda x: os.path.getctime(os.path.join(carpeta, x)), reverse=True)
131
- return archivos_ordenados
132
- except Exception as e:
133
- st.error(f"Error al listar archivos: {e}")
134
- return []
135
-
136
- def generar_pdf(dataframe, titulo, filename):
137
- pdf = FPDF()
138
- pdf.add_page()
139
- pdf.set_font("Arial", size=12)
140
- pdf.cell(200, 10, txt=titulo, ln=True, align='C')
141
-
142
- for i, row in dataframe.iterrows():
143
- row_text = ", ".join(f"{col}: {val}" for col, val in row.items())
144
- pdf.cell(200, 10, txt=row_text, ln=True)
145
-
146
- try:
147
- with tempfile.NamedTemporaryFile(delete=False, suffix='.pdf') as tmp_file:
148
- pdf.output(tmp_file.name)
149
- return tmp_file.name
150
- except Exception as e:
151
- st.error(f"Error al generar PDF: {e}")
152
- return None
153
-
154
- def enviar_correo(destinatario, asunto, contenido):
155
- url = "https://api.brevo.com/v3/smtp/email"
156
- headers = {
157
- "accept": "application/json",
158
- "api-key": brevo_api_key,
159
- "content-type": "application/json"
160
- }
161
- payload = {
162
- "sender": {"email": "tu_correo@dominio.com"},
163
- "to": [{"email": destinatario}],
164
- "subject": asunto,
165
- "htmlContent": contenido
166
- }
167
- try:
168
- response = requests.post(url, json=payload, headers=headers)
169
- if response.status_code == 201:
170
- st.success(f"Correo enviado a {destinatario}")
171
- else:
172
- st.error(f"Error al enviar el correo: {response.text}")
173
- except Exception as e:
174
- st.error(f"Error al enviar el correo: {e}")
175
-
176
- def enviar_whatsapp(numero, mensaje):
177
- url = "https://api.brevo.com/v3/whatsapp/send"
178
- headers = {
179
- "accept": "application/json",
180
- "api-key": brevo_api_key,
181
- "content-type": "application/json"
182
- }
183
- payload = {
184
- "recipient": {"number": numero},
185
- "sender": {"number": "tu_numero_whatsapp"},
186
- "content": mensaje
187
- }
188
- try:
189
- response = requests.post(url, json=payload, headers=headers)
190
- if response.status_code == 201:
191
- st.success(f"Mensaje de WhatsApp enviado a {numero}")
192
- else:
193
- st.error(f"Error al enviar el mensaje de WhatsApp: {response.text}")
194
- except Exception as e:
195
- st.error(f"Error al enviar el mensaje de WhatsApp: {e}")
196
-
197
- def flujo_laboratorio():
198
- st.title("🦷 Gestión de Trabajos de Laboratorio")
199
-
200
- if 'laboratorio' not in st.session_state:
201
- st.session_state.laboratorio = []
202
-
203
- with st.form("laboratorio_form"):
204
- tipo_trabajo = st.selectbox("Tipo de trabajo:", [
205
- "Protesis total", "Protesis removible metal-acrilico", "Parcialita acrilico",
206
- "Placa de blanqueamiento", "Placa de bruxismo", "Corona de acrilico",
207
- "Corona en zirconio", "Protesis flexible", "Acker flexible"
208
- ])
209
- doctor = st.selectbox("Doctor que requiere el trabajo:", ["Dr. Jose Daniel C", "Dr. Jose Omar C"])
210
- fecha_entrega = st.date_input("Fecha de entrega:")
211
- fecha_envio = st.date_input("Fecha de envío:")
212
- laboratorio = st.selectbox("Laboratorio dental:", ["Ernesto Correa lab", "Formando Sonrisas"])
213
- nombre_paciente = st.text_input("Nombre paciente:")
214
- observaciones = st.text_input("Observaciones:")
215
- numero_orden = st.text_input("Número de orden:")
216
- cantidad = st.number_input("Cantidad:", min_value=1, step=1)
217
-
218
- submitted = st.form_submit_button("Registrar Trabajo")
219
-
220
- if submitted:
221
- trabajo = {
222
- "tipo_trabajo": tipo_trabajo,
223
- "doctor": doctor,
224
- "fecha_entrega": str(fecha_entrega),
225
- "fecha_envio": str(fecha_envio),
226
- "laboratorio": laboratorio,
227
- "nombre_paciente": nombre_paciente,
228
- "observaciones": observaciones,
229
- "numero_orden": numero_orden,
230
- "cantidad": cantidad,
231
- "estado": "pendiente"
232
- }
233
- st.session_state.laboratorio.append(trabajo)
234
- datos_guardados = mostrar_datos_como_texto([trabajo]) # Append only the new entry
235
- guardar_en_txt('trabajos_laboratorio.txt', datos_guardados)
236
- st.success("Trabajo registrado con éxito.")
237
-
238
- if st.session_state.laboratorio:
239
- st.write("### Trabajos Registrados")
240
- df_trabajos = pd.DataFrame(st.session_state.laboratorio)
241
- st.write(df_trabajos)
242
-
243
- pdf_file = generar_pdf(df_trabajos, "Registro de Trabajos de Laboratorio", "trabajos_laboratorio.pdf")
244
- st.download_button(
245
- label="📥 Descargar PDF",
246
- data=open(pdf_file, 'rb').read(),
247
- file_name="trabajos_laboratorio.pdf",
248
- mime="application/pdf"
249
- )
250
-
251
- def flujo_insumos():
252
- st.title("📦 Gestión de Insumos")
253
-
254
- if 'insumos' not in st.session_state:
255
- st.session_state.insumos = []
256
-
257
- with st.form("insumos_form"):
258
- insumo_nombre = st.text_input("Nombre del Insumo:")
259
- insumo_cantidad = st.number_input("Cantidad Faltante:", min_value=0, step=1)
260
- submitted = st.form_submit_button("Agregar Insumo")
261
-
262
- if submitted and insumo_nombre:
263
- insumo = {"nombre": insumo_nombre, "cantidad": insumo_cantidad}
264
- st.session_state.insumos.append(insumo)
265
- datos_guardados = mostrar_datos_como_texto([insumo]) # Append only the new entry
266
- guardar_en_txt('insumos.txt', datos_guardados)
267
- st.success(f"Insumo '{insumo_nombre}' agregado con éxito.")
268
-
269
- if st.session_state.insumos:
270
- st.write("### Insumos Registrados")
271
- insumos_df = pd.DataFrame(st.session_state.insumos)
272
- st.write(insumos_df)
273
-
274
- pdf_file = generar_pdf(insumos_df, "Registro de Insumos Faltantes", "insumos.pdf")
275
- st.download_button(
276
- label="📥 Descargar PDF",
277
- data=open(pdf_file, 'rb').read(),
278
- file_name="insumos_faltantes.pdf",
279
- mime="application/pdf"
280
- )
281
 
282
- def buscar_datos_guardados():
283
- st.title("🔍 Buscar Datos Guardados")
284
-
285
- carpeta = "datos_guardados"
286
- if not os.path.exists(carpeta):
287
- st.info("No se encontraron archivos de datos guardados.")
288
- return
289
-
290
- archivos = listar_archivos_txt()
291
-
292
- if archivos:
293
- archivo_seleccionado = st.selectbox("Selecciona un archivo para ver:", archivos)
294
-
295
- if archivo_seleccionado:
296
- datos = cargar_desde_txt(os.path.join(carpeta, archivo_seleccionado))
297
- if datos:
298
- st.write(f"### Datos del archivo {archivo_seleccionado}")
299
- st.text_area("Datos", datos, height=300)
300
-
301
- # Link to download the file
302
- try:
303
- with open(os.path.join(carpeta, archivo_seleccionado), 'rb') as file:
304
- st.download_button(
305
- label="📥 Descargar Archivo TXT",
306
- data=file,
307
- file_name=archivo_seleccionado,
308
- mime="text/plain"
309
- )
310
- except Exception as e:
311
- st.error(f"Error al preparar la descarga: {e}")
312
-
313
- # Enviar el archivo seleccionado por correo
314
- if st.button("Enviar por correo"):
315
- contenido = f"Datos del archivo {archivo_seleccionado}:\n\n{datos}"
316
- enviar_correo("josedcape@gmail.com", f"Datos del archivo {archivo_seleccionado}", contenido)
317
-
318
- # Enviar el archivo seleccionado por WhatsApp
319
- if st.button("Enviar por WhatsApp"):
320
- mensaje = f"Datos del archivo {archivo_seleccionado}:\n\n{datos}"
321
- enviar_whatsapp("3114329322", mensaje)
322
-
323
- else:
324
- st.warning(f"No se encontraron datos en el archivo {archivo_seleccionado}")
325
- else:
326
- st.info("No se encontraron archivos de datos guardados.")
327
 
328
- def generar_notificaciones_pendientes():
329
- if 'laboratorio' not in st.session_state or not st.session_state.laboratorio:
330
- st.info("No hay trabajos pendientes.")
331
- return
332
-
333
- pendientes = [trabajo for trabajo in st.session_state.laboratorio if trabajo["estado"] == "pendiente"]
334
- if pendientes:
335
- st.write("### Notificaciones de Trabajos Pendientes")
336
- for trabajo in pendientes:
337
- st.info(f"Pendiente: {trabajo['tipo_trabajo']} - {trabajo['numero_orden']} para {trabajo['doctor']}. Enviado a {trabajo['laboratorio']} el {trabajo['fecha_envio']}.")
338
-
339
- def mostrar_datos_como_texto(datos):
340
- texto = ""
341
- if isinstance(datos, dict):
342
- for key, value in datos.items():
343
- texto += f"{key}: {value}\n"
344
- elif isinstance(datos, list):
345
- for item in datos:
346
- if isinstance(item, dict):
347
- for key, value in item.items():
348
- texto += f"{key}: {value}\n"
349
- texto += "\n"
350
- else:
351
- texto += f"{item}\n"
352
- return texto
353
-
354
- def flujo_presupuestos():
355
- st.title("💰 Asistente de Presupuestos")
356
- st.markdown("Hola Dr. cuénteme en que puedo ayudarle?")
357
-
358
- lista_precios = {
359
- "Restauraciones en resina de una superficie": 75000,
360
- "Restauraciones en resina de dos superficies": 95000,
361
- "Restauraciones en resina de tres o más superficies": 120000,
362
- "Restauración en resina cervical": 60000,
363
- "Coronas metal-porcelana": 750000,
364
- "Provisional": 80000,
365
- "Profilaxis simple": 75000,
366
- "Profilaxis completa": 90000,
367
- "Corona en zirconio": 980000,
368
- "Blanqueamiento dental láser por sesión": 150000,
369
- "Blanqueamiento dental casero": 330000,
370
- "Blanqueamiento mixto": 430000,
371
- "Prótesis parcial acrílico hasta 6 dientes": 530000,
372
- "Prótesis parcial acrílico de más de 6 dientes": 580000,
373
- "Prótesis flexible hasta 6 dientes": 800000,
374
- "Prótesis flexible de más de 6 dientes": 900000,
375
- "Prótesis total de alto impacto": 650000,
376
- "Acker flexible hasta 2 dientes": 480000,
377
- "Exodoncia por diente": 85000,
378
- "Exodoncia cordal": 130000,
379
- "Endodoncia con dientes terminados en 6": 580000,
380
- "Endodoncia de un conducto": 380000,
381
- "Endodoncia de premolares superiores": 480000,
382
- }
383
-
384
- if 'presupuesto' not in st.session_state:
385
- st.session_state['presupuesto'] = []
386
-
387
- with st.form("presupuesto_form"):
388
- tratamiento = st.selectbox("Selecciona el tratamiento", list(lista_precios.keys()))
389
- cantidad = st.number_input("Cantidad", min_value=1, step=1)
390
- agregar = st.form_submit_button("Agregar al Presupuesto")
391
-
392
- if agregar:
393
- precio_total = lista_precios[tratamiento] * cantidad
394
- st.session_state['presupuesto'].append({"tratamiento": tratamiento, "cantidad": cantidad, "precio_total": precio_total})
395
- st.success(f"Agregado: {cantidad} {tratamiento} - Total: {precio_total} COP")
396
-
397
- if st.session_state['presupuesto']:
398
- st.write("### Servicios Seleccionados")
399
- total_presupuesto = sum(item['precio_total'] for item in st.session_state['presupuesto'])
400
- for item in st.session_state['presupuesto']:
401
- st.write(f"{item['cantidad']} x {item['tratamiento']} - {item['precio_total']} COP")
402
- st.write(f"**Total: {total_presupuesto} COP**")
403
-
404
- if st.button("Copiar Presupuesto al Asistente"):
405
- servicios = "\n".join([f"{item['cantidad']} x {item['tratamiento']} - {item['precio_total']} COP" for item in st.session_state['presupuesto']])
406
- total = f"**Total: {total_presupuesto} COP**"
407
- st.session_state['presupuesto_texto'] = f"{servicios}\n{total}"
408
- st.success("Presupuesto copiado al asistente de chat.")
409
- st.session_state['mostrar_chat'] = True
410
-
411
- if st.session_state['mostrar_chat']:
412
- st.markdown("### Chat con Asistente")
413
- pregunta_usuario = st.text_input("Escribe tu pregunta aquí:", value=st.session_state.get('presupuesto_texto', ''))
414
- if st.button("Enviar Pregunta"):
415
- manejar_pregunta_usuario(pregunta_usuario)
416
-
417
- def flujo_radiografias():
418
- st.title("📸 Registro de Radiografías")
419
-
420
- if 'radiografias' not in st.session_state:
421
- st.session_state.radiografias = []
422
-
423
- with st.form("radiografias_form"):
424
- nombre_paciente = st.text_input("Nombre del Paciente:")
425
- tipo_radiografia = st.selectbox("Tipo de Radiografía:", ["Periapical", "Panorámica", "Cefalométrica"])
426
- fecha_realizacion = st.date_input("Fecha de Realización:")
427
- observaciones = st.text_area("Observaciones:")
428
-
429
- submitted = st.form_submit_button("Registrar Radiografía")
430
-
431
- if submitted:
432
- radiografia = {
433
- "nombre_paciente": nombre_paciente,
434
- "tipo_radiografia": tipo_radiografia,
435
- "fecha_realizacion": str(fecha_realizacion),
436
- "observaciones": observaciones
437
- }
438
- st.session_state.radiografias.append(radiografia)
439
- datos_guardados = mostrar_datos_como_texto([radiografia])
440
- guardar_en_txt('radiografias.txt', datos_guardados)
441
- st.success("Radiografía registrada con éxito.")
442
-
443
- if st.session_state.radiografias:
444
- st.write("### Radiografías Registradas")
445
- df_radiografias = pd.DataFrame(st.session_state.radiografias)
446
- st.write(df_radiografias)
447
-
448
- pdf_file = generar_pdf(df_radiografias, "Registro de Radiografías", "radiografias.pdf")
449
- st.download_button(
450
- label="📥 Descargar PDF",
451
- data=open(pdf_file, 'rb').read(),
452
- file_name="radiografias.pdf",
453
- mime="application/pdf"
454
- )
455
 
456
- def mostrar_recomendaciones():
457
- st.title(" Recomendaciones")
458
- st.write("Aquí puedes encontrar recomendaciones y consejos útiles.")
459
-
460
- def main():
461
- st.set_page_config(page_title="Galatea OMARDENT", layout="wide")
462
-
463
- # Inicializar el estado de la sesión
464
  if 'modelo' not in st.session_state:
465
- st.session_state['modelo'] = "gpt-3.5-turbo"
466
  if 'temperatura' not in st.session_state:
467
  st.session_state['temperatura'] = 0.5
468
  if 'mensajes_chat' not in st.session_state:
@@ -480,7 +76,9 @@ def main():
480
  if 'mostrar_chat' not in st.session_state:
481
  st.session_state['mostrar_chat'] = False
482
 
483
- # Barra lateral
 
 
484
  ruta_logo = os.path.join("assets", "Logo Omardent.png")
485
  if os.path.exists(ruta_logo):
486
  st.sidebar.image(ruta_logo, use_column_width=True)
@@ -529,7 +127,7 @@ def main():
529
  elif lateral_page == "Notificaciones":
530
  generar_notificaciones_pendientes()
531
  elif lateral_page == "Recomendaciones":
532
- mostrar_recomendaciones()
533
  elif lateral_page == "Asistente de Presupuestos":
534
  flujo_presupuestos()
535
  elif lateral_page == "Comunicación":
@@ -777,5 +375,115 @@ def capturar_voz():
777
  unsafe_allow_html=True
778
  )
779
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
780
  if __name__ == "__main__":
781
  main()
 
1
  import os
2
  import tempfile
3
  import openai
4
+ import base64
5
  from dotenv import load_dotenv
6
  import PyPDF2
7
  import nltk
 
13
  import streamlit as st
14
  import requests
15
  from google.cloud import texttospeech
16
+ import io
17
+ from docx import Document
18
+ from flask import Flask, request, jsonify
19
+ import threading
20
+ from google.oauth2.service_account import Credentials
21
+ from googleapiclient.discovery import build
22
+ from datetime import datetime, timedelta
23
 
24
  nltk.download('punkt', quiet=True)
25
  nltk.download('stopwords', quiet=True)
 
39
  if not brevo_api_key:
40
  st.error("No API key provided for Brevo. Please set your API key in the .env file.")
41
 
42
+ # Crear la aplicación Flask
43
+ app = Flask(__name__)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
44
 
45
+ @app.route('/process_audio', methods=['POST'])
46
+ def process_audio():
47
+ data = request.json
48
+ transcription = data['transcription']
49
+ return jsonify({'transcription': transcription})
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
50
 
51
+ def run_flask_app():
52
+ app.run(port=5000, debug=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
53
 
54
+ # Ejecutar Flask en un hilo separado
55
+ flask_thread = threading.Thread(target=run_flask_app)
56
+ flask_thread.start()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
57
 
58
+ def inicializar_estado():
59
+ """Inicializa el estado de la sesión si no está ya inicializado."""
 
 
 
 
 
 
60
  if 'modelo' not in st.session_state:
61
+ st.session_state['modelo'] = "gpt-3.5-turbo-16k"
62
  if 'temperatura' not in st.session_state:
63
  st.session_state['temperatura'] = 0.5
64
  if 'mensajes_chat' not in st.session_state:
 
76
  if 'mostrar_chat' not in st.session_state:
77
  st.session_state['mostrar_chat'] = False
78
 
79
+ inicializar_estado()
80
+
81
+ def barra_lateral():
82
  ruta_logo = os.path.join("assets", "Logo Omardent.png")
83
  if os.path.exists(ruta_logo):
84
  st.sidebar.image(ruta_logo, use_column_width=True)
 
127
  elif lateral_page == "Notificaciones":
128
  generar_notificaciones_pendientes()
129
  elif lateral_page == "Recomendaciones":
130
+ show_document_modification()
131
  elif lateral_page == "Asistente de Presupuestos":
132
  flujo_presupuestos()
133
  elif lateral_page == "Comunicación":
 
375
  unsafe_allow_html=True
376
  )
377
 
378
+ def consultar_google_calendar(pregunta):
379
+ SCOPES = ['https://www.googleapis.com/auth/calendar.readonly']
380
+ creds = None
381
+
382
+ if not os.path.exists('service_account.json'):
383
+ return 'Error: archivo service_account.json no encontrado.'
384
+
385
+ creds = Credentials.from_service_account_file('service_account.json', scopes=SCOPES)
386
+
387
+ service = build('calendar', 'v3', credentials=creds)
388
+
389
+ now = datetime.utcnow().isoformat() + 'Z'
390
+ events_result = service.events().list(
391
+ calendarId='primary', timeMin=now,
392
+ maxResults=10, singleEvents=True,
393
+ orderBy='startTime').execute()
394
+ events = events_result.get('items', [])
395
+
396
+ if not events:
397
+ return 'No hay próximas citas encontradas.'
398
+ else:
399
+ eventos = []
400
+ for event in events:
401
+ start = event['start'].get('dateTime', event['start'].get('date'))
402
+ eventos.append(f"{event['summary']} at {start}")
403
+ return '\n'.join(eventos)
404
+
405
+ def show_document_modification():
406
+ st.title("✍️ IA para Modificación de Documentos")
407
+
408
+ uploaded_file = st.file_uploader("Sube un documento (PDF o DOCX)", type=['pdf', 'docx'])
409
+
410
+ if uploaded_file:
411
+ if uploaded_file.type == "application/pdf":
412
+ texto_original = extraer_texto_pdf(uploaded_file)
413
+ st.text_area("Contenido del Documento Original", texto_original, height=300)
414
+ elif uploaded_file.type == "application/vnd.openxmlformats-officedocument.wordprocessingml.document":
415
+ documento = Document(uploaded_file)
416
+ texto_original = "\n".join([para.text for para in documento.paragraphs])
417
+ st.text_area("Contenido del Documento Original", texto_original, height=300)
418
+
419
+ st.markdown("### Modificar Documento")
420
+
421
+ receptor = st.text_input("Modificar Para (Nombre del Receptor):")
422
+ notas_adicionales = st.text_area("Notas Adicionales:", height=100)
423
+
424
+ if st.button("Generar Documento Modificado"):
425
+ contenido_modificado = modificar_documento(texto_original, receptor, notas_adicionales)
426
+ st.text_area("Contenido del Documento Modificado", contenido_modificado, height=300)
427
+
428
+ # Descargar documento modificado
429
+ if uploaded_file.type == "application/pdf":
430
+ pdf_modificado = modificar_pdf(uploaded_file, contenido_modificado)
431
+ st.download_button(
432
+ label="📥 Descargar PDF Modificado",
433
+ data=pdf_modificado,
434
+ file_name="documento_modificado.pdf",
435
+ mime="application/pdf"
436
+ )
437
+ elif uploaded_file.type == "application/vnd.openxmlformats-officedocument.wordprocessingml.document":
438
+ docx_modificado = modificar_docx(contenido_modificado)
439
+ st.download_button(
440
+ label="📥 Descargar DOCX Modificado",
441
+ data=docx_modificado,
442
+ file_name="documento_modificado.docx",
443
+ mime="application/vnd.openxmlformats-officedocument.wordprocessingml.document"
444
+ )
445
+
446
+ def modificar_documento(texto, receptor, notas):
447
+ """Modifica el contenido del documento basado en el receptor y notas adicionales."""
448
+ prompt = f"Modifica el siguiente texto para que esté dirigido a {receptor} y añade las siguientes notas: {notas}.\n\nTexto:\n{texto}"
449
+ response = openai.ChatCompletion.create(
450
+ model="gpt-3.5-turbo", # o "gpt-4" si estás usando ese modelo
451
+ messages=[
452
+ {"role": "system", "content": "Eres un asistente útil."},
453
+ {"role": "user", "content": prompt}
454
+ ]
455
+ )
456
+ return response.choices[0].message['content']
457
+
458
+ def modificar_pdf(pdf_file, nuevo_contenido):
459
+ """Modifica el contenido de un PDF."""
460
+ reader = PyPDF2.PdfReader(pdf_file)
461
+ writer = PyPDF2.PdfWriter()
462
+
463
+ # Añadir el contenido modificado a una nueva página del PDF
464
+ for page in reader.pages:
465
+ writer.add_page(page)
466
+
467
+ nueva_pagina = writer.add_blank_page(width=reader.pages[0].mediabox.width, height=reader.pages[0].mediabox.height)
468
+ nueva_pagina.insert_text(nuevo_contenido)
469
+
470
+ pdf_output = io.BytesIO()
471
+ writer.write(pdf_output)
472
+ pdf_output.seek(0)
473
+
474
+ return pdf_output
475
+
476
+ def modificar_docx(nuevo_contenido):
477
+ """Modifica el contenido de un DOCX."""
478
+ doc = Document()
479
+ for line in nuevo_contenido.split("\n"):
480
+ doc.add_paragraph(line)
481
+
482
+ docx_output = io.BytesIO()
483
+ doc.save(docx_output)
484
+ docx_output.seek(0)
485
+
486
+ return docx_output
487
+
488
  if __name__ == "__main__":
489
  main()