| """Configuration constants for the NITA bill Gradio app.""" |
|
|
| from __future__ import annotations |
|
|
| import os |
| import warnings |
| from dataclasses import dataclass |
| from pathlib import Path |
| from typing import Literal, Optional |
|
|
| from dotenv import load_dotenv |
|
|
| _PROJECT_ROOT = Path(__file__).resolve().parent |
| while _PROJECT_ROOT.name and _PROJECT_ROOT.name not in {"", "."}: |
| if (_PROJECT_ROOT / "pyproject.toml").exists(): |
| break |
| if _PROJECT_ROOT.parent == _PROJECT_ROOT: |
| break |
| _PROJECT_ROOT = _PROJECT_ROOT.parent |
|
|
| load_dotenv(dotenv_path=_PROJECT_ROOT / ".env", override=False) |
|
|
| |
| |
| os.environ.setdefault("TOKENIZERS_PARALLELISM", "false") |
|
|
| |
| |
| warnings.filterwarnings( |
| "ignore", |
| message=r"`resume_download` is deprecated and will be removed in version 1\.0\.0\.", |
| category=FutureWarning, |
| ) |
|
|
| SUPPORTED_PROVIDERS = ["qwen", "openai", "anthropic", "gemini", "cohere"] |
| DEFAULT_PROVIDER: str = "qwen" |
| DEFAULT_QWEN_MODEL = "Qwen/Qwen3-14B:cheapest" |
| DEFAULT_CHUNK_TOKENIZER_MODEL = "sentence-transformers/all-MiniLM-L6-v2" |
| DEFAULT_FALLBACK_EMBEDDING_MODEL = "sentence-transformers/all-MiniLM-L6-v2" |
| OPENAI_REASONING_EFFORT = "medium" |
| ANTHROPIC_THINKING_BUDGET = 2048 |
| DEFAULT_CHUNK_SIZE = 350 |
| DEFAULT_CHUNK_OVERLAP = 60 |
| SCAN_CHUNK_SIZE = 1200 |
| SCAN_CHUNK_OVERLAP = 150 |
| SCAN_MAX_WINDOWS = 40 |
| SCAN_TOP_K = 5 |
| SCAN_BATCH_SIZE = 6 |
| TOP_K_RETRIEVAL = 5 |
| MAX_UPLOAD_SIZE_MB = 25 |
| TIMEOUT_SECONDS = 30 |
|
|
| ProviderLiteral = Literal["qwen", "openai", "anthropic", "gemini", "cohere"] |
|
|
| |
| |
| PROVIDER_FULL_DOCUMENT_QA_TOKEN_BUDGETS: dict[ProviderLiteral, int] = { |
| "qwen": 24_000, |
| "openai": 900_000, |
| "anthropic": 900_000, |
| "gemini": 900_000, |
| "cohere": 220_000, |
| } |
|
|
|
|
| @dataclass(frozen=True) |
| class ProviderConfig: |
| name: ProviderLiteral |
| key_prefix: Optional[str] |
| display_name: str |
| instructions: str |
|
|
|
|
| def _read_env_key(var_name: str) -> Optional[str]: |
| value = os.getenv(var_name) |
| if value is None: |
| return None |
| sanitized = value.strip().strip('"').strip("'") |
| return sanitized or None |
|
|
|
|
| OPENAI_API_KEY: Optional[str] = _read_env_key("OPENAI_API_KEY") |
| ANTHROPIC_API_KEY: Optional[str] = _read_env_key("ANTHROPIC_API_KEY") |
| GEMINI_API_KEY: Optional[str] = _read_env_key("GEMINI_API_KEY") |
| COHERE_API_KEY: Optional[str] = _read_env_key("COHERE_API_KEY") |
| DEFAULT_COHERE_KEY: Optional[str] = _read_env_key("DEFAULT_COHERE_KEY") |
| HF_TOKEN: Optional[str] = _read_env_key("HF_TOKEN") |
|
|
|
|
| PROVIDER_METADATA: list[ProviderConfig] = [ |
| ProviderConfig( |
| name="qwen", |
| key_prefix=None, |
| display_name="Qwen3 14B", |
| instructions=( |
| "Use your Hugging Face token for the router-backed Qwen model. Leave blank to use HF_TOKEN from .env if configured." |
| ), |
| ), |
| ProviderConfig( |
| name="openai", |
| key_prefix="sk-", |
| display_name="OpenAI GPT-5.5", |
| instructions=( |
| "Enter your OpenAI API key. Leave blank to use OPENAI_API_KEY from .env if configured." |
| ), |
| ), |
| ProviderConfig( |
| name="anthropic", |
| key_prefix="sk-ant-", |
| display_name="Anthropic Claude Sonnet 4.6", |
| instructions=( |
| "Provide your Anthropic API key. Leave blank to use ANTHROPIC_API_KEY from .env if configured." |
| ), |
| ), |
| ProviderConfig( |
| name="gemini", |
| key_prefix=None, |
| display_name="Google Gemini 2.5 Flash", |
| instructions=( |
| "Use your Gemini API key. Leave blank to use the built-in GEMINI_API_KEY if configured." |
| ), |
| ), |
| ProviderConfig( |
| name="cohere", |
| key_prefix=None, |
| display_name="Cohere Command A Reasoning", |
| instructions=( |
| "Use your Cohere API key with Command R access. Leave blank to use COHERE_API_KEY or " |
| "DEFAULT_COHERE_KEY if configured." |
| ), |
| ), |
| ] |
|
|
|
|
| APP_TITLE = "Legislation Explainer" |
| APP_DESCRIPTION = ( |
| "A Gradio policy assistant for public-interest legislation. " |
| "Upload or link to a bill, generate a structured review, and ask grounded follow-up questions." |
| ) |
|
|