Files
Project_Velocity/backend/services/comms_provider.py
2026-04-28 13:41:14 +05:30

64 lines
2.1 KiB
Python

"""
Abstract provider interface for Velocity Comms.
"""
import os
from abc import ABC, abstractmethod
from typing import Any, Dict, List, Optional
class CommsProvider(ABC):
def __init__(self, base_url: str, api_key: str, instance_id: Optional[str] = None):
self.base_url = base_url.rstrip("/")
self.api_key = api_key
self.instance_id = instance_id
@abstractmethod
async def send_message(self, phone: str, message: str, message_type: str = "text", **kwargs) -> Dict[str, Any]:
"""Send a message. Return provider response dict."""
...
@abstractmethod
async def normalize_webhook(self, payload: Dict[str, Any]) -> Dict[str, Any]:
"""Convert provider webhook payload to Velocity canonical format."""
...
@abstractmethod
async def test_connection(self) -> Dict[str, Any]:
"""Test provider connectivity. Return {success, message, account_info}."""
...
async def fetch_templates(self) -> List[Dict[str, Any]]:
"""Optional: fetch message templates."""
return []
async def get_media(self, media_id: str) -> Optional[bytes]:
"""Optional: download media bytes."""
return None
async def send_template(self, phone: str, template_name: str, language: str, components: Optional[List] = None) -> Dict[str, Any]:
"""Optional: send a template message."""
raise NotImplementedError("Templates not supported by this provider.")
class MockProvider(CommsProvider):
"""Mock provider for local development and UI previews."""
async def send_message(self, phone: str, message: str, message_type: str = "text", **kwargs) -> Dict[str, Any]:
return {
"success": True,
"provider": "mock",
"external_message_id": f"mock-{os.urandom(4).hex()}",
"status": "sent",
}
async def normalize_webhook(self, payload: Dict[str, Any]) -> Dict[str, Any]:
return payload
async def test_connection(self) -> Dict[str, Any]:
return {
"success": True,
"message": "Mock provider is always healthy.",
"account_info": {"mode": "mock"},
}