Spaces:
Running
Running
| 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() | |