143 lines
6.6 KiB
Python
143 lines
6.6 KiB
Python
"""
|
||
云屋平台 - 配置设置
|
||
管理系统和环境变量
|
||
统一使用根目录的 .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轮=一组用户+AI),0表示不带历史上下文
|
||
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)
|