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.")