Spaces:
Runtime error
Runtime error
| from fastapi import FastAPI, Form | |
| from twilio.rest import Client | |
| from dotenv import load_dotenv | |
| import os | |
| from matching import match_technician, NLPProcessor | |
| from models import Database | |
| from transformers import pipeline | |
| from contextlib import asynccontextmanager | |
| nlp = NLPProcessor() | |
| app = FastAPI() | |
| load_dotenv() | |
| HF_API_URL = "https://api-inference.huggingface.co/models/Christy123/service-classifier" | |
| HF_TOKEN = os.getenv("HF_API_TOKEN") | |
| db = None | |
| async def lifespan(app): | |
| global db | |
| try: | |
| db = Database() | |
| yield | |
| finally: | |
| if db: | |
| db.conn.close() | |
| app.router.lifespan_context = lifespan | |
| # Twilio client | |
| twilio_client = Client(os.getenv("TWILIO_ACCOUNT_SID"), os.getenv("TWILIO_AUTH_TOKEN")) | |
| def send_message(to_number: str, body: str): | |
| try: | |
| if not to_number.startswith("whatsapp:"): | |
| to_number = f"whatsapp:{to_number.lstrip('+')}" | |
| message = twilio_client.messages.create( | |
| from_=os.getenv("TWILIO_NUMBER"), | |
| body=body, | |
| to="whatsapp:+254792552491" | |
| ) | |
| return message.sid | |
| except Exception as e: | |
| print(f"Twilio error: {str(e)}") | |
| return None | |
| def classify_text(text: str): | |
| headers = {"Authorization": f"Bearer {HF_TOKEN}"} | |
| response = requests.post(HF_API_URL, headers=headers, json={"inputs": text}) | |
| if response.status_code != 200: | |
| return {"error": "Model inference failed"} | |
| return response.json() | |
| async def predict(text: str): | |
| result = classify_text(text) | |
| return {"service": result[0]["label"], "confidence": result[0]["score"]} | |
| async def handle_message(From: str = Form(...), Body: str = Form(...)): | |
| db = Database() | |
| user_state = db.get_user_state(From) | |
| # Case 1: User is in menu flow (1/2/3 selection) | |
| if user_state and user_state["state"] == "awaiting_service" and Body.strip() in ["1", "2", "3"]: | |
| services = {"1": "plumbing", "2": "electrical", "3": "hvac"} | |
| service_type = services.get(Body.strip()) | |
| db.update_user_state(From, "awaiting_location", service_type) | |
| db.close() | |
| send_message(From, "Please share your city or area.") | |
| return {"status": "awaiting_location"} | |
| # Case 2: User sends free-text request (e.g., "AC repair in Mombasa") | |
| if not user_state or user_state["state"] == "idle": | |
| technician, error = match_technician(Body, From) | |
| if error: | |
| send_message(From, error) | |
| return {"status": "error"} | |
| response = ( | |
| f"Found {technician['name']} (Rating: {technician['rating']}/5) " | |
| f"for your {nlp.extract_service(Body)} request. " | |
| f"Contact: {technician['contact']}. Confirm? (Yes/No)" | |
| ) | |
| send_message(From, response) | |
| db.update_user_state(From, "awaiting_confirmation", response) | |
| db.close() | |
| return {"status": "success"} | |
| # Case 3: Handle confirmation/feedback | |
| db.close() | |
| return {"status": "processed"} | |
| # main.py | |
| async def startup_db(): | |
| db = Database() | |
| try: | |
| # Simple query to verify tables | |
| db.cursor.execute("SELECT 1 FROM users LIMIT 1") | |
| except psycopg2.Error as e: | |
| print(f"CRITICAL: Database not initialized. Run schema.sql first") | |
| raise | |
| finally: | |
| db.close() |