Spaces:
Runtime error
Runtime error
Commit Β·
d75f4a0
1
Parent(s): f2ac968
Uploaded
Browse files- .streamlit/config.toml +2 -0
- Dockerfile +10 -9
- app.py +6 -40
.streamlit/config.toml
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[browser]
|
| 2 |
+
gatherUsageStats = false
|
Dockerfile
CHANGED
|
@@ -1,27 +1,28 @@
|
|
| 1 |
# Use a stable, official Python image
|
| 2 |
FROM python:3.10-slim
|
| 3 |
|
| 4 |
-
# ---
|
| 5 |
-
# Install system-level dependencies needed to build audio packages like PyAudio.
|
| 6 |
-
# `build-essential` contains the gcc compiler.
|
| 7 |
-
# `portaudio19-dev` contains the development headers for PortAudio.
|
| 8 |
RUN apt-get update && apt-get install -y \
|
| 9 |
build-essential \
|
| 10 |
portaudio19-dev \
|
| 11 |
&& rm -rf /var/lib/apt/lists/*
|
| 12 |
|
| 13 |
-
# Set the working directory
|
| 14 |
WORKDIR /app
|
| 15 |
|
| 16 |
-
#
|
| 17 |
-
# This
|
|
|
|
|
|
|
|
|
|
|
|
|
| 18 |
COPY requirements.txt .
|
| 19 |
RUN pip install --no-cache-dir -r requirements.txt
|
| 20 |
|
| 21 |
-
# Copy the rest of
|
| 22 |
COPY . .
|
| 23 |
|
| 24 |
-
# Expose the port
|
| 25 |
EXPOSE 7860
|
| 26 |
|
| 27 |
# Command to run the application
|
|
|
|
| 1 |
# Use a stable, official Python image
|
| 2 |
FROM python:3.10-slim
|
| 3 |
|
| 4 |
+
# --- FIX 1: Install system dependencies for audio package compilation ---
|
|
|
|
|
|
|
|
|
|
| 5 |
RUN apt-get update && apt-get install -y \
|
| 6 |
build-essential \
|
| 7 |
portaudio19-dev \
|
| 8 |
&& rm -rf /var/lib/apt/lists/*
|
| 9 |
|
| 10 |
+
# Set the working directory
|
| 11 |
WORKDIR /app
|
| 12 |
|
| 13 |
+
# --- FIX 2: Create a directory for Streamlit config and copy our new config file ---
|
| 14 |
+
# This prevents the PermissionError by disabling telemetry.
|
| 15 |
+
RUN mkdir -p .streamlit
|
| 16 |
+
COPY .streamlit/config.toml .streamlit/
|
| 17 |
+
|
| 18 |
+
# Copy requirements and install them
|
| 19 |
COPY requirements.txt .
|
| 20 |
RUN pip install --no-cache-dir -r requirements.txt
|
| 21 |
|
| 22 |
+
# Copy the rest of the application files
|
| 23 |
COPY . .
|
| 24 |
|
| 25 |
+
# Expose the port Hugging Face uses
|
| 26 |
EXPOSE 7860
|
| 27 |
|
| 28 |
# Command to run the application
|
app.py
CHANGED
|
@@ -24,7 +24,6 @@ def load_and_set_config():
|
|
| 24 |
|
| 25 |
# --- VAPI Call Logic ---
|
| 26 |
def place_vapi_call(config, customer_number, raw_intent, target_name):
|
| 27 |
-
# Process intent to generate a good first message
|
| 28 |
genai.configure(api_key=config["GEMINI_API_KEY"])
|
| 29 |
model = genai.GenerativeModel('gemini-1.5-flash')
|
| 30 |
|
|
@@ -47,10 +46,9 @@ def place_vapi_call(config, customer_number, raw_intent, target_name):
|
|
| 47 |
st.error(f"Error with Gemini: {e}")
|
| 48 |
return None
|
| 49 |
|
| 50 |
-
# Place the actual call
|
| 51 |
try:
|
| 52 |
vapi = Vapi(token=config["VAPI_API_KEY"])
|
| 53 |
-
system_prompt = "You are a helpful and polite AI assistant named Alex. Your first sentence has already been spoken.
|
| 54 |
|
| 55 |
return vapi.calls.create(
|
| 56 |
assistant_id=config["VAPI_ASSISTANT_ID"],
|
|
@@ -68,12 +66,11 @@ def place_vapi_call(config, customer_number, raw_intent, target_name):
|
|
| 68 |
st.error(f"An error occurred placing the Vapi call: {e}")
|
| 69 |
return None
|
| 70 |
|
| 71 |
-
# --- FLASK WEBHOOK
|
| 72 |
flask_app = Flask(__name__)
|
| 73 |
|
| 74 |
def log_to_google_sheet(row_data, config):
|
| 75 |
try:
|
| 76 |
-
print("[Log] Attempting to log to Google Sheets...")
|
| 77 |
if not os.path.exists("credentials.json"):
|
| 78 |
print("[Log] FATAL: 'credentials.json' not found.")
|
| 79 |
return
|
|
@@ -89,7 +86,7 @@ def log_to_google_sheet(row_data, config):
|
|
| 89 |
|
| 90 |
@flask_app.route("/webhook", methods=['POST'])
|
| 91 |
def webhook_handler():
|
| 92 |
-
print(f"\n--- Webhook received POST request
|
| 93 |
try:
|
| 94 |
payload = request.json
|
| 95 |
if payload.get('message', {}).get('type') == 'hang':
|
|
@@ -108,45 +105,19 @@ def webhook_handler():
|
|
| 108 |
return jsonify({'status': 'success'}), 200
|
| 109 |
|
| 110 |
def run_flask():
|
| 111 |
-
# Running on a different port than Streamlit
|
| 112 |
flask_app.run(host="0.0.0.0", port=8080)
|
| 113 |
|
| 114 |
-
# --- STREAMLIT UI
|
| 115 |
def run_streamlit():
|
| 116 |
st.set_page_config(page_title="Voice AI Coordinator", layout="centered")
|
| 117 |
-
|
| 118 |
-
# Custom CSS for a pleasing look
|
| 119 |
-
st.markdown("""
|
| 120 |
-
<style>
|
| 121 |
-
.stApp {
|
| 122 |
-
background-color: #f0f2f5;
|
| 123 |
-
}
|
| 124 |
-
.stForm {
|
| 125 |
-
background-color: white;
|
| 126 |
-
padding: 2em;
|
| 127 |
-
border-radius: 10px;
|
| 128 |
-
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
|
| 129 |
-
}
|
| 130 |
-
.stButton>button {
|
| 131 |
-
width: 100%;
|
| 132 |
-
border: none;
|
| 133 |
-
border-radius: 5px;
|
| 134 |
-
padding: 10px;
|
| 135 |
-
font-weight: bold;
|
| 136 |
-
color: white;
|
| 137 |
-
background-color: #ff4b4b;
|
| 138 |
-
}
|
| 139 |
-
</style>
|
| 140 |
-
""", unsafe_allow_html=True)
|
| 141 |
-
|
| 142 |
st.title("π Voice AI Coordination Tool")
|
| 143 |
st.markdown("A unified interface to deploy intelligent voice agents on your behalf.")
|
| 144 |
|
| 145 |
-
# Load configuration
|
| 146 |
try:
|
| 147 |
config = load_and_set_config()
|
| 148 |
except Exception as e:
|
| 149 |
-
st.error(f"Failed to load configuration.
|
| 150 |
st.stop()
|
| 151 |
|
| 152 |
with st.form(key="call_form"):
|
|
@@ -154,7 +125,6 @@ def run_streamlit():
|
|
| 154 |
target_name = st.text_input("Whom are you calling? (Optional)", placeholder="e.g., Jane Doe")
|
| 155 |
phone_number = st.text_input("Phone Number (with country code)", placeholder="+911234567890")
|
| 156 |
raw_intent = st.text_area("Reason for Calling", placeholder="Ask if they would prefer tea or coffee", height=100)
|
| 157 |
-
|
| 158 |
submit_button = st.form_submit_button(label="Deploy Call")
|
| 159 |
|
| 160 |
if submit_button:
|
|
@@ -165,15 +135,11 @@ def run_streamlit():
|
|
| 165 |
call_response = place_vapi_call(config, phone_number, raw_intent, target_name)
|
| 166 |
if call_response and call_response.id:
|
| 167 |
st.success(f"β
Call deployed successfully! Call ID: {call_response.id}")
|
| 168 |
-
st.info("The call is being connected. Once it ends, the data will be logged to your Google Sheet.")
|
| 169 |
st.balloons()
|
| 170 |
else:
|
| 171 |
st.error("β Failed to deploy the call. Please check the Space logs for errors.")
|
| 172 |
|
| 173 |
if __name__ == "__main__":
|
| 174 |
-
# Run Flask in a background daemon thread
|
| 175 |
flask_thread = threading.Thread(target=run_flask, daemon=True)
|
| 176 |
flask_thread.start()
|
| 177 |
-
|
| 178 |
-
# Run the main Streamlit app
|
| 179 |
run_streamlit()
|
|
|
|
| 24 |
|
| 25 |
# --- VAPI Call Logic ---
|
| 26 |
def place_vapi_call(config, customer_number, raw_intent, target_name):
|
|
|
|
| 27 |
genai.configure(api_key=config["GEMINI_API_KEY"])
|
| 28 |
model = genai.GenerativeModel('gemini-1.5-flash')
|
| 29 |
|
|
|
|
| 46 |
st.error(f"Error with Gemini: {e}")
|
| 47 |
return None
|
| 48 |
|
|
|
|
| 49 |
try:
|
| 50 |
vapi = Vapi(token=config["VAPI_API_KEY"])
|
| 51 |
+
system_prompt = "You are a helpful and polite AI assistant named Alex. Your first sentence has already been spoken. Listen carefully and respond naturally. Continue the conversation in the language the other person is speaking (English or Hindi)."
|
| 52 |
|
| 53 |
return vapi.calls.create(
|
| 54 |
assistant_id=config["VAPI_ASSISTANT_ID"],
|
|
|
|
| 66 |
st.error(f"An error occurred placing the Vapi call: {e}")
|
| 67 |
return None
|
| 68 |
|
| 69 |
+
# --- FLASK WEBHOOK ---
|
| 70 |
flask_app = Flask(__name__)
|
| 71 |
|
| 72 |
def log_to_google_sheet(row_data, config):
|
| 73 |
try:
|
|
|
|
| 74 |
if not os.path.exists("credentials.json"):
|
| 75 |
print("[Log] FATAL: 'credentials.json' not found.")
|
| 76 |
return
|
|
|
|
| 86 |
|
| 87 |
@flask_app.route("/webhook", methods=['POST'])
|
| 88 |
def webhook_handler():
|
| 89 |
+
print(f"\n--- Webhook received POST request at {datetime.now()} ---")
|
| 90 |
try:
|
| 91 |
payload = request.json
|
| 92 |
if payload.get('message', {}).get('type') == 'hang':
|
|
|
|
| 105 |
return jsonify({'status': 'success'}), 200
|
| 106 |
|
| 107 |
def run_flask():
|
|
|
|
| 108 |
flask_app.run(host="0.0.0.0", port=8080)
|
| 109 |
|
| 110 |
+
# --- STREAMLIT UI ---
|
| 111 |
def run_streamlit():
|
| 112 |
st.set_page_config(page_title="Voice AI Coordinator", layout="centered")
|
| 113 |
+
st.markdown("""<style>.stApp{background-color: #f0f2f5;} .stForm{background-color: white; padding: 2em; border-radius: 10px; box-shadow: 0 4px 12px rgba(0,0,0,0.1);} .stButton>button{width: 100%; border: none; border-radius: 5px; padding: 10px; font-weight: bold; color: white; background-color: #ff4b4b;}</style>""", unsafe_allow_html=True)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 114 |
st.title("π Voice AI Coordination Tool")
|
| 115 |
st.markdown("A unified interface to deploy intelligent voice agents on your behalf.")
|
| 116 |
|
|
|
|
| 117 |
try:
|
| 118 |
config = load_and_set_config()
|
| 119 |
except Exception as e:
|
| 120 |
+
st.error(f"Failed to load configuration. Error: {e}")
|
| 121 |
st.stop()
|
| 122 |
|
| 123 |
with st.form(key="call_form"):
|
|
|
|
| 125 |
target_name = st.text_input("Whom are you calling? (Optional)", placeholder="e.g., Jane Doe")
|
| 126 |
phone_number = st.text_input("Phone Number (with country code)", placeholder="+911234567890")
|
| 127 |
raw_intent = st.text_area("Reason for Calling", placeholder="Ask if they would prefer tea or coffee", height=100)
|
|
|
|
| 128 |
submit_button = st.form_submit_button(label="Deploy Call")
|
| 129 |
|
| 130 |
if submit_button:
|
|
|
|
| 135 |
call_response = place_vapi_call(config, phone_number, raw_intent, target_name)
|
| 136 |
if call_response and call_response.id:
|
| 137 |
st.success(f"β
Call deployed successfully! Call ID: {call_response.id}")
|
|
|
|
| 138 |
st.balloons()
|
| 139 |
else:
|
| 140 |
st.error("β Failed to deploy the call. Please check the Space logs for errors.")
|
| 141 |
|
| 142 |
if __name__ == "__main__":
|
|
|
|
| 143 |
flask_thread = threading.Thread(target=run_flask, daemon=True)
|
| 144 |
flask_thread.start()
|
|
|
|
|
|
|
| 145 |
run_streamlit()
|