feat: add system settings with model connectivity and encrypted storage
This commit is contained in:
185
server/src/app/schemas/settings.py
Normal file
185
server/src/app/schemas/settings.py
Normal file
@@ -0,0 +1,185 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import datetime
|
||||
from typing import Literal
|
||||
|
||||
from pydantic import BaseModel, Field, field_validator
|
||||
|
||||
|
||||
class SettingsCompanyForm(BaseModel):
|
||||
companyName: str = Field(min_length=1, max_length=120)
|
||||
displayName: str = Field(min_length=1, max_length=120)
|
||||
companyCode: str = Field(default="", max_length=64)
|
||||
recordNumber: str = Field(default="", max_length=120)
|
||||
copyright: str = Field(default="", max_length=255)
|
||||
|
||||
@field_validator("companyName", "displayName", "companyCode", "recordNumber", "copyright", mode="before")
|
||||
@classmethod
|
||||
def strip_string(cls, value: str | None) -> str | None:
|
||||
if value is None:
|
||||
return None
|
||||
return value.strip()
|
||||
|
||||
|
||||
class SettingsAdminForm(BaseModel):
|
||||
adminAccount: str = Field(min_length=1, max_length=120)
|
||||
adminEmail: str = Field(min_length=1, max_length=255)
|
||||
newPassword: str = Field(default="", max_length=128)
|
||||
confirmPassword: str = Field(default="", max_length=128)
|
||||
sessionTimeout: int = Field(default=30, ge=5, le=240)
|
||||
noticeEmail: str = Field(default="", max_length=255)
|
||||
mfaEnabled: bool = True
|
||||
strongPassword: bool = True
|
||||
loginAlertEnabled: bool = True
|
||||
adminPasswordConfigured: bool = False
|
||||
|
||||
@field_validator("adminAccount", "adminEmail", "newPassword", "confirmPassword", "noticeEmail", mode="before")
|
||||
@classmethod
|
||||
def strip_string(cls, value: str | None) -> str | None:
|
||||
if value is None:
|
||||
return None
|
||||
return value.strip()
|
||||
|
||||
|
||||
class SettingsLlmForm(BaseModel):
|
||||
mainProvider: str = Field(min_length=1, max_length=64)
|
||||
mainModel: str = Field(min_length=1, max_length=255)
|
||||
mainEndpoint: str = Field(min_length=1, max_length=512)
|
||||
mainApiKey: str = Field(default="", max_length=1024)
|
||||
mainApiKeyConfigured: bool = False
|
||||
|
||||
backupProvider: str = Field(min_length=1, max_length=64)
|
||||
backupModel: str = Field(min_length=1, max_length=255)
|
||||
backupEndpoint: str = Field(min_length=1, max_length=512)
|
||||
backupApiKey: str = Field(default="", max_length=1024)
|
||||
backupApiKeyConfigured: bool = False
|
||||
|
||||
vlmProvider: str = Field(min_length=1, max_length=64)
|
||||
vlmModel: str = Field(min_length=1, max_length=255)
|
||||
vlmEndpoint: str = Field(min_length=1, max_length=512)
|
||||
vlmApiKey: str = Field(default="", max_length=1024)
|
||||
vlmApiKeyConfigured: bool = False
|
||||
|
||||
embeddingProvider: str = Field(min_length=1, max_length=64)
|
||||
embeddingModel: str = Field(min_length=1, max_length=255)
|
||||
embeddingEndpoint: str = Field(min_length=1, max_length=512)
|
||||
embeddingApiKey: str = Field(default="", max_length=1024)
|
||||
embeddingApiKeyConfigured: bool = False
|
||||
|
||||
@field_validator(
|
||||
"mainProvider",
|
||||
"mainModel",
|
||||
"mainEndpoint",
|
||||
"mainApiKey",
|
||||
"backupProvider",
|
||||
"backupModel",
|
||||
"backupEndpoint",
|
||||
"backupApiKey",
|
||||
"vlmProvider",
|
||||
"vlmModel",
|
||||
"vlmEndpoint",
|
||||
"vlmApiKey",
|
||||
"embeddingProvider",
|
||||
"embeddingModel",
|
||||
"embeddingEndpoint",
|
||||
"embeddingApiKey",
|
||||
mode="before",
|
||||
)
|
||||
@classmethod
|
||||
def strip_string(cls, value: str | None) -> str | None:
|
||||
if value is None:
|
||||
return None
|
||||
return value.strip()
|
||||
|
||||
|
||||
class SettingsLogForm(BaseModel):
|
||||
level: str = Field(min_length=1, max_length=16)
|
||||
retentionDays: int = Field(default=180, ge=1, le=3650)
|
||||
archiveCycle: str = Field(default="weekly", max_length=32)
|
||||
logPath: str = Field(min_length=1, max_length=255)
|
||||
alertEmail: str = Field(default="", max_length=255)
|
||||
operationAudit: bool = True
|
||||
loginAudit: bool = True
|
||||
maskSensitive: bool = True
|
||||
|
||||
@field_validator("level", "archiveCycle", "logPath", "alertEmail", mode="before")
|
||||
@classmethod
|
||||
def strip_string(cls, value: str | None) -> str | None:
|
||||
if value is None:
|
||||
return None
|
||||
return value.strip()
|
||||
|
||||
|
||||
class SettingsMailForm(BaseModel):
|
||||
smtpHost: str = Field(min_length=1, max_length=255)
|
||||
port: int = Field(default=465, ge=1, le=65535)
|
||||
encryption: str = Field(default="SSL/TLS", max_length=32)
|
||||
senderName: str = Field(default="", max_length=120)
|
||||
senderAddress: str = Field(default="", max_length=255)
|
||||
username: str = Field(default="", max_length=255)
|
||||
password: str = Field(default="", max_length=1024)
|
||||
passwordConfigured: bool = False
|
||||
alertEnabled: bool = True
|
||||
digestEnabled: bool = False
|
||||
digestTime: str = Field(default="09:00", max_length=16)
|
||||
defaultReceiver: str = Field(default="", max_length=255)
|
||||
|
||||
@field_validator(
|
||||
"smtpHost",
|
||||
"encryption",
|
||||
"senderName",
|
||||
"senderAddress",
|
||||
"username",
|
||||
"password",
|
||||
"digestTime",
|
||||
"defaultReceiver",
|
||||
mode="before",
|
||||
)
|
||||
@classmethod
|
||||
def strip_string(cls, value: str | None) -> str | None:
|
||||
if value is None:
|
||||
return None
|
||||
return value.strip()
|
||||
|
||||
|
||||
class SettingsRead(BaseModel):
|
||||
companyForm: SettingsCompanyForm
|
||||
adminForm: SettingsAdminForm
|
||||
llmForm: SettingsLlmForm
|
||||
logForm: SettingsLogForm
|
||||
mailForm: SettingsMailForm
|
||||
|
||||
|
||||
class SettingsWrite(BaseModel):
|
||||
companyForm: SettingsCompanyForm
|
||||
adminForm: SettingsAdminForm
|
||||
llmForm: SettingsLlmForm
|
||||
logForm: SettingsLogForm
|
||||
mailForm: SettingsMailForm
|
||||
|
||||
|
||||
class ModelConnectivityTestRequest(BaseModel):
|
||||
provider: str = Field(min_length=1, max_length=64)
|
||||
endpoint: str = Field(min_length=1, max_length=512)
|
||||
model: str = Field(min_length=1, max_length=255)
|
||||
api_key: str | None = Field(default=None, max_length=1024)
|
||||
capability: Literal["chat", "embedding"] = "chat"
|
||||
slot: Literal["main", "backup", "vlm", "embedding"] | None = None
|
||||
|
||||
@field_validator("provider", "endpoint", "model", "api_key", mode="before")
|
||||
@classmethod
|
||||
def strip_model_string(cls, value: str | None) -> str | None:
|
||||
if value is None:
|
||||
return None
|
||||
return value.strip()
|
||||
|
||||
|
||||
class ModelConnectivityTestRead(BaseModel):
|
||||
ok: bool
|
||||
provider: str
|
||||
model: str
|
||||
endpoint: str
|
||||
capability: str
|
||||
detail: str
|
||||
status_code: int | None = None
|
||||
checked_at: datetime
|
||||
Reference in New Issue
Block a user