Spaces:
Running
Running
File size: 4,540 Bytes
2570129 4e2165c 6a9fed6 4e2165c 2570129 484c797 2570129 484c797 2570129 484c797 2570129 484c797 2570129 484c797 2570129 484c797 2570129 484c797 4e2165c 2570129 6a9fed6 484c797 6a9fed6 484c797 2570129 484c797 4e2165c 484c797 2570129 6a9fed6 2570129 4e2165c 484c797 4e2165c 484c797 4e2165c 2570129 4e2165c 2570129 484c797 2570129 484c797 2570129 484c797 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 |
import os
import uuid
import json
import requests
import streamlit as st
from dotenv import load_dotenv
from utils import voice_map, get_voice_prompt_style, AUDIO_DIR
from generate_audio import generate_audio
from logger_setup import logger
# Load API keys
load_dotenv()
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
# Streamlit config
st.set_page_config(page_title="Voice Agent Pro", page_icon="π€")
st.title("ποΈ Voice Agent Pro")
st.markdown("Summarized answers with expressive AI voices.")
logger.info("π¬ Streamlit app started")
# Sidebar: voice picker
st.sidebar.header("ποΈ Voice Settings")
voice_label = st.sidebar.selectbox("Choose a voice:", list(voice_map.keys()))
voice_id = voice_map[voice_label]
tone_prompt = get_voice_prompt_style(voice_label)
# Session state setup
if "answer" not in st.session_state: st.session_state.answer = ""
if "audio_key" not in st.session_state: st.session_state.audio_key = None
if "file_text" not in st.session_state: st.session_state.file_text = ""
if "key_points" not in st.session_state: st.session_state.key_points = []
# Inputs
query = st.text_area("π¨οΈ Ask or refine something based on the bullets:", value="", placeholder="e.g., What makes you so cool, Grandma?", key="query")
url = st.text_input("π Optional URL to summarize:")
uploaded_file = st.file_uploader("π Or upload a file (PDF, TXT, DOCX)", type=["pdf", "txt", "docx"])
# Reset state
# Reset state safely without error
if st.button("π§Ή Clear All"):
logger.info("π§Ό Clear All clicked β reloading app")
st.rerun()
# Helper: GPT streaming
def stream_openai_response(payload, headers):
with requests.post("https://api.openai.com/v1/chat/completions", headers=headers, json=payload, stream=True) as r:
for line in r.iter_lines():
if line and line.startswith(b"data: "):
yield line[len(b"data: "):].decode()
# Main: Summarize and speak
if st.button("π Summarize"):
if not query and not url and not uploaded_file:
st.warning("Please enter a question, a URL, or upload a file.")
else:
with st.spinner("Talking to GPT..."):
try:
if uploaded_file:
st.session_state.file_text = uploaded_file.read().decode("utf-8")
context = ""
if st.session_state.file_text:
context += st.session_state.file_text + "\n\n"
if url:
context += f"Summarize this page: {url}\n\n"
context += f"{tone_prompt}\n\nNow answer: {query}"
headers = {"Authorization": f"Bearer {OPENAI_API_KEY}"}
payload = {
"model": "gpt-4o",
"messages": [{"role": "user", "content": context}],
"temperature": 0.7,
"stream": True
}
st.session_state.answer = ""
answer_box = st.empty()
logger.info("π§ Starting GPT streaming")
for chunk in stream_openai_response(payload, headers):
if chunk.strip() == "[DONE]":
logger.info("π’ GPT stream complete marker received")
continue
try:
parsed = json.loads(chunk)
delta = parsed['choices'][0]['delta'].get('content', '')
st.session_state.answer += delta
answer_box.markdown(st.session_state.answer)
except json.JSONDecodeError as json_err:
logger.warning(f"β οΈ Skipping non-JSON chunk: {chunk}")
continue
logger.info("π§ GPT response complete. Now generating audio...")
audio_key = str(uuid.uuid4())
generate_audio(st.session_state.answer, voice_id, audio_key)
st.session_state.audio_key = audio_key
except Exception as e:
st.error(f"π₯ Error: {e}")
logger.exception("π₯ Exception during summarize or audio generation")
# Final display
if st.session_state.answer:
st.subheader("π Answer")
st.success(st.session_state.answer)
if st.session_state.audio_key:
audio_path = os.path.join(AUDIO_DIR, f"{st.session_state.audio_key}.mp3")
if os.path.exists(audio_path):
st.audio(audio_path)
else:
st.error("β Audio file missing. Please check logs.")
|