Spaces:
Sleeping
Sleeping
| import httpx | |
| import resend | |
| from src.config.settings import settings | |
| from loguru import logger | |
| if settings.RESEND_API_KEY: | |
| resend.api_key = settings.RESEND_API_KEY.get_secret_value() | |
| else: | |
| logger.warning("RESEND_API_KEY not configured. Email notifications will be disabled.") | |
| from twilio.rest import Client | |
| def _meta_configured() -> bool: | |
| """Check if Meta API credentials are properly set.""" | |
| return bool( | |
| settings.META_ACCESS_TOKEN | |
| and settings.META_PHONE_NUMBER_ID | |
| and settings.META_ACCESS_TOKEN.get_secret_value() != "placeholder" | |
| ) | |
| def _twilio_configured() -> bool: | |
| """Check if Twilio credentials are properly set.""" | |
| return bool( | |
| settings.TWILIO_ACCOUNT_SID | |
| and settings.TWILIO_AUTH_TOKEN | |
| and settings.TWILIO_WHATSAPP_NUMBER | |
| ) | |
| async def send_whatsapp_reply(to_number: str, message: str): | |
| """ | |
| Send a WhatsApp reply via Meta Cloud API. | |
| """ | |
| if _meta_configured(): | |
| clean_number = to_number.replace("whatsapp:", "").replace("+", "") | |
| # Mask the token for logs but check if it's there | |
| token_preview = f"{settings.META_ACCESS_TOKEN.get_secret_value()[:10]}..." if settings.META_ACCESS_TOKEN else "MISSING" | |
| url = f"https://graph.facebook.com/v21.0/{settings.META_PHONE_NUMBER_ID}/messages" | |
| logger.info(f"π Meta Request: URL={url} | Phone={clean_number} | Token={token_preview}") | |
| headers = { | |
| "Authorization": f"Bearer {settings.META_ACCESS_TOKEN.get_secret_value()}", | |
| "Content-Type": "application/json", | |
| "User-Agent": "MehfoozAI/1.0", | |
| "Accept": "application/json" | |
| } | |
| data = { | |
| "messaging_product": "whatsapp", | |
| "recipient_type": "individual", | |
| "to": clean_number, | |
| "type": "text", | |
| "text": {"body": message} | |
| } | |
| import requests | |
| session = requests.Session() | |
| for attempt in range(1, 4): # Try 3 times | |
| try: | |
| logger.info(f"π€ [Attempt {attempt}] Sending to {clean_number}...") | |
| response = session.post(url, headers=headers, json=data, timeout=15) | |
| if response.status_code in (200, 201, 202): | |
| logger.info(f"β WhatsApp reply SUCCESS for {clean_number}") | |
| return | |
| logger.error(f"β Meta API Error {response.status_code}: {response.text}") | |
| if response.status_code in (401, 403): | |
| logger.error("π Auth Error. Check Token/Permissions.") | |
| return | |
| # On 500 or 429, we might want to retry | |
| except requests.exceptions.Timeout: | |
| logger.warning(f"β³ Timeout on attempt {attempt} (15s). Retrying...") | |
| except Exception as e: | |
| logger.error(f"π₯ Connection Error on attempt {attempt}: {type(e).__name__} - {str(e)}") | |
| import time | |
| time.sleep(1) # Small gap between retries | |
| else: | |
| logger.error("β Meta API not configured. Check META_ACCESS_TOKEN and META_PHONE_NUMBER_ID in .env") | |
| def send_case_confirmation(to_number: str, case_id: str, routing: dict) -> str: | |
| """Returns formatted case confirmation text (used as TwiML body).""" | |
| authority = routing.get("primary_authority", "Nearest Police Station") | |
| support = routing.get("secondary_support", "Madadgaar 15") | |
| return ( | |
| f"π‘οΈ *MehfoozAI* β Report Received Anonymously\n\n" | |
| f"π *Case ID:* `{case_id}`\n" | |
| f"_(Save this to track your case)_\n\n" | |
| f"β *FIR drafted* with relevant PPC sections\n" | |
| f"π *Routed to:* {authority}\n" | |
| f"π *Support:* {support}\n\n" | |
| f"π¬ To check status, reply: *STATUS {case_id}*\n\n" | |
| f"_Her awaz suni jaayegi β anonymously, safely._" | |
| ) | |