PetAgent/backend/config/settings.py
2026-04-12 20:26:24 +08:00

143 lines
6.6 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 文件
"""
import os
from pathlib import Path
from typing import List, Dict
from pydantic_settings import BaseSettings, SettingsConfigDict
ROOT_DIR = Path(__file__).resolve().parent.parent.parent
ENV_FILE_PATH = ROOT_DIR / '.env'
class Settings(BaseSettings):
model_config = SettingsConfigDict(
env_file=str(ENV_FILE_PATH),
env_file_encoding='utf-8',
extra='allow',
protected_namespaces=()
)
APP_NAME: str = "AI Pet Companion API"
DEBUG: bool = False
HOST: str = "0.0.0.0"
PORT: int = 8001
DATABASE_URL: str = os.getenv("DATABASE_URL", "mysql+pymysql://root:taiyi1224@localhost:3306/pet_companion")
JWT_SECRET_KEY: str = os.getenv("JWT_SECRET_KEY", "your-secret-key-change-in-production")
JWT_ALGORITHM: str = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES: int = 60 * 24 * 7
REFRESH_TOKEN_EXPIRE_DAYS: int = 7
ALLOWED_ORIGINS_STR: str = os.getenv("ALLOWED_ORIGINS",
"http://localhost:3000,http://127.0.0.1:3000,http://localhost:8080,http://localhost:3001,"
"http://127.0.0.1:3001,http://8.152.169.84:3000,https://www.wentuu.com,https://api.wentuu.com")
@property
def ALLOWED_ORIGINS(self) -> List[str]:
return [origin.strip() for origin in self.ALLOWED_ORIGINS_STR.split(",") if origin.strip()]
WECHAT_APP_ID: str = os.getenv("WECHAT_APP_ID", "")
WECHAT_APP_SECRET: str = os.getenv("WECHAT_APP_SECRET", "")
VOLCANO_APP_ID: str = os.getenv("VOLCANO_APP_ID", "2661618707")
VOLCANO_ACCESS_TOKEN: str = os.getenv("VOLCANO_ACCESS_TOKEN", "Ip4UpS92mfQBzkbTMHyGaIfpGcLUe1ZH")
VOLCANO_SECRET_KEY: str = os.getenv("VOLCANO_SECRET_KEY", "6lHMht8UPgS2yBV0c3AIRXUO7tB5dVTa")
VOLCANO_BIDIRECTIONAL_ENABLED: bool = os.getenv("VOLCANO_BIDIRECTIONAL_ENABLED", "False").lower() == "true"
VOLCANO_TTS_CLUSTER: str = os.getenv("VOLCANO_TTS_CLUSTER", "volcano_bigtts")
VOLCANO_ASR_CLUSTER: str = os.getenv("VOLCANO_ASR_CLUSTER", "volcano_bigtts")
VOLCANO_TTS_VOICE: str = os.getenv("VOLCANO_TTS_VOICE", "zh_female_vv_uranus_bigtts")
VOLCANO_TTS_RESOURCE_ID: str = os.getenv("VOLCANO_TTS_RESOURCE_ID", "seed-tts-2.0")
VOLCANO_ASR_RESOURCE_ID: str = os.getenv("VOLCANO_ASR_RESOURCE_ID", "volc.bigasr.sauc.duration")
ARK_API_KEY: str = os.getenv("ARK_API_KEY", "34e2f893-8133-440f-906d-f93406342bc0")
ARK_BASE_URL: str = os.getenv("ARK_BASE_URL", "https://ark.cn-beijing.volces.com/api/v3")
DOUBAO_API_KEY: str = os.getenv("DOUBAO_API_KEY", "")
DOUBAO_SECRET_KEY: str = os.getenv("DOUBAO_SECRET_KEY", "")
DOUBAO_APP_ID: str = os.getenv("DOUBAO_APP_ID", "")
DOUBAO_MODEL_NAME: str = os.getenv("DOUBAO_MODEL_NAME", "doubao-seed-1-6-lite-251015")
DOUBAO_REALTIME_URL: str = os.getenv("DOUBAO_REALTIME_URL", "wss://ark.cn-beijing.volces.com/api/v3/realtime")
REALTIME_VOICE_APP_ID: str = os.getenv("REALTIME_VOICE_APP_ID", "2661618707")
REALTIME_VOICE_ACCESS_KEY: str = os.getenv("REALTIME_VOICE_ACCESS_KEY", "Ip4UpS92mfQBzkbTMHyGaIfpGcLUe1ZH")
REALTIME_VOICE_API_URL: str = os.getenv("REALTIME_VOICE_API_URL", "wss://openspeech.bytedance.com/api/v3/realtime/dialogue")
REALTIME_VOICE_RESOURCE_ID: str = os.getenv("REALTIME_VOICE_RESOURCE_ID", "volc.speech.dialog")
ALIYUN_SMS_ACCESS_KEY_ID: str = os.getenv("ALIYUN_SMS_ACCESS_KEY_ID", "")
ALIYUN_SMS_ACCESS_KEY_SECRET: str = os.getenv("ALIYUN_SMS_ACCESS_KEY_SECRET", "")
ALIYUN_SMS_REGION_ID: str = os.getenv("ALIYUN_SMS_REGION_ID", "cn-hangzhou")
ALIYUN_SMS_SIGN_NAME: str = os.getenv("ALIYUN_SMS_SIGN_NAME", "")
ALIYUN_SMS_TEMPLATE_CODE: str = os.getenv("ALIYUN_SMS_TEMPLATE_CODE", "")
ALIYUN_SMS_ENABLED: bool = os.getenv("ALIYUN_SMS_ENABLED", "false").lower() == "true"
SMS_CODE_LENGTH: int = int(os.getenv("SMS_CODE_LENGTH", "6"))
SMS_CODE_VALID_SECONDS: int = int(os.getenv("SMS_CODE_VALID_SECONDS", "300"))
SMS_SEND_INTERVAL_SECONDS: int = int(os.getenv("SMS_SEND_INTERVAL_SECONDS", "60"))
UPLOAD_FOLDER: str = os.getenv("UPLOAD_FOLDER", "./uploads")
MAX_CONTENT_LENGTH: int | None = None
REDIS_URL: str = os.getenv("REDIS_URL", "redis://localhost:6379/0")
REDIS_PASSWORD: str = os.getenv("REDIS_PASSWORD", "")
LOG_LEVEL: str = os.getenv("LOG_LEVEL", "INFO")
DEFAULT_BACKGROUND_ID: int = int(os.getenv("DEFAULT_BACKGROUND_ID", "1"))
DEFAULT_DAILY_QUOTA: int = int(os.getenv("DEFAULT_DAILY_QUOTA", "20"))
# 聊天上下文轮数1轮=一组用户+AI0表示不带历史上下文
CHAT_CONTEXT_ROUNDS: int = int(os.getenv("CHAT_CONTEXT_ROUNDS", "0"))
settings = Settings()
# 运行时可动态更新(用于后台系统配置即时生效)
_runtime_chat_context_rounds = max(0, int(getattr(settings, "CHAT_CONTEXT_ROUNDS", 0) or 0))
def get_chat_context_rounds() -> int:
return max(0, int(_runtime_chat_context_rounds))
def set_chat_context_rounds(rounds: int) -> None:
global _runtime_chat_context_rounds
_runtime_chat_context_rounds = max(0, int(rounds))
_runtime_token_charge_config = {
"realtime_chat_fallback_tokens": int(os.getenv("REALTIME_CHAT_FALLBACK_TOKENS", "200")),
"e2e_realtime_voice_fallback_tokens": int(os.getenv("E2E_REALTIME_VOICE_FALLBACK_TOKENS", "200")),
"doubao_realtime_fallback_tokens": int(os.getenv("DOUBAO_REALTIME_FALLBACK_TOKENS", "200")),
"voice_chat_fallback_tokens": int(os.getenv("VOICE_CHAT_FALLBACK_TOKENS", "200")),
"voice_realtime_call_fallback_tokens": int(os.getenv("VOICE_REALTIME_CALL_FALLBACK_TOKENS", "200")),
}
def get_token_charge_config() -> Dict[str, int]:
return {
"realtime_chat_fallback_tokens": max(0, int(_runtime_token_charge_config.get("realtime_chat_fallback_tokens", 200))),
"e2e_realtime_voice_fallback_tokens": max(0, int(_runtime_token_charge_config.get("e2e_realtime_voice_fallback_tokens", 200))),
"doubao_realtime_fallback_tokens": max(0, int(_runtime_token_charge_config.get("doubao_realtime_fallback_tokens", 200))),
"voice_chat_fallback_tokens": max(0, int(_runtime_token_charge_config.get("voice_chat_fallback_tokens", 200))),
"voice_realtime_call_fallback_tokens": max(0, int(_runtime_token_charge_config.get("voice_realtime_call_fallback_tokens", 200))),
}
def set_token_charge_config(config: Dict[str, int]) -> None:
if not isinstance(config, dict):
return
for key in _runtime_token_charge_config.keys():
if key not in config:
continue
try:
value = int(config[key])
except (TypeError, ValueError):
continue
_runtime_token_charge_config[key] = max(0, value)