|
import streamlit as st |
|
import json |
|
import os |
|
import subprocess |
|
import time |
|
import pandas as pd |
|
from watchdog.observers import Observer |
|
from watchdog.events import FileSystemEventHandler |
|
|
|
st.set_page_config(layout="wide") |
|
|
|
|
|
SALES_SCRIPT_FILE = 'sales_script.txt' |
|
NUMBERS_FILE = 'numbers.txt' |
|
LOG_DIR = 'call_logs' |
|
APP_DATA_DIR = 'application_data' |
|
WEBHOOK_SERVER_FILE = 'webhook_server.py' |
|
|
|
|
|
def load_sales_script(): |
|
if os.path.exists(SALES_SCRIPT_FILE): |
|
with open(SALES_SCRIPT_FILE, 'r') as f: |
|
return f.read() |
|
return "" |
|
|
|
def save_sales_script(script): |
|
with open(SALES_SCRIPT_FILE, 'w') as f: |
|
f.write(script) |
|
|
|
def load_numbers(): |
|
if os.path.exists(NUMBERS_FILE): |
|
with open(NUMBERS_FILE, 'r') as f: |
|
return [line.strip() for line in f.readlines()] |
|
return [] |
|
|
|
def save_numbers(numbers): |
|
with open(NUMBERS_FILE, 'w') as f: |
|
f.write('\n'.join(numbers)) |
|
|
|
@st.cache_data |
|
def get_application_data(): |
|
data = [] |
|
if os.path.exists(APP_DATA_DIR): |
|
for filename in os.listdir(APP_DATA_DIR): |
|
if filename.endswith(".json"): |
|
with open(os.path.join(APP_DATA_DIR, filename), 'r') as f: |
|
call_data = json.load(f) |
|
call_data['call_sid'] = filename.replace('.json', '') |
|
data.append(call_data) |
|
return pd.DataFrame(data) |
|
|
|
|
|
st.title("AI Sales Calling Agent") |
|
|
|
|
|
with st.expander("Sales Script"): |
|
sales_script = st.text_area("Edit Sales Script", value=load_sales_script(), height=200) |
|
if st.button("Save Script"): |
|
save_sales_script(sales_script) |
|
st.success("Sales script saved!") |
|
|
|
|
|
with st.expander("Manage Numbers"): |
|
numbers = st.text_area("Enter numbers to call (one per line)", value='\n'.join(load_numbers()), height=150) |
|
if st.button("Save Numbers"): |
|
save_numbers(numbers.split('\n')) |
|
st.success("Numbers saved!") |
|
|
|
def get_huggingface_url(): |
|
hf_space_id = os.environ.get("HF_SPACE_ID") |
|
if hf_space_id: |
|
return f"https://{hf_space_id.replace('/', '-')}.hf.space" |
|
return None |
|
|
|
|
|
with st.expander("Call Control"): |
|
st.info("When running on Hugging Face Spaces, the webhook server will start automatically.") |
|
|
|
if os.environ.get("HF_SPACE_ID") and not hasattr(st, 'webhook_process'): |
|
try: |
|
st.webhook_process = subprocess.Popen(["python", WEBHOOK_SERVER_FILE]) |
|
st.success("Webhook server started automatically on Hugging Face Space.") |
|
except Exception as e: |
|
st.error(f"Error starting webhook server: {e}") |
|
|
|
webhook_url = get_huggingface_url() |
|
if webhook_url: |
|
st.success(f"Webhook URL detected: {webhook_url}") |
|
else: |
|
st.warning("Could not determine Hugging Face URL. Please run this in a Hugging Face Space.") |
|
|
|
number_to_call = st.selectbox("Select number to call", load_numbers()) |
|
if st.button("Initiate Call"): |
|
if webhook_url: |
|
try: |
|
from twilio.rest import Client |
|
client = Client(os.environ.get('TWILIO_ACCOUNT_SID'), os.environ.get('TWILIO_AUTH_TOKEN')) |
|
call = client.calls.create( |
|
to=number_to_call, |
|
from_=os.environ.get('TWILIO_PHONE_NUMBER'), |
|
url=f"{webhook_url}", |
|
status_callback=f"{webhook_url}/status", |
|
status_callback_method="POST", |
|
status_callback_event=['completed'] |
|
) |
|
st.success(f"Call initiated to {number_to_call} (SID: {call.sid})") |
|
except Exception as e: |
|
st.error(f"Error initiating call: {e}") |
|
else: |
|
st.error("Webhook URL is not set. Cannot initiate call.") |
|
|
|
|
|
st.header("Live Call Status") |
|
log_placeholder = st.empty() |
|
|
|
class LogHandler(FileSystemEventHandler): |
|
def on_modified(self, event): |
|
if not event.is_directory and event.src_path.endswith(".log"): |
|
with open(event.src_path, "r") as f: |
|
log_placeholder.text_area("Logs", f.read(), height=300) |
|
|
|
if not os.path.exists(LOG_DIR): |
|
os.makedirs(LOG_DIR) |
|
|
|
observer = Observer() |
|
observer.schedule(LogHandler(), LOG_DIR, recursive=True) |
|
observer.start() |
|
|
|
|
|
st.header("Extracted Application Data") |
|
df = get_application_data() |
|
if not df.empty: |
|
st.dataframe(df) |
|
csv = df.to_csv(index=False).encode('utf-8') |
|
st.download_button( |
|
label="Download Application Data as CSV", |
|
data=csv, |
|
file_name='application_data.csv', |
|
mime='text/csv', |
|
) |
|
else: |
|
st.info("No application data found.") |
|
|