Spaces:
Paused
Paused
| import streamlit as st | |
| import base64 | |
| import io | |
| import os | |
| from openai import OpenAI | |
| # ====================================== | |
| # CONFIGURACIÓN DE STREAMLIT | |
| # ====================================== | |
| st.set_page_config( | |
| page_title="AIDEN – Voz Latina", | |
| page_icon="🎙️", | |
| layout="centered" | |
| ) | |
| # ====================================== | |
| # LEER API KEY DESDE ENTORNO (HF Secrets) | |
| # ====================================== | |
| API_KEY = os.environ.get("OPENAI_API_KEY") | |
| if not API_KEY: | |
| st.error("❌ ERROR: No se encontró OPENAI_API_KEY en HuggingFace Secrets.") | |
| st.stop() | |
| client = OpenAI(api_key=API_KEY) | |
| # ====================================== | |
| # FUNCIONES AUXILIARES | |
| # ====================================== | |
| def cargar_logo(path): | |
| with open(path, "rb") as f: | |
| return base64.b64encode(f.read()).decode() | |
| logo_b64 = cargar_logo("assets/aiden_logo.png") | |
| def sintetizar_voz(texto): | |
| """Texto → Voz WAV usando OpenAI.""" | |
| reply = client.audio.speech.create( | |
| model="gpt-4o-mini-tts", | |
| voice="male", | |
| format="wav", | |
| input=texto | |
| ) | |
| return reply.read() | |
| def transcribir_audio(audio_bytes): | |
| """Voz → Texto (Whisper-1).""" | |
| transcript = client.audio.transcriptions.create( | |
| model="whisper-1", | |
| file=("audio.wav", audio_bytes, "audio/wav") | |
| ) | |
| return transcript.text | |
| def generar_respuesta(prompt): | |
| """Respuesta estilo AIDEN.""" | |
| completion = client.chat.completions.create( | |
| model="gpt-4o-mini", | |
| messages=[ | |
| {"role": "system", | |
| "content": ( | |
| "Eres AIDEN, IA de voz profesional creada por JMC Studio Digital " | |
| "en Guayaquil por George Márquez. Respondes SIEMPRE en español latino, " | |
| "tono humano, muy natural, cálido, profesional." | |
| )}, | |
| {"role": "user", "content": prompt} | |
| ], | |
| temperature=0.7, | |
| max_tokens=300 | |
| ) | |
| return completion.choices[0].message.content | |
| # ====================================== | |
| # INTERFAZ | |
| # ====================================== | |
| st.markdown( | |
| f""" | |
| <div style="text-align:center; margin-top:20px;"> | |
| <img src="data:image/png;base64,{logo_b64}" width="160"> | |
| <h1 style="color:white; margin-top:10px;">AIDEN — Conversación por Voz</h1> | |
| <p style="color:#cccccc; font-size:17px;"> | |
| Habla con AIDEN usando tu micrófono — voz natural, fluida y profesional. | |
| </p> | |
| </div> | |
| """, | |
| unsafe_allow_html=True | |
| ) | |
| st.write("### 🎙️ Hablar con AIDEN") | |
| audio_file = st.file_uploader( | |
| "Graba o sube un audio (WAV/MP3)…", | |
| type=["wav", "mp3"] | |
| ) | |
| # Historial (últimos 4 turnos) | |
| if "historial" not in st.session_state: | |
| st.session_state.historial = [] | |
| texto_manual = st.text_input("O escribe tu mensaje (opcional)…") | |
| # ====================================== | |
| # PROCESAR MENSAJE | |
| # ====================================== | |
| if st.button("Enviar mensaje a AIDEN"): | |
| if audio_file: | |
| st.info("🎧 Procesando tu voz…") | |
| audio_bytes = audio_file.read() | |
| try: | |
| texto_usuario = transcribir_audio(audio_bytes) | |
| except Exception as e: | |
| st.error(f"Error al transcribir audio: {e}") | |
| st.stop() | |
| st.write("### 🗣️ Lo que dijiste:") | |
| st.write(texto_usuario) | |
| elif texto_manual.strip(): | |
| texto_usuario = texto_manual.strip() | |
| st.write("### 🗣️ Mensaje enviado:") | |
| st.write(texto_usuario) | |
| else: | |
| st.warning("Debes subir un audio o escribir texto.") | |
| st.stop() | |
| # Guardar historial | |
| st.session_state.historial.append({"role": "user", "content": texto_usuario}) | |
| st.session_state.historial = st.session_state.historial[-4:] | |
| # Contexto | |
| contexto = "" | |
| for msg in st.session_state.historial: | |
| if msg["role"] == "user": | |
| contexto += f"Usuario: {msg['content']}\n" | |
| else: | |
| contexto += f"AIDEN: {msg['content']}\n" | |
| # Generación | |
| try: | |
| respuesta = generar_respuesta(contexto) | |
| except Exception as e: | |
| st.error(f"Error generando respuesta: {e}") | |
| st.stop() | |
| st.write("### 🤖 Respuesta de AIDEN:") | |
| st.write(respuesta) | |
| st.session_state.historial.append({"role": "assistant", "content": respuesta}) | |
| # TTS | |
| st.write("### 🔊 Voz de AIDEN") | |
| try: | |
| audio_out = sintetizar_voz(respuesta) | |
| st.audio(audio_out, format="audio/wav") | |
| except Exception as e: | |
| st.error(f"Error generando voz: {e}") | |
| # Footer | |
| st.write("---") | |
| st.markdown( | |
| "<p style='text-align:center; color:gray;'>AIDEN — Desarrollado por JMC Studio Digital</p>", | |
| unsafe_allow_html=True | |
| ) | |