from typing import Literal from pydantic_settings import BaseSettings class Settings(BaseSettings): # LLM llm_provider: Literal["anthropic", "openai", "gemini", "openrouter"] = "anthropic" llm_model: str = "claude-sonnet-4-6" # API Keys anthropic_api_key: str = "" openai_api_key: str = "" gemini_api_key: str = "" openrouter_api_key: str = "" # LandingAI ADE landingai_api_key: str = "" # PDF Parser: "landingai" | "docling" # "docling" uses a self-hosted Kaggle server discovered via ntfy.sh pdf_parser: Literal["landingai", "docling"] = "landingai" # Minimum extracted markdown length to consider a parse successful. Below this # the pipeline fails fast instead of generating a review from empty text. min_parsed_markdown_chars: int = 100 # ntfy.sh topic used to discover the Docling server URL from Kaggle ntfy_topic: str = "papermate_pdf2md" # Tavily tavily_api_key: str = "" # Tavily has no per-call credit API, so cost is computed locally: # cost_usd = successful_searches * tavily_credits_per_search * tavily_price_per_credit # Basic search = 1 credit; pricing snapshot $0.008/credit. tavily_price_per_credit: float = 0.008 tavily_credits_per_search: int = 1 # App app_base_url: str = "http://localhost:8000" max_file_size_mb: int = 10 jobs_dir: str = "data/jobs" logs_dir: str = "data/logs" # Supabase supabase_url: str = "" supabase_service_role_key: str = "" supabase_anon_key: str = "" # public key for the frontend (login) supabase_jwt_secret: str = "" # only needed for local HS256 verify (unused by default) supabase_storage_bucket: str = "paper-review-artifacts" # Auth / RBAC # Comma-separated emails auto-promoted to admin on first login (also seed via SQL). admin_emails: str = "" # When False, anonymous submit (email + access_key) keeps working as before. auth_required_for_submit: bool = False # Quota (per logged-in user, per calendar month). null/0 = unlimited. default_monthly_review_limit: int = 0 default_monthly_cost_limit_usd: float = 0.0 # Dashboard cost alert: flag a day whose total cost exceeds this (USD). 0 = off. cost_alert_daily_usd: float = 0.0 # Manual pricing snapshots, USD per 1M tokens. These default to zero so # missing prices never block review generation. openai_input_price_per_1m: float | None = None openai_output_price_per_1m: float | None = None anthropic_input_price_per_1m: float | None = None anthropic_output_price_per_1m: float | None = None gemini_input_price_per_1m: float | None = None gemini_output_price_per_1m: float | None = None openrouter_input_price_per_1m: float | None = None openrouter_output_price_per_1m: float | None = None class Config: env_file = ".env" env_file_encoding = "utf-8" extra = "ignore" # ignore unrelated env vars (e.g. HF_TOKEN, DOCLING_HF_SPACE) settings = Settings()