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

Update app.py

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