初始化提交
This commit is contained in:
commit
887c1f449e
963 files changed
+166869
No files matched your search
@@ -0,0 +1,16 @@
|
||||
"""配置集中入口。
|
||||
|
||||
所有配置集中在 ``core/config/``,按领域拆分子配置文件,主 ``Settings`` 多继承聚合。
|
||||
详见 [后端分层架构设计](../../../../../docs/architecture/backend-layering-design.md) §7。
|
||||
|
||||
- ``.env`` 永远放在项目根目录(backend 父级),``Settings`` 初始化时以**绝对路径**
|
||||
通过 ``_env_file`` 传入,不使用相对路径,不依赖 ``python-dotenv``。
|
||||
- ``ai_provider/`` 只**消费**本目录的配置,不持有自己的
|
||||
``settings.py`` / ``config.py``;领域数据结构(``ModelConfig`` 等)保留在
|
||||
``ai_provider/config/models.py``。
|
||||
"""
|
||||
|
||||
from app.core.config.sandbox_config import SandboxSettings
|
||||
from app.core.config.settings import Settings, settings
|
||||
|
||||
__all__ = ["SandboxSettings", "Settings", "settings"]
|
||||
@@ -0,0 +1,53 @@
|
||||
"""应用基础配置:运行环境、端口、CORS、默认模型提示等。"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Literal
|
||||
|
||||
from pydantic_settings import BaseSettings
|
||||
|
||||
|
||||
class AppConfig(BaseSettings):
|
||||
"""应用基础配置。"""
|
||||
|
||||
# ==================== 基础配置 ====================
|
||||
app_name: str = "魂镜后端" # 应用名称
|
||||
app_env: Literal["dev", "prod"] = "dev" # 运行环境:dev(开发) / prod(生产)
|
||||
debug: bool = False # 调试模式
|
||||
timezone: str = "Asia/Shanghai" # 时区
|
||||
api_prefix: str = "/api/v1" # API 路由前缀
|
||||
backend_host: str = "0.0.0.0" # 监听地址
|
||||
backend_port: int = 8000 # 监听端口
|
||||
cors_allow_origins: str = "http://localhost:3000" # CORS 允许的源,逗号分隔
|
||||
|
||||
# ==================== 业务默认值 ====================
|
||||
default_owner_scope: str = "local-user" # 默认所有者作用域
|
||||
default_model_hint: str = "deepseek-v4-flash" # 默认真实远程逻辑模型提示
|
||||
|
||||
# ==================== 默认人物模板配置 ====================
|
||||
character_templates_path: str = (
|
||||
"../config/character_templates.yaml" # 人物模板配置文件路径(相对 backend)
|
||||
)
|
||||
|
||||
# ==================== 文件存储 ====================
|
||||
avatar_dir: str = "../db/avatars" # 角色头像文件存储目录(相对 backend)
|
||||
|
||||
# ==================== 默认管理员用户 ====================
|
||||
default_admin_username: str = "admin" # 种子默认管理员用户名
|
||||
default_admin_email: str = "admin@hunjing.local" # 种子默认管理员邮箱
|
||||
default_admin_password: str = "admin123" # 种子默认管理员密码(引导用,生产立即修改)
|
||||
|
||||
@property
|
||||
def cors_origins(self) -> list[str]:
|
||||
"""解析 CORS 允许的源为列表。"""
|
||||
return [origin.strip() for origin in self.cors_allow_origins.split(",") if origin.strip()]
|
||||
|
||||
@property
|
||||
def is_development(self) -> bool:
|
||||
"""是否为开发环境。"""
|
||||
return self.app_env == "dev"
|
||||
|
||||
@property
|
||||
def is_production(self) -> bool:
|
||||
"""是否为生产环境。"""
|
||||
return self.app_env == "prod"
|
||||
@@ -0,0 +1,29 @@
|
||||
"""认证与鉴权配置。
|
||||
|
||||
当前(v1 单用户)仅含管理端点访问凭证 ``admin_token``;v2 多用户上线后扩展为
|
||||
完整认证配置(JWT 签发密钥、access/refresh token TTL 等),见
|
||||
[多用户与租户隔离设计](../../../docs/product/master-prd.md)。
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from pydantic_settings import BaseSettings
|
||||
|
||||
|
||||
class AuthConfig(BaseSettings):
|
||||
"""认证与鉴权配置。"""
|
||||
|
||||
# ==================== 管理端点访问(v1) ====================
|
||||
# 司命台管理 API(/admin/*)的访问凭证。部署期配置,非用户登录凭证:
|
||||
# 请求需在 Authorization 头携带 ``Bearer <ADMIN_TOKEN>``,经 require_admin 校验。
|
||||
# 为空时管理端点 fail-closed(返回 503),强制部署时配置,避免裸奔。
|
||||
# 生产环境务必使用强随机值;v2 多用户上线后由完整认证体系取代。
|
||||
admin_token: str = "" # 管理端点访问凭证(为空则 /admin 返回 503)
|
||||
|
||||
# ==================== JWT 配置(v2 多用户) ====================
|
||||
# JWT 签名密钥。为空时认证端点 fail-closed(503);生产环境务必配置强随机值。
|
||||
jwt_secret: str = ""
|
||||
# Access Token 有效期(秒),默认 15 分钟
|
||||
access_token_ttl: int = 900
|
||||
# Refresh Token 有效期(秒),默认 7 天
|
||||
refresh_token_ttl: int = 604800
|
||||
@@ -0,0 +1,27 @@
|
||||
"""数据库配置:SQLite / PostgreSQL 连接参数。"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Literal
|
||||
|
||||
from pydantic_settings import BaseSettings
|
||||
|
||||
|
||||
class DatabaseConfig(BaseSettings):
|
||||
"""数据库配置。
|
||||
|
||||
本地开发默认使用 SQLite(``aiosqlite``);正式环境通过 ``DATABASE_TYPE=pgsql``
|
||||
切换到 PostgreSQL(``asyncpg``)。``DATABASE_URL`` 优先级最高,可直接覆盖。
|
||||
"""
|
||||
|
||||
database_type: Literal["sqlite", "pgsql"] = "sqlite" # 数据库类型
|
||||
sqlite_database_path: str = "../db/hunjing.sqlite3" # SQLite 数据库路径(相对 backend)
|
||||
database_url: str = "" # 自定义数据库连接 URL(优先级最高)
|
||||
postgres_host: str = "127.0.0.1" # PostgreSQL 主机
|
||||
postgres_port: int = 5432 # PostgreSQL 端口
|
||||
postgres_db: str = "hunjing" # PostgreSQL 数据库名
|
||||
postgres_user: str = "hunjing" # PostgreSQL 用户名
|
||||
postgres_password: str = "change-me" # PostgreSQL 密码
|
||||
postgres_ssl: bool = False # 是否启用 SSL
|
||||
postgres_pool_size: int = 10 # 连接池大小
|
||||
postgres_max_overflow: int = 20 # 连接池最大溢出连接数
|
||||
@@ -0,0 +1,15 @@
|
||||
"""日志配置。"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from pydantic_settings import BaseSettings
|
||||
|
||||
|
||||
class LogConfig(BaseSettings):
|
||||
"""日志配置(loguru)。"""
|
||||
|
||||
log_dir: str = "../logs" # 日志目录(相对于 backend 目录)
|
||||
log_level: str = "INFO" # 日志级别:DEBUG/INFO/WARNING/ERROR
|
||||
log_access: bool = True # 是否启用访问日志
|
||||
log_retention_days: int = 14 # 日志保留天数
|
||||
log_rotation_size: str = "10 MB" # 日志轮转大小
|
||||
@@ -0,0 +1,46 @@
|
||||
"""模型网关(神识)env 配置:各 provider 的 API Key / Base URL 与 endpoint 池策略。
|
||||
|
||||
注意区分**配置字段**与**领域数据结构**:
|
||||
- 本文件只承载「从 env 读的开关 / 参数 / 密钥」。
|
||||
- 领域数据结构(``ModelConfig`` / ``ModelEndpointConfig``,从 ``config/models.yaml`` 加载)
|
||||
保留在 ``ai_provider/config/models.py``,不外迁到 ``core/config``。
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from pydantic_settings import BaseSettings
|
||||
|
||||
|
||||
class ModelGatewayConfig(BaseSettings):
|
||||
"""模型网关 env 配置。"""
|
||||
|
||||
# ==================== 模型配置文件 ====================
|
||||
model_config_path: str = "../config/models.yaml" # 模型配置文件路径(相对 backend)
|
||||
|
||||
# ==================== provider API Key / Base URL ====================
|
||||
openai_api_key: str = "" # OpenAI API Key
|
||||
openai_base_url: str = "https://api.openai.com/v1" # OpenAI API 地址
|
||||
deepseek_api_key: str = "" # DeepSeek API Key
|
||||
deepseek_base_url: str = "https://api.deepseek.com" # DeepSeek API 地址(OpenAI 兼容)
|
||||
xiaomi_mimo_api_key: str = "" # 小米 MiMo API Key
|
||||
xiaomi_mimo_base_url: str = "https://api.xiaomimimo.com/v1" # 小米 MiMo API 地址
|
||||
anthropic_api_key: str = "" # Anthropic API Key
|
||||
anthropic_base_url: str = "https://api.anthropic.com" # Anthropic API 地址
|
||||
volcengine_ark_api_key: str = "" # 火山方舟 / 豆包 API Key
|
||||
volcengine_ark_base_url: str = "https://ark.cn-beijing.volces.com/api/v3" # 火山方舟 API 地址
|
||||
custom_llm_api_key: str = "" # 自定义 LLM API Key
|
||||
custom_llm_base_url: str = "" # 自定义 LLM API 地址
|
||||
yuanqi_api_key: str = "" # 元炁本地推理引擎 API Key
|
||||
yuanqi_base_url: str = "http://localhost:11434" # 元炁本地推理引擎 API 地址
|
||||
|
||||
# ==================== endpoint 池配置 ====================
|
||||
# 物理 endpoint 池路由、failover 与重试策略(见 ai_provider/pool.py 与 resilience.py)
|
||||
model_endpoint_pool_enabled: bool = True # 是否启用 endpoint 池路由(False 时走逻辑模型直连)
|
||||
model_endpoint_pool_dry_run_selection: bool = False # dry-run:只预选并记录,不实际路由
|
||||
model_endpoint_pool_expose_debug_headers: bool = False # 是否在响应头暴露 endpoint 路由调试信息
|
||||
model_endpoint_pool_agent_failover_enabled: bool = (
|
||||
False # Agent 调用是否允许跨 endpoint failover
|
||||
)
|
||||
model_endpoint_pool_per_endpoint_max_retries: int = 1 # 单 endpoint 失败时的本地重试次数
|
||||
model_endpoint_pool_retry_base_delay_seconds: float = 0.25 # endpoint 本地重试基础退避(秒)
|
||||
model_endpoint_pool_retry_max_delay_seconds: float = 2.0 # endpoint 本地重试最大退避(秒)
|
||||
@@ -0,0 +1,99 @@
|
||||
"""运行时与 SSE 配置:事件流、超时、工具运行时开关等。"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from pydantic_settings import BaseSettings
|
||||
|
||||
|
||||
class RuntimeConfig(BaseSettings):
|
||||
"""SSE / 运行时 / 工具运行时配置。"""
|
||||
|
||||
# ==================== SSE 配置 ====================
|
||||
enable_sse: bool = True # 是否启用 SSE
|
||||
max_text_message_bytes: int = 32768 # 最大文本消息字节数
|
||||
sse_poll_interval_seconds: float = 0.01 # SSE 轮询间隔(秒,10ms:前端逐段平滑增量)
|
||||
sse_heartbeat_seconds: float = 15.0 # SSE 心跳间隔(秒)
|
||||
run_timeout_seconds: int = 120 # 运行超时时间(秒)
|
||||
# Agent 循环最大轮数:模型每轮仍带工具调用则继续,超限截断返回(见 agent.runtime.DEFAULT_MAX_ITERATIONS)
|
||||
agent_max_iterations: int = 8
|
||||
# 单次高风险工具确认挂起超时(秒):须小于 run_timeout_seconds,超时按拒绝处理;
|
||||
# 若 >= run_timeout_seconds,run 整体超时会先到,导致确认中的 run 直接 failed
|
||||
confirmation_timeout_seconds: int = 60
|
||||
# 是否启用数据库持久化的确认存储(用于多 worker 部署);关闭则使用进程内 InMemoryConfirmationStore(默认)
|
||||
use_db_confirmation_store: bool = False
|
||||
run_max_events: int = 1000 # 最大事件数
|
||||
event_payload_max_bytes: int = 65536 # 事件负载最大字节数
|
||||
memory_injection_limit: int = 5 # 记忆注入条数上限
|
||||
|
||||
# ==================== 工具运行时配置 ====================
|
||||
enable_tool_runtime: bool = True # 是否启用百工工具运行时(司命 + 沙箱)
|
||||
tool_timeout_seconds: int = 600 # 单个工具调用超时秒数
|
||||
|
||||
# ==================== 洛书规划器 ====================
|
||||
enable_deliberative_planning: bool = False # 是否启用显式多步规划(§10.2 增强能力)
|
||||
|
||||
# ==================== 大周天(长期演化循环) ====================
|
||||
enable_big_cycle: bool = True # 是否启用大周天自动触发
|
||||
big_cycle_memory_threshold: int = 20 # 触发大周天的记忆数阈值
|
||||
big_cycle_min_interval_seconds: int = 300 # 两次大周天最小间隔(秒),避免频繁触发
|
||||
big_cycle_model: str = "deepseek-v4-flash" # 大周天候选生成所用模型(models.yaml name 或 tag)
|
||||
big_cycle_max_candidates: int = 10 # 单次大周天生成的演化候选上限
|
||||
big_cycle_token_budget: int = 64000 # 单次大周天的 token 预算上限(超限跳过非关键阶段)
|
||||
big_cycle_max_drift: float = 2.0 # 最大累积漂移值(超过后暂停自动演化)
|
||||
big_cycle_drift_threshold: float = 0.6 # 单次演化候选的漂移阈值(>= 此值不自动应用)
|
||||
|
||||
# ==================== 内驱力(太一枢)[PLANNED] ====================
|
||||
enable_intrinsic_drive: bool = False # 是否启用内驱力扫描(curiosity / exploration)
|
||||
drive_scan_interval_seconds: int = 3600 # 内驱力扫描间隔秒数
|
||||
drive_max_curiosity_per_scan: int = 5 # 单次扫描最多好奇问题数
|
||||
drive_allow_interrupt: bool = False # 是否允许内驱力中断当前任务
|
||||
|
||||
# ==================== 司命安全策略 ====================
|
||||
# 工具策略 YAML 路径(相对 backend);未配置时 SafetyGovernor 使用内置默认空策略。
|
||||
safety_policy_path: str = ""
|
||||
safety_always_confirm_high_risk: bool = True # 高风险动作是否总是确认
|
||||
|
||||
# ==================== MCP / 联网工具网络超时 ====================
|
||||
mcp_list_timeout_seconds: float = 10.0 # MCP tools/list 请求超时(秒)
|
||||
mcp_call_timeout_seconds: float = 30.0 # MCP tools/call 请求超时(秒)
|
||||
tool_web_http_timeout_seconds: float = 15.0 # fetch_url 的 HTTP 超时(秒)
|
||||
|
||||
# ==================== MCP stdio 子进程 ====================
|
||||
mcp_stdio_start_timeout_seconds: float = 15.0 # stdio 子进程启动超时(秒)
|
||||
mcp_stdio_call_timeout_seconds: float = 30.0 # stdio 单次 tools/call 超时(秒)
|
||||
mcp_stdio_stop_timeout_seconds: float = 5.0 # SIGTERM → SIGKILL 等待(秒)
|
||||
|
||||
# ==================== 向量记忆检索 ====================
|
||||
vector_db_enabled: bool = False # 是否启用向量数据库(关则纯 SQL 检索)
|
||||
vector_db_type: str = "chroma" # 向量库类型:chroma / milvus
|
||||
chromadb_host: str = "" # ChromaDB HTTP 主机(空则内存模式)
|
||||
chromadb_port: int = 8000 # ChromaDB HTTP 端口
|
||||
chroma_collection: str = "hunjing_memories" # ChromaDB collection 名
|
||||
chroma_persist_directory: str = "../db/chroma" # ChromaDB 持久化目录(相对 backend)
|
||||
embedding_model_hint: str = "bge-m3" # embedding 模型逻辑名
|
||||
|
||||
# ==================== 自动记忆候选 [PLANNED] ====================
|
||||
enable_memory_candidates: bool = False # 是否启用自动记忆候选抽取
|
||||
memory_candidate_min_importance: float = 0.7 # 候选记忆重要性阈值(0.0~1.0)
|
||||
|
||||
# ==================== 审计日志(司命枢·起居注)[PLANNED] ====================
|
||||
enable_audit_log: bool = True # 是否启用审计日志
|
||||
|
||||
# ==================== 感知(烛照枢)[PLANNED] ====================
|
||||
enable_camera: bool = False # 是否启用摄像头(视觉感知)
|
||||
enable_microphone: bool = False # 是否启用麦克风(听觉感知)
|
||||
perception_save_raw_media: bool = False # 是否保存原始感知文件
|
||||
perception_max_media_mb: int = 20 # 感知文件最大大小(MB)
|
||||
|
||||
# ==================== 语音服务 [PLANNED] ====================
|
||||
enable_asr: bool = False # 是否启用 ASR(语音转文字)
|
||||
enable_tts: bool = False # 是否启用 TTS(文字转语音)
|
||||
enable_voice_training: bool = False # 是否启用语音训练(微调 TTS 音色)
|
||||
enable_voice_chat: bool = False # 是否启用实时语音对话
|
||||
|
||||
# ==================== 导入限制 [PLANNED] ====================
|
||||
import_max_file_mb: int = 20 # 人物资料导入文件最大大小(MB)
|
||||
import_audio_max_duration_seconds: int = 600 # 语音样本最大时长(秒)
|
||||
import_allowed_audio_mime_types: str = (
|
||||
"audio/wav,audio/mpeg,audio/mp4,audio/flac" # 允许上传的语音样本 MIME 类型
|
||||
)
|
||||
@@ -0,0 +1,29 @@
|
||||
"""乾坤沙箱配置。
|
||||
|
||||
从环境变量加载(与根目录 ``.env`` 统一)。字段名与 env 名一一对应(去除前缀后 snake_case
|
||||
即 env 名),由 ``pydantic-settings`` 自动绑定,无需手动 ``os.getenv``。
|
||||
|
||||
- ``rust_sandbox_url`` 取自 ``RUST_SANDBOX_URL``(后端连沙箱的地址)。
|
||||
- ``sandbox_auth_secret`` 与沙箱端 ``SANDBOX_AUTH_SECRET`` 共享,用于 HMAC 授权凭证签发。
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from pydantic_settings import BaseSettings
|
||||
|
||||
|
||||
class SandboxSettings(BaseSettings):
|
||||
"""沙箱客户端运行配置。"""
|
||||
|
||||
rust_sandbox_url: str = "http://127.0.0.1:8090" # RUST_SANDBOX_URL:后端连沙箱的地址
|
||||
sandbox_auth_enabled: bool = True # SANDBOX_AUTH_ENABLED:是否启用 HMAC 授权
|
||||
sandbox_auth_secret: str = "" # SANDBOX_AUTH_SECRET:与沙箱端共享的 HMAC 密钥
|
||||
sandbox_default_timeout_ms: int = 30_000 # SANDBOX_DEFAULT_TIMEOUT_MS:默认执行超时
|
||||
sandbox_auth_ttl_seconds: int = 30 # SANDBOX_AUTH_TTL_SECONDS:授权凭证有效期
|
||||
|
||||
def http_timeout(self, exec_timeout_ms: int | None) -> float:
|
||||
"""HTTP 读取超时:执行超时 + 5s 余量,下限 10s。"""
|
||||
exec_ms = (
|
||||
exec_timeout_ms if exec_timeout_ms is not None else self.sandbox_default_timeout_ms
|
||||
)
|
||||
return max(exec_ms / 1000 + 5.0, 10.0)
|
||||
@@ -0,0 +1,144 @@
|
||||
"""主 Settings:多继承所有子配置,统一以绝对路径 ``_env_file`` 加载 ``.env``。
|
||||
|
||||
子配置见同目录下的 ``app_config`` / ``auth_config`` / ``database_config`` / ``log_config`` /
|
||||
``runtime_config`` / ``model_config`` / ``sandbox_config``。本文件聚合字段,并承载
|
||||
跨子配置的路径解析与计算属性。
|
||||
|
||||
配置优先级(自高到低):命令行参数 > 系统环境变量 > ``.env`` > 类属性默认值。
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from functools import cached_property
|
||||
from pathlib import Path
|
||||
|
||||
from pydantic_settings import BaseSettings, SettingsConfigDict
|
||||
|
||||
from app.core.config.app_config import AppConfig
|
||||
from app.core.config.auth_config import AuthConfig
|
||||
from app.core.config.database_config import DatabaseConfig
|
||||
from app.core.config.log_config import LogConfig
|
||||
from app.core.config.model_config import ModelGatewayConfig
|
||||
from app.core.config.runtime_config import RuntimeConfig
|
||||
from app.core.config.sandbox_config import SandboxSettings
|
||||
from app.core.config.time_config import TimeConfig
|
||||
|
||||
# backend 目录:app/core/config/settings.py → parents[3] = backend/
|
||||
_BACKEND_DIR = Path(__file__).resolve().parents[3]
|
||||
# .env 永远在项目根目录(backend 父级),以绝对路径定位
|
||||
_ENV_FILE = _BACKEND_DIR.parent / ".env"
|
||||
|
||||
|
||||
class Settings(
|
||||
AppConfig,
|
||||
AuthConfig,
|
||||
DatabaseConfig,
|
||||
LogConfig,
|
||||
RuntimeConfig,
|
||||
ModelGatewayConfig,
|
||||
SandboxSettings,
|
||||
TimeConfig,
|
||||
BaseSettings,
|
||||
):
|
||||
"""应用配置类。
|
||||
|
||||
所有配置项可通过 ``.env`` 文件或环境变量覆盖。路径配置会自动解析为绝对路径。
|
||||
"""
|
||||
|
||||
model_config = SettingsConfigDict(
|
||||
env_file=str(_ENV_FILE), # 绝对路径,不使用 python-dotenv
|
||||
env_file_encoding="utf-8",
|
||||
case_sensitive=False, # 环境变量名不区分大小写
|
||||
extra="ignore", # 忽略未定义的额外字段
|
||||
)
|
||||
|
||||
# ==================== 路径解析 ====================
|
||||
|
||||
@cached_property
|
||||
def backend_dir(self) -> Path:
|
||||
"""backend 目录路径。"""
|
||||
return _BACKEND_DIR
|
||||
|
||||
@cached_property
|
||||
def project_root(self) -> Path:
|
||||
"""项目根目录路径(backend 的父级)。"""
|
||||
return _BACKEND_DIR.parent
|
||||
|
||||
def resolve_from_backend(self, value: str) -> Path:
|
||||
"""解析相对于 backend 目录的路径为绝对路径。
|
||||
|
||||
Args:
|
||||
value: 相对路径或绝对路径字符串
|
||||
|
||||
Returns:
|
||||
解析后的绝对路径
|
||||
"""
|
||||
path = Path(value)
|
||||
if path.is_absolute():
|
||||
return path
|
||||
return (self.backend_dir / path).resolve()
|
||||
|
||||
# ==================== 计算属性 ====================
|
||||
|
||||
@property
|
||||
def resolved_database_url(self) -> str:
|
||||
"""解析数据库连接 URL。
|
||||
|
||||
如果设置了 ``database_url`` 则直接使用,否则根据 ``database_type`` 构建。
|
||||
"""
|
||||
if self.database_url:
|
||||
return self.database_url
|
||||
if self.database_type == "sqlite":
|
||||
db_path = self.resolve_from_backend(self.sqlite_database_path)
|
||||
return f"sqlite+aiosqlite:///{db_path}"
|
||||
password = self.postgres_password
|
||||
ssl = "?ssl=require" if self.postgres_ssl else ""
|
||||
return (
|
||||
f"postgresql+asyncpg://{self.postgres_user}:{password}"
|
||||
f"@{self.postgres_host}:{self.postgres_port}/{self.postgres_db}{ssl}"
|
||||
)
|
||||
|
||||
@cached_property
|
||||
def resolved_log_dir(self) -> Path:
|
||||
"""解析日志目录为绝对路径。"""
|
||||
return self.resolve_from_backend(self.log_dir)
|
||||
|
||||
@cached_property
|
||||
def resolved_character_templates_path(self) -> Path:
|
||||
"""解析人物模板配置文件路径。
|
||||
|
||||
如果配置文件不存在,尝试使用示例配置文件。
|
||||
"""
|
||||
configured = self.resolve_from_backend(self.character_templates_path)
|
||||
if configured.exists():
|
||||
return configured
|
||||
example = self.project_root / "config" / "character_templates.example.yaml"
|
||||
if example.exists():
|
||||
return example
|
||||
return configured
|
||||
|
||||
@cached_property
|
||||
def resolved_model_config_path(self) -> Path:
|
||||
"""解析模型配置文件路径。
|
||||
|
||||
如果配置文件不存在,尝试使用示例配置文件。
|
||||
"""
|
||||
configured = self.resolve_from_backend(self.model_config_path)
|
||||
if configured.exists():
|
||||
return configured
|
||||
# 如果配置文件不存在,尝试使用示例配置
|
||||
example = self.project_root / "config" / "models.example.yaml"
|
||||
if example.exists():
|
||||
return example
|
||||
return configured
|
||||
|
||||
@cached_property
|
||||
def resolved_avatar_dir(self) -> Path:
|
||||
"""解析角色头像存储目录为绝对路径。"""
|
||||
path = self.resolve_from_backend(self.avatar_dir)
|
||||
path.mkdir(parents=True, exist_ok=True)
|
||||
return path
|
||||
|
||||
|
||||
# 全局配置实例
|
||||
settings = Settings()
|
||||
@@ -0,0 +1,49 @@
|
||||
"""辰正时态配置。
|
||||
|
||||
所有字段可通过环境变量或 ``.env`` 覆盖(字段名即环境变量名,由 ``Settings.model_config``
|
||||
统一加载,无前缀,与既有 ``AppConfig`` 等同级配置一致)。默认值对齐辰正设计 §7.1
|
||||
离线档位与 §7.2/§7.3 触发阈值。v1 输入无 character 维度的时区/位置(character 模型
|
||||
未持有时区字段),统一用此处的默认值;v2 从档案/会话覆盖。
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from pydantic_settings import BaseSettings
|
||||
|
||||
|
||||
class TimeConfig(BaseSettings):
|
||||
"""辰正时态服务配置。"""
|
||||
|
||||
# 时区与位置(v1 全局默认;v2 从档案/会话覆盖)
|
||||
user_timezone: str = "Asia/Shanghai"
|
||||
home_timezone: str = "Asia/Shanghai"
|
||||
default_city: str = "上海"
|
||||
default_locale: str = "zh-CN"
|
||||
|
||||
# 离线档位阈值(分钟),对齐设计 §7.1 / duration.py 默认
|
||||
offline_active_minutes: float = 60
|
||||
offline_short_absence_minutes: float = 720
|
||||
offline_long_absence_minutes: float = 4320
|
||||
offline_reunion_impact_minutes: float = 4320
|
||||
|
||||
# 感慨触发(§7.2)
|
||||
sentiment_prewarm_days: int = 7
|
||||
# 认识天数有感节点(逗号分隔;§7.2 duration_node)
|
||||
sentiment_duration_nodes: str = "100,200,365,500,730,1000"
|
||||
# 强节气名(§7.2 solar_term;立春/冬至/清明/中秋/除夕等)
|
||||
sentiment_strong_solar_terms: str = "立春,清明,冬至,立夏,立秋,立冬"
|
||||
|
||||
# 关怀触发(§7.3)
|
||||
care_enabled: bool = True
|
||||
jetlag_threshold_minutes: int = 180
|
||||
late_night_min_turns: int = 3
|
||||
|
||||
@property
|
||||
def duration_nodes(self) -> set[int]:
|
||||
"""解析 ``sentiment_duration_nodes`` 为整数集合。"""
|
||||
return {int(x) for x in self.sentiment_duration_nodes.split(",") if x.strip()}
|
||||
|
||||
@property
|
||||
def strong_solar_terms(self) -> set[str]:
|
||||
"""解析强节气名集合。"""
|
||||
return {s.strip() for s in self.sentiment_strong_solar_terms.split(",") if s.strip()}
|
||||
Reference in new issue
Block a user