Spaces:
Runtime error
Runtime error
import os | |
import gradio as gr | |
from datetime import datetime | |
from threading import Lock | |
import requests | |
import logging | |
# Simple configuration | |
BUSINESS_NAME = "Jay's Mobile Wash" | |
JAY_PHONE = os.environ.get('JAY_PHONE_NUMBER', '+15622289429') | |
AI_PHONE = os.environ.get('AI_PHONE_NUMBER', '+17149278841') | |
DEEPSEEK_KEY = os.environ.get('DEEPSEEK_API_KEY', '') | |
# Simple state management | |
class SimpleState: | |
def __init__(self): | |
self.lock = Lock() | |
self.data = { | |
'calls': 0, 'sms': 0, 'ai_responses': 0, | |
'start_time': datetime.now(), 'log': [] | |
} | |
def increment(self, key): | |
with self.lock: | |
self.data[key] += 1 | |
def add_log(self, entry): | |
with self.lock: | |
self.data['log'].insert(0, entry) | |
if len(self.data['log']) > 20: | |
self.data['log'] = self.data['log'][:20] | |
def get_all(self): | |
with self.lock: | |
return self.data.copy() | |
state = SimpleState() | |
# Simple AI | |
class SimpleAI: | |
def detect_intent(self, text): | |
text = text.lower() | |
if any(word in text for word in ['price', 'cost', 'much']): | |
return 'pricing' | |
elif any(word in text for word in ['book', 'schedule', 'appointment']): | |
return 'booking' | |
elif any(word in text for word in ['urgent', 'emergency']): | |
return 'urgent' | |
elif any(word in text for word in ['jay', 'human', 'person']): | |
return 'human' | |
return 'general' | |
def generate_response(self, text, forwarded=False): | |
intent = self.detect_intent(text) | |
prefix = "Thanks for your patience. " if forwarded else "" | |
responses = { | |
'pricing': f"{prefix}Our services: Basic wash $25, Premium $45, Full detail $85. Which interests you?", | |
'booking': f"{prefix}We're available Mon-Sat 8AM-6PM, Sun 10AM-4PM. What day works for you?", | |
'urgent': f"{prefix}I understand this is urgent. Let me connect you with Jay right away.", | |
'human': f"{prefix}Let me connect you with Jay personally.", | |
'general': f"{prefix}Hi! I'm Jay's AI assistant. I can help with pricing, scheduling, or questions about our mobile car wash services." | |
} | |
response = responses.get(intent, responses['general']) | |
# Try DeepSeek if available | |
if DEEPSEEK_KEY and intent not in ['urgent', 'human']: | |
try: | |
enhanced = self.get_deepseek_response(text) | |
if enhanced: | |
response = enhanced | |
except: | |
pass | |
return response | |
def get_deepseek_response(self, prompt): | |
try: | |
headers = {"Authorization": f"Bearer {DEEPSEEK_KEY}", "Content-Type": "application/json"} | |
data = { | |
"model": "deepseek-chat", | |
"messages": [ | |
{"role": "system", "content": f"You are {BUSINESS_NAME} AI assistant. Be friendly and professional. Services: Basic wash ($25), Premium ($45), Full detail ($85), Ceramic coating ($150). Hours: Mon-Sat 8AM-6PM, Sun 10AM-4PM. Phone: {JAY_PHONE}"}, | |
{"role": "user", "content": prompt} | |
], | |
"max_tokens": 150 | |
} | |
response = requests.post("https://api.deepseek.com/v1/chat/completions", | |
headers=headers, json=data, timeout=10) | |
if response.status_code == 200: | |
return response.json()['choices'][0]['message']['content'].strip() | |
except: | |
pass | |
return None | |
ai = SimpleAI() | |
# Dashboard function | |
def get_dashboard(): | |
stats = state.get_all() | |
uptime = datetime.now() - stats['start_time'] | |
return f""" | |
<div style="font-family: Arial; padding: 20px; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); border-radius: 15px; color: white;"> | |
<h1 style="text-align: center;">๐ {BUSINESS_NAME} - AI Dashboard</h1> | |
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 15px; margin: 20px 0;"> | |
<div style="background: rgba(255,255,255,0.15); padding: 15px; border-radius: 10px; text-align: center;"> | |
<h2 style="color: #4facfe; font-size: 2em; margin: 0;">{stats['calls']}</h2> | |
<p style="margin: 5px 0;">๐ Calls</p> | |
</div> | |
<div style="background: rgba(255,255,255,0.15); padding: 15px; border-radius: 10px; text-align: center;"> | |
<h2 style="color: #4facfe; font-size: 2em; margin: 0;">{stats['sms']}</h2> | |
<p style="margin: 5px 0;">๐ฑ SMS</p> | |
</div> | |
<div style="background: rgba(255,255,255,0.15); padding: 15px; border-radius: 10px; text-align: center;"> | |
<h2 style="color: #4facfe; font-size: 2em; margin: 0;">{stats['ai_responses']}</h2> | |
<p style="margin: 5px 0;">๐ค AI Responses</p> | |
</div> | |
</div> | |
<div style="background: rgba(255,255,255,0.1); padding: 15px; border-radius: 10px; margin: 20px 0;"> | |
<h3 style="color: #4facfe;">๐ iPhone Forwarding Status</h3> | |
<p><strong>Jay's iPhone:</strong> {JAY_PHONE}</p> | |
<p><strong>AI Number:</strong> {AI_PHONE}</p> | |
<p><strong>DeepSeek AI:</strong> {'โ Connected' if DEEPSEEK_KEY else 'โ ๏ธ Not configured'}</p> | |
<p><strong>Uptime:</strong> {int(uptime.total_seconds() / 3600)} hours</p> | |
</div> | |
<div style="background: rgba(255,255,255,0.1); padding: 15px; border-radius: 10px;"> | |
<h3 style="color: #4facfe;">๐ผ Services</h3> | |
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); gap: 10px;"> | |
<div style="background: rgba(79,172,254,0.2); padding: 10px; border-radius: 8px; text-align: center;"> | |
<h4 style="margin: 0; color: white;">Basic Wash</h4> | |
<p style="margin: 5px 0; color: #00ff88; font-size: 1.2em;">$25</p> | |
</div> | |
<div style="background: rgba(79,172,254,0.2); padding: 10px; border-radius: 8px; text-align: center;"> | |
<h4 style="margin: 0; color: white;">Premium</h4> | |
<p style="margin: 5px 0; color: #00ff88; font-size: 1.2em;">$45</p> | |
</div> | |
<div style="background: rgba(79,172,254,0.2); padding: 10px; border-radius: 8px; text-align: center;"> | |
<h4 style="margin: 0; color: white;">Full Detail</h4> | |
<p style="margin: 5px 0; color: #00ff88; font-size: 1.2em;">$85</p> | |
</div> | |
<div style="background: rgba(79,172,254,0.2); padding: 10px; border-radius: 8px; text-align: center;"> | |
<h4 style="margin: 0; color: white;">Ceramic</h4> | |
<p style="margin: 5px 0; color: #00ff88; font-size: 1.2em;">$150</p> | |
</div> | |
</div> | |
</div> | |
</div> | |
""" | |
# Test AI function | |
def test_ai(message): | |
if not message.strip(): | |
return "Please enter a message to test." | |
try: | |
intent = ai.detect_intent(message) | |
response = ai.generate_response(message) | |
state.increment('ai_responses') | |
return f""" | |
<div style="font-family: Arial; padding: 15px; background: #f9f9f9; border-radius: 10px;"> | |
<h3>๐ค AI Response Test</h3> | |
<p><strong>Your Message:</strong> {message}</p> | |
<p><strong>Detected Intent:</strong> {intent}</p> | |
<div style="background: #e3f2fd; padding: 10px; border-radius: 5px; margin-top: 10px;"> | |
<strong>AI Response:</strong><br>{response} | |
</div> | |
</div> | |
""" | |
except Exception as e: | |
return f"Error: {e}" | |
# Simulate functions | |
def simulate_call(phone, forwarded): | |
entry = { | |
'time': datetime.now().strftime('%H:%M:%S'), | |
'type': 'Call', | |
'from': phone or '+1555123456', | |
'forwarded': forwarded | |
} | |
state.add_log(entry) | |
state.increment('calls') | |
return f"โ Simulated {'forwarded' if forwarded else 'direct'} call from {entry['from']}" | |
def simulate_sms(phone, message): | |
if not message.strip(): | |
return "Please enter a message." | |
# Log incoming SMS | |
entry = { | |
'time': datetime.now().strftime('%H:%M:%S'), | |
'type': 'SMS', | |
'from': phone or '+1555123456', | |
'message': message | |
} | |
state.add_log(entry) | |
state.increment('sms') | |
# Generate AI response | |
response = ai.generate_response(message) | |
state.increment('ai_responses') | |
# Log AI response | |
response_entry = { | |
'time': datetime.now().strftime('%H:%M:%S'), | |
'type': 'AI Response', | |
'from': 'AI Assistant', | |
'message': response | |
} | |
state.add_log(response_entry) | |
return f"โ SMS processed!\n\n**Customer:** {message}\n\n**AI Response:** {response}" | |
# Activity log | |
def get_activity(): | |
stats = state.get_all() | |
log = stats.get('log', []) | |
if not log: | |
return "No activity yet. Try the demo!" | |
html = "<div style='font-family: Arial;'><h3>๐ Recent Activity</h3>" | |
for entry in log[:10]: | |
color = "#4facfe" if entry['type'] == 'Call' else "#00ff88" if entry['type'] == 'SMS' else "#ff6b6b" | |
html += f""" | |
<div style="background: #f5f5f5; padding: 10px; margin: 5px 0; border-radius: 5px; border-left: 4px solid {color};"> | |
<strong>{entry['time']}</strong> | {entry['type']} | {entry['from']}<br> | |
{entry.get('message', entry.get('forwarded', ''))} | |
</div> | |
""" | |
html += "</div>" | |
return html | |
# Create Gradio interface | |
with gr.Blocks(title=f"{BUSINESS_NAME} - AI Dashboard", theme=gr.themes.Soft()) as demo: | |
gr.Markdown(f""" | |
# ๐ {BUSINESS_NAME} - iPhone Forwarding AI System | |
**Jay's iPhone:** {JAY_PHONE} โ **AI Assistant:** {AI_PHONE} | |
""") | |
with gr.Tabs(): | |
with gr.Tab("๐ Dashboard"): | |
dashboard = gr.HTML(value=get_dashboard()) | |
gr.Button("๐ Refresh").click(fn=get_dashboard, outputs=dashboard) | |
with gr.Tab("๐งช Test AI"): | |
with gr.Row(): | |
with gr.Column(): | |
test_input = gr.Textbox(label="Test Message", placeholder="How much for a car wash?", lines=2) | |
test_btn = gr.Button("๐ค Test AI", variant="primary") | |
with gr.Column(): | |
test_output = gr.HTML() | |
test_btn.click(fn=test_ai, inputs=test_input, outputs=test_output) | |
with gr.Tab("๐ฎ Demo"): | |
with gr.Row(): | |
with gr.Column(): | |
gr.Markdown("#### ๐ Simulate Call") | |
call_phone = gr.Textbox(label="Phone", value="+1555123456") | |
call_forwarded = gr.Checkbox(label="Forwarded Call", value=True) | |
call_btn = gr.Button("๐ Simulate") | |
call_result = gr.Textbox(label |