AI coaching service (backend/app/services/ai_provider.py): - Two code paths: OpenAI-compatible (6 providers) + Anthropic (Claude) - Streaming SSE responses via httpx async - System prompt built from AGENT_GUIDE + live user context - Graceful error handling for all provider failures - Gemini adapter for Google's generateContent API Chat endpoint (backend/app/routers/ai_chat.py): - POST /api/ai/chat — SSE streaming response - GET /api/ai/status — check configured provider - History capped at 20 messages, content at 4K chars Provider registry expanded to 20 providers: - 9 device integrations (strava, polar, garmin, whoop, oura, coros, fitbit, withings, suunto) - 8 AI providers (openai, openrouter, huggingface, groq, ollama, claude, gemini, custom_ai) - 3 other (usda, nutritionix, telegram) - Categorized: device, ai_provider, nutrition, notifications - COROS: MCP bridge approach (no API integration needed) - Strava: AI/ML warning per their ToS Frontend ChatCoach.jsx to follow in next commit.
235 lines
9 KiB
Python
235 lines
9 KiB
Python
"""Provider registry — drives integration UI cards and agent help text."""
|
|
from __future__ import annotations
|
|
|
|
PROVIDER_REGISTRY: dict[str, dict] = {
|
|
|
|
# ═══ Device Integrations ═══
|
|
|
|
"strava": {
|
|
"name": "Strava",
|
|
"type": "oauth2",
|
|
"category": "device",
|
|
"fields": ["client_id", "client_secret"],
|
|
"auth_url": "https://www.strava.com/oauth/authorize",
|
|
"token_url": "https://www.strava.com/oauth/token",
|
|
"scopes": "read,activity:read_all",
|
|
"help_url": "https://developers.strava.com/",
|
|
"help_text": "Create an app at developers.strava.com. Set the callback URL to {BASE_URL}/api/integrations/strava/callback",
|
|
"warning": "Strava ToS prohibits use of their data for AI/ML. Activity sync works but AI coaching should not reference Strava data.",
|
|
"has_webhook": False,
|
|
"sync_service": "strava_sync",
|
|
},
|
|
"polar": {
|
|
"name": "Polar",
|
|
"type": "oauth2",
|
|
"category": "device",
|
|
"fields": ["client_id", "client_secret"],
|
|
"auth_url": "https://flow.polar.com/oauth2/authorization",
|
|
"token_url": "https://polarremote.com/v2/oauth2/token",
|
|
"help_url": "https://admin.polaraccesslink.com/",
|
|
"help_text": "Register at admin.polaraccesslink.com",
|
|
"has_webhook": False,
|
|
"sync_service": "polar_sync",
|
|
},
|
|
"garmin": {
|
|
"name": "Garmin Connect",
|
|
"type": "oauth2",
|
|
"category": "device",
|
|
"fields": ["client_id", "client_secret"],
|
|
"auth_url": "https://connect.garmin.com/oauthConfirm",
|
|
"token_url": "https://connectapi.garmin.com/oauth-service/oauth/token",
|
|
"scopes": "HEALTH,ACTIVITY",
|
|
"help_url": "https://developer.garmin.com/gc-developer-program/",
|
|
"help_text": "Apply at developer.garmin.com — approval ~2 business days, requires a business entity.",
|
|
"has_webhook": True,
|
|
"sync_service": "garmin_sync",
|
|
},
|
|
"whoop": {
|
|
"name": "WHOOP",
|
|
"type": "oauth2",
|
|
"category": "device",
|
|
"fields": ["client_id", "client_secret"],
|
|
"auth_url": "https://api.prod.whoop.com/oauth/oauth2/auth",
|
|
"token_url": "https://api.prod.whoop.com/oauth/oauth2/token",
|
|
"scopes": "read:workout,read:recovery,read:sleep,read:profile,offline",
|
|
"help_url": "https://developer.whoop.com/",
|
|
"help_text": "Self-serve at developer.whoop.com. Requires WHOOP device. <10 users without app approval.",
|
|
"has_webhook": True,
|
|
"sync_service": "whoop_sync",
|
|
},
|
|
"oura": {
|
|
"name": "Oura Ring",
|
|
"type": "oauth2",
|
|
"category": "device",
|
|
"fields": ["client_id", "client_secret"],
|
|
"auth_url": "https://cloud.ouraring.com/oauth/authorize",
|
|
"token_url": "https://api.ouraring.com/oauth/token",
|
|
"scopes": "daily,workout,heartrate,session",
|
|
"help_url": "https://cloud.ouraring.com/v2/docs",
|
|
"help_text": "Register at cloud.ouraring.com — self-serve, immediate access.",
|
|
"has_webhook": True,
|
|
"sync_service": "oura_sync",
|
|
},
|
|
"coros": {
|
|
"name": "COROS (via MCP)",
|
|
"type": "mcp_bridge",
|
|
"category": "device",
|
|
"fields": [],
|
|
"help_url": "https://support.coros.com/hc/en-us/articles/17085887816340",
|
|
"help_text": "COROS has an official MCP server. Add it alongside Diligence in your AI agent config.",
|
|
"has_webhook": False,
|
|
"sync_service": None,
|
|
},
|
|
"fitbit": {
|
|
"name": "Fitbit",
|
|
"type": "oauth2",
|
|
"category": "device",
|
|
"fields": ["client_id", "client_secret"],
|
|
"auth_url": "https://www.fitbit.com/oauth2/authorize",
|
|
"token_url": "https://api.fitbit.com/oauth2/token",
|
|
"help_url": "https://dev.fitbit.com/",
|
|
"help_text": "Register at dev.fitbit.com via Google Cloud Console.",
|
|
"has_webhook": True,
|
|
"sync_service": None,
|
|
},
|
|
"withings": {
|
|
"name": "Withings",
|
|
"type": "oauth2",
|
|
"category": "device",
|
|
"fields": ["client_id", "client_secret"],
|
|
"help_url": "https://developer.withings.com/",
|
|
"help_text": "Register at developer.withings.com — body metrics, scales, blood pressure.",
|
|
"has_webhook": False,
|
|
"sync_service": None,
|
|
},
|
|
"suunto": {
|
|
"name": "Suunto",
|
|
"type": "oauth2",
|
|
"category": "device",
|
|
"fields": ["client_id", "client_secret"],
|
|
"help_url": "https://apizone.suunto.com/",
|
|
"help_text": "Apply at Suunto developer portal — contract required, ~2 week response.",
|
|
"has_webhook": True,
|
|
"sync_service": None,
|
|
},
|
|
|
|
# ═══ AI Coaching Providers ═══
|
|
|
|
"openai": {
|
|
"name": "OpenAI",
|
|
"type": "api_key",
|
|
"category": "ai_provider",
|
|
"fields": ["api_key"],
|
|
"base_url": "https://api.openai.com/v1",
|
|
"api_format": "openai",
|
|
"help_url": "https://platform.openai.com/api-keys",
|
|
"help_text": "Get API key from platform.openai.com. Models: gpt-4o, gpt-4o-mini.",
|
|
"default_model": "gpt-4o-mini",
|
|
},
|
|
"openrouter": {
|
|
"name": "OpenRouter",
|
|
"type": "api_key",
|
|
"category": "ai_provider",
|
|
"fields": ["api_key"],
|
|
"base_url": "https://openrouter.ai/api/v1",
|
|
"api_format": "openai",
|
|
"help_url": "https://openrouter.ai/keys",
|
|
"help_text": "One key, 300+ models. 26 free models. Pay-as-you-go, no subscription.",
|
|
"default_model": "openai/gpt-4o-mini",
|
|
},
|
|
"huggingface": {
|
|
"name": "Hugging Face",
|
|
"type": "api_key",
|
|
"category": "ai_provider",
|
|
"fields": ["api_key"],
|
|
"base_url": "https://router.huggingface.co/v1",
|
|
"api_format": "openai",
|
|
"help_url": "https://huggingface.co/settings/tokens",
|
|
"help_text": "Free HF token. Thousands of open-source models via 20+ inference providers.",
|
|
"default_model": "meta-llama/Llama-3.3-70B-Instruct",
|
|
},
|
|
"groq": {
|
|
"name": "Groq",
|
|
"type": "api_key",
|
|
"category": "ai_provider",
|
|
"fields": ["api_key"],
|
|
"base_url": "https://api.groq.com/openai/v1",
|
|
"api_format": "openai",
|
|
"help_url": "https://console.groq.com/keys",
|
|
"help_text": "Ultra-fast inference. Free tier available. Also used for program research.",
|
|
"default_model": "llama-3.3-70b-versatile",
|
|
},
|
|
"ollama": {
|
|
"name": "Ollama (Local)",
|
|
"type": "endpoint",
|
|
"category": "ai_provider",
|
|
"fields": ["endpoint_url"],
|
|
"base_url": "http://host.docker.internal:11434/v1",
|
|
"api_format": "openai",
|
|
"help_url": "https://ollama.com/",
|
|
"help_text": "Run LLMs locally. No API key, no cost. Default: http://host.docker.internal:11434",
|
|
"default_model": "llama3.1",
|
|
},
|
|
"claude": {
|
|
"name": "Anthropic Claude",
|
|
"type": "api_key",
|
|
"category": "ai_provider",
|
|
"fields": ["api_key"],
|
|
"base_url": "https://api.anthropic.com/v1",
|
|
"api_format": "anthropic",
|
|
"help_url": "https://console.anthropic.com/",
|
|
"help_text": "Get API key from console.anthropic.com. Models: claude-sonnet-4-6, claude-opus-4-8.",
|
|
"default_model": "claude-sonnet-4-6",
|
|
},
|
|
"gemini": {
|
|
"name": "Google Gemini",
|
|
"type": "api_key",
|
|
"category": "ai_provider",
|
|
"fields": ["api_key"],
|
|
"base_url": "https://generativelanguage.googleapis.com/v1beta",
|
|
"api_format": "gemini",
|
|
"help_url": "https://aistudio.google.com/apikey",
|
|
"help_text": "Get API key from AI Studio. Models: gemini-2.0-flash, gemini-2.5-pro.",
|
|
"default_model": "gemini-2.0-flash",
|
|
},
|
|
"custom_ai": {
|
|
"name": "Custom (OpenAI-compatible)",
|
|
"type": "endpoint",
|
|
"category": "ai_provider",
|
|
"fields": ["endpoint_url", "api_key"],
|
|
"api_format": "openai",
|
|
"help_url": "",
|
|
"help_text": "Any server with an OpenAI-compatible /v1/chat/completions endpoint (vLLM, TGI, LiteLLM).",
|
|
"default_model": "",
|
|
},
|
|
|
|
# ═══ Nutrition & Data ═══
|
|
|
|
"usda": {
|
|
"name": "USDA FoodData Central",
|
|
"type": "api_key",
|
|
"category": "nutrition",
|
|
"fields": ["api_key"],
|
|
"help_url": "https://fdc.nal.usda.gov/api-key-signup",
|
|
"help_text": "Free API key, no approval needed. 400K+ foods with research-grade nutrition data.",
|
|
},
|
|
"nutritionix": {
|
|
"name": "Nutritionix",
|
|
"type": "api_key",
|
|
"category": "nutrition",
|
|
"fields": ["app_id", "api_key"],
|
|
"help_url": "https://developer.nutritionix.com/",
|
|
"help_text": "Free tier: 1K calls/month. Natural language food parsing.",
|
|
},
|
|
|
|
# ═══ Notifications ═══
|
|
|
|
"telegram": {
|
|
"name": "Telegram Notifications",
|
|
"type": "api_key",
|
|
"category": "notifications",
|
|
"fields": ["bot_token", "chat_id"],
|
|
"help_url": "https://core.telegram.org/bots#botfather",
|
|
"help_text": "Create a bot via @BotFather, then get your chat ID.",
|
|
},
|
|
}
|