303 lines
11 KiB
Python
303 lines
11 KiB
Python
from typing import Any, Literal
|
|
|
|
from pydantic import BaseModel, Field
|
|
|
|
|
|
FieldKind = Literal["text", "password", "url", "select", "combobox", "toggle", "number", "status"]
|
|
|
|
|
|
class SettingOption(BaseModel):
|
|
value: str
|
|
label: str
|
|
help: str
|
|
|
|
|
|
class SettingField(BaseModel):
|
|
key: str
|
|
label: str
|
|
description: str
|
|
kind: FieldKind
|
|
required: bool = False
|
|
secret: bool = False
|
|
default: Any = None
|
|
placeholder: str = ""
|
|
options: list[SettingOption] = Field(default_factory=list)
|
|
generator: Literal["hex24", "hex32", "base64_32"] | None = None
|
|
advanced: bool = False
|
|
visible_when: dict[str, Any] | None = None
|
|
|
|
|
|
class SettingCategory(BaseModel):
|
|
id: str
|
|
label: str
|
|
description: str
|
|
test_targets: list[str] = Field(default_factory=list)
|
|
required_for_workflow: bool = False
|
|
fields: list[SettingField]
|
|
|
|
|
|
def option(value: str, label: str, help_text: str) -> SettingOption:
|
|
return SettingOption(value=value, label=label, help=help_text)
|
|
|
|
|
|
CATEGORIES = [
|
|
SettingCategory(
|
|
id="deployment",
|
|
label="基础运行",
|
|
description="由安装器自动管理,通常不需要手动填写。修改数据库密码需要重启服务。",
|
|
test_targets=["infrastructure"],
|
|
required_for_workflow=True,
|
|
fields=[
|
|
SettingField(
|
|
key="database_status",
|
|
label="PostgreSQL",
|
|
description="保存项目、版本、任务和结构化设计状态。密码由启动脚本自动生成。",
|
|
kind="status",
|
|
required=True,
|
|
),
|
|
SettingField(
|
|
key="redis_status",
|
|
label="Redis",
|
|
description="用于任务队列、缓存和并发锁。密码由启动脚本自动生成。",
|
|
kind="status",
|
|
required=True,
|
|
),
|
|
SettingField(
|
|
key="encryption_status",
|
|
label="配置加密",
|
|
description="模型 API Key 会加密保存;主密钥首次启动时自动生成,不显示在页面中。",
|
|
kind="status",
|
|
required=True,
|
|
),
|
|
],
|
|
),
|
|
SettingCategory(
|
|
id="storage",
|
|
label="文件存储",
|
|
description="保存原始户型、清洗图、3D 白模和效果图。你的 NAS MinIO 可以直接使用。",
|
|
test_targets=["storage"],
|
|
required_for_workflow=True,
|
|
fields=[
|
|
SettingField(
|
|
key="s3_endpoint",
|
|
label="MinIO 内部地址",
|
|
description="后端访问 NAS 的 S3 API 地址,不是 MinIO 控制台地址。",
|
|
kind="url",
|
|
required=True,
|
|
placeholder="http://192.168.200.36:9000",
|
|
),
|
|
SettingField(
|
|
key="s3_public_endpoint",
|
|
label="浏览器可访问地址",
|
|
description="上传和预览文件时使用;纯内网部署通常与内部地址相同。",
|
|
kind="url",
|
|
required=True,
|
|
placeholder="http://192.168.200.36:9000",
|
|
),
|
|
SettingField(
|
|
key="s3_access_key_id",
|
|
label="服务账号 Access Key",
|
|
description="建议在 MinIO 中单独创建服务账号,不要使用 Root 账号。",
|
|
kind="password",
|
|
required=True,
|
|
secret=True,
|
|
),
|
|
SettingField(
|
|
key="s3_secret_access_key",
|
|
label="服务账号 Secret Key",
|
|
description="仅加密保存于后端,不会返回到浏览器。",
|
|
kind="password",
|
|
required=True,
|
|
secret=True,
|
|
),
|
|
SettingField(
|
|
key="s3_bucket_inputs",
|
|
label="原始文件空间",
|
|
description="保存用户上传的 PDF、DXF 和图片;测试会提示是否缺失。",
|
|
kind="text",
|
|
required=True,
|
|
default="renovation-inputs",
|
|
),
|
|
SettingField(
|
|
key="s3_bucket_derived",
|
|
label="中间结果空间",
|
|
description="保存 SVG、控制图、蒙版和 GLB 白模。",
|
|
kind="text",
|
|
required=True,
|
|
default="renovation-derived",
|
|
),
|
|
SettingField(
|
|
key="s3_bucket_renders",
|
|
label="效果图空间",
|
|
description="保存方向图、效果图和局部修改版本。",
|
|
kind="text",
|
|
required=True,
|
|
default="renovation-renders",
|
|
),
|
|
SettingField(
|
|
key="s3_force_path_style",
|
|
label="MinIO 兼容模式",
|
|
description="MinIO 通常保持开启;AWS S3 可以关闭。",
|
|
kind="toggle",
|
|
default=True,
|
|
advanced=True,
|
|
),
|
|
],
|
|
),
|
|
SettingCategory(
|
|
id="document",
|
|
label="图纸识别",
|
|
description="矢量 PDF 优先直接解析;只有扫描图或文字层损坏时才调用 OCR。",
|
|
test_targets=["baidu_ocr"],
|
|
fields=[
|
|
SettingField(
|
|
key="baidu_ocr_enabled",
|
|
label="启用百度 OCR",
|
|
description="开启后,扫描户型图会使用百度 OCR 识别尺寸和文字。",
|
|
kind="toggle",
|
|
default=False,
|
|
),
|
|
SettingField(
|
|
key="baidu_ocr_api_key",
|
|
label="百度 OCR API Key",
|
|
description="来自百度智能云 OCR 应用。",
|
|
kind="password",
|
|
required=True,
|
|
secret=True,
|
|
visible_when={"baidu_ocr_enabled": True},
|
|
),
|
|
SettingField(
|
|
key="baidu_ocr_secret_key",
|
|
label="百度 OCR Secret Key",
|
|
description="只用于换取访问令牌,不会返回前端。",
|
|
kind="password",
|
|
required=True,
|
|
secret=True,
|
|
visible_when={"baidu_ocr_enabled": True},
|
|
),
|
|
],
|
|
),
|
|
SettingCategory(
|
|
id="models",
|
|
label="模型池",
|
|
description="分别添加大语言模型与多模态模型。每个模型独立配置、独立测试,再用于总调度、空间理解或生图路由。",
|
|
required_for_workflow=True,
|
|
fields=[],
|
|
),
|
|
SettingCategory(
|
|
id="gpu",
|
|
label="本地算力",
|
|
description="GPU 主要用于户型分割、深度估计和本地视觉模型,不是调用云端生图 API 的必需项。",
|
|
test_targets=["gpu"],
|
|
fields=[
|
|
SettingField(
|
|
key="gpu_mode",
|
|
label="运行方式",
|
|
description="同机 Worker 会自动使用本机地址;只有独立 GPU 服务器才需要手填地址。",
|
|
kind="select",
|
|
default="disabled",
|
|
options=[
|
|
option("disabled", "暂不使用本地 GPU", "全部使用云端 API,最容易部署。"),
|
|
option("local", "本机 GPU Worker", "API 通过本机 Worker 调用显卡,页面无需填写地址。"),
|
|
option("remote", "局域网 GPU 服务器", "GPU 在另一台机器时填写内网地址。"),
|
|
],
|
|
),
|
|
SettingField(
|
|
key="gpu_service_url",
|
|
label="GPU 服务地址",
|
|
description="仅远程模式需要,例如 http://192.168.200.50:8100。",
|
|
kind="url",
|
|
required=True,
|
|
placeholder="http://192.168.200.50:8100",
|
|
visible_when={"gpu_mode": "remote"},
|
|
),
|
|
SettingField(
|
|
key="gpu_service_token",
|
|
label="内部访问令牌",
|
|
description="用于阻止其他内网设备随意调用 GPU;可以一键生成。",
|
|
kind="password",
|
|
required=True,
|
|
secret=True,
|
|
generator="hex32",
|
|
visible_when={"gpu_mode__not": "disabled"},
|
|
),
|
|
],
|
|
),
|
|
SettingCategory(
|
|
id="observability",
|
|
label="监控与追踪",
|
|
description="均为可选项。Langfuse 用于评估模型链路,Sentry 用于发现程序异常。",
|
|
test_targets=["langfuse", "sentry"],
|
|
fields=[
|
|
SettingField(
|
|
key="langfuse_enabled",
|
|
label="启用 Langfuse",
|
|
description="记录每次 Agent 调用、模型耗时、费用与评测结果。",
|
|
kind="toggle",
|
|
default=False,
|
|
),
|
|
SettingField(
|
|
key="langfuse_host",
|
|
label="Langfuse 地址",
|
|
description="支持自部署地址,例如 http://192.168.200.20:3001。",
|
|
kind="url",
|
|
required=True,
|
|
visible_when={"langfuse_enabled": True},
|
|
),
|
|
SettingField(
|
|
key="langfuse_public_key",
|
|
label="Langfuse Public Key",
|
|
description="从 Langfuse 项目设置中复制。",
|
|
kind="password",
|
|
required=True,
|
|
secret=True,
|
|
visible_when={"langfuse_enabled": True},
|
|
),
|
|
SettingField(
|
|
key="langfuse_secret_key",
|
|
label="Langfuse Secret Key",
|
|
description="只保存在后端。",
|
|
kind="password",
|
|
required=True,
|
|
secret=True,
|
|
visible_when={"langfuse_enabled": True},
|
|
),
|
|
SettingField(
|
|
key="sentry_enabled",
|
|
label="启用 Sentry",
|
|
description="收集异常和性能问题,支持自部署。",
|
|
kind="toggle",
|
|
default=False,
|
|
),
|
|
SettingField(
|
|
key="sentry_dsn",
|
|
label="Sentry DSN",
|
|
description="从 Sentry 项目的 Client Keys 页面复制。",
|
|
kind="password",
|
|
required=True,
|
|
secret=True,
|
|
visible_when={"sentry_enabled": True},
|
|
),
|
|
SettingField(
|
|
key="sentry_traces_sample_rate",
|
|
label="性能采样率",
|
|
description="0 表示关闭,0.1 表示记录约 10% 的请求。",
|
|
kind="select",
|
|
default="0",
|
|
visible_when={"sentry_enabled": True},
|
|
options=[
|
|
option("0", "仅错误,不采集性能", "最省资源,适合初期。"),
|
|
option("0.05", "采样 5%", "适合请求量较大的生产环境。"),
|
|
option("0.1", "采样 10%", "排障信息和资源消耗较均衡。"),
|
|
option("1", "全部采样", "仅建议短期排障使用。"),
|
|
],
|
|
),
|
|
],
|
|
),
|
|
]
|
|
|
|
|
|
FIELDS = {field.key: field for category in CATEGORIES for field in category.fields}
|
|
SECRET_FIELDS = {key for key, field in FIELDS.items() if field.secret}
|
|
EDITABLE_FIELDS = {key for key, field in FIELDS.items() if field.kind != "status"}
|