Merge origin/main into main
commit
73b9afa037
|
|
@ -34,7 +34,6 @@ DEFAULT_BOT_SYSTEM_TIMEZONE=Asia/Shanghai
|
|||
# The following platform-level items are initialized by SQL and managed in sys_setting / 平台参数:
|
||||
# - page_size
|
||||
# - chat_pull_page_size
|
||||
# - command_auto_unlock_seconds
|
||||
# - upload_max_mb
|
||||
# - allowed_attachment_extensions
|
||||
# - workspace_download_extensions
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ from services.bot_management_service import (
|
|||
list_bots_with_cache,
|
||||
update_bot_record,
|
||||
)
|
||||
from services.image_service import list_registered_images
|
||||
from services.provider_service import test_provider_connection
|
||||
|
||||
router = APIRouter()
|
||||
|
|
@ -28,6 +29,22 @@ async def test_provider(payload: dict):
|
|||
return await test_provider_connection(payload)
|
||||
|
||||
|
||||
@router.post("/api/bots/{bot_id}/providers/test")
|
||||
async def test_bot_provider(bot_id: str, payload: dict, session: Session = Depends(get_session)):
|
||||
bot = session.get(BotInstance, bot_id)
|
||||
if not bot:
|
||||
raise HTTPException(status_code=404, detail="Bot not found")
|
||||
return await test_provider_connection(payload)
|
||||
|
||||
|
||||
@router.get("/api/bots/{bot_id}/images")
|
||||
def list_bot_images(bot_id: str, session: Session = Depends(get_session)):
|
||||
bot = session.get(BotInstance, bot_id)
|
||||
if not bot:
|
||||
raise HTTPException(status_code=404, detail="Bot not found")
|
||||
return list_registered_images(session)
|
||||
|
||||
|
||||
@router.post("/api/bots")
|
||||
def create_bot(payload: BotCreateRequest, session: Session = Depends(get_session)):
|
||||
return create_bot_record(session, payload=payload)
|
||||
|
|
|
|||
|
|
@ -34,7 +34,6 @@ def get_system_defaults():
|
|||
"chat": {
|
||||
"pull_page_size": platform_settings.chat_pull_page_size,
|
||||
"page_size": platform_settings.page_size,
|
||||
"command_auto_unlock_seconds": platform_settings.command_auto_unlock_seconds,
|
||||
},
|
||||
"topic_presets": get_topic_presets()["presets"],
|
||||
"speech": {
|
||||
|
|
|
|||
|
|
@ -45,7 +45,6 @@ REQUIRED_TABLES = (
|
|||
REQUIRED_SYS_SETTING_KEYS = (
|
||||
"page_size",
|
||||
"chat_pull_page_size",
|
||||
"command_auto_unlock_seconds",
|
||||
"auth_token_ttl_hours",
|
||||
"auth_token_max_active",
|
||||
"upload_max_mb",
|
||||
|
|
|
|||
|
|
@ -187,7 +187,6 @@ DATABASE_POOL_RECYCLE: Final[int] = _env_int("DATABASE_POOL_RECYCLE", 1800, 30,
|
|||
DEFAULT_UPLOAD_MAX_MB: Final[int] = 100
|
||||
DEFAULT_PAGE_SIZE: Final[int] = 10
|
||||
DEFAULT_CHAT_PULL_PAGE_SIZE: Final[int] = 60
|
||||
DEFAULT_COMMAND_AUTO_UNLOCK_SECONDS: Final[int] = 10
|
||||
DEFAULT_AUTH_TOKEN_TTL_HOURS: Final[int] = _env_int("AUTH_TOKEN_TTL_HOURS", 24, 1, 720)
|
||||
DEFAULT_AUTH_TOKEN_MAX_ACTIVE: Final[int] = _env_int("AUTH_TOKEN_MAX_ACTIVE", 2, 1, 20)
|
||||
DEFAULT_BOT_SYSTEM_TIMEZONE: Final[str] = str(
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ from pydantic import BaseModel, Field
|
|||
class PlatformSettingsPayload(BaseModel):
|
||||
page_size: int = Field(default=10, ge=1, le=100)
|
||||
chat_pull_page_size: int = Field(default=60, ge=10, le=500)
|
||||
command_auto_unlock_seconds: int = Field(default=10, ge=1, le=600)
|
||||
auth_token_ttl_hours: int = Field(default=24, ge=1, le=720)
|
||||
auth_token_max_active: int = Field(default=2, ge=1, le=20)
|
||||
upload_max_mb: int = Field(default=100, ge=1, le=2048)
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ from core.settings import (
|
|||
DEFAULT_AUTH_TOKEN_MAX_ACTIVE,
|
||||
DEFAULT_AUTH_TOKEN_TTL_HOURS,
|
||||
DEFAULT_CHAT_PULL_PAGE_SIZE,
|
||||
DEFAULT_COMMAND_AUTO_UNLOCK_SECONDS,
|
||||
DEFAULT_PAGE_SIZE,
|
||||
DEFAULT_UPLOAD_MAX_MB,
|
||||
DEFAULT_WORKSPACE_DOWNLOAD_EXTENSIONS,
|
||||
|
|
@ -24,7 +23,6 @@ ACTIVITY_EVENT_RETENTION_SETTING_KEY = "activity_event_retention_days"
|
|||
SETTING_KEYS = (
|
||||
"page_size",
|
||||
"chat_pull_page_size",
|
||||
"command_auto_unlock_seconds",
|
||||
"auth_token_ttl_hours",
|
||||
"auth_token_max_active",
|
||||
"upload_max_mb",
|
||||
|
|
@ -52,15 +50,6 @@ SYSTEM_SETTING_DEFINITIONS: Dict[str, Dict[str, Any]] = {
|
|||
"is_public": True,
|
||||
"sort_order": 8,
|
||||
},
|
||||
"command_auto_unlock_seconds": {
|
||||
"name": "发送按钮自动恢复秒数",
|
||||
"category": "chat",
|
||||
"description": "对话发送后按钮保持停止态的最长秒数,超时后自动恢复为可发送状态。",
|
||||
"value_type": "integer",
|
||||
"value": DEFAULT_COMMAND_AUTO_UNLOCK_SECONDS,
|
||||
"is_public": True,
|
||||
"sort_order": 9,
|
||||
},
|
||||
"auth_token_ttl_hours": {
|
||||
"name": "认证 Token 过期小时数",
|
||||
"category": "auth",
|
||||
|
|
|
|||
|
|
@ -50,7 +50,6 @@ def get_platform_settings(session: Session) -> PlatformSettingsPayload:
|
|||
{
|
||||
"page_size": max(1, min(100, int(data["page_size"]))),
|
||||
"chat_pull_page_size": max(10, min(500, int(data["chat_pull_page_size"]))),
|
||||
"command_auto_unlock_seconds": max(1, min(600, int(data["command_auto_unlock_seconds"]))),
|
||||
"auth_token_ttl_hours": max(1, min(720, int(data["auth_token_ttl_hours"]))),
|
||||
"auth_token_max_active": max(1, min(20, int(data["auth_token_max_active"]))),
|
||||
"upload_max_mb": int(data["upload_max_mb"]),
|
||||
|
|
@ -70,7 +69,6 @@ def save_platform_settings(session: Session, payload: PlatformSettingsPayload) -
|
|||
normalized = PlatformSettingsPayload(
|
||||
page_size=max(1, min(100, int(payload.page_size))),
|
||||
chat_pull_page_size=max(10, min(500, int(payload.chat_pull_page_size))),
|
||||
command_auto_unlock_seconds=max(1, min(600, int(payload.command_auto_unlock_seconds))),
|
||||
auth_token_ttl_hours=max(1, min(720, int(payload.auth_token_ttl_hours))),
|
||||
auth_token_max_active=max(1, min(20, int(payload.auth_token_max_active))),
|
||||
upload_max_mb=payload.upload_max_mb,
|
||||
|
|
|
|||
|
|
@ -15,9 +15,23 @@ from services.platform_settings_core import (
|
|||
)
|
||||
|
||||
REQUIRED_SYSTEM_SETTING_KEYS = tuple(SYSTEM_SETTING_DEFINITIONS.keys())
|
||||
DEPRECATED_SYSTEM_SETTING_KEYS = ("command_auto_unlock_seconds",)
|
||||
|
||||
|
||||
def _prune_deprecated_system_settings(session: Session) -> None:
|
||||
removed = False
|
||||
for key in DEPRECATED_SYSTEM_SETTING_KEYS:
|
||||
row = session.get(PlatformSetting, key)
|
||||
if row is None:
|
||||
continue
|
||||
session.delete(row)
|
||||
removed = True
|
||||
if removed:
|
||||
session.commit()
|
||||
|
||||
|
||||
def validate_required_system_settings(session: Session) -> None:
|
||||
_prune_deprecated_system_settings(session)
|
||||
stmt = select(PlatformSetting.key).where(PlatformSetting.key.in_(REQUIRED_SYSTEM_SETTING_KEYS))
|
||||
present = {
|
||||
str(key or "").strip()
|
||||
|
|
@ -53,6 +67,8 @@ def list_system_settings(session: Session, search: str = "") -> List[Dict[str, A
|
|||
|
||||
def create_or_update_system_setting(session: Session, payload: SystemSettingPayload) -> Dict[str, Any]:
|
||||
normalized_key = _normalize_setting_key(payload.key)
|
||||
if normalized_key in DEPRECATED_SYSTEM_SETTING_KEYS:
|
||||
raise ValueError("Setting key has been removed")
|
||||
definition = SYSTEM_SETTING_DEFINITIONS.get(normalized_key, {})
|
||||
row = _upsert_setting_row(
|
||||
session,
|
||||
|
|
|
|||
|
|
@ -266,7 +266,7 @@ export const dashboardZhCn = {
|
|||
modelName: '模型名称',
|
||||
modelNamePlaceholder: '如 qwen-plus',
|
||||
newApiKey: 'API Key',
|
||||
newApiKeyPlaceholder: '输入 API Key',
|
||||
newApiKeyPlaceholder: '请输入 API Key',
|
||||
testing: '测试中...',
|
||||
testModelConnection: '测试模型连接',
|
||||
cancel: '取消',
|
||||
|
|
|
|||
|
|
@ -44,7 +44,6 @@ export function useBotDashboardModule({
|
|||
const fileNotPreviewableLabel = locale === 'zh' ? '当前文件类型不支持预览' : 'This file type is not previewable';
|
||||
const [botListPageSize, setBotListPageSize] = useState(10);
|
||||
const [chatPullPageSize, setChatPullPageSize] = useState(60);
|
||||
const [commandAutoUnlockSeconds, setCommandAutoUnlockSeconds] = useState(10);
|
||||
const isZh = locale === 'zh';
|
||||
const botSearchInputName = `nbot-search-${useId().replace(/:/g, '-')}`;
|
||||
const workspaceSearchInputName = `nbot-workspace-search-${useId().replace(/:/g, '-')}`;
|
||||
|
|
@ -63,7 +62,6 @@ export function useBotDashboardModule({
|
|||
notify,
|
||||
setBotListPageSize,
|
||||
setChatPullPageSize,
|
||||
setCommandAutoUnlockSeconds,
|
||||
});
|
||||
const {
|
||||
botListMenuOpen,
|
||||
|
|
@ -435,7 +433,6 @@ export function useBotDashboardModule({
|
|||
filePickerRef,
|
||||
interruptExecution,
|
||||
isInterrupting,
|
||||
isSendingBlocked,
|
||||
jumpConversationToDate,
|
||||
loadInitialChatPage,
|
||||
onChatScroll,
|
||||
|
|
@ -466,7 +463,6 @@ export function useBotDashboardModule({
|
|||
canChat,
|
||||
isTaskRunningExternally: isBotThinking,
|
||||
chatPullPageSize,
|
||||
commandAutoUnlockSeconds,
|
||||
pendingAttachments,
|
||||
setPendingAttachments,
|
||||
isUploadingAttachments,
|
||||
|
|
@ -500,7 +496,6 @@ export function useBotDashboardModule({
|
|||
isChatEnabled,
|
||||
} = useDashboardInteractionState({
|
||||
canChat,
|
||||
isSendingBlocked,
|
||||
isVoiceRecording,
|
||||
isVoiceTranscribing,
|
||||
selectedBot,
|
||||
|
|
|
|||
|
|
@ -193,10 +193,14 @@ export function useDashboardBotEditor({
|
|||
notify(t.providerRequired, { tone: 'warning' });
|
||||
return;
|
||||
}
|
||||
const targetBotId = String(selectedBot?.id || selectedBotId || '').trim();
|
||||
const endpoint = targetBotId
|
||||
? `${APP_ENDPOINTS.apiBase}/bots/${encodeURIComponent(targetBotId)}/providers/test`
|
||||
: `${APP_ENDPOINTS.apiBase}/providers/test`;
|
||||
setIsTestingProvider(true);
|
||||
setProviderTestResult('');
|
||||
try {
|
||||
const res = await axios.post(`${APP_ENDPOINTS.apiBase}/providers/test`, {
|
||||
const res = await axios.post(endpoint, {
|
||||
provider: editForm.llm_provider,
|
||||
model: editForm.llm_model,
|
||||
api_key: editForm.api_key.trim(),
|
||||
|
|
@ -214,7 +218,7 @@ export function useDashboardBotEditor({
|
|||
} finally {
|
||||
setIsTestingProvider(false);
|
||||
}
|
||||
}, [editForm.api_base, editForm.api_key, editForm.llm_model, editForm.llm_provider, notify, t]);
|
||||
}, [editForm.api_base, editForm.api_key, editForm.llm_model, editForm.llm_provider, notify, selectedBot?.id, selectedBotId, t]);
|
||||
|
||||
const saveBot = useCallback(async (mode: 'params' | 'agent' | 'base') => {
|
||||
const targetBotId = String(selectedBot?.id || selectedBotId || '').trim();
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { useCallback, useEffect, useState, type Dispatch, type SetStateAction } from 'react';
|
||||
import { useCallback, useState, type Dispatch, type SetStateAction } from 'react';
|
||||
import axios from 'axios';
|
||||
|
||||
import { APP_ENDPOINTS } from '../../../config/env';
|
||||
|
|
@ -42,7 +42,6 @@ interface UseDashboardChatCommandDispatchOptions {
|
|||
selectedBot?: { id: string } | null;
|
||||
canChat: boolean;
|
||||
isTaskRunningExternally: boolean;
|
||||
commandAutoUnlockSeconds: number;
|
||||
command: string;
|
||||
pendingAttachments: string[];
|
||||
quotedReply: QuotedReply | null;
|
||||
|
|
@ -62,7 +61,6 @@ export function useDashboardChatCommandDispatch({
|
|||
selectedBot,
|
||||
canChat,
|
||||
isTaskRunningExternally,
|
||||
commandAutoUnlockSeconds,
|
||||
command,
|
||||
pendingAttachments,
|
||||
quotedReply,
|
||||
|
|
@ -78,40 +76,15 @@ export function useDashboardChatCommandDispatch({
|
|||
t,
|
||||
}: UseDashboardChatCommandDispatchOptions) {
|
||||
const [sendingByBot, setSendingByBot] = useState<Record<string, number>>({});
|
||||
const [commandAutoUnlockDeadlineByBot, setCommandAutoUnlockDeadlineByBot] = useState<Record<string, number>>({});
|
||||
const [interruptingByBot, setInterruptingByBot] = useState<Record<string, boolean>>({});
|
||||
const [controlCommandByBot, setControlCommandByBot] = useState<Record<string, string>>({});
|
||||
|
||||
const selectedBotSendingCount = selectedBot ? Number(sendingByBot[selectedBot.id] || 0) : 0;
|
||||
const selectedBotAutoUnlockDeadline = selectedBot ? Number(commandAutoUnlockDeadlineByBot[selectedBot.id] || 0) : 0;
|
||||
const activeControlCommand = selectedBot ? controlCommandByBot[selectedBot.id] || '' : '';
|
||||
const isSending = selectedBotSendingCount > 0;
|
||||
const isTaskRunning = Boolean(selectedBot && (isSending || isTaskRunningExternally));
|
||||
const isCommandAutoUnlockWindowActive = selectedBotAutoUnlockDeadline > Date.now();
|
||||
const isSendingBlocked = isSending && isCommandAutoUnlockWindowActive;
|
||||
const isInterrupting = Boolean(selectedBot && interruptingByBot[selectedBot.id]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!selectedBot?.id || selectedBotAutoUnlockDeadline <= 0) return;
|
||||
const remaining = selectedBotAutoUnlockDeadline - Date.now();
|
||||
if (remaining <= 0) {
|
||||
setCommandAutoUnlockDeadlineByBot((prev) => {
|
||||
const next = { ...prev };
|
||||
delete next[selectedBot.id];
|
||||
return next;
|
||||
});
|
||||
return;
|
||||
}
|
||||
const timer = window.setTimeout(() => {
|
||||
setCommandAutoUnlockDeadlineByBot((prev) => {
|
||||
const next = { ...prev };
|
||||
delete next[selectedBot.id];
|
||||
return next;
|
||||
});
|
||||
}, remaining + 20);
|
||||
return () => window.clearTimeout(timer);
|
||||
}, [selectedBot?.id, selectedBotAutoUnlockDeadline]);
|
||||
|
||||
const submitChatPayload = useCallback(async ({
|
||||
commandRaw,
|
||||
attachmentsRaw,
|
||||
|
|
@ -137,10 +110,6 @@ export function useDashboardChatCommandDispatch({
|
|||
try {
|
||||
requestAnimationFrame(() => scrollConversationToBottom('auto'));
|
||||
setSendingByBot((prev) => ({ ...prev, [selectedBot.id]: Number(prev[selectedBot.id] || 0) + 1 }));
|
||||
setCommandAutoUnlockDeadlineByBot((prev) => ({
|
||||
...prev,
|
||||
[selectedBot.id]: Date.now() + (commandAutoUnlockSeconds * 1000),
|
||||
}));
|
||||
const res = await axios.post<CommandResponse>(
|
||||
`${APP_ENDPOINTS.apiBase}/bots/${selectedBot.id}/command`,
|
||||
{ command: payloadText, attachments },
|
||||
|
|
@ -168,11 +137,6 @@ export function useDashboardChatCommandDispatch({
|
|||
return true;
|
||||
} catch (error: unknown) {
|
||||
const msg = resolveApiErrorMessage(error, t.sendFail);
|
||||
setCommandAutoUnlockDeadlineByBot((prev) => {
|
||||
const next = { ...prev };
|
||||
delete next[selectedBot.id];
|
||||
return next;
|
||||
});
|
||||
addBotMessage(selectedBot.id, {
|
||||
role: 'assistant',
|
||||
text: t.sendFailMsg(msg),
|
||||
|
|
@ -196,7 +160,6 @@ export function useDashboardChatCommandDispatch({
|
|||
}, [
|
||||
addBotMessage,
|
||||
canChat,
|
||||
commandAutoUnlockSeconds,
|
||||
completeLeadingStagedSubmission,
|
||||
notify,
|
||||
scrollConversationToBottom,
|
||||
|
|
@ -302,7 +265,6 @@ export function useDashboardChatCommandDispatch({
|
|||
interruptExecution,
|
||||
isInterrupting,
|
||||
isSending,
|
||||
isSendingBlocked,
|
||||
isTaskRunning,
|
||||
sendControlCommand,
|
||||
sendCurrentDraft,
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@ interface UseDashboardChatComposerOptions {
|
|||
selectedBot?: { id: string } | null;
|
||||
canChat: boolean;
|
||||
isTaskRunningExternally: boolean;
|
||||
commandAutoUnlockSeconds: number;
|
||||
pendingAttachments: string[];
|
||||
setPendingAttachments: Dispatch<SetStateAction<string[]>>;
|
||||
isUploadingAttachments: boolean;
|
||||
|
|
@ -41,7 +40,6 @@ export function useDashboardChatComposer({
|
|||
selectedBot,
|
||||
canChat,
|
||||
isTaskRunningExternally,
|
||||
commandAutoUnlockSeconds,
|
||||
pendingAttachments,
|
||||
setPendingAttachments,
|
||||
isUploadingAttachments,
|
||||
|
|
@ -111,7 +109,6 @@ export function useDashboardChatComposer({
|
|||
interruptExecution,
|
||||
isInterrupting,
|
||||
isSending,
|
||||
isSendingBlocked,
|
||||
isTaskRunning,
|
||||
sendControlCommand,
|
||||
sendCurrentDraft,
|
||||
|
|
@ -120,7 +117,6 @@ export function useDashboardChatComposer({
|
|||
selectedBot,
|
||||
canChat,
|
||||
isTaskRunningExternally,
|
||||
commandAutoUnlockSeconds,
|
||||
command,
|
||||
pendingAttachments,
|
||||
quotedReply,
|
||||
|
|
@ -281,7 +277,6 @@ export function useDashboardChatComposer({
|
|||
interruptExecution,
|
||||
isInterrupting,
|
||||
isSending,
|
||||
isSendingBlocked,
|
||||
onComposerKeyDown,
|
||||
quoteAssistantReply,
|
||||
quotedReply,
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@ interface UseDashboardConversationOptions {
|
|||
canChat: boolean;
|
||||
isTaskRunningExternally: boolean;
|
||||
chatPullPageSize: number;
|
||||
commandAutoUnlockSeconds: number;
|
||||
pendingAttachments: string[];
|
||||
setPendingAttachments: Dispatch<SetStateAction<string[]>>;
|
||||
isUploadingAttachments: boolean;
|
||||
|
|
@ -50,7 +49,6 @@ export function useDashboardConversation(options: UseDashboardConversationOption
|
|||
selectedBot: options.selectedBot,
|
||||
canChat: options.canChat,
|
||||
isTaskRunningExternally: options.isTaskRunningExternally,
|
||||
commandAutoUnlockSeconds: options.commandAutoUnlockSeconds,
|
||||
pendingAttachments: options.pendingAttachments,
|
||||
setPendingAttachments: options.setPendingAttachments,
|
||||
isUploadingAttachments: options.isUploadingAttachments,
|
||||
|
|
|
|||
|
|
@ -30,7 +30,6 @@ interface UseDashboardBaseStateOptions {
|
|||
|
||||
interface UseDashboardInteractionStateOptions {
|
||||
canChat: boolean;
|
||||
isSendingBlocked?: boolean;
|
||||
isVoiceRecording?: boolean;
|
||||
isVoiceTranscribing?: boolean;
|
||||
selectedBot?: BotState;
|
||||
|
|
@ -227,12 +226,11 @@ export function useDashboardBaseState({
|
|||
|
||||
export function useDashboardInteractionState({
|
||||
canChat,
|
||||
isSendingBlocked = false,
|
||||
isVoiceRecording = false,
|
||||
isVoiceTranscribing = false,
|
||||
selectedBot,
|
||||
}: UseDashboardInteractionStateOptions) {
|
||||
const isChatEnabled = Boolean(canChat && !isSendingBlocked);
|
||||
const isChatEnabled = Boolean(canChat);
|
||||
const canSendControlCommand = Boolean(
|
||||
selectedBot && canChat && !isVoiceRecording && !isVoiceTranscribing,
|
||||
);
|
||||
|
|
|
|||
|
|
@ -71,15 +71,19 @@ export function useDashboardRuntimeControl({
|
|||
);
|
||||
|
||||
const loadImageOptions = useCallback(async () => {
|
||||
const targetBotId = String(selectedBotId || forcedBotId || '').trim();
|
||||
const endpoint = targetBotId
|
||||
? `${APP_ENDPOINTS.apiBase}/bots/${encodeURIComponent(targetBotId)}/images`
|
||||
: `${APP_ENDPOINTS.apiBase}/images`;
|
||||
const [imagesRes] = await Promise.allSettled([
|
||||
axios.get<NanobotImage[]>(`${APP_ENDPOINTS.apiBase}/images`),
|
||||
axios.get<NanobotImage[]>(endpoint),
|
||||
]);
|
||||
if (imagesRes.status === 'fulfilled') {
|
||||
setAvailableImages(Array.isArray(imagesRes.value.data) ? imagesRes.value.data : []);
|
||||
} else {
|
||||
setAvailableImages([]);
|
||||
}
|
||||
}, []);
|
||||
}, [forcedBotId, selectedBotId]);
|
||||
|
||||
const refresh = useCallback(async () => {
|
||||
const forced = String(forcedBotId || '').trim();
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@ interface UseDashboardSystemDefaultsOptions {
|
|||
notify: (message: string, options?: { tone?: 'error' | 'success' | 'warning' | 'info' }) => void;
|
||||
setBotListPageSize: Dispatch<SetStateAction<number>>;
|
||||
setChatPullPageSize?: Dispatch<SetStateAction<number>>;
|
||||
setCommandAutoUnlockSeconds?: Dispatch<SetStateAction<number>>;
|
||||
setVoiceCountdown?: Dispatch<SetStateAction<number>>;
|
||||
}
|
||||
|
||||
|
|
@ -34,18 +33,11 @@ function resolveChatPullPageSize(raw: unknown) {
|
|||
return Math.max(10, Math.min(500, Math.floor(configured)));
|
||||
}
|
||||
|
||||
function resolveCommandAutoUnlockSeconds(raw: unknown) {
|
||||
const configured = Number(raw);
|
||||
if (!Number.isFinite(configured) || configured <= 0) return 10;
|
||||
return Math.max(1, Math.min(600, Math.floor(configured)));
|
||||
}
|
||||
|
||||
export function useDashboardSystemDefaults({
|
||||
isZh,
|
||||
notify,
|
||||
setBotListPageSize,
|
||||
setChatPullPageSize,
|
||||
setCommandAutoUnlockSeconds,
|
||||
setVoiceCountdown,
|
||||
}: UseDashboardSystemDefaultsOptions) {
|
||||
const [botListPageSizeReady, setBotListPageSizeReady] = useState(false);
|
||||
|
|
@ -66,7 +58,6 @@ export function useDashboardSystemDefaults({
|
|||
|
||||
setBotListPageSize(normalizePlatformPageSize(data?.chat?.page_size, 10));
|
||||
setChatPullPageSize?.(resolveChatPullPageSize(data?.chat?.pull_page_size));
|
||||
setCommandAutoUnlockSeconds?.(resolveCommandAutoUnlockSeconds(data?.chat?.command_auto_unlock_seconds));
|
||||
setAllowedAttachmentExtensions(
|
||||
parseAllowedAttachmentExtensions(data?.workspace?.allowed_attachment_extensions),
|
||||
);
|
||||
|
|
@ -85,7 +76,7 @@ export function useDashboardSystemDefaults({
|
|||
setVoiceMaxSeconds(nextVoiceMaxSeconds);
|
||||
setVoiceCountdown?.(nextVoiceMaxSeconds);
|
||||
}
|
||||
}, [setBotListPageSize, setChatPullPageSize, setCommandAutoUnlockSeconds, setVoiceCountdown]);
|
||||
}, [setBotListPageSize, setChatPullPageSize, setVoiceCountdown]);
|
||||
|
||||
useEffect(() => {
|
||||
let alive = true;
|
||||
|
|
|
|||
|
|
@ -280,7 +280,6 @@ export interface SystemDefaultsResponse {
|
|||
chat?: {
|
||||
page_size?: number;
|
||||
pull_page_size?: number;
|
||||
command_auto_unlock_seconds?: number;
|
||||
};
|
||||
topic_presets?: unknown;
|
||||
speech?: {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
export interface PlatformSettings {
|
||||
page_size: number;
|
||||
chat_pull_page_size: number;
|
||||
command_auto_unlock_seconds: number;
|
||||
auth_token_ttl_hours: number;
|
||||
auth_token_max_active: number;
|
||||
upload_max_mb: number;
|
||||
|
|
|
|||
|
|
@ -71,6 +71,7 @@ export const useAppStore = create<AppStore>((set) => ({
|
|||
image_tag: preferDefined(bot.image_tag, prev?.image_tag),
|
||||
llm_provider: preferDefined(bot.llm_provider, prev?.llm_provider),
|
||||
llm_model: preferDefined(bot.llm_model, prev?.llm_model),
|
||||
api_key: preferDefined(bot.api_key, prev?.api_key),
|
||||
api_base: preferDefined(bot.api_base, prev?.api_base),
|
||||
temperature: preferDefined(bot.temperature, prev?.temperature),
|
||||
top_p: preferDefined(bot.top_p, prev?.top_p),
|
||||
|
|
@ -108,6 +109,7 @@ export const useAppStore = create<AppStore>((set) => ({
|
|||
enabled: preferDefined(bot.enabled, prev?.enabled),
|
||||
created_at: preferDefined(bot.created_at, prev?.created_at),
|
||||
updated_at: preferDefined(bot.updated_at, prev?.updated_at),
|
||||
api_key: preferDefined(bot.api_key, prev?.api_key),
|
||||
logs: prev?.logs ?? bot.logs ?? [],
|
||||
messages: prev?.messages ?? bot.messages ?? [],
|
||||
events: prev?.events ?? bot.events ?? [],
|
||||
|
|
|
|||
|
|
@ -150,7 +150,6 @@ docker compose --env-file "$ENV_FILE" -f "$COMPOSE_FILE" exec -T \
|
|||
|
||||
PAGE_SIZE_JSON="10"
|
||||
CHAT_PULL_PAGE_SIZE_JSON="60"
|
||||
COMMAND_AUTO_UNLOCK_SECONDS_JSON="10"
|
||||
AUTH_TOKEN_TTL_HOURS_JSON="24"
|
||||
AUTH_TOKEN_MAX_ACTIVE_JSON="2"
|
||||
UPLOAD_MAX_MB_JSON="$UPLOAD_MAX_MB"
|
||||
|
|
@ -171,7 +170,6 @@ docker compose --env-file "$ENV_FILE" -f "$COMPOSE_FILE" exec -T \
|
|||
-v ON_ERROR_STOP=1 \
|
||||
-v page_size_json="$PAGE_SIZE_JSON" \
|
||||
-v chat_pull_page_size_json="$CHAT_PULL_PAGE_SIZE_JSON" \
|
||||
-v command_auto_unlock_seconds_json="$COMMAND_AUTO_UNLOCK_SECONDS_JSON" \
|
||||
-v auth_token_ttl_hours_json="$AUTH_TOKEN_TTL_HOURS_JSON" \
|
||||
-v auth_token_max_active_json="$AUTH_TOKEN_MAX_ACTIVE_JSON" \
|
||||
-v upload_max_mb_json="$UPLOAD_MAX_MB_JSON" \
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@ INSERT INTO sys_setting (
|
|||
VALUES
|
||||
('page_size', '分页大小', 'ui', '平台各类列表默认每页条数。', 'integer', :'page_size_json', TRUE, 5, NOW(), NOW()),
|
||||
('chat_pull_page_size', '对话懒加载条数', 'chat', 'Bot 对话区向上懒加载时每次读取的消息条数。', 'integer', :'chat_pull_page_size_json', TRUE, 8, NOW(), NOW()),
|
||||
('command_auto_unlock_seconds', '发送按钮自动恢复秒数', 'chat', '对话发送后按钮保持停止态的最长秒数,超时后自动恢复为可发送状态。', 'integer', :'command_auto_unlock_seconds_json', TRUE, 9, NOW(), NOW()),
|
||||
('auth_token_ttl_hours', '认证 Token 过期小时数', 'auth', 'Panel 与 Bot 登录 Token 的统一有效时长,单位小时。', 'integer', :'auth_token_ttl_hours_json', FALSE, 10, NOW(), NOW()),
|
||||
('auth_token_max_active', '认证 Token 最大并发数', 'auth', '同一主体允许同时活跃的 Token 数量,超过时自动撤销最旧 Token。', 'integer', :'auth_token_max_active_json', FALSE, 11, NOW(), NOW()),
|
||||
('upload_max_mb', '上传大小限制', 'upload', '单文件上传大小限制,单位 MB。', 'integer', :'upload_max_mb_json', FALSE, 20, NOW(), NOW()),
|
||||
|
|
@ -35,6 +34,8 @@ SET
|
|||
sort_order = EXCLUDED.sort_order,
|
||||
updated_at = NOW();
|
||||
|
||||
DELETE FROM sys_setting WHERE key = 'command_auto_unlock_seconds';
|
||||
|
||||
INSERT INTO skill_market_item (
|
||||
skill_key,
|
||||
display_name,
|
||||
|
|
|
|||
Loading…
Reference in New Issue