Python 76.2%
JavaScript 11.3%
CSS 6.3%
HTML 5.9%
1"""Configuration Trawls — un seul point d'entrée (pydantic-settings, préfixe TRAWLS_).23Invariants : toutes les valeurs ont un défaut sûr permettant un fonctionnement 100 % self-host4sans clé externe. Les valeurs dangereuses sont loguées explicitement au démarrage.5"""67from __future__ import annotations89import os10from functools import lru_cache11from pathlib import Path1213from pydantic import Field14from pydantic_settings import BaseSettings, SettingsConfigDict151617class Settings(BaseSettings):18 model_config = SettingsConfigDict(env_prefix="TRAWLS_", env_file=".env", extra="ignore")1920 env: str = "development"21 host: str = "0.0.0.0"22 port: int = 818023 public_url: str = "http://localhost:8180"24 data_dir: Path = Field(default_factory=lambda: Path(os.environ.get("TRAWLS_DATA_DIR", "./data")))2526 # Persistance (SQLite par défaut : self-host sans dépendance)27 database_url: str | None = None # réservé : PostgreSQL ultérieur28 redis_url: str | None = None # réservé : queue arq ultérieure29 result_ttl_days: int = 73031 # Fetch32 browser_pool_size: int = Field(default_factory=lambda: max(2, min(8, (os.cpu_count() or 4))))33 browser_context_max_pages: int = 5034 browser_context_max_age_s: int = 60035 max_concurrency_per_host: int = 436 max_concurrency_global: int = 1637 max_size_mb: int = 5038 max_pages_pdf: int = 50039 proxy_urls: str = "" # séparés par des virgules40 user_agent_extra: str = ""41 host_mode_cache_ttl_s: int = 36004243 # Sécurité44 require_auth: bool = False45 admin_key: str | None = None # clé maître pour créer des clés API46 allow_private_targets: bool = False # SSRF : jamais true en prod47 rate_limit_per_minute: int = 3004849 # LLM50 llm_provider: str = "openai" # openai | anthropic | none51 llm_api_key: str | None = None52 llm_base_url: str | None = "http://localhost:11434/v1" # Ollama par défaut53 llm_model: str = "qwen2.5:7b"5455 # Jobs56 worker_concurrency: int = 457 job_default_max_pages: int = 1005859 log_level: str = "INFO"6061 @property62 def proxies(self) -> list[str]:63 return [p.strip() for p in self.proxy_urls.split(",") if p.strip()]6465 @property66 def db_path(self) -> Path:67 self.data_dir.mkdir(parents=True, exist_ok=True)68 return self.data_dir / "trawls.db"6970 @property71 def blob_dir(self) -> Path:72 d = self.data_dir / "blobs"73 d.mkdir(parents=True, exist_ok=True)74 return d757677@lru_cache78def get_settings() -> Settings:79 return Settings()80