| import os |
| import time |
| import groq |
| from google.cloud import texttospeech_v1 as texttospeech |
| import streamlit as st |
| from dotenv import load_dotenv |
| import speech_recognition as sr |
| from datetime import datetime, timedelta |
| from streamlit_autorefresh import st_autorefresh |
|
|
| |
| st.set_page_config(page_title="Galatea Asistente - OMARDENT", layout="wide") |
|
|
| |
| st.markdown( |
| """ |
| <style> |
| .reportview-container { |
| background: radial-gradient(circle, rgba(209,238,174,1) 0%, rgba(11,135,128,1) 90%); |
| } |
| </style> |
| """, |
| unsafe_allow_html=True |
| ) |
|
|
| |
| st.image("Logo icon.jpg", use_column_width=True) |
|
|
| |
| load_dotenv() |
| groq_api_key = os.getenv("GROQ_API_KEY") |
| os.environ["GOOGLE_APPLICATION_CREDENTIALS"] = "credentials/botidinamix-g.json" |
|
|
| |
| if not groq_api_key: |
| st.error("No API key provided for Groq. Please set your API key in the .env file.") |
| else: |
| |
| client_groq = groq.Groq(api_key=groq_api_key) |
|
|
| |
| def obtener_respuesta_groq(pregunta, contexto="", modelo="llama3-8b-8192", temperatura=0.5): |
| if not pregunta: |
| st.error("La pregunta no puede estar vacía.") |
| return "Lo siento, la pregunta no puede estar vacía." |
|
|
| try: |
| with st.spinner('Evaluando su respuesta...'): |
| |
| contexto = "Actúas como Galatea, la asistente virtual de la clínica odontológica Omardent. Tu función es recordar citas y eventos de forma clara y profesional." |
| response = client_groq.chat.completions.create( |
| messages=[ |
| {"role": "system", "content": contexto}, |
| {"role": "user", "content": pregunta} |
| ], |
| model=modelo |
| ) |
| |
| |
| respuesta = response.choices[0].message.content.strip() |
|
|
| |
| client = texttospeech.TextToSpeechClient() |
| input_text = texttospeech.SynthesisInput(text=respuesta) |
| voice = texttospeech.VoiceSelectionParams( |
| language_code="es-ES", ssml_gender=texttospeech.SsmlVoiceGender.FEMALE |
| ) |
| audio_config = texttospeech.AudioConfig( |
| audio_encoding=texttospeech.AudioEncoding.MP3 |
| ) |
|
|
| |
| response_audio = client.synthesize_speech( |
| input=input_text, voice=voice, audio_config=audio_config |
| ) |
|
|
| |
| audio_file_path = f'tmp_respuesta_{int(time.time())}.mp3' |
| with open(audio_file_path, 'wb') as audio_file: |
| audio_file.write(response_audio.audio_content) |
| |
| |
| return respuesta, audio_file_path |
|
|
| except Exception as e: |
| st.error(f"Error al generar la respuesta y el audio: {e}") |
| return "Lo siento, ocurrió un error al procesar tu solicitud.", None |
|
|
| |
| def mostrar_galatea_asistente(): |
| st.title("🦷 Galatea - Asistente Virtual OMARDENT") |
|
|
| |
| if 'mensajes_chat' not in st.session_state: |
| st.session_state['mensajes_chat'] = [] |
|
|
| if 'respuesta_programada' not in st.session_state: |
| st.session_state['respuesta_programada'] = None |
|
|
| |
| for mensaje in st.session_state['mensajes_chat']: |
| clase = "user" if mensaje["role"] == "user" else "assistant" |
| st.markdown(f'<div class="chat-message {clase}">{mensaje["content"]}</div>', unsafe_allow_html=True) |
|
|
| |
| pregunta_usuario = st.text_input("Escribe tu pregunta aquí:") |
|
|
| |
| intervalo = st.selectbox("Selecciona el intervalo de tiempo (minutos)", [1, 2, 5, 10, 15, 30, 60]) |
|
|
| |
| if st.button("Grabar y Transcribir Audio"): |
| recognizer = sr.Recognizer() |
| with sr.Microphone() as source: |
| st.info("Grabando...") |
| audio = recognizer.listen(source, timeout=5) |
| st.info("Grabación completa") |
|
|
| try: |
| text = recognizer.recognize_google(audio, language="es-ES") |
| pregunta_usuario = text |
| except sr.UnknownValueError: |
| st.error("No se pudo entender el audio") |
| except sr.RequestError: |
| st.error("Error al solicitar el servicio de reconocimiento de voz") |
|
|
| |
| if st.button("Programar Respuesta"): |
| if pregunta_usuario: |
| |
| st.session_state['mensajes_chat'].append({"role": "user", "content": pregunta_usuario}) |
|
|
| |
| tiempo_en_segundos = intervalo * 60 |
| tiempo_ejecucion = datetime.now() + timedelta(minutes=intervalo) |
| st.success(f"La respuesta se generará a las {tiempo_ejecucion.strftime('%H:%M:%S')}") |
|
|
| |
| st.session_state['respuesta_programada'] = { |
| 'pregunta': pregunta_usuario, |
| 'tiempo_ejecucion': tiempo_ejecucion, |
| 'tiempo_en_segundos': tiempo_en_segundos, |
| 'audio_file_path': None, |
| 'notificacion_reproducida': False |
| } |
|
|
| |
| st_autorefresh(interval=1000, key="data_refresh") |
|
|
| |
| if 'respuesta_programada' in st.session_state and st.session_state['respuesta_programada']: |
| respuesta_programada = st.session_state['respuesta_programada'] |
|
|
| |
| tiempo_restante = respuesta_programada['tiempo_ejecucion'] - datetime.now() |
| if tiempo_restante.total_seconds() > 0: |
| minutos, segundos = divmod(int(tiempo_restante.total_seconds()), 60) |
| horas, minutos = divmod(minutos, 60) |
| tiempo_restante_str = f"{horas}h {minutos}m {segundos}s" if horas > 0 else f"{minutos}m {segundos}s" |
| st.info(f"Tiempo restante: {tiempo_restante_str}") |
| if st.session_state['respuesta_programada']['notificacion_reproducida'] and st.session_state['respuesta_programada']['audio_file_path'] is None: |
| respuesta, audio_file_path = obtener_respuesta_groq(respuesta_programada['pregunta']) |
|
|
| |
| st.session_state['mensajes_chat'].append({"role": "assistant", "content": respuesta}) |
| st.session_state['respuesta_programada']['audio_file_path'] = audio_file_path |
|
|
| |
| if st.session_state['respuesta_programada']['audio_file_path']: |
| audio_file_path = st.session_state['respuesta_programada']['audio_file_path'] |
| with open(audio_file_path, "rb") as audio_file: |
| st.audio(audio_file.read(), format="audio/mp3") |
|
|
| |
| def main(): |
| mostrar_galatea_asistente() |
|
|
| if __name__ == "__main__": |
| main() |