Create app.py
Browse files
app.py
ADDED
@@ -0,0 +1,137 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import gradio as gr
|
2 |
+
import os
|
3 |
+
import logging
|
4 |
+
from fastapi import FastAPI, Request
|
5 |
+
from main import PhoneChatbotApp
|
6 |
+
import asyncio
|
7 |
+
import uvicorn
|
8 |
+
from threading import Thread
|
9 |
+
from elevenlabs import ElevenLabs
|
10 |
+
|
11 |
+
logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s")
|
12 |
+
logger = logging.getLogger(__name__)
|
13 |
+
|
14 |
+
app = FastAPI()
|
15 |
+
phone_app = PhoneChatbotApp()
|
16 |
+
log_output = ""
|
17 |
+
|
18 |
+
def append_log(message):
|
19 |
+
global log_output
|
20 |
+
log_output += f"{message}\n"
|
21 |
+
logger.info(message)
|
22 |
+
|
23 |
+
@app.post("/webhook")
|
24 |
+
async def webhook(request: Request):
|
25 |
+
data = await request.json()
|
26 |
+
append_log(f"Webhook received: {data}")
|
27 |
+
return {"status": "ok"}
|
28 |
+
|
29 |
+
def get_elevenlabs_voices(elevenlabs_api_key):
|
30 |
+
try:
|
31 |
+
client = ElevenLabs(api_key=elevenlabs_api_key)
|
32 |
+
voices = client.voices.get_all()
|
33 |
+
return {voice.name: voice.voice_id for voice in voices.voices}
|
34 |
+
except Exception as e:
|
35 |
+
append_log(f"Error fetching ElevenLabs voices: {e}")
|
36 |
+
return {"Default (Rachel)": "cgSgspJ2msm6clMCkdW9"}
|
37 |
+
|
38 |
+
def save_config(daily_api_key, daily_domain, deepgram_api_key, elevenlabs_api_key, elevenlabs_voice_id, azure_openai_api_key, silence_timeout, max_prompts):
|
39 |
+
instructions = """
|
40 |
+
Set the following Hugging Face Secrets in your Space (Settings > Secrets):
|
41 |
+
- deepgram: {}
|
42 |
+
- elevenlabs: {}
|
43 |
+
- dailyco: {}
|
44 |
+
- azure_openai: {}
|
45 |
+
- DAILY_DOMAIN: {}
|
46 |
+
- ELEVENLABS_VOICE_ID: {}
|
47 |
+
- SILENCE_TIMEOUT_SECONDS: {}
|
48 |
+
- MAX_SILENCE_PROMPTS: {}
|
49 |
+
|
50 |
+
1. Go to your Hugging Face Space > Settings > Secrets.
|
51 |
+
2. Add each secret with the exact name and value shown above.
|
52 |
+
3. Redeploy the Space to apply the changes.
|
53 |
+
""".format(
|
54 |
+
deepgram_api_key, elevenlabs_api_key, daily_api_key, azure_openai_api_key,
|
55 |
+
daily_domain, elevenlabs_voice_id, silence_timeout, max_prompts
|
56 |
+
)
|
57 |
+
append_log("Generated Hugging Face Secrets instructions")
|
58 |
+
return instructions
|
59 |
+
|
60 |
+
def get_call_summary():
|
61 |
+
if phone_app.current_call_stats["start_time"]:
|
62 |
+
return [[
|
63 |
+
phone_app.current_call_stats["start_time"],
|
64 |
+
phone_app.current_call_stats["end_time"],
|
65 |
+
phone_app.current_call_stats["duration_seconds"],
|
66 |
+
phone_app.current_call_stats["silence_events"],
|
67 |
+
phone_app.current_call_stats["ended_by_silence"]
|
68 |
+
]]
|
69 |
+
return []
|
70 |
+
|
71 |
+
def run_phone_app():
|
72 |
+
asyncio.run(phone_app.run())
|
73 |
+
|
74 |
+
with gr.Blocks(theme=gr.themes.Soft(), css="static/style.css") as demo:
|
75 |
+
gr.Markdown("# Phone Chatbot Web App")
|
76 |
+
|
77 |
+
with gr.Tabs():
|
78 |
+
with gr.TabItem("Configuration"):
|
79 |
+
daily_api_key = gr.Textbox(label="Daily API Key", type="password")
|
80 |
+
daily_domain = gr.Textbox(label="Daily Domain", value="your-username.daily.co")
|
81 |
+
deepgram_api_key = gr.Textbox(label="Deepgram API Key", type="password")
|
82 |
+
elevenlabs_api_key = gr.Textbox(label="ElevenLabs API Key", type="password")
|
83 |
+
elevenlabs_voice = gr.Dropdown(
|
84 |
+
label="ElevenLabs Voice",
|
85 |
+
choices=["Default (Rachel)"],
|
86 |
+
value="Default (Rachel)"
|
87 |
+
)
|
88 |
+
azure_openai_api_key = gr.Textbox(label="Azure OpenAI API Key", type="password")
|
89 |
+
silence_timeout = gr.Slider(5, 30, value=10, step=1, label="Silence Timeout (seconds)")
|
90 |
+
max_prompts = gr.Slider(1, 5, value=3, step=1, label="Max Silence Prompts")
|
91 |
+
save_btn = gr.Button("Generate Hugging Face Secrets Instructions")
|
92 |
+
config_output = gr.Textbox(label="Instructions", lines=10)
|
93 |
+
|
94 |
+
def update_voices(elevenlabs_api_key):
|
95 |
+
voices = get_elevenlabs_voices(elevenlabs_api_key)
|
96 |
+
return gr.Dropdown.update(choices=list(voices.keys()), value=list(voices.keys())[0])
|
97 |
+
|
98 |
+
elevenlabs_api_key.change(
|
99 |
+
fn=update_voices,
|
100 |
+
inputs=elevenlabs_api_key,
|
101 |
+
outputs=elevenlabs_voice
|
102 |
+
)
|
103 |
+
|
104 |
+
def prepare_config(daily_api_key, daily_domain, deepgram_api_key, elevenlabs_api_key, elevenlabs_voice, azure_openai_api_key, silence_timeout, max_prompts):
|
105 |
+
voices = get_elevenlabs_voices(elevenlabs_api_key)
|
106 |
+
voice_id = voices.get(elevenlabs_voice, "cgSgspJ2msm6clMCkdW9")
|
107 |
+
return save_config(daily_api_key, daily_domain, deepgram_api_key, elevenlabs_api_key, voice_id, azure_openai_api_key, silence_timeout, max_prompts)
|
108 |
+
|
109 |
+
save_btn.click(
|
110 |
+
fn=prepare_config,
|
111 |
+
inputs=[daily_api_key, daily_domain, deepgram_api_key, elevenlabs_api_key,
|
112 |
+
elevenlabs_voice, azure_openai_api_key, silence_timeout, max_prompts],
|
113 |
+
outputs=config_output
|
114 |
+
)
|
115 |
+
|
116 |
+
with gr.TabItem("Call Status"):
|
117 |
+
log_box = gr.Textbox(label="Real-time Logs", lines=20, value=lambda: log_output)
|
118 |
+
|
119 |
+
with gr.TabItem("Call Summary"):
|
120 |
+
summary_table = gr.Dataframe(
|
121 |
+
headers=["Start Time", "End Time", "Duration (s)", "Silence Events", "Ended by Silence"],
|
122 |
+
value=get_call_summary,
|
123 |
+
label="Call Summaries"
|
124 |
+
)
|
125 |
+
refresh_btn = gr.Button("Refresh Summary")
|
126 |
+
refresh_btn.click(fn=get_call_summary, outputs=summary_table)
|
127 |
+
|
128 |
+
# Start phone app in a separate thread
|
129 |
+
Thread(target=run_phone_app, daemon=True).start()
|
130 |
+
|
131 |
+
# Start FastAPI server
|
132 |
+
def start_server():
|
133 |
+
uvicorn.run(app, host="0.0.0.0", port=7860)
|
134 |
+
|
135 |
+
Thread(target=start_server, daemon=True).start()
|
136 |
+
|
137 |
+
demo.launch(server_name="0.0.0.0", server_port=7861)
|