File size: 3,743 Bytes
f817912
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ede84b4
f817912
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
"""
webapi/settings.py — ค่าตั้งทั้งหมดของ backend อ่านจาก environment (HF Space → Settings → Variables/Secrets)

ไม่มีค่าไหนผูกกับแบรนด์ — แบรนด์และโมเดลรูปอยู่ใน image_models.yaml
"""
from __future__ import annotations

import os
from dataclasses import dataclass, field


def _int(name: str, default: int) -> int:
    try:
        return int(os.environ.get(name, default))
    except ValueError:
        return default


def _list(name: str, default: str) -> list[str]:
    return [x.strip() for x in os.environ.get(name, default).split(",") if x.strip()]


@dataclass
class Settings:
    # ── บอท ──
    bot_module: str = field(default_factory=lambda: os.environ.get("BOT_MODULE", "assistant"))
    warm_on_start: bool = field(default_factory=lambda: os.environ.get("WARM_ON_START", "1") == "1")

    # ── ความปลอดภัย ──
    # ตั้ง PROXY_SECRET ให้ตรงกับฝั่ง Vercel → Space รับเฉพาะคำขอที่ผ่าน Vercel
    # และเชื่อ X-Client-IP ที่ Vercel ส่งมา (ไม่ตั้ง = ใช้ X-Forwarded-For ของ HF และไม่เชื่อ X-Client-IP)
    proxy_secret: str = field(default_factory=lambda: os.environ.get("PROXY_SECRET", ""))
    allowed_origins: list[str] = field(default_factory=lambda: _list("ALLOWED_ORIGINS", ""))

    # ── rate limit ต่อ IP ──
    rl_per_minute: int = field(default_factory=lambda: _int("RL_PER_MINUTE", 8))
    rl_per_hour: int = field(default_factory=lambda: _int("RL_PER_HOUR", 60))
    rl_images_per_hour: int = field(default_factory=lambda: _int("RL_IMAGES_PER_HOUR", 15))
    # เพดานรวมทั้งระบบต่อวัน (กันโควตา Gemini หมด) 0 = ไม่จำกัด
    global_per_day: int = field(default_factory=lambda: _int("GLOBAL_PER_DAY", 1500))
    # จำนวนเทิร์นที่ประมวลผลพร้อมกัน (CPU ฟรีของ HF มี 2 คอร์)
    max_concurrent: int = field(default_factory=lambda: _int("MAX_CONCURRENT", 2))
    queue_wait_s: int = field(default_factory=lambda: _int("QUEUE_WAIT_S", 20))

    # ── ข้อความ / รูป ──
    max_text_chars: int = field(default_factory=lambda: _int("MAX_TEXT_CHARS", 1000))
    max_image_bytes: int = field(default_factory=lambda: _int("MAX_IMAGE_BYTES", 5 * 1024 * 1024))
    max_image_pixels: int = field(default_factory=lambda: _int("MAX_IMAGE_PIXELS", 40_000_000))
    image_max_side: int = field(default_factory=lambda: _int("IMAGE_MAX_SIDE", 1600))

    # ── session ──
    session_ttl_s: int = field(default_factory=lambda: _int("SESSION_TTL_S", 2 * 3600))
    max_sessions: int = field(default_factory=lambda: _int("MAX_SESSIONS", 3000))
    max_turns: int = field(default_factory=lambda: _int("MAX_TURNS", 40))

    # ── รูปที่บอทส่งกลับ (drawing ของ Movex) — เสิร์ฟได้เฉพาะไฟล์ใต้โฟลเดอร์เหล่านี้ ──
    media_roots: list[str] = field(default_factory=lambda: _list("MEDIA_ROOTS", "image,images"))

    # แทนรหัสภายใน movex_chain_… ในคำตอบด้วยรหัสที่ลูกค้าอ่านได้ (GRAPH-001) — ชั้นแสดงผลเท่านั้น
    scrub_internal_ids: bool = field(default_factory=lambda: os.environ.get("SCRUB_INTERNAL_IDS", "1") == "1")


settings = Settings()