from pydantic_settings import BaseSettings from typing import List, Optional import os class Settings(BaseSettings): # App app_env: str = "development" app_secret_key: str = "dev-secret-key" allowed_origins: str = "http://localhost:5173,http://localhost:3000" # Supabase supabase_url: str = "" supabase_anon_key: str = "" supabase_service_role_key: str = "" # Qdrant qdrant_url: str = "http://localhost:6333" qdrant_api_key: Optional[str] = None # LLM Providers openai_api_key: Optional[str] = None anthropic_api_key: Optional[str] = None google_api_key: Optional[str] = None fireworks_api_key: Optional[str] = None # Embeddings embedding_model: str = "text-embedding-3-small" # Stripe stripe_secret_key: str = "" stripe_webhook_secret: str = "" stripe_starter_price_id: str = "" stripe_pro_price_id: str = "" # Redis redis_url: str = "redis://localhost:6379" # Sentry sentry_dsn: Optional[str] = None # Files max_file_size_mb: int = 50 @property def allowed_origins_list(self) -> List[str]: return [o.strip() for o in self.allowed_origins.split(",")] class Config: env_file = ".env" case_sensitive = False settings = Settings() # ═══════════════════════════════════════════════════════════════════════════════ # MODEL CATALOG — Single source of truth for all model metadata # ═══════════════════════════════════════════════════════════════════════════════ # To add a new model: # 1. Add it here with name/provider/badge/description # 2. Add its model_id → provider mapping in MODEL_PROVIDERS # 3. Add it to the appropriate plan(s) in PLAN_LIMITS # That's it — the frontend loads everything from GET /api/v1/models/available # ═══════════════════════════════════════════════════════════════════════════════ MODEL_CATALOG = { # ── Free tier (Fireworks - lightweight) ──────────────────────────────────── "accounts/fireworks/models/llama-v3p3-70b-instruct": { "name": "Llama 3.3 70B", "provider": "Fireworks AI", "badge": "Free", "description": "Free model for building and testing chatbots", }, # ── Starter tier (Fireworks - powerful serverless models) ────────────────── "accounts/fireworks/models/qwen3-235b-a22b": { "name": "Qwen3 235B", "provider": "Fireworks AI", "badge": "Powerful", "description": "High-capability open model with great reasoning", }, "accounts/fireworks/models/deepseek-v3p1": { "name": "DeepSeek V3.1", "provider": "Fireworks AI", "badge": "Smart", "description": "Cost-effective and highly capable model", }, "accounts/fireworks/models/kimi-k2-instruct-0905": { "name": "Kimi K2", "provider": "Fireworks AI", "badge": "Multilingual", "description": "Strong multilingual and coding capabilities", }, # ── Pro tier (Premium providers) ─────────────────────────────────────────── # OpenAI "gpt-4o": { "name": "GPT-4o", "provider": "OpenAI", "badge": "Powerful", "description": "Most capable OpenAI model", }, "gpt-4o-mini": { "name": "GPT-4o Mini", "provider": "OpenAI", "badge": "Efficient", "description": "Fast and cost-effective OpenAI model", }, # Anthropic "claude-haiku-4-5-20251001": { "name": "Claude Haiku 4.5", "provider": "Anthropic", "badge": "Fast", "description": "Fast and affordable Anthropic model", }, # Google Gemini "gemini-2.5-flash": { "name": "Gemini 2.5 Flash", "provider": "Google", "badge": "Fast", "description": "Fast and efficient Google model", }, "gemini-2.5-lite": { "name": "Gemini 2.5 Lite", "provider": "Google", "badge": "Lightweight", "description": "Cost-effective Google model", }, "gemini-2.5-pro": { "name": "Gemini 2.5 Pro", "provider": "Google", "badge": "Advanced", "description": "Most capable Google model with long context", }, } # ─── Model ID → LLM provider mapping (used by llm_client.py for routing) ───── MODEL_PROVIDERS = { # Fireworks "accounts/fireworks/models/llama-v3p3-70b-instruct": "fireworks", "accounts/fireworks/models/qwen3-235b-a22b": "fireworks", "accounts/fireworks/models/deepseek-v3p1": "fireworks", "accounts/fireworks/models/kimi-k2-instruct-0905": "fireworks", # OpenAI "gpt-4o": "openai", "gpt-4o-mini": "openai", # Anthropic "claude-haiku-4-5-20251001": "anthropic", # Google "gemini-2.5-flash": "google", "gemini-2.5-lite": "google", "gemini-2.5-pro": "google", } # ─── Default model per plan (pre-selected in the frontend) ──────────────────── DEFAULT_MODELS = { "free": "accounts/fireworks/models/llama-v3p3-70b-instruct", "starter": "accounts/fireworks/models/qwen3-235b-a22b", "pro": "gpt-4o", "enterprise": "gpt-4o", } # ═══════════════════════════════════════════════════════════════════════════════ # PLAN LIMITS — Pricing: Starter $3/mo, Pro $20/mo # ═══════════════════════════════════════════════════════════════════════════════ # # Cost analysis (per 1M tokens approx): # Fireworks Llama 3.3 70B: $0.90/M # Fireworks Qwen3 235B: $0.22 in / $0.88 out # Fireworks DeepSeek V3.1: $0.56 in / $1.68 out # Fireworks Kimi K2: $0.60 in / $2.50 out # GPT-4o: $2.50 in / $10.00 out # GPT-4o Mini: $0.15 in / $0.60 out # Claude Haiku 4.5: $0.80 in / $4.00 out # Gemini 2.5 Flash: ~$0.15 in / $0.60 out # Gemini 2.5 Lite: ~$0.075 in / $0.30 out # Gemini 2.5 Pro: ~$1.25 in / $10.00 out # # Avg conversation: ~2K tokens input + 1K output = ~3K tokens # Fireworks models: ~$0.001-$0.004 per conversation # GPT-4o: ~$0.015 per conversation # GPT-4o Mini: ~$0.001 per conversation # Claude Haiku: ~$0.006 per conversation # Gemini Flash: ~$0.001 per conversation # Gemini Pro: ~$0.013 per conversation # # Starter at $3/mo with 500 convos: max cost ~$2/mo (fireworks) → margin OK # Pro at $20/mo with 2,000 convos: max cost ~$12/mo (if all GPT-4o) → margin OK # Typical mix: ~$5-8/mo actual cost → healthy margin # ═══════════════════════════════════════════════════════════════════════════════ PLAN_LIMITS = { "free": { "max_chatbots": 999999, # unlimited creation "max_published": 0, # cannot publish "max_documents_per_chatbot": 3, "max_document_size_mb": 5, "models": [ "accounts/fireworks/models/llama-v3p3-70b-instruct", ], "conversations_limit": 50, # 50 preview conversations/month "code_export": False, "analytics": False, "features": ["preview_mode", "testing"], }, "starter": { "max_chatbots": 999999, "max_published": 1, "max_documents_per_chatbot": 10, "max_document_size_mb": 10, "models": [ "accounts/fireworks/models/llama-v3p3-70b-instruct", "accounts/fireworks/models/qwen3-235b-a22b", "accounts/fireworks/models/deepseek-v3p1", "accounts/fireworks/models/kimi-k2-instruct-0905", ], "conversations_limit": 500, # 500 conversations/month "code_export": False, "analytics": True, "features": ["marketplace", "analytics", "branding"], }, "pro": { "max_chatbots": 5, "max_published": 5, "max_documents_per_chatbot": 50, "max_document_size_mb": 50, "models": [ # Fireworks (included) "accounts/fireworks/models/llama-v3p3-70b-instruct", "accounts/fireworks/models/qwen3-235b-a22b", "accounts/fireworks/models/deepseek-v3p1", "accounts/fireworks/models/kimi-k2-instruct-0905", # OpenAI "gpt-4o", "gpt-4o-mini", # Anthropic "claude-haiku-4-5-20251001", # Google "gemini-2.5-flash", "gemini-2.5-lite", "gemini-2.5-pro", ], "conversations_limit": 2000, # 2,000 conversations/month "code_export": True, "analytics": True, "features": [ "marketplace", "code_export", "advanced_analytics", "priority_support", "custom_domain", ], }, "enterprise": { "max_chatbots": 999999, "max_published": 999999, "max_documents_per_chatbot": 999999, "max_document_size_mb": 200, "models": ["*"], # resolves to all MODEL_CATALOG keys "conversations_limit": 999999, "code_export": True, "analytics": True, "features": ["*"], }, }