File size: 2,314 Bytes
42d88ae
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
from functools import lru_cache
from pathlib import Path
from typing import Optional
from pydantic_settings import BaseSettings, SettingsConfigDict
from pydantic import field_validator


class Settings(BaseSettings):
    model_config = SettingsConfigDict(
        env_file=".env",
        env_file_encoding="utf-8",
        extra="ignore"
    )
    
    database_url: str
    
    supabase_url: str
    supabase_key: str
    supabase_jwt_secret: str
    supabase_bucket: str = "city-issues"
    
    supabase_s3_endpoint: Optional[str] = None
    supabase_s3_region: str = "ap-southeast-1"
    supabase_s3_access_key: Optional[str] = None
    supabase_s3_secret_key: Optional[str] = None
    
    model_path: Path = Path("Backend/agents/vision/model.pt")
    model_confidence_threshold: float = 0.25
    model_input_size: int = 512
    
    local_temp_dir: Path = Path("static/temp")
    
    sla_critical_hours: int = 4
    sla_high_hours: int = 12
    sla_medium_hours: int = 48
    sla_low_hours: int = 168
    
    api_host: str = "0.0.0.0"
    api_port: int = 8000
    api_workers: int = 4
    
    max_upload_size_mb: int = 10
    allowed_extensions: set[str] = {"jpg", "jpeg", "png", "webp"}
    
    duplicate_radius_meters: float = 50.0
    
    debug: bool = False
    
    resend_api_key: Optional[str] = None
    google_client_id: Optional[str] = None
    gemini_api_key: Optional[str] = None
    google_client_secret: Optional[str] = None
    project_id: Optional[str] = None
    sender_email: str = "noreply@urbanlens.city"
    admin_email: str = "admin@urbanlens.city"

    frontend_url: Optional[str] = None
    
    cors_origins: list[str] = []
    jwt_algorithm: str = "HS256"
    jwt_expire_hours: int = 24
    
    @field_validator("database_url")
    @classmethod
    def validate_database_url(cls, v: str) -> str:
        if not v.startswith("postgresql"):
            raise ValueError("DATABASE_URL must be a PostgreSQL connection string")
        return v
    
    @field_validator("supabase_jwt_secret")
    @classmethod
    def validate_jwt_secret(cls, v: str) -> str:
        if len(v) < 32:
            raise ValueError("SUPABASE_JWT_SECRET must be at least 32 characters")
        return v


@lru_cache
def get_settings() -> Settings:
    return Settings()


settings = get_settings()