Spaces:
Runtime error
Runtime error
Update app.py
Browse files
app.py
CHANGED
@@ -1,7 +1,7 @@
|
|
1 |
#!/usr/bin/env python3
|
2 |
"""
|
3 |
-
π JAY'S MOBILE WASH -
|
4 |
-
iPhone Forwarding + AI Assistant -
|
5 |
"""
|
6 |
|
7 |
import os
|
@@ -14,6 +14,9 @@ from datetime import datetime, timedelta
|
|
14 |
from collections import defaultdict
|
15 |
from threading import Lock
|
16 |
import gradio as gr
|
|
|
|
|
|
|
17 |
|
18 |
# Load environment variables
|
19 |
from dotenv import load_dotenv
|
@@ -157,7 +160,6 @@ class SimpleAI:
|
|
157 |
|
158 |
def generate_response(self, user_input, context=None):
|
159 |
"""Generate AI response"""
|
160 |
-
|
161 |
intent = self.detect_intent(user_input)
|
162 |
sentiment = self.analyze_sentiment(user_input)
|
163 |
|
@@ -246,22 +248,22 @@ BUSINESS INFO:
|
|
246 |
# Initialize AI processor
|
247 |
ai = SimpleAI()
|
248 |
|
249 |
-
#
|
250 |
-
|
251 |
-
|
252 |
-
flask_app = Flask(__name__)
|
253 |
|
254 |
-
@
|
255 |
-
def handle_voice():
|
256 |
"""Handle incoming voice calls"""
|
257 |
try:
|
|
|
|
|
258 |
if not signalwire_client or not VoiceResponse:
|
259 |
-
return "Service unavailable", 503
|
260 |
|
261 |
-
call_sid =
|
262 |
-
from_number =
|
263 |
-
to_number =
|
264 |
-
forwarded_from =
|
265 |
|
266 |
# Detect forwarding
|
267 |
is_forwarded = bool(forwarded_from) or (to_number == SIGNALWIRE_PHONE)
|
@@ -302,29 +304,32 @@ def handle_voice():
|
|
302 |
response.say("I didn't catch that. Let me connect you with Jay.", voice='alice')
|
303 |
response.dial(JAY_PHONE, timeout=30)
|
304 |
|
305 |
-
return str(response)
|
306 |
|
307 |
except Exception as e:
|
308 |
logger.error(f"Voice error: {e}")
|
309 |
response = VoiceResponse()
|
310 |
response.say("Technical issue. Connecting you with Jay.", voice='alice')
|
311 |
response.dial(JAY_PHONE, timeout=30)
|
312 |
-
return str(response)
|
313 |
|
314 |
-
@
|
315 |
-
def process_speech():
|
316 |
"""Process customer speech"""
|
317 |
try:
|
318 |
-
|
319 |
-
|
320 |
-
|
321 |
-
|
|
|
|
|
|
|
322 |
|
323 |
if not speech_result or confidence < 0.4:
|
324 |
response = VoiceResponse()
|
325 |
response.say("I didn't understand clearly. Let me connect you with Jay.", voice='alice')
|
326 |
response.dial(JAY_PHONE, timeout=30)
|
327 |
-
return str(response)
|
328 |
|
329 |
# Analyze intent
|
330 |
intent = ai.detect_intent(speech_result)
|
@@ -334,7 +339,7 @@ def process_speech():
|
|
334 |
response = VoiceResponse()
|
335 |
response.say("Let me connect you with Jay right away.", voice='alice')
|
336 |
response.dial(JAY_PHONE, timeout=30)
|
337 |
-
return str(response)
|
338 |
|
339 |
# Generate AI response
|
340 |
context = {'forwarded': is_forwarded, 'call_sid': call_sid}
|
@@ -354,22 +359,24 @@ def process_speech():
|
|
354 |
)
|
355 |
|
356 |
response.say("Thank you for calling Jay's Mobile Wash! Have a great day!", voice='alice')
|
357 |
-
return str(response)
|
358 |
|
359 |
except Exception as e:
|
360 |
logger.error(f"Speech processing error: {e}")
|
361 |
response = VoiceResponse()
|
362 |
response.say("Technical issue. Connecting with Jay.", voice='alice')
|
363 |
response.dial(JAY_PHONE, timeout=30)
|
364 |
-
return str(response)
|
365 |
|
366 |
-
@
|
367 |
-
def handle_sms():
|
368 |
"""Handle incoming SMS"""
|
369 |
try:
|
370 |
-
|
371 |
-
|
372 |
-
|
|
|
|
|
373 |
|
374 |
# Log the SMS
|
375 |
sms_entry = {
|
@@ -383,7 +390,8 @@ def handle_sms():
|
|
383 |
system_state.increment('sms_today')
|
384 |
|
385 |
if not message_body:
|
386 |
-
|
|
|
387 |
|
388 |
# Analyze message
|
389 |
intent = ai.detect_intent(message_body)
|
@@ -395,7 +403,8 @@ def handle_sms():
|
|
395 |
'jay' in message_body.lower()):
|
396 |
|
397 |
response_text = f"I'll have Jay respond to you personally. For immediate assistance, call {JAY_PHONE}."
|
398 |
-
|
|
|
399 |
|
400 |
# Generate AI response
|
401 |
ai_response = ai.generate_response(message_body, {'sms': True})
|
@@ -406,13 +415,15 @@ def handle_sms():
|
|
406 |
|
407 |
system_state.increment('ai_responses')
|
408 |
|
409 |
-
|
|
|
410 |
|
411 |
except Exception as e:
|
412 |
logger.error(f"SMS error: {e}")
|
413 |
-
|
|
|
414 |
|
415 |
-
def send_sms(message, to_number):
|
416 |
"""Send SMS response"""
|
417 |
try:
|
418 |
if signalwire_client:
|
@@ -431,13 +442,11 @@ def send_sms(message, to_number):
|
|
431 |
}
|
432 |
system_state.add_sms_log(sms_entry)
|
433 |
|
434 |
-
return str(MessagingResponse()) if MessagingResponse else ""
|
435 |
except Exception as e:
|
436 |
logger.error(f"SMS send error: {e}")
|
437 |
-
return ""
|
438 |
|
439 |
-
@
|
440 |
-
def health_check():
|
441 |
"""Health check endpoint"""
|
442 |
health = {
|
443 |
'status': 'healthy',
|
@@ -584,12 +593,12 @@ def test_ai_response(message):
|
|
584 |
except Exception as e:
|
585 |
return f"Error testing AI response: {e}"
|
586 |
|
587 |
-
# Start
|
588 |
-
def
|
589 |
-
|
590 |
|
591 |
-
|
592 |
-
|
593 |
|
594 |
# Create Gradio Interface
|
595 |
with gr.Blocks(
|
@@ -672,6 +681,7 @@ with gr.Blocks(
|
|
672 |
|
673 |
- **SignalWire:** {'β
Connected' if signalwire_client else 'β Not configured'}
|
674 |
- **DeepSeek AI:** {'β
Connected' if DEEPSEEK_API_KEY else 'β οΈ Using fallback responses'}
|
|
|
675 |
- **Health Check:** [/health](./health)
|
676 |
""")
|
677 |
|
@@ -691,8 +701,8 @@ if __name__ == "__main__":
|
|
691 |
print(f"π SignalWire: {'β
Connected' if signalwire_client else 'β Not configured'}")
|
692 |
print(f"π§ DeepSeek: {'β
Connected' if DEEPSEEK_API_KEY else 'β Not configured'}")
|
693 |
print("="*60)
|
694 |
-
print("π Starting Gradio interface...")
|
695 |
-
print("π
|
696 |
print("="*60)
|
697 |
|
698 |
interface.launch(
|
|
|
1 |
#!/usr/bin/env python3
|
2 |
"""
|
3 |
+
π JAY'S MOBILE WASH - GRADIO + FASTAPI VERSION
|
4 |
+
iPhone Forwarding + AI Assistant - HuggingFace Spaces Optimized
|
5 |
"""
|
6 |
|
7 |
import os
|
|
|
14 |
from collections import defaultdict
|
15 |
from threading import Lock
|
16 |
import gradio as gr
|
17 |
+
from fastapi import FastAPI, Request, Form
|
18 |
+
from fastapi.responses import PlainTextResponse
|
19 |
+
import uvicorn
|
20 |
|
21 |
# Load environment variables
|
22 |
from dotenv import load_dotenv
|
|
|
160 |
|
161 |
def generate_response(self, user_input, context=None):
|
162 |
"""Generate AI response"""
|
|
|
163 |
intent = self.detect_intent(user_input)
|
164 |
sentiment = self.analyze_sentiment(user_input)
|
165 |
|
|
|
248 |
# Initialize AI processor
|
249 |
ai = SimpleAI()
|
250 |
|
251 |
+
# FastAPI app for webhooks
|
252 |
+
fastapi_app = FastAPI()
|
|
|
|
|
253 |
|
254 |
+
@fastapi_app.post("/voice/incoming")
|
255 |
+
async def handle_voice(request: Request):
|
256 |
"""Handle incoming voice calls"""
|
257 |
try:
|
258 |
+
form = await request.form()
|
259 |
+
|
260 |
if not signalwire_client or not VoiceResponse:
|
261 |
+
return PlainTextResponse("Service unavailable", status_code=503)
|
262 |
|
263 |
+
call_sid = form.get('CallSid')
|
264 |
+
from_number = form.get('From')
|
265 |
+
to_number = form.get('To')
|
266 |
+
forwarded_from = form.get('ForwardedFrom')
|
267 |
|
268 |
# Detect forwarding
|
269 |
is_forwarded = bool(forwarded_from) or (to_number == SIGNALWIRE_PHONE)
|
|
|
304 |
response.say("I didn't catch that. Let me connect you with Jay.", voice='alice')
|
305 |
response.dial(JAY_PHONE, timeout=30)
|
306 |
|
307 |
+
return PlainTextResponse(str(response), media_type="application/xml")
|
308 |
|
309 |
except Exception as e:
|
310 |
logger.error(f"Voice error: {e}")
|
311 |
response = VoiceResponse()
|
312 |
response.say("Technical issue. Connecting you with Jay.", voice='alice')
|
313 |
response.dial(JAY_PHONE, timeout=30)
|
314 |
+
return PlainTextResponse(str(response), media_type="application/xml")
|
315 |
|
316 |
+
@fastapi_app.post("/voice/process")
|
317 |
+
async def process_speech(request: Request):
|
318 |
"""Process customer speech"""
|
319 |
try:
|
320 |
+
form = await request.form()
|
321 |
+
query_params = request.query_params
|
322 |
+
|
323 |
+
call_sid = query_params.get('call_sid')
|
324 |
+
is_forwarded = query_params.get('forwarded') == 'True'
|
325 |
+
speech_result = form.get('SpeechResult', '')
|
326 |
+
confidence = float(form.get('Confidence', '0.0'))
|
327 |
|
328 |
if not speech_result or confidence < 0.4:
|
329 |
response = VoiceResponse()
|
330 |
response.say("I didn't understand clearly. Let me connect you with Jay.", voice='alice')
|
331 |
response.dial(JAY_PHONE, timeout=30)
|
332 |
+
return PlainTextResponse(str(response), media_type="application/xml")
|
333 |
|
334 |
# Analyze intent
|
335 |
intent = ai.detect_intent(speech_result)
|
|
|
339 |
response = VoiceResponse()
|
340 |
response.say("Let me connect you with Jay right away.", voice='alice')
|
341 |
response.dial(JAY_PHONE, timeout=30)
|
342 |
+
return PlainTextResponse(str(response), media_type="application/xml")
|
343 |
|
344 |
# Generate AI response
|
345 |
context = {'forwarded': is_forwarded, 'call_sid': call_sid}
|
|
|
359 |
)
|
360 |
|
361 |
response.say("Thank you for calling Jay's Mobile Wash! Have a great day!", voice='alice')
|
362 |
+
return PlainTextResponse(str(response), media_type="application/xml")
|
363 |
|
364 |
except Exception as e:
|
365 |
logger.error(f"Speech processing error: {e}")
|
366 |
response = VoiceResponse()
|
367 |
response.say("Technical issue. Connecting with Jay.", voice='alice')
|
368 |
response.dial(JAY_PHONE, timeout=30)
|
369 |
+
return PlainTextResponse(str(response), media_type="application/xml")
|
370 |
|
371 |
+
@fastapi_app.post("/sms/incoming")
|
372 |
+
async def handle_sms(request: Request):
|
373 |
"""Handle incoming SMS"""
|
374 |
try:
|
375 |
+
form = await request.form()
|
376 |
+
|
377 |
+
message_sid = form.get('MessageSid')
|
378 |
+
from_number = form.get('From')
|
379 |
+
message_body = form.get('Body', '').strip()
|
380 |
|
381 |
# Log the SMS
|
382 |
sms_entry = {
|
|
|
390 |
system_state.increment('sms_today')
|
391 |
|
392 |
if not message_body:
|
393 |
+
await send_sms("Hi! How can I help you with Jay's Mobile Wash today?", from_number)
|
394 |
+
return PlainTextResponse(str(MessagingResponse()) if MessagingResponse else "", media_type="application/xml")
|
395 |
|
396 |
# Analyze message
|
397 |
intent = ai.detect_intent(message_body)
|
|
|
403 |
'jay' in message_body.lower()):
|
404 |
|
405 |
response_text = f"I'll have Jay respond to you personally. For immediate assistance, call {JAY_PHONE}."
|
406 |
+
await send_sms(response_text, from_number)
|
407 |
+
return PlainTextResponse(str(MessagingResponse()) if MessagingResponse else "", media_type="application/xml")
|
408 |
|
409 |
# Generate AI response
|
410 |
ai_response = ai.generate_response(message_body, {'sms': True})
|
|
|
415 |
|
416 |
system_state.increment('ai_responses')
|
417 |
|
418 |
+
await send_sms(ai_response, from_number)
|
419 |
+
return PlainTextResponse(str(MessagingResponse()) if MessagingResponse else "", media_type="application/xml")
|
420 |
|
421 |
except Exception as e:
|
422 |
logger.error(f"SMS error: {e}")
|
423 |
+
await send_sms("Thanks for your message! Jay will get back to you soon.", from_number)
|
424 |
+
return PlainTextResponse(str(MessagingResponse()) if MessagingResponse else "", media_type="application/xml")
|
425 |
|
426 |
+
async def send_sms(message, to_number):
|
427 |
"""Send SMS response"""
|
428 |
try:
|
429 |
if signalwire_client:
|
|
|
442 |
}
|
443 |
system_state.add_sms_log(sms_entry)
|
444 |
|
|
|
445 |
except Exception as e:
|
446 |
logger.error(f"SMS send error: {e}")
|
|
|
447 |
|
448 |
+
@fastapi_app.get("/health")
|
449 |
+
async def health_check():
|
450 |
"""Health check endpoint"""
|
451 |
health = {
|
452 |
'status': 'healthy',
|
|
|
593 |
except Exception as e:
|
594 |
return f"Error testing AI response: {e}"
|
595 |
|
596 |
+
# Start FastAPI in background thread
|
597 |
+
def run_fastapi():
|
598 |
+
uvicorn.run(fastapi_app, host="0.0.0.0", port=8000, log_level="info")
|
599 |
|
600 |
+
fastapi_thread = threading.Thread(target=run_fastapi, daemon=True)
|
601 |
+
fastapi_thread.start()
|
602 |
|
603 |
# Create Gradio Interface
|
604 |
with gr.Blocks(
|
|
|
681 |
|
682 |
- **SignalWire:** {'β
Connected' if signalwire_client else 'β Not configured'}
|
683 |
- **DeepSeek AI:** {'β
Connected' if DEEPSEEK_API_KEY else 'β οΈ Using fallback responses'}
|
684 |
+
- **FastAPI Webhooks:** β
Running on port 8000
|
685 |
- **Health Check:** [/health](./health)
|
686 |
""")
|
687 |
|
|
|
701 |
print(f"π SignalWire: {'β
Connected' if signalwire_client else 'β Not configured'}")
|
702 |
print(f"π§ DeepSeek: {'β
Connected' if DEEPSEEK_API_KEY else 'β Not configured'}")
|
703 |
print("="*60)
|
704 |
+
print("π Starting Gradio interface on port 7860...")
|
705 |
+
print("π FastAPI webhooks running on port 8000")
|
706 |
print("="*60)
|
707 |
|
708 |
interface.launch(
|