{"openapi":"3.1.0","info":{"title":"Sunbird AI API","description":"\nWelcome to the Sunbird AI API documentation. The Sunbird AI API provides access to Sunbird's language models and AI services for Ugandan languages.\n\n## Supported Languages\n**English**, **Acholi**, **Ateso**, **Luganda**, **Lugbara**, **Runyankole**, **Swahili** and **20+** more Ugandan languages supported via sunflower.\n\n## Getting Started\nYou can checkout the [usage guide](https://salt.sunbird.ai/API/) for a full tutorial.\n\nFor quickstart tutorials, visit our [GitHub repository](https://github.com/SunbirdAI/sunbird-ai-api/blob/main/docs/tutorial.md)\n\n### Authentication\n\n#### Signing Up\nIf you don't already have an account, use the `/auth/register` endpoint to create one.\n\n#### Getting an Access Token\nAuthentication is done via a Bearer token. Use the `/auth/token` endpoint to get your access token. This token lasts for 7 days.\n\nUse the `Authorize` button below to login and access the protected endpoints.\n\n## API Endpoints\n\n### Speech-to-Text (STT)\n- **`POST /tasks/modal/stt`** - Modal-based STT using Whisper large-v3 model\n  - Upload audio files directly for transcription\n  - Powered by Modal serverless GPU infrastructure\n  - Supports various audio formats (WAV, MP3, OGG, M4A, etc.)\n  - Optional `language` parameter: pass a 3-letter code (e.g. `eng`, `lug`) or full name (e.g. `english`, `luganda`) to improve transcription accuracy for local languages. Auto-detects if omitted.\n- **`POST /tasks/stt`** - RunPod-based STT for supported languages with language/adapter selection\n\n### Translation\n- **`POST /tasks/translate`** - Translate text between English and local languages (Acholi, Ateso, Luganda, Lugbara, Runyankole)\n\n### Language Detection\n- **`POST /tasks/language_id`** - Auto-detect the language of text input (supports Acholi, Ateso, English, Luganda, Lugbara, Runyankole)\n\n### Text-to-Speech (TTS)\n- **`POST /tasks/modal/tts`** - Modal-based TTS with streaming support\n  - **Multiple Languages**: Acholi, Ateso, Runyankore, Lugbara, Swahili, and Luganda\n  - **Signed URLs**: Audio files are stored in GCP Storage with 30-minute expiring URLs\n  - **Streaming Support**: Stream audio chunks for large text inputs\n  - **Response Modes**:\n    - `url` - Generate audio, upload to GCP, return signed URL\n    - `stream` - Stream raw audio chunks directly\n    - `both` - Stream audio AND get a final signed URL\n- **`POST /tasks/runpod/tts`** - RunPod-based TTS for Ugandan language voices\n  - Supports all major Ugandan languages\n  - Fast inference with RunPod serverless infrastructure\n\n### Inference (Sunflower Chat)\n- **`POST /tasks/sunflower_inference`** - Conversational AI powered by Sunflower model with chat history\n- **`POST /tasks/sunflower_simple`** - Simple text generation without chat history\n\n### File Upload\n- **`POST /tasks/generate-upload-url`** - Generate signed URLs for direct client uploads to GCP Storage\n  - Supports audio files, images, and other content types\n  - Includes path traversal protection and input validation\n  - Returns temporary signed URL valid for 30 minutes\n\n### WhatsApp Integration (Webhooks)\n- **`POST /tasks/webhook`** - Handle incoming WhatsApp Business API messages\n- **`GET /tasks/webhook`** - Verify webhook endpoint ownership for WhatsApp\n\n### Legacy Endpoints\n- **`POST /tasks/summarise`** - *(Deprecated)* Anonymized text summarization (use Sunflower inference instead)\n\n## Rate Limiting\nAPI endpoints are rate-limited to ensure fair usage. Authentication is required for most endpoints.\n","version":"0.1.0"},"paths":{"/auth/register":{"post":{"tags":["Authentication Endpoints"],"summary":"Register","operationId":"register_auth_register_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserCreate"}}},"required":true},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/User"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/auth/token":{"post":{"tags":["Authentication Endpoints"],"summary":"Login For Access Token","operationId":"login_for_access_token_auth_token_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_login_for_access_token_auth_token_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Token"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/auth/me":{"get":{"tags":["Authentication Endpoints"],"summary":"Read Users Me","operationId":"read_users_me_auth_me_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"OAuth2PasswordBearer":[]}]}},"/auth/forgot-password":{"post":{"tags":["Authentication Endpoints"],"summary":"Request Password Reset","operationId":"request_password_reset_auth_forgot_password_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForgotPassword"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/auth/reset-password":{"post":{"tags":["Authentication Endpoints"],"summary":"Reset Password","operationId":"reset_password_auth_reset_password_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResetPassword"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/auth/change-password":{"post":{"tags":["Authentication Endpoints"],"summary":"Change Password","operationId":"change_password_auth_change_password_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangePassword"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"OAuth2PasswordBearer":[]}]}},"/auth/profile":{"put":{"tags":["Authentication Endpoints"],"summary":"Update Profile","operationId":"update_profile_auth_profile_put","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProfileUpdate"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/User"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"OAuth2PasswordBearer":[]}]}},"/auth/profile/status":{"get":{"tags":["Authentication Endpoints"],"summary":"Profile Status","operationId":"profile_status_auth_profile_status_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProfileCompletionStatus"}}}}},"security":[{"OAuth2PasswordBearer":[]}]}},"/auth/google/login":{"get":{"tags":["Authentication Endpoints"],"summary":"Auth:Google Login","operationId":"auth_google_login_auth_google_login_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/auth/google/callback":{"get":{"tags":["Authentication Endpoints"],"summary":"Auth:Google Callback","operationId":"auth_google_callback_auth_google_callback_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/tasks/stt_from_gcs":{"post":{"tags":["Speech-to-Text"],"summary":"Speech To Text From Gcs","description":"Transcribe audio from a Google Cloud Storage blob.\n\nAccepts a GCS blob name, downloads the file from GCS, trims if >10 minutes,\nuploads a final version (if trimmed), then calls the transcription service.\n\nArgs:\n\n    request: The FastAPI request object.\n    gcs_blob_name: Name of the blob in GCS bucket.\n    language: Target language for transcription. Defaults to Luganda.\n    adapter: Language adapter to use. Defaults to Luganda.\n    recognise_speakers: Enable speaker diarization. Defaults to False.\n    whisper: Use Whisper model for transcription. Defaults to False.\n    db: Database session.\n    current_user: The authenticated user.\n    service: The STT service instance.\n\nReturns:\n\n    STTTranscript containing the transcription results.\n\nRaises:\n\n    BadRequestError: If audio processing fails.\n    ExternalServiceError: If transcription service fails.","operationId":"speech_to_text_from_gcs_tasks_stt_from_gcs_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_speech_to_text_from_gcs_tasks_stt_from_gcs_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/STTTranscript"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"OAuth2PasswordBearer":[]}]}},"/tasks/stt":{"post":{"tags":["Speech-to-Text"],"summary":"Speech To Text","description":"Upload an audio file and get the transcription text.\n\nUpload an audio file for transcription. Supports various audio formats\nincluding MP3, WAV, OGG, M4A, and AAC.\n\nLimitations:\n\n    - Maximum audio duration: Files longer than 10 minutes will be trimmed\n    - Supported formats: MP3, WAV, OGG, M4A, AAC\n    - Large files are supported but only first 10 minutes will be transcribed\n\nNote:\n\n    For files larger than 100MB, please use chunked upload or consider\n    splitting the audio file.\n\nArgs:\n\n    request: The FastAPI request object.\n    audio: The uploaded audio file.\n    language: Target language for transcription. Defaults to Luganda.\n    adapter: Language adapter to use. Defaults to Luganda.\n    recognise_speakers: Enable speaker diarization. Defaults to False.\n    whisper: Use Whisper model for transcription. Defaults to False.\n    db: Database session.\n    current_user: The authenticated user.\n    service: The STT service instance.\n\nReturns:\n\n    STTTranscript containing the transcription results.\n\nRaises:\n\n    ValidationError: If audio file validation fails.\n    BadRequestError: If audio processing fails.\n    ExternalServiceError: If transcription service fails.","operationId":"speech_to_text_tasks_stt_post","requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_speech_to_text_tasks_stt_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/STTTranscript"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"OAuth2PasswordBearer":[]}]}},"/tasks/org/stt":{"post":{"tags":["Speech-to-Text"],"summary":"Speech To Text Org","description":"Upload an audio file for organization transcription.\n\nSimplified endpoint for organization use cases. Automatically\ndetects language and provides transcription with optional\nspeaker diarization.\n\nArgs:\n\n    request: The FastAPI request object (required for rate limiting).\n    audio: The uploaded audio file.\n    recognise_speakers: Enable speaker diarization. Defaults to False.\n    current_user: The authenticated user (enforces authentication).\n    service: The STT service instance.\n\nReturns:\n\n    STTTranscript containing the transcription results.\n\nRaises:\n\n    BadRequestError: If audio processing fails.\n    ServiceUnavailableError: If service times out.\n    ExternalServiceError: If transcription service fails.","operationId":"speech_to_text_org_tasks_org_stt_post","requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_speech_to_text_org_tasks_org_stt_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/STTTranscript"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"OAuth2PasswordBearer":[]}]}},"/tasks/modal/stt":{"post":{"tags":["Speech-to-Text"],"summary":"Transcribe Audio via Modal Whisper ASR","description":"Upload an audio file and get transcription using the Modal-hosted Whisper model. Optionally specify a language to improve accuracy.","operationId":"modal_speech_to_text_tasks_modal_stt_post","requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_modal_speech_to_text_tasks_modal_stt_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/STTTranscript"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"OAuth2PasswordBearer":[]}]}},"/tasks/translate":{"post":{"tags":["Translation"],"summary":"Translate","description":"Translate text between languages using NLLB model.\n\nSource and Target Language can be one of:\n- ach (Acholi)\n- teo (Ateso)\n- eng (English)\n- lug (Luganda)\n- lgg (Lugbara)\n- nyn (Runyankole)\n\nWe currently only support English to Local languages and Local to English\ntranslations. When the source language is one of the listed languages,\nthe target can be any of the other languages.\n\nArgs:\n\n    request: The FastAPI request object.\n    translation_request: The translation request containing source/target\n        languages and text to translate.\n    db: Database session.\n    current_user: The authenticated user.\n    service: The translation service instance.\n\nReturns:\n\n    WorkerTranslationResponse containing the translation result.\n\nRaises:\n\n    ServiceUnavailableError: If service times out.\n    ExternalServiceError: If translation service fails or returns invalid response.\n\nExample:\n\n    Request body:\n    {\n        \"source_language\": \"eng\",\n        \"target_language\": \"lug\",\n        \"text\": \"Hello, how are you?\"\n    }\n\n    Response:\n    {\n        \"id\": \"job-123\",\n        \"status\": \"COMPLETED\",\n        \"output\": {\n            \"translated_text\": \"Oli otya?\",\n            \"source_language\": \"eng\",\n            \"target_language\": \"lug\"\n        }\n    }","operationId":"translate_tasks_translate_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NllbTranslationRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorkerTranslationResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"OAuth2PasswordBearer":[]}]}},"/tasks/language_id":{"post":{"tags":["Language"],"summary":"Language Id","description":"Identify the language of a given text using auto-detection.\n\nThis endpoint identifies the language of a given text. It supports a limited\nset of local languages including Acholi (ach), Ateso (teo), English (eng),\nLuganda (lug), Lugbara (lgg), and Runyankole (nyn).\n\nArgs:\n\n    languageId_request: The language identification request containing text.\n    current_user: The authenticated user.\n    service: The language service instance.\n\nReturns:\n\n    LanguageIdResponse containing the identified language.\n\nRaises:\n\n    ServiceUnavailableError: If the service times out.\n    ExternalServiceError: If language identification service fails.\n\nExample:\n\n    Request body:\n    {\n        \"text\": \"Oli otya?\"\n    }\n\n    Response:\n    {\n        \"language\": \"lug\"\n    }","operationId":"language_id_tasks_language_id_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LanguageIdRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LanguageIdResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"OAuth2PasswordBearer":[]}]}},"/tasks/classify_language":{"post":{"tags":["Language"],"summary":"Classify Language","description":"Classify the language of a given text with confidence scores.\n\nThis endpoint identifies the language of a given text using a\nclassification model with probability scores. A language is only\nreported if confidence exceeds a threshold (default 0.9).\n\nIt supports a limited set of local languages including Acholi (ach),\nAteso (teo), English (eng), Luganda (lug), Lugbara (lgg), and\nRunyankole (nyn).\n\nArgs:\n\n    languageId_request: The language identification request containing text.\n    current_user: The authenticated user.\n    service: The language service instance.\n\nReturns:\n\n    LanguageIdResponse containing the classified language.\n\nRaises:\n\n    ServiceUnavailableError: If the service times out.\n    ExternalServiceError: If language classification service fails or returns unexpected response format.\n\nExample:\n\n    Request body:\n    {\n        \"text\": \"Oli otya?\"\n    }\n\n    Response:\n    {\n        \"language\": \"lug\"\n    }\n\n    If confidence is below threshold:\n    {\n        \"language\": \"language not detected\"\n    }","operationId":"classify_language_tasks_classify_language_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LanguageIdRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LanguageIdResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"OAuth2PasswordBearer":[]}]}},"/tasks/auto_detect_audio_language":{"post":{"tags":["Language"],"summary":"Auto Detect Audio Language","description":"Detect the language of an audio file.\n\nUpload an audio file and detect the language of the spoken content.\nThe audio file is uploaded to cloud storage for processing.\n\nArgs:\n\n    request: The FastAPI request object (required for rate limiting).\n    audio: The audio file to analyze.\n    current_user: The authenticated user.\n    service: The language service instance.\n\nReturns:\n\n    AudioDetectedLanguageResponse containing the detected language.\n\nRaises:\n\n    ServiceUnavailableError: If the service times out.\n    ExternalServiceError: If language detection service fails or has connection errors.\n\nExample:\n\n    Response:\n    {\n        \"detected_language\": \"lug\"\n    }","operationId":"auto_detect_audio_language_tasks_auto_detect_audio_language_post","requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_auto_detect_audio_language_tasks_auto_detect_audio_language_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AudioDetectedLanguageResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"OAuth2PasswordBearer":[]}]}},"/tasks/sunflower_inference":{"post":{"tags":["Sunflower"],"summary":"Sunflower Inference","description":"Professional Sunflower inference endpoint for multilingual chat completions.\n\nThis endpoint provides access to Sunbird AI's Sunflower model, specialized in:\n- Multilingual conversations in Ugandan languages (Luganda, Acholi, Ateso, etc.)\n- Cross-lingual translations and explanations\n- Cultural context understanding\n- Educational content in local languages\n\nFeatures:\n- Automatic retry with exponential backoff\n- Context-aware responses\n- Usage tracking and monitoring\n- Support for custom system messages\n- Message history management\n\nArgs:\n\n    request: The FastAPI request object (required for rate limiting).\n    chat_request: The chat request containing messages and parameters.\n    background_tasks: FastAPI background tasks for async operations.\n    current_user: The authenticated user (enforces authentication).\n    service: The inference service instance.\n\nReturns:\n\n    SunflowerChatResponse containing the AI's response and usage stats.\n\nRaises:\n\n    BadRequestError: For validation errors.\n    ValidationError: For invalid message format.\n    ServiceUnavailableError: If the model is loading or request times out.\n    ExternalServiceError: For empty model response or unexpected errors.\n\nExample:\n\n    Request body with message history:\n\n    {\n        \"messages\": [\n            {\"role\": \"system\", \"content\": \"You are Sunflower...\"},\n            {\"role\": \"user\", \"content\": \"Translate 'How are you?' to Luganda.\"},\n            {\"role\": \"assistant\", \"content\": \"In Luganda, 'How are you?' is 'Oli otya?'.\"},\n            {\"role\": \"user\", \"content\": \"How do I say 'Good morning' in Acholi?\"}\n        ],\n        \"model_type\": \"qwen\",\n        \"temperature\": 0.3\n    }\n\n    Response:\n\n    {\n        \"content\": \"In Acholi, 'Good morning' is 'Icwiny atir'.\",\n        \"model_type\": \"qwen\",\n        \"usage\": {\"completion_tokens\": 15, \"prompt_tokens\": 50, \"total_tokens\": 65},\n        \"processing_time\": 2.5,\n        \"inference_time\": 2.0,\n        \"message_count\": 5\n    }","operationId":"sunflower_inference_tasks_sunflower_inference_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SunflowerChatRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SunflowerChatResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"OAuth2PasswordBearer":[]}]}},"/tasks/sunflower_simple":{"post":{"tags":["Sunflower"],"summary":"Sunflower Simple Inference","description":"Simple Sunflower inference endpoint for single instruction/response.\n\nThis is a simplified interface for users who want to send a single instruction\nrather than managing conversation history. Uses form-based input for easier\nintegration with simple clients.\n\nArgs:\n\n    request: The FastAPI request object (required for rate limiting).\n    background_tasks: FastAPI background tasks for async operations.\n    instruction: The question or instruction for the AI.\n    model_type: Either 'qwen' (default) or 'gemma'.\n    temperature: Controls randomness (0.0 = deterministic, 1.0 = creative).\n    system_message: Optional custom system message.\n    db: Database session.\n    current_user: The authenticated user.\n\nReturns:\n\n    Dictionary containing response, model_type, processing_time, usage, and success.\n\nRaises:\n\n    BadRequestError: For validation errors.\n    ValidationError: For invalid model type.\n    ServiceUnavailableError: If the model is loading or request times out.\n    ExternalServiceError: For unexpected errors.\n\nExample:\n\n    Form data:\n    - instruction: \"Translate 'hello' to Luganda\"\n    - model_type: \"qwen\"\n    - temperature: 0.3\n\n    Response:\n    {\n        \"response\": \"In Luganda, 'hello' is 'Gyebaleko' or 'Wasuze otya' (Good morning).\",\n        \"model_type\": \"qwen\",\n        \"processing_time\": 1.5,\n        \"usage\": {\"completion_tokens\": 20, \"prompt_tokens\": 10, \"total_tokens\": 30},\n        \"success\": true\n    }","operationId":"sunflower_simple_inference_tasks_sunflower_simple_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_sunflower_simple_inference_tasks_sunflower_simple_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Sunflower Simple Inference Tasks Sunflower Simple Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"OAuth2PasswordBearer":[]}]}},"/tasks/generate-upload-url":{"post":{"tags":["Upload"],"summary":"Generate Upload URL","description":"Generate a signed URL for direct upload to Google Cloud Storage.","operationId":"generate_upload_url_tasks_generate_upload_url_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UploadRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UploadResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/tasks/webhook/":{"post":{"tags":["Webhooks"],"summary":"Webhook","description":"Handle incoming WhatsApp webhooks.\n\nThis endpoint processes incoming WhatsApp messages and events,\nproviding fast responses for text messages and background processing\nfor heavy operations.\n\nFeatures:\n- Fast text responses (2-4 seconds)\n- Background processing for heavy operations\n- No external caching dependencies\n- Duplicate message detection\n- Language preference support\n\nArgs:\n    payload: WhatsApp webhook payload.\n    background_tasks: FastAPI background tasks for async processing.\n\nReturns:\n    WebhookResponse with processing status and time.\n\nResponse Status Codes:\n    - 200: Successfully processed\n    - 400: Invalid payload format\n    - 500: Internal server error\n\nExample Payload:\n    {\n        \"entry\": [{\n            \"changes\": [{\n                \"value\": {\n                    \"messages\": [{\n                        \"from\": \"1234567890\",\n                        \"text\": {\"body\": \"Hello\"}\n                    }],\n                    \"contacts\": [{\n                        \"profile\": {\"name\": \"John\"}\n                    }],\n                    \"metadata\": {\n                        \"phone_number_id\": \"9876543210\"\n                    }\n                }\n            }]\n        }]\n    }\n\nExample Response:\n    {\n        \"status\": \"success\",\n        \"processing_time\": 2.5\n    }","operationId":"webhook_tasks_webhook__post","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Payload"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["Webhooks"],"summary":"Verify Webhook","description":"Verify webhook endpoint ownership for WhatsApp.\n\nWhatsApp sends a verification request when you register a webhook URL.\nThis endpoint validates the request and returns the challenge string\nto complete the verification process.\n\nArgs:\n    request: The incoming HTTP request.\n    hub_mode: Should be \"subscribe\" (query param: hub.mode).\n    hub_challenge: Challenge string to echo back (query param: hub.challenge).\n    hub_verify_token: Verification token (query param: hub.verify_token).\n\nReturns:\n    Plain text response with the challenge string.\n\nRaises:\n    AuthorizationError: If webhook verification fails.\n    BadRequestError: If required parameters are missing.\n\nVerification Process:\n    1. WhatsApp sends GET request with query parameters\n    2. Endpoint validates hub.mode == \"subscribe\"\n    3. Endpoint validates hub.verify_token matches configured token\n    4. Endpoint returns hub.challenge as plain text response\n    5. WhatsApp completes webhook registration\n\nExample Request:\n    GET /tasks/webhook?hub.mode=subscribe&hub.challenge=12345&hub.verify_token=mytoken\n\nExample Response:\n    12345  # Plain text","operationId":"verify_webhook_tasks_webhook__get","parameters":[{"name":"hub_mode","in":"query","required":false,"schema":{"type":"string","title":"Hub Mode"}},{"name":"hub_challenge","in":"query","required":false,"schema":{"type":"string","title":"Hub Challenge"}},{"name":"hub_verify_token","in":"query","required":false,"schema":{"type":"string","title":"Hub Verify Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/tasks/webhook":{"post":{"tags":["Webhooks"],"summary":"Webhook","description":"Handle incoming WhatsApp webhooks.\n\nThis endpoint processes incoming WhatsApp messages and events,\nproviding fast responses for text messages and background processing\nfor heavy operations.\n\nFeatures:\n- Fast text responses (2-4 seconds)\n- Background processing for heavy operations\n- No external caching dependencies\n- Duplicate message detection\n- Language preference support\n\nArgs:\n    payload: WhatsApp webhook payload.\n    background_tasks: FastAPI background tasks for async processing.\n\nReturns:\n    WebhookResponse with processing status and time.\n\nResponse Status Codes:\n    - 200: Successfully processed\n    - 400: Invalid payload format\n    - 500: Internal server error\n\nExample Payload:\n    {\n        \"entry\": [{\n            \"changes\": [{\n                \"value\": {\n                    \"messages\": [{\n                        \"from\": \"1234567890\",\n                        \"text\": {\"body\": \"Hello\"}\n                    }],\n                    \"contacts\": [{\n                        \"profile\": {\"name\": \"John\"}\n                    }],\n                    \"metadata\": {\n                        \"phone_number_id\": \"9876543210\"\n                    }\n                }\n            }]\n        }]\n    }\n\nExample Response:\n    {\n        \"status\": \"success\",\n        \"processing_time\": 2.5\n    }","operationId":"webhook_tasks_webhook_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Payload"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["Webhooks"],"summary":"Verify Webhook","description":"Verify webhook endpoint ownership for WhatsApp.\n\nWhatsApp sends a verification request when you register a webhook URL.\nThis endpoint validates the request and returns the challenge string\nto complete the verification process.\n\nArgs:\n    request: The incoming HTTP request.\n    hub_mode: Should be \"subscribe\" (query param: hub.mode).\n    hub_challenge: Challenge string to echo back (query param: hub.challenge).\n    hub_verify_token: Verification token (query param: hub.verify_token).\n\nReturns:\n    Plain text response with the challenge string.\n\nRaises:\n    AuthorizationError: If webhook verification fails.\n    BadRequestError: If required parameters are missing.\n\nVerification Process:\n    1. WhatsApp sends GET request with query parameters\n    2. Endpoint validates hub.mode == \"subscribe\"\n    3. Endpoint validates hub.verify_token matches configured token\n    4. Endpoint returns hub.challenge as plain text response\n    5. WhatsApp completes webhook registration\n\nExample Request:\n    GET /tasks/webhook?hub.mode=subscribe&hub.challenge=12345&hub.verify_token=mytoken\n\nExample Response:\n    12345  # Plain text","operationId":"verify_webhook_tasks_webhook_get","parameters":[{"name":"hub_mode","in":"query","required":false,"schema":{"type":"string","title":"Hub Mode"}},{"name":"hub_challenge","in":"query","required":false,"schema":{"type":"string","title":"Hub Challenge"}},{"name":"hub_verify_token","in":"query","required":false,"schema":{"type":"string","title":"Hub Verify Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/tasks/summarise":{"post":{"tags":["AI Tasks"],"summary":"Summarise","description":"This endpoint does anonymised summarisation of a given text. The text languages\nsupported for now are English (eng) and Luganda (lug).","operationId":"summarise_tasks_summarise_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SummarisationRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SummarisationResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"OAuth2PasswordBearer":[]}]}},"/tasks/tts":{"post":{"tags":["AI Tasks"],"summary":"Text To Speech","description":"**DEPRECATED**: This endpoint is maintained for backward compatibility only.\n\nPlease use the new endpoint at `/tasks/runpod/tts` instead.\n\nLegacy RunPod text-to-speech endpoint.\nConverts input text to speech audio using a specified speaker voice.\n\nArgs:\n    request (Request): The incoming HTTP request object (required for rate limiting).\n    tts_request (TTSRequest): The request body containing text, speaker ID, and synthesis parameters.\n    background_tasks (BackgroundTasks): FastAPI background tasks for logging.\n    current_user (User): The authenticated user making the request.\n\nReturns:\n    dict: A dictionary containing the generated speech audio with signed URL and metadata.\n\nRaises:\n    HTTPException: Returns 503 if the service is unavailable due to timeout or connection error.\n    HTTPException: Returns 500 for any other internal server errors.\n\nSpeaker IDs:\n    241: Acholi (female)\n    242: Ateso (female)\n    243: Runyankore (female)\n    245: Lugbara (female)\n    246: Swahili (male)\n    248: Luganda (female)\n\nExample Response:\n    {\n        \"output\": {\n            \"audio_url\": \"https:...\",\n            \"blob\": \"tts/20251003082338_f2ff97b3-9cb9-42fb-850d-0657f51e539e.mp3\",\n            \"sample_rate\": 16000\n        }\n    }","operationId":"text_to_speech_tasks_tts_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/app__schemas__tasks__TTSRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"deprecated":true,"security":[{"OAuth2PasswordBearer":[]}]}},"/tasks/modal/health":{"get":{"tags":["TTS (Modal)"],"summary":"Health Check","description":"Check if the service is healthy.","operationId":"health_check_tasks_modal_health_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HealthResponse"}}}}}}},"/tasks/modal/tts/speakers":{"get":{"tags":["TTS (Modal)"],"summary":"List Available Speakers","description":"Get all available speaker voices for TTS generation.","operationId":"list_speakers_tasks_modal_tts_speakers_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SpeakersListResponse"}}}}},"security":[{"OAuth2PasswordBearer":[]}]}},"/tasks/modal/tts":{"post":{"tags":["TTS (Modal)"],"summary":"Generate Text-to-Speech Audio","description":"Convert text to speech and return a signed URL to the audio file.","operationId":"generate_tts_tasks_modal_tts_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/app__schemas__tts__TTSRequest"}}},"required":true},"responses":{"200":{"description":"Audio generated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TTSResponse-Input"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"OAuth2PasswordBearer":[]}]}},"/tasks/modal/tts/stream":{"post":{"tags":["TTS (Modal)"],"summary":"Stream TTS Audio","description":"Stream audio chunks as they are generated.","operationId":"stream_tts_tasks_modal_tts_stream_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/app__schemas__tts__TTSRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"OAuth2PasswordBearer":[]}]}},"/tasks/modal/tts/stream-with-url":{"post":{"tags":["TTS (Modal)"],"summary":"Stream TTS Audio with Final URL","description":"Stream audio chunks and return a signed URL at completion.","operationId":"stream_tts_with_url_tasks_modal_tts_stream_with_url_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/app__schemas__tts__TTSRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"OAuth2PasswordBearer":[]}]}},"/tasks/modal/tts/refresh-url":{"get":{"tags":["TTS (Modal)"],"summary":"Refresh Signed URL","description":"Generate a new signed URL for an existing audio file.","operationId":"refresh_signed_url_tasks_modal_tts_refresh_url_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"file_name","in":"query","required":true,"schema":{"type":"string","description":"The file name in GCP Storage","title":"File Name"},"description":"The file name in GCP Storage"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TTSResponse-Output"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/tasks/runpod/tts":{"post":{"tags":["TTS (RunPod)"],"summary":"Text To Speech","description":"RunPod Text-to-Speech endpoint.\nConverts input text to speech audio using a specified speaker voice.\n\nThis endpoint uses the RunPod inference server for TTS generation.\n\nArgs:\n\n    request (Request): The incoming HTTP request object (required for rate limiting).\n    tts_request (TTSRequest): The request body containing text, speaker ID, and synthesis parameters.\n    background_tasks (BackgroundTasks): FastAPI background tasks for logging.\n    current_user (User): The authenticated user making the request.\n\nReturns:\n\n    dict: A dictionary containing the generated speech audio with signed URL and metadata.\n\nRaises:\n\n    BadRequestError: For invalid input parameters.\n    ValidationError: For invalid speaker_id, temperature, or max_new_audio_tokens.\n    ServiceUnavailableError: If the service is unavailable due to timeout.\n    ExternalServiceError: For connection errors or worker errors.\n\nSpeaker IDs:\n\n    241: Acholi (female)\n    242: Ateso (female)\n    243: Runyankore (female)\n    245: Lugbara (female)\n    246: Swahili (male)\n    248: Luganda (female)\n\nExample Response:\n    {\n        \"output\": {\n            \"audio_url\": \"https:...\",\n            \"blob\": \"tts/20251003082338_f2ff97b3-9cb9-42fb-850d-0657f51e539e.mp3\",\n            \"sample_rate\": 16000\n        }\n    }","operationId":"text_to_speech_tasks_runpod_tts_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/app__schemas__tasks__TTSRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"OAuth2PasswordBearer":[]}]}},"/api/dashboard/usage":{"get":{"tags":["Dashboard"],"summary":"Get Usage Stats","description":"Get usage statistics for the current user","operationId":"get_usage_stats_api_dashboard_usage_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"time_range","in":"query","required":false,"schema":{"type":"string","default":"7d","title":"Time Range"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/admin/analytics/filters":{"get":{"tags":["Admin Analytics"],"summary":"Get Filter Options","description":"Return available filter values for admin analytics dropdowns.","operationId":"get_filter_options_api_admin_analytics_filters_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"OAuth2PasswordBearer":[]}]}},"/api/admin/analytics/overview":{"get":{"tags":["Admin Analytics"],"summary":"Get Overview","description":"Get overall usage analytics across all users.","operationId":"get_overview_api_admin_analytics_overview_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"time_range","in":"query","required":false,"schema":{"type":"string","default":"7d","title":"Time Range"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/admin/analytics/by-organization":{"get":{"tags":["Admin Analytics"],"summary":"Get By Organization","description":"Get usage analytics filtered by organization, with per-user breakdown.","operationId":"get_by_organization_api_admin_analytics_by_organization_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"organization","in":"query","required":true,"schema":{"type":"string","title":"Organization"}},{"name":"time_range","in":"query","required":false,"schema":{"type":"string","default":"7d","title":"Time Range"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/admin/analytics/by-organization-type":{"get":{"tags":["Admin Analytics"],"summary":"Get By Organization Type","description":"Get usage analytics filtered by organization type.","operationId":"get_by_organization_type_api_admin_analytics_by_organization_type_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"organization_type","in":"query","required":true,"schema":{"type":"string","title":"Organization Type"}},{"name":"time_range","in":"query","required":false,"schema":{"type":"string","default":"7d","title":"Time Range"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/admin/analytics/by-sector":{"get":{"tags":["Admin Analytics"],"summary":"Get By Sector","description":"Get usage analytics filtered by sector.","operationId":"get_by_sector_api_admin_analytics_by_sector_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"sector","in":"query","required":true,"schema":{"type":"string","title":"Sector"}},{"name":"time_range","in":"query","required":false,"schema":{"type":"string","default":"7d","title":"Time Range"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/admin/analytics/export":{"get":{"tags":["Admin Analytics"],"summary":"Export Csv","description":"Export aggregated analytics data as CSV.","operationId":"export_csv_api_admin_analytics_export_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"view","in":"query","required":false,"schema":{"type":"string","default":"overview","title":"View"}},{"name":"time_range","in":"query","required":false,"schema":{"type":"string","default":"7d","title":"Time Range"}},{"name":"organization","in":"query","required":false,"schema":{"type":"string","title":"Organization"}},{"name":"organization_type","in":"query","required":false,"schema":{"type":"string","title":"Organization Type"}},{"name":"sector","in":"query","required":false,"schema":{"type":"string","title":"Sector"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/{full_path}":{"get":{"tags":["Dashboard"],"summary":"Serve Spa","description":"Serve the React Single Page Application.\nAny route not matched by other API routers will fall back to this,\nreturning index.html so React Router can handle the routing.","operationId":"serve_spa__full_path__get","parameters":[{"name":"full_path","in":"path","required":true,"schema":{"type":"string","title":"Full Path"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}},"components":{"schemas":{"AccountType":{"type":"string","enum":["Free","Premium","Admin"],"title":"AccountType"},"AudioDetectedLanguageResponse":{"properties":{"detected_language":{"type":"string","title":"Detected Language","description":"The detected language code from the audio"}},"type":"object","required":["detected_language"],"title":"AudioDetectedLanguageResponse","description":"Response model for audio language detection.\n\nThis model represents the response from audio language detection operations.\n\nAttributes:\n    detected_language: The detected language code from the audio.\n\nExample:\n    >>> response = AudioDetectedLanguageResponse(detected_language=\"lug\")"},"Body_auto_detect_audio_language_tasks_auto_detect_audio_language_post":{"properties":{"audio":{"type":"string","format":"binary","title":"Audio"}},"type":"object","required":["audio"],"title":"Body_auto_detect_audio_language_tasks_auto_detect_audio_language_post"},"Body_login_for_access_token_auth_token_post":{"properties":{"grant_type":{"anyOf":[{"type":"string","pattern":"password"},{"type":"null"}],"title":"Grant Type"},"username":{"type":"string","title":"Username"},"password":{"type":"string","title":"Password"},"scope":{"type":"string","title":"Scope","default":""},"client_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Client Id"},"client_secret":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Client Secret"}},"type":"object","required":["username","password"],"title":"Body_login_for_access_token_auth_token_post"},"Body_modal_speech_to_text_tasks_modal_stt_post":{"properties":{"audio":{"type":"string","format":"binary","title":"Audio","description":"Audio file to transcribe"},"language":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Language","description":"Optional language hint for better transcriptions especially in local languages. Accepts a 3-letter ISO 639-2 code (e.g. 'eng', 'lug') or a full language name (e.g. 'english', 'luganda'). If omitted, the model auto-detects the language."}},"type":"object","required":["audio"],"title":"Body_modal_speech_to_text_tasks_modal_stt_post"},"Body_speech_to_text_from_gcs_tasks_stt_from_gcs_post":{"properties":{"gcs_blob_name":{"type":"string","title":"Gcs Blob Name"},"language":{"$ref":"#/components/schemas/SttbLanguage","default":"lug"},"adapter":{"$ref":"#/components/schemas/SttbLanguage","default":"lug"},"recognise_speakers":{"type":"boolean","title":"Recognise Speakers","default":false},"whisper":{"type":"boolean","title":"Whisper","default":false}},"type":"object","required":["gcs_blob_name"],"title":"Body_speech_to_text_from_gcs_tasks_stt_from_gcs_post"},"Body_speech_to_text_org_tasks_org_stt_post":{"properties":{"audio":{"type":"string","format":"binary","title":"Audio"},"recognise_speakers":{"type":"boolean","title":"Recognise Speakers","default":false}},"type":"object","required":["audio"],"title":"Body_speech_to_text_org_tasks_org_stt_post"},"Body_speech_to_text_tasks_stt_post":{"properties":{"audio":{"type":"string","format":"binary","title":"Audio","description":"Audio file to transcribe"},"language":{"$ref":"#/components/schemas/SttbLanguage","default":"lug"},"adapter":{"$ref":"#/components/schemas/SttbLanguage","default":"lug"},"recognise_speakers":{"type":"boolean","title":"Recognise Speakers","default":false},"whisper":{"type":"boolean","title":"Whisper","default":false}},"type":"object","required":["audio"],"title":"Body_speech_to_text_tasks_stt_post"},"Body_sunflower_simple_inference_tasks_sunflower_simple_post":{"properties":{"instruction":{"type":"string","title":"Instruction","description":"The instruction or question for the AI"},"model_type":{"type":"string","title":"Model Type","description":"Model type (qwen or gemma)","default":"qwen"},"temperature":{"type":"number","maximum":2.0,"minimum":0.0,"title":"Temperature","description":"Sampling temperature","default":0.3},"system_message":{"type":"string","title":"System Message","description":"Custom system message"}},"type":"object","required":["instruction"],"title":"Body_sunflower_simple_inference_tasks_sunflower_simple_post"},"ChangePassword":{"properties":{"old_password":{"type":"string","title":"Old Password"},"new_password":{"type":"string","title":"New Password"}},"type":"object","required":["old_password","new_password"],"title":"ChangePassword"},"ErrorResponse":{"properties":{"success":{"type":"boolean","title":"Success","default":false},"error":{"type":"string","title":"Error","description":"Error message"},"detail":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Detail","description":"Detailed error information"}},"type":"object","required":["error"],"title":"ErrorResponse","description":"Error response model."},"ForgotPassword":{"properties":{"email":{"type":"string","format":"email","title":"Email"}},"type":"object","required":["email"],"title":"ForgotPassword"},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"HealthResponse":{"properties":{"status":{"type":"string","title":"Status","description":"Service status"},"service":{"type":"string","title":"Service","description":"Service name"},"version":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Version","description":"Service version"}},"type":"object","required":["status","service"],"title":"HealthResponse","description":"Health check response."},"LanguageIdRequest":{"properties":{"text":{"type":"string","maxLength":200,"minLength":3,"title":"Text","description":"The text to identify the language of"}},"type":"object","required":["text"],"title":"LanguageIdRequest","description":"Request model for language identification.\n\nThis model validates language identification requests with text input.\n\nAttributes:\n    text: The text to identify the language of (3-200 characters).\n\nExample:\n    >>> request = LanguageIdRequest(text=\"Oli otya?\")"},"LanguageIdResponse":{"properties":{"language":{"type":"string","title":"Language","description":"The identified language code"}},"type":"object","required":["language"],"title":"LanguageIdResponse","description":"Response model for language identification.\n\nThis model represents the response from language identification operations.\n\nAttributes:\n    language: The identified language code (e.g., 'lug', 'eng', 'ach').\n\nExample:\n    >>> response = LanguageIdResponse(language=\"lug\")"},"NllbLanguage":{"type":"string","enum":["ach","teo","eng","lug","lgg","nyn"],"title":"NllbLanguage","description":"Supported languages for NLLB translation.\n\nThis enum defines the language codes supported by the NLLB translation\nservice. Each value represents an ISO 639-3 language code.\n\nAttributes:\n    acholi: Acholi language (ach).\n    ateso: Ateso language (teo).\n    english: English language (eng).\n    luganda: Luganda language (lug).\n    lugbara: Lugbara language (lgg).\n    runyankole: Runyankole language (nyn)."},"NllbTranslationRequest":{"properties":{"source_language":{"$ref":"#/components/schemas/NllbLanguage","description":"The source language for translation"},"target_language":{"$ref":"#/components/schemas/NllbLanguage","description":"The target language for translation"},"text":{"type":"string","minLength":1,"title":"Text","description":"The text to translate"}},"type":"object","required":["source_language","target_language","text"],"title":"NllbTranslationRequest","description":"Request model for NLLB text translation.\n\nThis model validates translation requests with source and target\nlanguages along with the text to translate.\n\nAttributes:\n    source_language: The source language for translation.\n    target_language: The target language for translation.\n    text: The text to translate (min 1 character, whitespace stripped).\n\nExample:\n    >>> request = NllbTranslationRequest(\n    ...     source_language=NllbLanguage.english,\n    ...     target_language=NllbLanguage.luganda,\n    ...     text=\"Hello world\"\n    ... )"},"OAuthType":{"type":"string","enum":["Credentials","Google","GitHub"],"title":"OAuthType"},"ProfileCompletionStatus":{"properties":{"is_complete":{"type":"boolean","title":"Is Complete"},"missing_fields":{"items":{"type":"string"},"type":"array","title":"Missing Fields"}},"type":"object","required":["is_complete","missing_fields"],"title":"ProfileCompletionStatus"},"ProfileUpdate":{"properties":{"full_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Full Name"},"organization":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Organization"},"organization_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Organization Type"},"sector":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Sector"}},"type":"object","title":"ProfileUpdate"},"ResetPassword":{"properties":{"token":{"type":"string","title":"Token"},"new_password":{"type":"string","title":"New Password"}},"type":"object","required":["token","new_password"],"title":"ResetPassword"},"STTTranscript":{"properties":{"audio_transcription":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Audio Transcription","description":"The transcribed text from the audio"},"diarization_output":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Diarization Output","description":"Speaker diarization data"},"formatted_diarization_output":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Formatted Diarization Output","description":"Human-readable diarization output"},"audio_transcription_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Audio Transcription Id","description":"Database ID of the saved transcription"},"audio_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Audio Url","description":"URL or path to the processed audio file"},"language":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Language","description":"The language code used for transcription"},"was_audio_trimmed":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Was Audio Trimmed","description":"Whether the audio was trimmed to max duration","default":false},"original_duration_minutes":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Original Duration Minutes","description":"Original duration in minutes if audio was trimmed"}},"type":"object","title":"STTTranscript","description":"Response model for speech-to-text transcription results.\n\nThis model represents the output of an STT transcription request,\nincluding the transcribed text, diarization data, and metadata.\n\nAttributes:\n    audio_transcription: The transcribed text from the audio.\n    diarization_output: Speaker diarization data as a dictionary.\n    formatted_diarization_output: Human-readable diarization output.\n    audio_transcription_id: Database ID of the saved transcription.\n    audio_url: URL or path to the processed audio file.\n    language: The language code used for transcription.\n    was_audio_trimmed: Whether the audio was trimmed to max duration.\n    original_duration_minutes: Original duration if audio was trimmed."},"SpeakerID-Output":{"type":"integer","enum":[241,242,243,245,246,248],"title":"SpeakerID","description":"Available speaker voices for TTS generation.\n\nEach speaker represents a different language/voice combination\nsupported by the TTS service."},"SpeakerInfo":{"properties":{"id":{"type":"integer","title":"Id","description":"Speaker ID"},"name":{"type":"string","title":"Name","description":"Speaker enum name"},"display_name":{"type":"string","title":"Display Name","description":"Human-readable name"},"language":{"type":"string","title":"Language","description":"Language"},"gender":{"type":"string","title":"Gender","description":"Gender"}},"type":"object","required":["id","name","display_name","language","gender"],"title":"SpeakerInfo","description":"Information about a speaker voice."},"SpeakersListResponse":{"properties":{"speakers":{"items":{"$ref":"#/components/schemas/SpeakerInfo"},"type":"array","title":"Speakers","description":"List of available speakers"}},"type":"object","required":["speakers"],"title":"SpeakersListResponse","description":"Response containing all available speakers."},"SttbLanguage":{"type":"string","enum":["ach","teo","eng","lug","lgg","nyn","swa","kin","xog","myx"],"title":"SttbLanguage","description":"Supported languages for Speech-to-Text transcription.\n\nThis enum defines the language codes supported by the STT service.\nEach value represents an ISO 639-3 language code.\n\nAttributes:\n    acholi: Acholi language (ach).\n    ateso: Ateso language (teo).\n    english: English language (eng).\n    luganda: Luganda language (lug).\n    lugbara: Lugbara language (lgg).\n    runyankole: Runyankole language (nyn).\n    swahili: Swahili language (swa).\n    kinyarwanda: Kinyarwanda language (kin).\n    lusoga: Lusoga language (xog).\n    lumasaba: Lumasaba language (myx)."},"SummarisationRequest":{"properties":{"text":{"type":"string","title":"Text"}},"type":"object","required":["text"],"title":"SummarisationRequest"},"SummarisationResponse":{"properties":{"summarized_text":{"type":"string","title":"Summarized Text"}},"type":"object","required":["summarized_text"],"title":"SummarisationResponse"},"SunflowerChatMessage":{"properties":{"role":{"type":"string","title":"Role","description":"Message role: 'system', 'user', or 'assistant'"},"content":{"type":"string","title":"Content","description":"Message content"}},"type":"object","required":["role","content"],"title":"SunflowerChatMessage","description":"A single message in the chat conversation.\n\nAttributes:\n    role: The role of the message sender ('system', 'user', or 'assistant').\n    content: The content of the message."},"SunflowerChatRequest":{"properties":{"messages":{"items":{"$ref":"#/components/schemas/SunflowerChatMessage"},"type":"array","title":"Messages","description":"List of conversation messages"},"model_type":{"type":"string","title":"Model Type","description":"Model type: 'qwen'","default":"qwen"},"temperature":{"type":"number","maximum":2.0,"minimum":0.0,"title":"Temperature","description":"Sampling temperature","default":0.3},"stream":{"type":"boolean","title":"Stream","description":"Whether to stream the response","default":false},"system_message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"System Message","description":"Custom system message"}},"type":"object","required":["messages"],"title":"SunflowerChatRequest","description":"Request model for Sunflower chat inference.\n\nAttributes:\n    messages: List of conversation messages.\n    model_type: The model to use ('qwen').\n    temperature: Sampling temperature (0.0 to 2.0).\n    stream: Whether to stream the response.\n    system_message: Optional custom system message."},"SunflowerChatResponse":{"properties":{"content":{"type":"string","title":"Content","description":"The AI's response"},"model_type":{"type":"string","title":"Model Type","description":"Model used for inference"},"usage":{"$ref":"#/components/schemas/SunflowerUsageStats","description":"Token usage statistics"},"processing_time":{"type":"number","title":"Processing Time","description":"Total processing time in seconds"},"inference_time":{"type":"number","title":"Inference Time","description":"Model inference time in seconds","default":0.0},"message_count":{"type":"integer","title":"Message Count","description":"Number of messages processed","default":0}},"type":"object","required":["content","model_type","usage","processing_time"],"title":"SunflowerChatResponse","description":"Response model from Sunflower chat inference.\n\nAttributes:\n    content: The AI's response text.\n    model_type: The model used for inference.\n    usage: Token usage statistics.\n    processing_time: Total processing time in seconds.\n    inference_time: Model inference time in seconds.\n    message_count: Number of messages processed."},"SunflowerUsageStats":{"properties":{"completion_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Completion Tokens","description":"Number of tokens in the completion"},"prompt_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Prompt Tokens","description":"Number of tokens in the prompt"},"total_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Total Tokens","description":"Total number of tokens used"}},"type":"object","title":"SunflowerUsageStats","description":"Token usage statistics from the inference.\n\nAttributes:\n    completion_tokens: Number of tokens in the completion.\n    prompt_tokens: Number of tokens in the prompt.\n    total_tokens: Total number of tokens used."},"TTSResponse-Input":{"properties":{"success":{"type":"boolean","title":"Success","description":"Whether the request was successful"},"audio_url":{"type":"string","title":"Audio Url","description":"Signed URL to access the audio file"},"expires_at":{"type":"string","format":"date-time","title":"Expires At","description":"When the signed URL expires"},"file_name":{"type":"string","title":"File Name","description":"Name of the audio file in storage"},"duration_estimate_seconds":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Duration Estimate Seconds","description":"Estimated audio duration in seconds"},"text_length":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Text Length","description":"Length of the input text"},"speaker_id":{"anyOf":[{"$ref":"#/components/schemas/app__models__enums__SpeakerID"},{"type":"null"}],"description":"Speaker voice used for generation"},"speaker_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Speaker Name","description":"Human-readable speaker name"}},"type":"object","required":["success","audio_url","expires_at","file_name"],"title":"TTSResponse","description":"Response model for TTS generation (URL mode)."},"TTSResponse-Output":{"properties":{"success":{"type":"boolean","title":"Success","description":"Whether the request was successful"},"audio_url":{"type":"string","title":"Audio Url","description":"Signed URL to access the audio file"},"expires_at":{"type":"string","format":"date-time","title":"Expires At","description":"When the signed URL expires"},"file_name":{"type":"string","title":"File Name","description":"Name of the audio file in storage"},"duration_estimate_seconds":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Duration Estimate Seconds","description":"Estimated audio duration in seconds"},"text_length":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Text Length","description":"Length of the input text"},"speaker_id":{"anyOf":[{"$ref":"#/components/schemas/SpeakerID-Output"},{"type":"null"}],"description":"Speaker voice used for generation"},"speaker_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Speaker Name","description":"Human-readable speaker name"}},"type":"object","required":["success","audio_url","expires_at","file_name"],"title":"TTSResponse","description":"Response model for TTS generation (URL mode)."},"TTSResponseMode":{"type":"string","enum":["url","stream","both"],"title":"TTSResponseMode","description":"Response mode for the TTS endpoint.\n\nAttributes:\n    URL: Return only the signed URL after generation completes\n    STREAM: Stream audio chunks directly to the client\n    BOTH: Stream audio chunks AND return a signed URL at the end"},"Token":{"properties":{"access_token":{"type":"string","title":"Access Token"},"token_type":{"type":"string","title":"Token Type"}},"type":"object","required":["access_token","token_type"],"title":"Token"},"UploadRequest":{"properties":{"file_name":{"type":"string","maxLength":255,"minLength":1,"title":"File Name","description":"Name of the file to upload","example":"recording.wav"},"content_type":{"type":"string","maxLength":100,"minLength":1,"title":"Content Type","description":"MIME type of the file","example":"audio/wav"}},"type":"object","required":["file_name","content_type"],"title":"UploadRequest","description":"Request model for generating a signed upload URL.\n\nAttributes:\n    file_name: Name of the file to upload.\n    content_type: MIME type of the file (e.g., \"audio/wav\", \"image/png\").\n\nExample:\n    {\n        \"file_name\": \"recording.wav\",\n        \"content_type\": \"audio/wav\"\n    }"},"UploadResponse":{"properties":{"upload_url":{"type":"string","title":"Upload Url","description":"Pre-signed URL for direct upload to GCS"},"file_id":{"type":"string","title":"File Id","description":"Unique identifier for tracking the upload"},"expires_at":{"type":"string","format":"date-time","title":"Expires At","description":"When the upload URL expires"}},"type":"object","required":["upload_url","file_id","expires_at"],"title":"UploadResponse","description":"Response model for upload URL generation.\n\nAttributes:\n    upload_url: Pre-signed URL for direct upload to GCS.\n    file_id: Unique identifier for the uploaded file.\n    expires_at: When the upload URL expires.\n\nExample:\n    {\n        \"upload_url\": \"https://storage.googleapis.com/...\",\n        \"file_id\": \"550e8400-e29b-41d4-a716-446655440000\",\n        \"expires_at\": \"2024-01-15T10:30:00Z\"\n    }"},"User":{"properties":{"username":{"type":"string","title":"Username"},"email":{"type":"string","format":"email","title":"Email"},"organization":{"type":"string","title":"Organization"},"account_type":{"$ref":"#/components/schemas/AccountType","default":"Free"},"oauth_type":{"$ref":"#/components/schemas/OAuthType","default":"Credentials"},"full_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Full Name"},"organization_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Organization Type"},"sector":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Sector"},"id":{"type":"integer","title":"Id"}},"type":"object","required":["username","email","organization","id"],"title":"User"},"UserCreate":{"properties":{"username":{"type":"string","title":"Username"},"email":{"type":"string","format":"email","title":"Email"},"organization":{"type":"string","title":"Organization"},"account_type":{"$ref":"#/components/schemas/AccountType","default":"Free"},"oauth_type":{"$ref":"#/components/schemas/OAuthType","default":"Credentials"},"full_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Full Name"},"organization_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Organization Type"},"sector":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Sector"},"password":{"type":"string","title":"Password"}},"type":"object","required":["username","email","organization","password"],"title":"UserCreate"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"},"WebhookResponse":{"properties":{"status":{"type":"string","title":"Status","description":"Status of the webhook processing","example":"success"},"processing_time":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Processing Time","description":"Time taken to process the webhook in seconds"},"message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Message","description":"Additional information about the processing"}},"type":"object","required":["status"],"title":"WebhookResponse","description":"Response model for webhook handling.\n\nAttributes:\n    status: Status of the webhook processing.\n    processing_time: Time taken to process the webhook (optional).\n    message: Additional information about the processing (optional).\n\nExample:\n    {\n        \"status\": \"success\",\n        \"processing_time\": 2.5\n    }"},"WorkerTranslationOutput":{"properties":{"text":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Text","description":"Translated text output"},"translated_text":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Translated Text","description":"Alternative translated text field"},"source_language":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source Language","description":"Source language code if returned"},"target_language":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Target Language","description":"Target language code if returned"},"Error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error","description":"Error message if translation failed"}},"additionalProperties":true,"type":"object","title":"WorkerTranslationOutput","description":"Output model for translation worker results.\n\nThis model represents the output from the RunPod translation worker.\nIt handles various response formats from the worker.\n\nAttributes:\n    text: The translated text (some workers use this field).\n    translated_text: The translated text (alternative field name).\n    source_language: The source language code if returned.\n    target_language: The target language code if returned.\n    error: Error message if translation failed."},"WorkerTranslationResponse":{"properties":{"delayTime":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Delaytime","description":"Time spent waiting in queue (ms)"},"executionTime":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Executiontime","description":"Time spent executing the job (ms)"},"id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Id","description":"Unique job identifier"},"output":{"anyOf":[{"$ref":"#/components/schemas/WorkerTranslationOutput"},{"type":"null"}],"description":"The translation output data"},"status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status","description":"Job status (e.g., COMPLETED, FAILED)"},"workerId":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Workerid","description":"Identifier of the worker that processed the job"}},"additionalProperties":true,"type":"object","title":"WorkerTranslationResponse","description":"Response model for translation worker API calls.\n\nThis model wraps the translation worker output with metadata\nabout the job execution.\n\nAttributes:\n    delayTime: Time spent waiting in queue (ms).\n    executionTime: Time spent executing the job (ms).\n    id: Unique job identifier.\n    output: The translation output data.\n    status: Job status (e.g., \"COMPLETED\", \"FAILED\").\n    workerId: Identifier of the worker that processed the job."},"app__models__enums__SpeakerID":{"type":"integer","enum":[241,242,243,245,246,248],"title":"SpeakerID","description":"Available speaker voices for TTS generation.\n\nEach speaker represents a different language/voice combination\nsupported by the TTS service."},"app__schemas__tasks__SpeakerID":{"type":"integer","enum":[241,242,243,245,246,248],"title":"SpeakerID"},"app__schemas__tasks__TTSRequest":{"properties":{"text":{"type":"string","title":"Text"},"speaker_id":{"$ref":"#/components/schemas/app__schemas__tasks__SpeakerID","default":248},"temperature":{"type":"number","title":"Temperature","default":0.7},"max_new_audio_tokens":{"type":"integer","title":"Max New Audio Tokens","default":2000}},"type":"object","required":["text"],"title":"TTSRequest"},"app__schemas__tts__TTSRequest":{"properties":{"text":{"type":"string","maxLength":10000,"minLength":1,"title":"Text","description":"Text to convert to speech","examples":["Hello, this is a text-to-speech test."]},"speaker_id":{"$ref":"#/components/schemas/app__models__enums__SpeakerID","description":"Speaker voice for TTS generation","default":248,"examples":[248,246]},"response_mode":{"$ref":"#/components/schemas/TTSResponseMode","description":"How to return the audio: 'url' for signed URL, 'stream' for streaming, 'both' for streaming with final URL","default":"url"}},"type":"object","required":["text"],"title":"TTSRequest","description":"Request model for TTS generation.","examples":[{"response_mode":"url","speaker_id":248,"text":"I am a nurse who takes care of many people."}]}},"securitySchemes":{"OAuth2PasswordBearer":{"type":"oauth2","flows":{"password":{"scopes":{},"tokenUrl":"/auth/token"}}}}},"tags":[{"name":"Authentication Endpoints","description":"Operations for authentication, including user registration and login. Get access tokens to use protected endpoints."},{"name":"Speech-to-Text","description":"Convert speech audio to text. Supports English, Acholi, Ateso, Luganda, Lugbara, and Runyankole."},{"name":"Translation","description":"Translate text between English and local languages using the NLLB model. Supports bidirectional translation for Acholi, Ateso, Luganda, Lugbara, and Runyankole."},{"name":"Language","description":"Language identification and detection. Automatically detect the language of text input from supported languages."},{"name":"TTS (Modal)","description":"Modal-based Text-to-Speech services for Ugandan languages. Generate audio from text with support for streaming, signed URLs, and multiple language voices."},{"name":"TTS (RunPod)","description":"RunPod-based Text-to-Speech services for Ugandan languages. Fast inference using RunPod serverless infrastructure with support for multiple speaker voices."},{"name":"Sunflower","description":"Conversational AI powered by the Sunflower model. Supports chat-based interactions with context and simple text generation."},{"name":"Upload","description":"File upload utilities. Generate signed URLs for direct client uploads to GCP Storage with security validation."},{"name":"Webhooks","description":"WhatsApp Business API webhook integration. Handle incoming messages and verify webhook endpoints for WhatsApp chatbot functionality."},{"name":"AI Tasks","description":"Legacy AI task endpoints. Contains deprecated endpoints maintained for backward compatibility."},{"name":"Frontend Routes","description":"Web interface routes for the Sunbird AI application."}]}