Files
life-echo/api/app/core/config.py
Kevin 07979bfb09 feat(api): use Tencent ASR flash with 16k_zh_large and dev transcript logs
Replace CreateRecTask polling with recording-file flash API, add TENCENT_APP_ID,
remove server-side pydub slicing, and log ASR recognition text at INFO in development.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-25 11:28:22 +08:00

139 lines
4.2 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
统一配置:密钥与连接串经 .env / Settings其余非密钥项见 config/*.tomlAppConfig
本地开发时由 api/development.sh 在启动前将 .env.development 同步为 .env。
"""
from __future__ import annotations
from pydantic import AliasChoices, Field, model_validator
from pydantic_settings import BaseSettings, SettingsConfigDict
from app.core.app_config_models import DeployConfig
from app.core.redis_urls import resolve_redis_urls
_DEV_SECRET_KEY = "dev-only-secret-key-do-not-use-in-production"
_DEPLOY_FIELD_NAMES = frozenset(DeployConfig.model_fields.keys())
class Settings(BaseSettings):
"""Secrets and bootstrap only — non-secret deploy/product config lives in TOML."""
model_config = SettingsConfigDict(
env_file=".env",
env_file_encoding="utf-8",
case_sensitive=False,
extra="ignore",
)
database_url: str = "postgresql://postgres:postgres@localhost:48291/life_echo"
redis_url: str = "redis://localhost:48307/0"
redis_password: str = ""
celery_redis_url: str = ""
app_environment: str = Field(
default="development",
validation_alias=AliasChoices("APP_ENV", "APP_ENVIRONMENT"),
)
secret_key: str = _DEV_SECRET_KEY
deepseek_api_key: str = ""
zhipu_api_key: str = ""
tencent_secret_id: str = ""
tencent_secret_key: str = ""
tencent_app_id: str = ""
wechat_pay_api_v3_key: str = ""
wechat_pay_private_key: str = ""
wechat_pay_platform_public_key: str = ""
alipay_private_key: str = ""
alipay_public_key: str = ""
liblib_access_key: str = ""
liblib_secret_key: str = ""
internal_eval_api_key: str = ""
@model_validator(mode="after")
def _validate_secret_key(self) -> "Settings":
env = (self.app_environment or "").strip().lower()
if env in ("production", "staging") and (
not self.secret_key or self.secret_key == _DEV_SECRET_KEY
):
raise ValueError(
"SECRET_KEY must be set to a strong random value in production/staging"
)
return self
@property
def is_production(self) -> bool:
return (self.app_environment or "").strip().lower() == "production"
@property
def enable_test_subscription(self) -> bool:
return not self.is_production
@property
def enable_test_plan(self) -> bool:
return not self.is_production
@property
def redis_url_resolved(self) -> str:
business, _ = resolve_redis_urls(
self.redis_url,
redis_password=self.redis_password or None,
celery_redis_url_override=None,
)
return business
@property
def celery_redis_url_resolved(self) -> str:
override = (self.celery_redis_url or "").strip() or None
_, celery = resolve_redis_urls(
self.redis_url,
redis_password=self.redis_password or None,
celery_redis_url_override=override,
)
return celery
class SettingsFacade:
"""Backward-compatible facade: secrets from Settings, deploy flags from TOML."""
__slots__ = ("_secrets",)
def __init__(self, secrets: Settings) -> None:
object.__setattr__(self, "_secrets", secrets)
@property
def _deploy(self) -> DeployConfig:
from app.core.app_config import get_app_config
return get_app_config().deploy
def __getattr__(self, name: str):
secrets = object.__getattribute__(self, "_secrets")
if hasattr(secrets, name):
return getattr(secrets, name)
if name in _DEPLOY_FIELD_NAMES:
return getattr(self._deploy, name)
raise AttributeError(f"Settings has no attribute {name!r}")
def __setattr__(self, name: str, value) -> None:
if name == "_secrets":
object.__setattr__(self, name, value)
return
secrets = object.__getattribute__(self, "_secrets")
if hasattr(type(secrets), name) and name not in _DEPLOY_FIELD_NAMES:
setattr(secrets, name, value)
return
if name in _DEPLOY_FIELD_NAMES:
setattr(self._deploy, name, value)
return
setattr(secrets, name, value)
settings = SettingsFacade(Settings())