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") # Paths 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' # --- Helper Functions --- 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) # --- UI --- st.title("AI Sales Calling Agent") # --- Sales Script --- 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!") # --- Numbers --- 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 # --- Call Control --- 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.") # --- Real-time Logs & Data --- 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() # --- Application Data --- 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.")