Spaces:
Running
Running
File size: 3,514 Bytes
5c9b605 c20d7c0 5c9b605 f403cbc 5c9b605 3a08f21 5c9b605 | 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 | """Runtime configuration loaded from environment variables."""
from __future__ import annotations
import os
from dataclasses import dataclass
from dotenv import load_dotenv
load_dotenv()
def _bool_env(name: str, default: bool) -> bool:
value = os.getenv(name)
if value is None:
return default
return value.strip().lower() in {"1", "true", "yes", "y", "on"}
def _int_env(name: str, default: int) -> int:
value = os.getenv(name)
if value is None or not value.strip():
return default
try:
return int(value)
except ValueError:
return default
def _float_env(name: str, default: float) -> float:
value = os.getenv(name)
if value is None or not value.strip():
return default
try:
return float(value)
except ValueError:
return default
@dataclass(frozen=True)
class Settings:
app_name: str = os.getenv("APP_NAME", "A Share Stock Data API")
api_prefix: str = os.getenv("API_PREFIX", "/api/v1")
api_key: str = os.getenv("STOCK_DATA_API_KEY", "")
database_url: str = os.getenv("DATABASE_URL") or os.getenv("CACHE_DATABASE_URL") or "sqlite:///./.cache/stock_data_cache.db"
database_ssl: bool = _bool_env("DATABASE_SSL", False)
cache_enabled: bool = _bool_env("CACHE_ENABLED", True)
cache_table_name: str = os.getenv("CACHE_TABLE_NAME", "api_cache")
cache_schema_version: str = os.getenv("CACHE_SCHEMA_VERSION", "v1")
source_timeout_seconds: int = _int_env("SOURCE_TIMEOUT_SECONDS", 15)
source_retry_attempts: int = _int_env("SOURCE_RETRY_ATTEMPTS", 1)
source_retry_backoff_seconds: float = _float_env("SOURCE_RETRY_BACKOFF_SECONDS", 0.5)
source_retry_max_backoff_seconds: float = _float_env("SOURCE_RETRY_MAX_BACKOFF_SECONDS", 10.0)
source_retry_jitter_seconds: float = _float_env("SOURCE_RETRY_JITTER_SECONDS", 0.25)
suppress_source_output: bool = _bool_env("SUPPRESS_SOURCE_OUTPUT", True)
disable_proxy_for_akshare: bool = _bool_env("DISABLE_PROXY_FOR_AKSHARE", True)
search_api_base_url: str = os.getenv("SEARCH_API_BASE_URL", "https://jiuuij.de5.net/").strip()
search_api_key: str = os.getenv("SEARCH_API_KEY", "").strip()
search_api_model: str = os.getenv("SEARCH_API_MODEL", "grok-4.20-multi-agent-xhigh").strip()
search_api_timeout_seconds: int = _int_env("SEARCH_API_TIMEOUT_SECONDS", 180)
search_api_max_attempts: int = _int_env("SEARCH_API_MAX_ATTEMPTS", 8)
search_api_temperature: float = _float_env("SEARCH_API_TEMPERATURE", 0.2)
search_api_max_tokens: int = _int_env("SEARCH_API_MAX_TOKENS", 4096)
search_cache_ttl_seconds: int = _int_env("SEARCH_CACHE_TTL_SECONDS", 3600)
ai_search_hub_repo_path: str = os.getenv("AI_SEARCH_HUB_REPO_PATH", "").strip()
ai_search_hub_timeout: int = _int_env("AI_SEARCH_HUB_TIMEOUT", 120)
ai_search_hub_default_sites: str = os.getenv("AI_SEARCH_HUB_DEFAULT_SITES", "").strip()
ai_search_hub_headless: bool = _bool_env("AI_SEARCH_HUB_HEADLESS", False)
ai_search_hub_max_concurrent: int = _int_env("AI_SEARCH_HUB_MAX_CONCURRENT", 3)
cors_origins: tuple[str, ...] = tuple(
item.strip()
for item in os.getenv("CORS_ORIGINS", "*").split(",")
if item.strip()
)
# 源调用池配置 - 防止 HF Space worker pool 饱和
max_concurrent_sources: int = _int_env("MAX_CONCURRENT_SOURCES", 2) # HF Free tier: 2, Pro: 10
source_pool_workers: int = _int_env("SOURCE_POOL_WORKERS", 4) # 线程池大小
settings = Settings()
|