AIDEN_VOZ / app.py
GoergeMarckus's picture
Update app.py
64bff4d verified
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
)