diff --git a/NOTICE b/NOTICE index 7cfacabb3..01f49905d 100644 --- a/NOTICE +++ b/NOTICE @@ -1,7 +1,7 @@ new-api Notices new-api -Copyright (c) QuantumNous and contributors. +Copyright (c) modelstoken and contributors. This project is licensed under the GNU Affero General Public License v3.0. See LICENSE for the full project license terms. @@ -19,7 +19,7 @@ Modified versions that present a user interface must also preserve a visible link to the original project in a prominent about, legal, footer, or attribution location: -https://github.com/QuantumNous/new-api +https://git.viaeon.com/admin/new-api Modified versions must not misrepresent the origin of the software and must mark their changes in accordance with AGPLv3 Section 7(c). diff --git a/common/constants.go b/common/constants.go index b0386178e..ec2cbf1db 100644 --- a/common/constants.go +++ b/common/constants.go @@ -14,7 +14,7 @@ import ( var StartTime = time.Now().Unix() // unit: second var Version = "v0.0.0" // this hard coding will be replaced automatically when building, no need to manually change -var SystemName = "New API" +var SystemName = "ModelsToken" var Footer = "" var Logo = "" var TopUpLink = "" diff --git a/electron/package.json b/electron/package.json index 137785b24..78c04c2f3 100644 --- a/electron/package.json +++ b/electron/package.json @@ -18,10 +18,10 @@ "openai", "claude" ], - "author": "QuantumNous", + "author": "modelstoken", "repository": { "type": "git", - "url": "https://github.com/QuantumNous/new-api" + "url": "https://git.viaeon.com/admin/new-api" }, "devDependencies": { "cross-env": "^7.0.3", diff --git a/main.go b/main.go index 3361b8ce9..2470e8656 100644 --- a/main.go +++ b/main.go @@ -164,7 +164,7 @@ func main() { common.SysLog(fmt.Sprintf("panic detected: %v", err)) c.JSON(http.StatusInternalServerError, gin.H{ "error": gin.H{ - "message": fmt.Sprintf("Panic detected, error: %v. Please submit a issue here: https://github.com/Calcium-Ion/new-api", err), + "message": fmt.Sprintf("Panic detected, error: %v. Please submit a issue here: https://git.viaeon.com/admin/new-api/issues", err), "type": "new_api_panic", }, }) diff --git a/middleware/recover.go b/middleware/recover.go index 745a61015..5b172cd3a 100644 --- a/middleware/recover.go +++ b/middleware/recover.go @@ -17,7 +17,7 @@ func RelayPanicRecover() gin.HandlerFunc { common.SysLog(fmt.Sprintf("stacktrace from panic: %s", string(debug.Stack()))) c.JSON(http.StatusInternalServerError, gin.H{ "error": gin.H{ - "message": fmt.Sprintf("Panic detected, error: %v. Please submit a issue here: https://github.com/Calcium-Ion/new-api", err), + "message": fmt.Sprintf("Panic detected, error: %v. Please submit a issue here: https://git.viaeon.com/admin/new-api/issues", err), "type": "new_api_panic", }, }) diff --git a/relay/channel/openai/adaptor.go b/relay/channel/openai/adaptor.go index 2c230107d..80dbf4f4c 100644 --- a/relay/channel/openai/adaptor.go +++ b/relay/channel/openai/adaptor.go @@ -221,7 +221,7 @@ func (a *Adaptor) SetupRequestHeader(c *gin.Context, header *http.Header, info * header.Set("HTTP-Referer", "https://www.newapi.ai") } if header.Get("X-OpenRouter-Title") == "" { - header.Set("X-OpenRouter-Title", "New API") + header.Set("X-OpenRouter-Title", "ModelsToken") } } return nil diff --git a/web/classic/index.html b/web/classic/index.html index 814b8e6af..baed8b4e8 100644 --- a/web/classic/index.html +++ b/web/classic/index.html @@ -16,7 +16,7 @@ content="A unified AI model hub for aggregation & distribution. It supports cross-converting various LLMs into OpenAI-compatible, Claude-compatible, or Gemini-compatible formats. A centralized gateway for personal and enterprise model management." /> - New API + ModelsToken diff --git a/web/classic/src/App.jsx b/web/classic/src/App.jsx index a5d1ebc00..fe5c92fd0 100644 --- a/web/classic/src/App.jsx +++ b/web/classic/src/App.jsx @@ -1,5 +1,5 @@ /* -Copyright (C) 2025 QuantumNous +Copyright (C) 2025 modelstoken This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as @@ -14,7 +14,7 @@ GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . -For commercial licensing, please contact support@quantumnous.com +For commercial licensing, please contact admin@modelstoken.com */ import React, { lazy, Suspense, useContext, useMemo } from 'react'; @@ -72,20 +72,16 @@ function App() { try { const modules = JSON.parse(headerNavModulesConfig); - // 处理向后兼容性:如果pricing是boolean,默认不需要登录 - if (typeof modules.pricing === 'boolean') { - return false; // 默认不需要登录鉴权 - } + // 处理向后兼容性:如果pricing是boolean,默认不需要登? if (typeof modules.pricing === 'boolean') { + return false; // 默认不需要登录鉴? } // 如果是对象格式,使用requireAuth配置 return modules.pricing?.requireAuth === true; } catch (error) { console.error('解析顶栏模块配置失败:', error); - return false; // 默认不需要登录 - } + return false; // 默认不需要登? } } - return false; // 默认不需要登录 - }, [statusState?.status?.HeaderNavModules]); + return false; // 默认不需要登? }, [statusState?.status?.HeaderNavModules]); return ( diff --git a/web/classic/src/components/auth/LoginForm.jsx b/web/classic/src/components/auth/LoginForm.jsx index 63305e832..5cc06579e 100644 --- a/web/classic/src/components/auth/LoginForm.jsx +++ b/web/classic/src/components/auth/LoginForm.jsx @@ -1,5 +1,5 @@ /* -Copyright (C) 2025 QuantumNous +Copyright (C) 2025 modelstoken This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as @@ -14,7 +14,7 @@ GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . -For commercial licensing, please contact support@quantumnous.com +For commercial licensing, please contact admin@modelstoken.com */ import React, { useContext, useEffect, useMemo, useRef, useState } from 'react'; @@ -73,7 +73,7 @@ const LoginForm = () => { const githubButtonTextKeyByState = { idle: '使用 GitHub 继续', redirecting: '正在跳转 GitHub...', - timeout: '请求超时,请刷新页面后重新发起 GitHub 登录', + timeout: '请求超时,请刷新页面后重新发?GitHub 登录', }; const [inputs, setInputs] = useState({ username: '', @@ -149,8 +149,7 @@ const LoginForm = () => { setTurnstileSiteKey(status.turnstile_site_key); } - // 从 status 获取用户协议和隐私政策的启用状态 - setHasUserAgreement(status?.user_agreement_enabled || false); + // ?status 获取用户协议和隐私政策的启用状? setHasUserAgreement(status?.user_agreement_enabled || false); setHasPrivacyPolicy(status?.privacy_policy_enabled || false); }, [status]); @@ -168,7 +167,7 @@ const LoginForm = () => { useEffect(() => { if (searchParams.get('expired')) { - showError(t('未登录或登录已过期,请重新登录')); + showError(t('未登录或登录已过期,请重新登?)); } }, []); @@ -199,7 +198,7 @@ const LoginForm = () => { setUserData(data); updateAPI(); navigate('/'); - showSuccess('登录成功!'); + showSuccess('登录成功?); setShowWeChatLoginModal(false); } else { showError(message); @@ -237,7 +236,7 @@ const LoginForm = () => { ); const { success, message, data } = res.data; if (success) { - // 检查是否需要2FA验证 + // 检查是否需?FA验证 if (data && data.require_2fa) { setShowTwoFA(true); setLoginLoading(false); @@ -247,7 +246,7 @@ const LoginForm = () => { userDispatch({ type: 'login', payload: data }); setUserData(data); updateAPI(); - showSuccess('登录成功!'); + showSuccess('登录成功?); if (username === 'root' && password === '123456') { Modal.error({ title: '您正在使用默认密码!', @@ -297,7 +296,7 @@ const LoginForm = () => { if (success) { userDispatch({ type: 'login', payload: data }); localStorage.setItem('user', JSON.stringify(data)); - showSuccess('登录成功!'); + showSuccess('登录成功?); setUserData(data); updateAPI(); navigate('/'); @@ -332,8 +331,7 @@ const LoginForm = () => { try { onGitHubOAuthClicked(status.github_client_id, { shouldLogout: true }); } finally { - // 由于重定向,这里不会执行到,但为了完整性添加 - setTimeout(() => setGithubLoading(false), 3000); + // 由于重定向,这里不会执行到,但为了完整性添? setTimeout(() => setGithubLoading(false), 3000); } }; @@ -347,8 +345,7 @@ const LoginForm = () => { try { onDiscordOAuthClicked(status.discord_client_id, { shouldLogout: true }); } finally { - // 由于重定向,这里不会执行到,但为了完整性添加 - setTimeout(() => setDiscordLoading(false), 3000); + // 由于重定向,这里不会执行到,但为了完整性添? setTimeout(() => setDiscordLoading(false), 3000); } }; @@ -367,8 +364,7 @@ const LoginForm = () => { { shouldLogout: true }, ); } finally { - // 由于重定向,这里不会执行到,但为了完整性添加 - setTimeout(() => setOidcLoading(false), 3000); + // 由于重定向,这里不会执行到,但为了完整性添? setTimeout(() => setOidcLoading(false), 3000); } }; @@ -382,8 +378,7 @@ const LoginForm = () => { try { onLinuxDOOAuthClicked(status.linuxdo_client_id, { shouldLogout: true }); } finally { - // 由于重定向,这里不会执行到,但为了完整性添加 - setTimeout(() => setLinuxdoLoading(false), 3000); + // 由于重定向,这里不会执行到,但为了完整性添? setTimeout(() => setLinuxdoLoading(false), 3000); } }; @@ -397,8 +392,7 @@ const LoginForm = () => { try { onCustomOAuthClicked(provider, { shouldLogout: true }); } finally { - // 由于重定向,这里不会执行到,但为了完整性添加 - setTimeout(() => { + // 由于重定向,这里不会执行到,但为了完整性添? setTimeout(() => { setCustomOAuthLoading((prev) => ({ ...prev, [provider.slug]: false })); }, 3000); } @@ -455,14 +449,14 @@ const LoginForm = () => { userDispatch({ type: 'login', payload: finish.data }); setUserData(finish.data); updateAPI(); - showSuccess('登录成功!'); + showSuccess('登录成功?); navigate('/console'); } else { showError(finish.message || 'Passkey 登录失败,请重试'); } } catch (error) { if (error?.name === 'AbortError') { - showInfo('已取消 Passkey 登录'); + showInfo('已取?Passkey 登录'); } else { showError('Passkey 登录失败,请重试'); } @@ -471,8 +465,7 @@ const LoginForm = () => { } }; - // 包装的重置密码点击处理 - const handleResetPasswordClick = () => { + // 包装的重置密码点击处? const handleResetPasswordClick = () => { setResetPasswordLoading(true); navigate('/reset'); setResetPasswordLoading(false); @@ -490,7 +483,7 @@ const LoginForm = () => { userDispatch({ type: 'login', payload: data }); setUserData(data); updateAPI(); - showSuccess('登录成功!'); + showSuccess('登录成功?); navigate('/console'); }; @@ -514,7 +507,7 @@ const LoginForm = () => {
- {t('登 录')} + {t('??)}
@@ -643,7 +636,7 @@ const LoginForm = () => { )} - {t('或')} + {t('?)}
@@ -832,7 +825,7 @@ const LoginForm = () => { {hasOAuthLoginOptions && ( <> - {t('或')} + {t('?)}
@@ -852,7 +845,7 @@ const LoginForm = () => { {!status.self_use_mode_enabled && (
- {t('没有账户?')}{' '} + {t('没有账户?)}{' '} { }} >
- 微信二维码 + 微信二维? className=
@@ -897,8 +890,8 @@ const LoginForm = () => {
handleChange('wechat_verification_code', value) @@ -948,7 +941,7 @@ const LoginForm = () => { return (
- {/* 背景模糊晕染球 */} + {/* 背景模糊晕染?*/}
. -For commercial licensing, please contact support@quantumnous.com +For commercial licensing, please contact admin@modelstoken.com */ import React, { useContext, useEffect, useRef } from 'react'; @@ -36,11 +36,9 @@ const OAuth2Callback = (props) => { const [, userDispatch] = useContext(UserContext); const navigate = useNavigate(); - // 防止 React 18 Strict Mode 下重复执行 - const hasExecuted = useRef(false); + // 防止 React 18 Strict Mode 下重复执? const hasExecuted = useRef(false); - // 最大重试次数 - const MAX_RETRIES = 3; + // 最大重试次? const MAX_RETRIES = 3; const sendCode = async (code, state, retry = 0) => { try { @@ -57,21 +55,20 @@ const OAuth2Callback = (props) => { } if (data?.action === 'bind') { - showSuccess(t('绑定成功!')); + showSuccess(t('绑定成功?)); navigate('/console/personal'); } else { userDispatch({ type: 'login', payload: data }); localStorage.setItem('user', JSON.stringify(data)); setUserData(data); updateAPI(); - showSuccess(t('登录成功!')); + showSuccess(t('登录成功?)); navigate('/console/token'); } } catch (error) { // 网络错误等可重试 if (retry < MAX_RETRIES) { - // 递增的退避等待 - await new Promise((resolve) => setTimeout(resolve, (retry + 1) * 2000)); + // 递增的退避等? await new Promise((resolve) => setTimeout(resolve, (retry + 1) * 2000)); return sendCode(code, state, retry + 1); } @@ -82,8 +79,7 @@ const OAuth2Callback = (props) => { }; useEffect(() => { - // 防止 React 18 Strict Mode 下重复执行 - if (hasExecuted.current) { + // 防止 React 18 Strict Mode 下重复执? if (hasExecuted.current) { return; } hasExecuted.current = true; @@ -93,7 +89,7 @@ const OAuth2Callback = (props) => { // 参数缺失直接返回 if (!code) { - showError(t('未获取到授权码')); + showError(t('未获取到授权?)); navigate('/console/personal'); return; } diff --git a/web/classic/src/components/auth/PasswordResetConfirm.jsx b/web/classic/src/components/auth/PasswordResetConfirm.jsx index d4f4b2286..bdd768b00 100644 --- a/web/classic/src/components/auth/PasswordResetConfirm.jsx +++ b/web/classic/src/components/auth/PasswordResetConfirm.jsx @@ -1,5 +1,5 @@ /* -Copyright (C) 2025 QuantumNous +Copyright (C) 2025 modelstoken This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as @@ -14,7 +14,7 @@ GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . -For commercial licensing, please contact support@quantumnous.com +For commercial licensing, please contact admin@modelstoken.com */ import React, { useEffect, useState } from 'react'; @@ -82,7 +82,7 @@ const PasswordResetConfirm = () => { async function handleSubmit(e) { if (!email || !token) { - showError(t('无效的重置链接,请重新发起密码重置请求')); + showError(t('无效的重置链接,请重新发起密码重置请?)); return; } setDisableButton(true); @@ -105,7 +105,7 @@ const PasswordResetConfirm = () => { return (
- {/* 背景模糊晕染球 */} + {/* 背景模糊晕染?*/}
{ {!isValidResetLink && ( @@ -159,7 +159,7 @@ const PasswordResetConfirm = () => { {newPassword && ( } diff --git a/web/classic/src/components/auth/PasswordResetForm.jsx b/web/classic/src/components/auth/PasswordResetForm.jsx index 4ccc8a52c..273b398e1 100644 --- a/web/classic/src/components/auth/PasswordResetForm.jsx +++ b/web/classic/src/components/auth/PasswordResetForm.jsx @@ -1,5 +1,5 @@ /* -Copyright (C) 2025 QuantumNous +Copyright (C) 2025 modelstoken This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as @@ -14,7 +14,7 @@ GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . -For commercial licensing, please contact support@quantumnous.com +For commercial licensing, please contact admin@modelstoken.com */ import React, { useEffect, useState } from 'react'; @@ -105,7 +105,7 @@ const PasswordResetForm = () => { return (
- {/* 背景模糊晕染球 */} + {/* 背景模糊晕染?*/}
{
- {t('想起来了?')}{' '} + {t('想起来了?)}{' '} . -For commercial licensing, please contact support@quantumnous.com +For commercial licensing, please contact admin@modelstoken.com */ import React, { useContext, useEffect, useMemo, useRef, useState } from 'react'; @@ -71,7 +71,7 @@ const RegisterForm = () => { const githubButtonTextKeyByState = { idle: '使用 GitHub 继续', redirecting: '正在跳转 GitHub...', - timeout: '请求超时,请刷新页面后重新发起 GitHub 登录', + timeout: '请求超时,请刷新页面后重新发?GitHub 登录', }; const [inputs, setInputs] = useState({ username: '', @@ -150,8 +150,7 @@ const RegisterForm = () => { setTurnstileSiteKey(status.turnstile_site_key); } - // 从 status 获取用户协议和隐私政策的启用状态 - setHasUserAgreement(status?.user_agreement_enabled || false); + // ?status 获取用户协议和隐私政策的启用状? setHasUserAgreement(status?.user_agreement_enabled || false); setHasPrivacyPolicy(status?.privacy_policy_enabled || false); }, [status]); @@ -199,7 +198,7 @@ const RegisterForm = () => { setUserData(data); updateAPI(); navigate('/'); - showSuccess('登录成功!'); + showSuccess('登录成功?); setShowWeChatLoginModal(false); } else { showError(message); @@ -221,7 +220,7 @@ const RegisterForm = () => { return; } if (password !== password2) { - showInfo('两次输入的密码不一致'); + showInfo('两次输入的密码不一?); return; } if (username && password) { @@ -242,7 +241,7 @@ const RegisterForm = () => { const { success, message } = res.data; if (success) { navigate('/login'); - showSuccess('注册成功!'); + showSuccess('注册成功?); } else { showError(message); } @@ -268,8 +267,7 @@ const RegisterForm = () => { const { success, message } = res.data; if (success) { showSuccess('验证码发送成功,请检查你的邮箱!'); - setDisableButton(true); // 发送成功后禁用按钮,开始倒计时 - } else { + setDisableButton(true); // 发送成功后禁用按钮,开始倒计? } else { showError(message); } } catch (error) { @@ -379,7 +377,7 @@ const RegisterForm = () => { if (success) { userDispatch({ type: 'login', payload: data }); localStorage.setItem('user', JSON.stringify(data)); - showSuccess('登录成功!'); + showSuccess('登录成功?); setUserData(data); updateAPI(); navigate('/'); @@ -405,7 +403,7 @@ const RegisterForm = () => {
- {t('注 册')} + {t('??)}
@@ -521,7 +519,7 @@ const RegisterForm = () => { )} - {t('或')} + {t('?)}
- {t('已有账户?')}{' '} + {t('已有账户?)}{' '} {
- {t('注 册')} + {t('??)}
handleChange('username', value)} @@ -585,7 +583,7 @@ const RegisterForm = () => { handleChange('password', value)} @@ -619,15 +617,15 @@ const RegisterForm = () => { disabled={disableButton || verificationCodeLoading} > {disableButton - ? `${t('重新发送')} (${countdown})` - : t('获取验证码')} + ? `${t('重新发?)} (${countdown})` + : t('获取验证?)} } /> handleChange('verification_code', value) @@ -644,7 +642,7 @@ const RegisterForm = () => { onChange={(e) => setAgreedToTerms(e.target.checked)} > - {t('我已阅读并同意')} + {t('我已阅读并同?)} {hasUserAgreement && ( <> { )} - {hasUserAgreement && hasPrivacyPolicy && t('和')} + {hasUserAgreement && hasPrivacyPolicy && t('?)} {hasPrivacyPolicy && ( <> { {hasOAuthRegisterOptions && ( <> - {t('或')} + {t('?)}
@@ -714,7 +712,7 @@ const RegisterForm = () => {
- {t('已有账户?')}{' '} + {t('已有账户?)}{' '} { }} >
- 微信二维码 + 微信二维? className=
@@ -757,8 +755,8 @@ const RegisterForm = () => { handleChange('wechat_verification_code', value) @@ -771,7 +769,7 @@ const RegisterForm = () => { return (
- {/* 背景模糊晕染球 */} + {/* 背景模糊晕染?*/}
. -For commercial licensing, please contact support@quantumnous.com +For commercial licensing, please contact admin@modelstoken.com */ import { API, showError, showSuccess } from '../../helpers'; import { @@ -41,10 +41,10 @@ const TwoFAVerification = ({ onSuccess, onBack, isModal = false }) => { } // Validate code format if (useBackupCode && verificationCode.length !== 8) { - showError('备用码必须是8位'); + showError('备用码必须是8?); return; } else if (!useBackupCode && !/^\d{6}$/.test(verificationCode)) { - showError('验证码必须是6位数字'); + showError('验证码必须是6位数?); return; } @@ -56,8 +56,7 @@ const TwoFAVerification = ({ onSuccess, onBack, isModal = false }) => { if (res.data.success) { showSuccess('登录成功'); - // 保存用户信息到本地存储 - localStorage.setItem('user', JSON.stringify(res.data.data)); + // 保存用户信息到本地存? localStorage.setItem('user', JSON.stringify(res.data.data)); if (onSuccess) { onSuccess(res.data.data); } @@ -87,8 +86,8 @@ const TwoFAVerification = ({ onSuccess, onBack, isModal = false }) => { { size='large' style={{ marginBottom: 16 }} > - 验证并登录 - + 验证并登? @@ -121,7 +119,7 @@ const TwoFAVerification = ({ onSuccess, onBack, isModal = false }) => { }} style={{ marginRight: 16, color: '#1890ff', padding: 0 }} > - {useBackupCode ? '使用认证器验证码' : '使用备用码'} + {useBackupCode ? '使用认证器验证码' : '使用备用?} {onBack && ( @@ -138,13 +136,11 @@ const TwoFAVerification = ({ onSuccess, onBack, isModal = false }) => {
- 提示: + 提示?/strong>
- • 验证码每30秒更新一次 -
- • 如果无法获取验证码,请使用备用码 -
• 每个备用码只能使用一次 -
+ ?验证码每30秒更新一?
+ ?如果无法获取验证码,请使用备用码 +
?每个备用码只能使用一?
); @@ -170,8 +166,8 @@ const TwoFAVerification = ({ onSuccess, onBack, isModal = false }) => {
{ size='large' style={{ marginBottom: 16 }} > - 验证并登录 - + 验证并登? @@ -204,7 +199,7 @@ const TwoFAVerification = ({ onSuccess, onBack, isModal = false }) => { }} style={{ marginRight: 16, color: '#1890ff', padding: 0 }} > - {useBackupCode ? '使用认证器验证码' : '使用备用码'} + {useBackupCode ? '使用认证器验证码' : '使用备用?} {onBack && ( @@ -228,13 +223,11 @@ const TwoFAVerification = ({ onSuccess, onBack, isModal = false }) => { }} > - 提示: + 提示?/strong>
- • 验证码每30秒更新一次 -
- • 如果无法获取验证码,请使用备用码 -
• 每个备用码只能使用一次 -
+ ?验证码每30秒更新一?
+ ?如果无法获取验证码,请使用备用码 +
?每个备用码只能使用一?
diff --git a/web/classic/src/components/common/DocumentRenderer/index.jsx b/web/classic/src/components/common/DocumentRenderer/index.jsx index 3325b2feb..61c3774c2 100644 --- a/web/classic/src/components/common/DocumentRenderer/index.jsx +++ b/web/classic/src/components/common/DocumentRenderer/index.jsx @@ -1,5 +1,5 @@ /* -Copyright (C) 2025 QuantumNous +Copyright (C) 2025 modelstoken This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as @@ -14,7 +14,7 @@ GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . -For commercial licensing, please contact support@quantumnous.com +For commercial licensing, please contact admin@modelstoken.com */ import React, { useEffect, useMemo, useState } from 'react'; @@ -65,9 +65,7 @@ const sanitizeHtml = (html) => { * 通用文档渲染组件 * @param {string} apiEndpoint - API 接口地址 * @param {string} title - 文档标题 - * @param {string} cacheKey - 本地存储缓存键 - * @param {string} emptyMessage - 空内容时的提示消息 - */ + * @param {string} cacheKey - 本地存储缓存? * @param {string} emptyMessage - 空内容时的提示消? */ const DocumentRenderer = ({ apiEndpoint, title, cacheKey, emptyMessage }) => { const { t } = useTranslation(); const [content, setContent] = useState(''); @@ -138,8 +136,7 @@ const DocumentRenderer = ({ apiEndpoint, title, cacheKey, emptyMessage }) => { }; }, [cacheKey, htmlPayload]); - // 显示加载状态 - if (loading) { + // 显示加载状? if (loading) { return (
@@ -147,8 +144,7 @@ const DocumentRenderer = ({ apiEndpoint, title, cacheKey, emptyMessage }) => { ); } - // 如果没有内容,显示空状态 - if (!content || content.trim() === '') { + // 如果没有内容,显示空状? if (!content || content.trim() === '') { return (
{ ); } - // 如果是 URL,显示链接卡片 - if (isUrl(content)) { + // 如果?URL,显示链接卡? if (isUrl(content)) { return (
@@ -175,7 +170,7 @@ const DocumentRenderer = ({ apiEndpoint, title, cacheKey, emptyMessage }) => { {title}

- {t('管理员设置了外部链接,点击下方按钮访问')} + {t('管理员设置了外部链接,点击下方按钮访?)}

{ ); } - // 如果是 HTML 内容,直接渲染 - if (isHtmlContent(content)) { + // 如果?HTML 内容,直接渲? if (isHtmlContent(content)) { return (
@@ -212,8 +206,7 @@ const DocumentRenderer = ({ apiEndpoint, title, cacheKey, emptyMessage }) => { ); } - // 其他内容统一使用 Markdown 渲染器 - return ( + // 其他内容统一使用 Markdown 渲染? return (
diff --git a/web/classic/src/components/common/examples/ChannelKeyViewExample.jsx b/web/classic/src/components/common/examples/ChannelKeyViewExample.jsx index 1bb2998b2..a0d2e8dec 100644 --- a/web/classic/src/components/common/examples/ChannelKeyViewExample.jsx +++ b/web/classic/src/components/common/examples/ChannelKeyViewExample.jsx @@ -1,5 +1,5 @@ /* -Copyright (C) 2025 QuantumNous +Copyright (C) 2025 modelstoken This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as @@ -14,7 +14,7 @@ GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . -For commercial licensing, please contact support@quantumnous.com +For commercial licensing, please contact admin@modelstoken.com */ import React, { useState } from 'react'; @@ -46,8 +46,7 @@ const ChannelKeyViewExample = ({ channelId }) => { switchVerificationMethod, } = useSecureVerification({ onSuccess: (result) => { - // 验证成功后处理结果 - if (result.success && result.data?.key) { + // 验证成功后处理结? if (result.success && result.data?.key) { setKeyData(result.data.key); setShowKeyModal(true); } @@ -55,15 +54,13 @@ const ChannelKeyViewExample = ({ channelId }) => { successMessage: t('密钥获取成功'), }); - // 开始查看密钥流程 - const handleViewKey = async () => { + // 开始查看密钥流? const handleViewKey = async () => { const apiCall = createApiCalls.viewChannelKey(channelId); await startVerification(apiCall, { title: t('查看渠道密钥'), - description: t('为了保护账户安全,请验证您的身份。'), - preferredMethod: 'passkey', // 可以指定首选验证方式 - }); + description: t('为了保护账户安全,请验证您的身份?), + preferredMethod: 'passkey', // 可以指定首选验证方? }); }; return ( diff --git a/web/classic/src/components/common/logo/LinuxDoIcon.jsx b/web/classic/src/components/common/logo/LinuxDoIcon.jsx index 861f19d4f..c237f8955 100644 --- a/web/classic/src/components/common/logo/LinuxDoIcon.jsx +++ b/web/classic/src/components/common/logo/LinuxDoIcon.jsx @@ -1,5 +1,5 @@ /* -Copyright (C) 2025 QuantumNous +Copyright (C) 2025 modelstoken This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as @@ -14,7 +14,7 @@ GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . -For commercial licensing, please contact support@quantumnous.com +For commercial licensing, please contact admin@modelstoken.com */ import React from 'react'; diff --git a/web/classic/src/components/common/logo/OIDCIcon.jsx b/web/classic/src/components/common/logo/OIDCIcon.jsx index 28d538eb0..c83a4942d 100644 --- a/web/classic/src/components/common/logo/OIDCIcon.jsx +++ b/web/classic/src/components/common/logo/OIDCIcon.jsx @@ -1,5 +1,5 @@ /* -Copyright (C) 2025 QuantumNous +Copyright (C) 2025 modelstoken This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as @@ -14,7 +14,7 @@ GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . -For commercial licensing, please contact support@quantumnous.com +For commercial licensing, please contact admin@modelstoken.com */ import React from 'react'; diff --git a/web/classic/src/components/common/logo/WeChatIcon.jsx b/web/classic/src/components/common/logo/WeChatIcon.jsx index f9f7057cf..a3fab081a 100644 --- a/web/classic/src/components/common/logo/WeChatIcon.jsx +++ b/web/classic/src/components/common/logo/WeChatIcon.jsx @@ -1,5 +1,5 @@ /* -Copyright (C) 2025 QuantumNous +Copyright (C) 2025 modelstoken This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as @@ -14,7 +14,7 @@ GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . -For commercial licensing, please contact support@quantumnous.com +For commercial licensing, please contact admin@modelstoken.com */ import React from 'react'; diff --git a/web/classic/src/components/common/markdown/MarkdownRenderer.jsx b/web/classic/src/components/common/markdown/MarkdownRenderer.jsx index 6a71c695f..fe3908691 100644 --- a/web/classic/src/components/common/markdown/MarkdownRenderer.jsx +++ b/web/classic/src/components/common/markdown/MarkdownRenderer.jsx @@ -1,5 +1,5 @@ /* -Copyright (C) 2025 QuantumNous +Copyright (C) 2025 modelstoken This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as @@ -14,7 +14,7 @@ GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . -For commercial licensing, please contact support@quantumnous.com +For commercial licensing, please contact admin@modelstoken.com */ import ReactMarkdown from 'react-markdown'; @@ -228,7 +228,7 @@ export function PreCode(props) { const code = codeElement?.textContent ?? ''; copy(code).then((success) => { if (success) { - Toast.success(t('代码已复制到剪贴板')); + Toast.success(t('代码已复制到剪贴?)); } else { Toast.error(t('复制失败,请手动复制')); } @@ -390,8 +390,7 @@ function _MarkdownContent(props) { return tryWrapHtmlCode(escapeBrackets(content)); }, [content]); - // 判断是否为用户消息 - const isUserMessage = className && className.includes('user-message'); + // 判断是否为用户消? const isUserMessage = className && className.includes('user-message'); const rehypePluginsBase = useMemo(() => { const base = [ diff --git a/web/classic/src/components/common/markdown/markdown.css b/web/classic/src/components/common/markdown/markdown.css index e1e9e9cb4..6d1c827ee 100644 --- a/web/classic/src/components/common/markdown/markdown.css +++ b/web/classic/src/components/common/markdown/markdown.css @@ -60,7 +60,7 @@ .user-message a { color: #87ceeb !important; - /* 浅蓝色链接 */ + /* 浅蓝色链?*/ } .user-message a:hover { @@ -68,7 +68,7 @@ /* hover时更浅的蓝色 */ } -/* 表格在用户消息中的样式 */ +/* 表格在用户消息中的样?*/ .user-message table { border-color: rgba(255, 255, 255, 0.3) !important; } @@ -197,7 +197,7 @@ transform: translateY(-1px); } -/* 代码块样式增强 */ +/* 代码块样式增?*/ pre { position: relative; font-family: 'Consolas', 'Monaco', 'Courier New', monospace; @@ -229,7 +229,7 @@ pre:hover .copy-code-button { cursor: pointer !important; } -/* 确保按钮可点击 */ +/* 确保按钮可点?*/ .copy-code-button .semi-button { pointer-events: auto !important; cursor: pointer !important; @@ -242,7 +242,7 @@ pre:hover .copy-code-button { transform: scale(1.05); } -/* 表格响应式 */ +/* 表格响应?*/ @media (max-width: 768px) { .markdown-body table { font-size: 12px; @@ -269,7 +269,7 @@ pre:hover .copy-code-button { transition: all 0.2s ease; } -/* 引用块样式增强 */ +/* 引用块样式增?*/ .markdown-body blockquote { position: relative; } @@ -294,7 +294,7 @@ pre:hover .copy-code-button { font-weight: bold; } -/* 分隔线样式 */ +/* 分隔线样?*/ .markdown-body hr { border: none; height: 1px; @@ -393,7 +393,7 @@ pre:hover .copy-code-button { text-decoration: underline; } -/* 警告块样式 */ +/* 警告块样?*/ .markdown-body .warning { background-color: var(--semi-color-warning-light-default); border-left: 4px solid var(--semi-color-warning); diff --git a/web/classic/src/components/common/modals/RiskAcknowledgementModal.jsx b/web/classic/src/components/common/modals/RiskAcknowledgementModal.jsx index 812a8e87c..e3cfad97d 100644 --- a/web/classic/src/components/common/modals/RiskAcknowledgementModal.jsx +++ b/web/classic/src/components/common/modals/RiskAcknowledgementModal.jsx @@ -1,5 +1,5 @@ /* -Copyright (C) 2025 QuantumNous +Copyright (C) 2025 modelstoken This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as @@ -14,7 +14,7 @@ GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . -For commercial licensing, please contact support@quantumnous.com +For commercial licensing, please contact admin@modelstoken.com */ import React, { useCallback, useEffect, useMemo, useState } from 'react'; diff --git a/web/classic/src/components/common/modals/SecureVerificationModal.jsx b/web/classic/src/components/common/modals/SecureVerificationModal.jsx index 6c61c291d..a39711a2e 100644 --- a/web/classic/src/components/common/modals/SecureVerificationModal.jsx +++ b/web/classic/src/components/common/modals/SecureVerificationModal.jsx @@ -1,5 +1,5 @@ /* -Copyright (C) 2025 QuantumNous +Copyright (C) 2025 modelstoken This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as @@ -14,7 +14,7 @@ GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . -For commercial licensing, please contact support@quantumnous.com +For commercial licensing, please contact admin@modelstoken.com */ import React, { useEffect, useState } from 'react'; @@ -35,12 +35,9 @@ import { * 配合 useSecureVerification Hook 使用 * @param {Object} props * @param {boolean} props.visible - 是否显示模态框 - * @param {Object} props.verificationMethods - 可用的验证方式 - * @param {Object} props.verificationState - 当前验证状态 - * @param {Function} props.onVerify - 验证回调 + * @param {Object} props.verificationMethods - 可用的验证方? * @param {Object} props.verificationState - 当前验证状? * @param {Function} props.onVerify - 验证回调 * @param {Function} props.onCancel - 取消回调 - * @param {Function} props.onCodeChange - 验证码变化回调 - * @param {Function} props.onMethodSwitch - 验证方式切换回调 + * @param {Function} props.onCodeChange - 验证码变化回? * @param {Function} props.onMethodSwitch - 验证方式切换回调 * @param {string} props.title - 模态框标题 * @param {string} props.description - 验证描述文本 */ @@ -106,14 +103,14 @@ const SecureVerificationModal = ({
- {t('需要安全验证')} + {t('需要安全验?)} - {t('您需要先启用两步验证或 Passkey 才能查看敏感信息。')} + {t('您需要先启用两步验证?Passkey 才能查看敏感信息?)}
- {t('请前往个人设置 → 安全设置进行配置。')} + {t('请前往个人设置 ?安全设置进行配置?)}
@@ -164,7 +161,7 @@ const SecureVerificationModal = ({
- {t('从认证器应用中获取验证码,或使用备用码')} + {t('从认证器应用中获取验证码,或使用备用?)}
. -For commercial licensing, please contact support@quantumnous.com +For commercial licensing, please contact admin@modelstoken.com */ import React from 'react'; @@ -25,15 +25,12 @@ import { Modal, Button, Input, Typography } from '@douyinfe/semi-ui'; * 可复用的两步验证模态框组件 * @param {Object} props * @param {boolean} props.visible - 是否显示模态框 - * @param {string} props.code - 验证码值 - * @param {boolean} props.loading - 是否正在验证 - * @param {Function} props.onCodeChange - 验证码变化回调 - * @param {Function} props.onVerify - 验证回调 + * @param {string} props.code - 验证码? * @param {boolean} props.loading - 是否正在验证 + * @param {Function} props.onCodeChange - 验证码变化回? * @param {Function} props.onVerify - 验证回调 * @param {Function} props.onCancel - 取消回调 * @param {string} props.title - 模态框标题 * @param {string} props.description - 验证描述文本 - * @param {string} props.placeholder - 输入框占位文本 - */ + * @param {string} props.placeholder - 输入框占位文? */ const TwoFactorAuthModal = ({ visible, code, @@ -114,19 +111,19 @@ const TwoFactorAuthModal = ({ {t('安全验证')} - {description || t('为了保护账户安全,请验证您的两步验证码。')} + {description || t('为了保护账户安全,请验证您的两步验证码?)}
- {/* 验证码输入 */} + {/* 验证码输?*/}
{t('验证身份')} {t( - '支持6位TOTP验证码或8位备用码,可到`个人设置-安全设置-两步验证设置`配置或查看。', + '支持6位TOTP验证码或8位备用码,可到`个人设置-安全设置-两步验证设置`配置或查看?, )}
diff --git a/web/classic/src/components/common/ui/CardPro.jsx b/web/classic/src/components/common/ui/CardPro.jsx index 2c95f97c7..1c1cee1c2 100644 --- a/web/classic/src/components/common/ui/CardPro.jsx +++ b/web/classic/src/components/common/ui/CardPro.jsx @@ -1,5 +1,5 @@ /* -Copyright (C) 2025 QuantumNous +Copyright (C) 2025 modelstoken This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as @@ -14,7 +14,7 @@ GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . -For commercial licensing, please contact support@quantumnous.com +For commercial licensing, please contact admin@modelstoken.com */ import React, { useState } from 'react'; @@ -34,31 +34,25 @@ const { Text } = Typography; * 3. 类型切换/标签区域 (tabsArea) * 4. 操作按钮区域 (actionsArea) * 5. 搜索表单区域 (searchArea) - * 6. 分页区域 (paginationArea) - 固定在卡片底部 - * - * 支持三种布局类型: - * - type1: 操作型 (如TokensTable) - 描述信息 + 操作按钮 + 搜索表单 - * - type2: 查询型 (如LogsTable) - 统计信息 + 搜索表单 - * - type3: 复杂型 (如ChannelsTable) - 描述信息 + 类型切换 + 操作按钮 + 搜索表单 + * 6. 分页区域 (paginationArea) - 固定在卡片底? * + * 支持三种布局类型? * - type1: 操作?(如TokensTable) - 描述信息 + 操作按钮 + 搜索表单 + * - type2: 查询?(如LogsTable) - 统计信息 + 搜索表单 + * - type3: 复杂?(如ChannelsTable) - 描述信息 + 类型切换 + 操作按钮 + 搜索表单 */ const CardPro = ({ type = 'type1', className = '', children, - // 各个区域的内容 - statsArea, + // 各个区域的内? statsArea, descriptionArea, tabsArea, actionsArea, searchArea, paginationArea, // 新增分页区域 - // 卡片属性 - shadows = '', + // 卡片属? shadows = '', bordered = true, - // 自定义样式 - style, - // 国际化函数 - t = (key) => key, + // 自定义样? style, + // 国际化函? t = (key) => key, ...props }) => { const isMobile = useIsMobile(); @@ -94,7 +88,7 @@ const CardPro = ({ {/* 类型切换/标签区域 - 主要用于type3 */} {type === 'type3' && tabsArea && <>{tabsArea}} - {/* 移动端操作切换按钮 */} + {/* 移动端操作切换按?*/} {isMobile && hasMobileHideableContent && ( <>
@@ -106,7 +100,7 @@ const CardPro = ({ theme='outline' block > - {showMobileActions ? t('隐藏操作项') : t('显示操作项')} + {showMobileActions ? t('隐藏操作?) : t('显示操作?)}
@@ -130,10 +124,10 @@ const CardPro = ({
{actionsArea}
))} - {/* 当同时存在操作区和搜索区时,插入分隔线 */} + {/* 当同时存在操作区和搜索区时,插入分隔?*/} {actionsArea && searchArea && } - {/* 搜索表单区域 - 所有类型都可能有 */} + {/* 搜索表单区域 - 所有类型都可能?*/} {searchArea &&
{searchArea}
}
@@ -193,8 +187,7 @@ CardPro.propTypes = { paginationArea: PropTypes.node, // 表格内容 children: PropTypes.node, - // 国际化函数 - t: PropTypes.func, + // 国际化函? t: PropTypes.func, }; export default CardPro; diff --git a/web/classic/src/components/common/ui/CardTable.jsx b/web/classic/src/components/common/ui/CardTable.jsx index 8a331d07e..08879aff0 100644 --- a/web/classic/src/components/common/ui/CardTable.jsx +++ b/web/classic/src/components/common/ui/CardTable.jsx @@ -1,5 +1,5 @@ /* -Copyright (C) 2025 QuantumNous +Copyright (C) 2025 modelstoken This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as @@ -14,7 +14,7 @@ GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . -For commercial licensing, please contact support@quantumnous.com +For commercial licensing, please contact admin@modelstoken.com */ import React, { useState, useEffect, useRef } from 'react'; @@ -34,11 +34,8 @@ import { useIsMobile } from '../../../hooks/common/useIsMobile'; import { useMinimumLoadingTime } from '../../../hooks/common/useMinimumLoadingTime'; /** - * CardTable 响应式表格组件 - * - * 在桌面端渲染 Semi-UI 的 Table 组件,在移动端则将每一行数据渲染成 Card 形式。 - * 该组件与 Table 组件的大部分 API 保持一致,只需将原 Table 换成 CardTable 即可。 - */ + * CardTable 响应式表格组? * + * 在桌面端渲染 Semi-UI ?Table 组件,在移动端则将每一行数据渲染成 Card 形式? * 该组件与 Table 组件的大部分 API 保持一致,只需将原 Table 换成 CardTable 即可? */ const CardTable = ({ columns = [], dataSource = [], diff --git a/web/classic/src/components/common/ui/ChannelKeyDisplay.jsx b/web/classic/src/components/common/ui/ChannelKeyDisplay.jsx index 79aa3eec7..a0c08e76d 100644 --- a/web/classic/src/components/common/ui/ChannelKeyDisplay.jsx +++ b/web/classic/src/components/common/ui/ChannelKeyDisplay.jsx @@ -1,5 +1,5 @@ /* -Copyright (C) 2025 QuantumNous +Copyright (C) 2025 modelstoken This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as @@ -14,7 +14,7 @@ GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . -For commercial licensing, please contact support@quantumnous.com +For commercial licensing, please contact admin@modelstoken.com */ import React from 'react'; @@ -23,8 +23,7 @@ import { Card, Button, Typography, Tag } from '@douyinfe/semi-ui'; import { copy, showSuccess } from '../../../helpers'; /** - * 解析密钥数据,支持多种格式 - * @param {string} keyData - 密钥数据 + * 解析密钥数据,支持多种格? * @param {string} keyData - 密钥数据 * @param {Function} t - 翻译函数 * @returns {Array} 解析后的密钥数组 */ @@ -33,8 +32,7 @@ const parseChannelKeys = (keyData, t) => { const trimmed = keyData.trim(); - // 检查是否是JSON数组格式(如Vertex AI) - if (trimmed.startsWith('[')) { + // 检查是否是JSON数组格式(如Vertex AI? if (trimmed.startsWith('[')) { try { const parsed = JSON.parse(trimmed); if (Array.isArray(parsed)) { @@ -47,8 +45,7 @@ const parseChannelKeys = (keyData, t) => { })); } } catch (e) { - // 如果解析失败,按普通文本处理 - console.warn('Failed to parse JSON keys:', e); + // 如果解析失败,按普通文本处? console.warn('Failed to parse JSON keys:', e); } } @@ -102,12 +99,12 @@ const ChannelKeyDisplay = ({ const handleCopyKey = (content) => { copy(content); - showSuccess(t('密钥已复制到剪贴板')); + showSuccess(t('密钥已复制到剪贴?)); }; return (
- {/* 成功状态 */} + {/* 成功状?*/} {showSuccessIcon && (
- {t('共 {{count}} 个密钥', { count: parsedKeys.length })} + {t('?{{count}} 个密?, { count: parsedKeys.length })} {t( - '检测到多个密钥,您可以单独复制每个密钥,或点击复制全部获取完整内容。', + '检测到多个密钥,您可以单独复制每个密钥,或点击复制全部获取完整内容?, )}
@@ -266,7 +263,7 @@ const ChannelKeyDisplay = ({ {warningText || t( - '请妥善保管密钥信息,不要泄露给他人。如有安全疑虑,请及时更换密钥。', + '请妥善保管密钥信息,不要泄露给他人。如有安全疑虑,请及时更换密钥?, )}
diff --git a/web/classic/src/components/common/ui/CompactModeToggle.jsx b/web/classic/src/components/common/ui/CompactModeToggle.jsx index 40da0abc0..ad1076261 100644 --- a/web/classic/src/components/common/ui/CompactModeToggle.jsx +++ b/web/classic/src/components/common/ui/CompactModeToggle.jsx @@ -1,5 +1,5 @@ /* -Copyright (C) 2025 QuantumNous +Copyright (C) 2025 modelstoken This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as @@ -14,7 +14,7 @@ GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . -For commercial licensing, please contact support@quantumnous.com +For commercial licensing, please contact admin@modelstoken.com */ import React from 'react'; @@ -24,9 +24,7 @@ import { useIsMobile } from '../../../hooks/common/useIsMobile'; /** * 紧凑模式切换按钮组件 - * 用于在自适应列表和紧凑列表之间切换 - * 在移动端时自动隐藏,因为移动端使用"显示操作项"按钮来控制内容显示 - */ + * 用于在自适应列表和紧凑列表之间切? * 在移动端时自动隐藏,因为移动端使?显示操作?按钮来控制内容显? */ const CompactModeToggle = ({ compactMode, setCompactMode, diff --git a/web/classic/src/components/common/ui/JSONEditor.jsx b/web/classic/src/components/common/ui/JSONEditor.jsx index 21530db39..31ea20d60 100644 --- a/web/classic/src/components/common/ui/JSONEditor.jsx +++ b/web/classic/src/components/common/ui/JSONEditor.jsx @@ -1,5 +1,5 @@ /* -Copyright (C) 2025 QuantumNous +Copyright (C) 2025 modelstoken This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as @@ -14,7 +14,7 @@ GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . -For commercial licensing, please contact support@quantumnous.com +For commercial licensing, please contact admin@modelstoken.com */ import React, { useState, useEffect, useCallback, useMemo } from 'react'; @@ -65,13 +65,12 @@ const JSONEditor = ({ }) => { const { t } = useTranslation(); - // 将对象转换为键值对数组(包含唯一ID) - const objectToKeyValueArray = useCallback((obj, prevPairs = []) => { + // 将对象转换为键值对数组(包含唯一ID? const objectToKeyValueArray = useCallback((obj, prevPairs = []) => { if (!obj || typeof obj !== 'object') return []; const entries = Object.entries(obj); return entries.map(([key, value], index) => { - // 如果上一次转换后同位置的键一致,则沿用其 id,保持 React key 稳定 + // 如果上一次转换后同位置的键一致,则沿用其 id,保?React key 稳定 const prev = prevPairs[index]; const shouldReuseId = prev && prev.key === key; return { @@ -117,8 +116,7 @@ const JSONEditor = ({ return ''; }); - // 根据键数量决定默认编辑模式 - const [editMode, setEditMode] = useState(() => { + // 根据键数量决定默认编辑模? const [editMode, setEditMode] = useState(() => { if (typeof value === 'string' && value.trim()) { try { const parsed = JSON.parse(value); @@ -160,8 +158,7 @@ const JSONEditor = ({ parsed = value; } - // 只在外部值真正改变时更新,避免循环更新 - const currentObj = keyValueArrayToObject(keyValuePairs); + // 只在外部值真正改变时更新,避免循环更? const currentObj = keyValueArrayToObject(keyValuePairs); if (JSON.stringify(parsed) !== JSON.stringify(currentObj)) { setKeyValuePairs(objectToKeyValueArray(parsed, keyValuePairs)); } @@ -172,8 +169,7 @@ const JSONEditor = ({ } }, [value]); - // 外部 value 变化时,若不在手动模式,则同步手动文本 - useEffect(() => { + // 外部 value 变化时,若不在手动模式,则同步手动文? useEffect(() => { if (editMode !== 'manual') { if (typeof value === 'string') setManualText(value); else if (value && typeof value === 'object') @@ -194,8 +190,7 @@ const JSONEditor = ({ setJsonError(''); - // 通过formApi设置值 - if (formApi && field) { + // 通过formApi设置? if (formApi && field) { formApi.setValue(field, jsonString); } @@ -204,8 +199,7 @@ const JSONEditor = ({ [onChange, formApi, field, keyValueArrayToObject], ); - // 处理手动编辑的数据变化 - const handleManualChange = useCallback( + // 处理手动编辑的数据变? const handleManualChange = useCallback( (newValue) => { setManualText(newValue); if (newValue && newValue.trim()) { @@ -301,8 +295,7 @@ const JSONEditor = ({ [keyValuePairs, handleVisualChange], ); - // 更新值 - const updateValue = useCallback( + // 更新? const updateValue = useCallback( (id, newValue) => { const newPairs = keyValuePairs.map((pair) => pair.id === id ? { ...pair, value: newValue } : pair, @@ -335,8 +328,7 @@ const JSONEditor = ({ keyValuePairs, ]); - // 渲染值输入控件(支持嵌套) - const renderValueInput = (pairId, pairKey, value) => { + // 渲染值输入控件(支持嵌套? const renderValueInput = (pairId, pairKey, value) => { const valueType = typeof value; if (valueType === 'boolean') { @@ -386,7 +378,7 @@ const JSONEditor = ({ // 字符串或其他原始类型 return ( { @@ -406,11 +398,10 @@ const JSONEditor = ({ ); }; - // 渲染键值对编辑器 - const renderKeyValueEditor = () => { + // 渲染键值对编辑? const renderKeyValueEditor = () => { return (
- {/* 重复键警告 */} + {/* 重复键警?*/} {duplicateKeys.size > 0 && ( {Array.from(duplicateKeys).join(', ')}
- {t('注意:JSON中重复的键只会保留最后一个同名键的值')} + {t('注意:JSON中重复的键只会保留最后一个同名键的?)}
} @@ -457,8 +448,8 @@ const JSONEditor = ({ { + // 渲染区域编辑器(特殊格式? 也需要改造以支持重复? const renderRegionEditor = () => { const defaultPair = keyValuePairs.find((pair) => pair.key === 'default'); const modelPairs = keyValuePairs.filter((pair) => pair.key !== 'default'); return (
- {/* 重复键警告 */} + {/* 重复键警?*/} {duplicateKeys.size > 0 && ( {Array.from(duplicateKeys).join(', ')}
- {t('注意:JSON中重复的键只会保留最后一个同名键的值')} + {t('注意:JSON中重复的键只会保留最后一个同名键的?)}
} @@ -567,7 +557,7 @@ const JSONEditor = ({ status={isDuplicate ? 'warning' : undefined} /> {isDuplicate && ( - + - + @@ -666,11 +656,11 @@ const JSONEditor = ({ /> )} - {/* 编辑器内容 */} + {/* 编辑器内?*/} {editMode === 'visual' ? (
{renderVisualEditor()} - {/* 隐藏的Form字段用于验证和数据绑定 */} + {/* 隐藏的Form字段用于验证和数据绑?*/} - {/* 隐藏的Form字段用于验证和数据绑定 */} + {/* 隐藏的Form字段用于验证和数据绑?*/} )} - {/* 额外文本显示在卡片底部 */} + {/* 额外文本显示在卡片底?*/} {extraText && ( diff --git a/web/classic/src/components/common/ui/Loading.jsx b/web/classic/src/components/common/ui/Loading.jsx index a2fc6f8e9..017fd8020 100644 --- a/web/classic/src/components/common/ui/Loading.jsx +++ b/web/classic/src/components/common/ui/Loading.jsx @@ -1,5 +1,5 @@ /* -Copyright (C) 2025 QuantumNous +Copyright (C) 2025 modelstoken This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as @@ -14,7 +14,7 @@ GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . -For commercial licensing, please contact support@quantumnous.com +For commercial licensing, please contact admin@modelstoken.com */ import React from 'react'; diff --git a/web/classic/src/components/common/ui/RenderUtils.jsx b/web/classic/src/components/common/ui/RenderUtils.jsx index 3411649ce..60b73d37d 100644 --- a/web/classic/src/components/common/ui/RenderUtils.jsx +++ b/web/classic/src/components/common/ui/RenderUtils.jsx @@ -1,5 +1,5 @@ /* -Copyright (C) 2025 QuantumNous +Copyright (C) 2025 modelstoken This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as @@ -14,7 +14,7 @@ GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . -For commercial licensing, please contact support@quantumnous.com +For commercial licensing, please contact admin@modelstoken.com */ import React from 'react'; diff --git a/web/classic/src/components/common/ui/ScrollableContainer.jsx b/web/classic/src/components/common/ui/ScrollableContainer.jsx index 441c8c030..e17dfa640 100644 --- a/web/classic/src/components/common/ui/ScrollableContainer.jsx +++ b/web/classic/src/components/common/ui/ScrollableContainer.jsx @@ -1,5 +1,5 @@ /* -Copyright (C) 2025 QuantumNous +Copyright (C) 2025 modelstoken This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as @@ -14,7 +14,7 @@ GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . -For commercial licensing, please contact support@quantumnous.com +For commercial licensing, please contact admin@modelstoken.com */ import React, { @@ -28,8 +28,7 @@ import React, { } from 'react'; /** - * ScrollableContainer 可滚动容器组件 - * + * ScrollableContainer 可滚动容器组? * * 提供自动检测滚动状态和显示渐变指示器的功能 * 当内容超出容器高度且未滚动到底部时,会显示底部渐变指示器 * diff --git a/web/classic/src/components/common/ui/SelectableButtonGroup.jsx b/web/classic/src/components/common/ui/SelectableButtonGroup.jsx index dc5c428b5..776117493 100644 --- a/web/classic/src/components/common/ui/SelectableButtonGroup.jsx +++ b/web/classic/src/components/common/ui/SelectableButtonGroup.jsx @@ -1,5 +1,5 @@ /* -Copyright (C) 2025 QuantumNous +Copyright (C) 2025 modelstoken This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as @@ -14,7 +14,7 @@ GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . -For commercial licensing, please contact support@quantumnous.com +For commercial licensing, please contact admin@modelstoken.com */ import React, { useState, useRef, useEffect } from 'react'; @@ -33,19 +33,15 @@ import { import { IconChevronDown, IconChevronUp } from '@douyinfe/semi-icons'; /** - * 通用可选择按钮组组件 - * + * 通用可选择按钮组组? * * @param {string} title 标题 - * @param {Array<{value:any,label:string,icon?:React.ReactNode,tagCount?:number}>} items 按钮项 - * @param {*|Array} activeValue 当前激活的值,可以是单个值或数组(多选) + * @param {Array<{value:any,label:string,icon?:React.ReactNode,tagCount?:number}>} items 按钮? * @param {*|Array} activeValue 当前激活的值,可以是单个值或数组(多选) * @param {(value:any)=>void} onChange 选择改变回调 * @param {function} t i18n * @param {object} style 额外样式 * @param {boolean} collapsible 是否支持折叠,默认true - * @param {number} collapseHeight 折叠时的高度,默认200 - * @param {boolean} withCheckbox 是否启用前缀 Checkbox 来控制激活状态 - * @param {boolean} loading 是否处于加载状态 - * @param {string} variant 颜色变体: 'violet' | 'teal' | 'amber' | 'rose' | 'green',不传则使用默认蓝色 + * @param {number} collapseHeight 折叠时的高度,默?00 + * @param {boolean} withCheckbox 是否启用前缀 Checkbox 来控制激活状? * @param {boolean} loading 是否处于加载状? * @param {string} variant 颜色变体: 'violet' | 'teal' | 'amber' | 'rose' | 'green',不传则使用默认蓝色 */ const SelectableButtonGroup = ({ title, @@ -89,10 +85,9 @@ const SelectableButtonGroup = ({ // 基于容器宽度计算响应式列数和标签显示策略 const getResponsiveConfig = () => { - if (containerWidth <= 280) return { columns: 1, showTags: true }; // 极窄:1列+标签 - if (containerWidth <= 380) return { columns: 2, showTags: true }; // 窄屏:2列+标签 - if (containerWidth <= 460) return { columns: 3, showTags: false }; // 中等:3列不加标签 - return { columns: 3, showTags: true }; // 最宽:3列+标签 + if (containerWidth <= 280) return { columns: 1, showTags: true }; // 极窄??标签 + if (containerWidth <= 380) return { columns: 2, showTags: true }; // 窄屏??标签 + if (containerWidth <= 460) return { columns: 3, showTags: false }; // 中等?列不加标? return { columns: 3, showTags: true }; // 最宽:3?标签 }; const { columns: perRow, showTags: shouldShowTags } = getResponsiveConfig(); @@ -100,11 +95,9 @@ const SelectableButtonGroup = ({ const needCollapse = collapsible && items.length > perRow * maxVisibleRows; const showSkeleton = useMinimumLoadingTime(loading); - // 统一使用紧凑的网格间距 - const gutterSize = [4, 4]; + // 统一使用紧凑的网格间? const gutterSize = [4, 4]; - // 计算 Semi UI Col 的 span 值 - const getColSpan = () => { + // 计算 Semi UI Col ?span ? const getColSpan = () => { return Math.floor(24 / perRow); }; diff --git a/web/classic/src/components/dashboard/AnnouncementsPanel.jsx b/web/classic/src/components/dashboard/AnnouncementsPanel.jsx index c62850b3b..839e7dde2 100644 --- a/web/classic/src/components/dashboard/AnnouncementsPanel.jsx +++ b/web/classic/src/components/dashboard/AnnouncementsPanel.jsx @@ -1,5 +1,5 @@ /* -Copyright (C) 2025 QuantumNous +Copyright (C) 2025 modelstoken This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as @@ -14,7 +14,7 @@ GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . -For commercial licensing, please contact support@quantumnous.com +For commercial licensing, please contact admin@modelstoken.com */ import React from 'react'; @@ -44,7 +44,7 @@ const AnnouncementsPanel = ({ {t('系统公告')} - {t('显示最新20条')} + {t('显示最?0?)}
{/* 图例 */} diff --git a/web/classic/src/components/dashboard/ApiInfoPanel.jsx b/web/classic/src/components/dashboard/ApiInfoPanel.jsx index c93ada441..a80fca6d5 100644 --- a/web/classic/src/components/dashboard/ApiInfoPanel.jsx +++ b/web/classic/src/components/dashboard/ApiInfoPanel.jsx @@ -1,5 +1,5 @@ /* -Copyright (C) 2025 QuantumNous +Copyright (C) 2025 modelstoken This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as @@ -14,7 +14,7 @@ GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . -For commercial licensing, please contact support@quantumnous.com +For commercial licensing, please contact admin@modelstoken.com */ import React from 'react'; @@ -71,7 +71,7 @@ const ApiInfoPanel = ({ onClick={() => handleSpeedTest(api.url)} className='cursor-pointer hover:opacity-80 text-xs' > - {t('测速')} + {t('测?)} } diff --git a/web/classic/src/components/dashboard/ChartsPanel.jsx b/web/classic/src/components/dashboard/ChartsPanel.jsx index 0034ffd90..c12b17c7a 100644 --- a/web/classic/src/components/dashboard/ChartsPanel.jsx +++ b/web/classic/src/components/dashboard/ChartsPanel.jsx @@ -1,5 +1,5 @@ /* -Copyright (C) 2025 QuantumNous +Copyright (C) 2025 modelstoken This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as @@ -14,7 +14,7 @@ GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . -For commercial licensing, please contact support@quantumnous.com +For commercial licensing, please contact admin@modelstoken.com */ import React from 'react'; @@ -53,15 +53,15 @@ const ChartsPanel = ({ activeKey={activeChartTab} onChange={setActiveChartTab} > - {t('消耗分布')}} itemKey='1' /> + {t('消耗分?)}} itemKey='1' /> {t('调用趋势')}} itemKey='2' /> {t('调用次数分布')}} itemKey='3' /> {t('调用次数排行')}} itemKey='4' /> {isAdminUser && ( - {t('用户消耗排行')}} itemKey='5' /> + {t('用户消耗排?)}} itemKey='5' /> )} {isAdminUser && ( - {t('用户消耗趋势')}} itemKey='6' /> + {t('用户消耗趋?)}} itemKey='6' /> )}
diff --git a/web/classic/src/components/dashboard/DashboardHeader.jsx b/web/classic/src/components/dashboard/DashboardHeader.jsx index c2867e90c..7bbb62848 100644 --- a/web/classic/src/components/dashboard/DashboardHeader.jsx +++ b/web/classic/src/components/dashboard/DashboardHeader.jsx @@ -1,5 +1,5 @@ /* -Copyright (C) 2025 QuantumNous +Copyright (C) 2025 modelstoken This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as @@ -14,7 +14,7 @@ GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . -For commercial licensing, please contact support@quantumnous.com +For commercial licensing, please contact admin@modelstoken.com */ import React from 'react'; diff --git a/web/classic/src/components/dashboard/FaqPanel.jsx b/web/classic/src/components/dashboard/FaqPanel.jsx index a092abbd1..b2b70e94a 100644 --- a/web/classic/src/components/dashboard/FaqPanel.jsx +++ b/web/classic/src/components/dashboard/FaqPanel.jsx @@ -1,5 +1,5 @@ /* -Copyright (C) 2025 QuantumNous +Copyright (C) 2025 modelstoken This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as @@ -14,7 +14,7 @@ GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . -For commercial licensing, please contact support@quantumnous.com +For commercial licensing, please contact admin@modelstoken.com */ import React from 'react'; diff --git a/web/classic/src/components/dashboard/StatsCards.jsx b/web/classic/src/components/dashboard/StatsCards.jsx index ce7256835..1655c974a 100644 --- a/web/classic/src/components/dashboard/StatsCards.jsx +++ b/web/classic/src/components/dashboard/StatsCards.jsx @@ -1,5 +1,5 @@ /* -Copyright (C) 2025 QuantumNous +Copyright (C) 2025 modelstoken This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as @@ -14,7 +14,7 @@ GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . -For commercial licensing, please contact support@quantumnous.com +For commercial licensing, please contact admin@modelstoken.com */ import React from 'react'; @@ -90,7 +90,7 @@ const StatsCards = ({ navigate('/console/topup'); }} > - {t('充值')} + {t('充?)} ) : ( (loading || diff --git a/web/classic/src/components/dashboard/UptimePanel.jsx b/web/classic/src/components/dashboard/UptimePanel.jsx index ed978d99e..c54b31287 100644 --- a/web/classic/src/components/dashboard/UptimePanel.jsx +++ b/web/classic/src/components/dashboard/UptimePanel.jsx @@ -1,5 +1,5 @@ /* -Copyright (C) 2025 QuantumNous +Copyright (C) 2025 modelstoken This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as @@ -14,7 +14,7 @@ GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . -For commercial licensing, please contact support@quantumnous.com +For commercial licensing, please contact admin@modelstoken.com */ import React from 'react'; @@ -54,7 +54,7 @@ const UptimePanel = ({
- {t('服务可用性')} + {t('服务可用?)}
diff --git a/web/classic/src/components/layout/components/SkeletonWrapper.jsx b/web/classic/src/components/layout/components/SkeletonWrapper.jsx index 3d4981668..48a44e820 100644 --- a/web/classic/src/components/layout/components/SkeletonWrapper.jsx +++ b/web/classic/src/components/layout/components/SkeletonWrapper.jsx @@ -1,5 +1,5 @@ /* -Copyright (C) 2025 QuantumNous +Copyright (C) 2025 modelstoken This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as @@ -14,7 +14,7 @@ GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . -For commercial licensing, please contact support@quantumnous.com +For commercial licensing, please contact admin@modelstoken.com */ import React from 'react'; @@ -37,8 +37,7 @@ const SkeletonWrapper = ({ return children; } - // 导航链接骨架屏 - const renderNavigationSkeleton = () => { + // 导航链接骨架? const renderNavigationSkeleton = () => { const skeletonLinkClasses = isMobile ? 'flex items-center gap-1 p-1 w-full rounded-md' : 'flex items-center gap-1 p-2 rounded-md'; @@ -60,7 +59,7 @@ const SkeletonWrapper = ({ )); }; - // 用户区域骨架屏 (头像 + 文本) + // 用户区域骨架?(头像 + 文本) const renderUserAreaSkeleton = () => { return (
{ + // Logo图片骨架? const renderImageSkeleton = () => { return ( { + // 系统名称骨架? const renderTitleSkeleton = () => { return ( { + // 通用文本骨架? const renderTextSkeleton = () => { return (
{ + // 按钮骨架屏(支持圆角? const renderButtonSkeleton = () => { return (
{ return Array(count) .fill(null) @@ -152,7 +147,7 @@ const SkeletonWrapper = ({ key={index} className={`flex items-center p-2 mb-1 rounded-md ${className}`} > - {/* 图标骨架屏 */} + {/* 图标骨架?*/}
- {/* 文本骨架屏 */} + {/* 文本骨架?*/} { + // 侧边栏组标题骨架? const renderSidebarGroupTitleSkeleton = () => { return (
{ + // 完整侧边栏骨架屏 - 1:1 还原,去重实? const renderSidebarSkeleton = () => { const NAV_WIDTH = 164; const NAV_HEIGHT = 30; const COLLAPSED_WIDTH = 44; diff --git a/web/classic/src/components/layout/headerbar/ActionButtons.jsx b/web/classic/src/components/layout/headerbar/ActionButtons.jsx index 545b5227b..8cb96bba9 100644 --- a/web/classic/src/components/layout/headerbar/ActionButtons.jsx +++ b/web/classic/src/components/layout/headerbar/ActionButtons.jsx @@ -1,5 +1,5 @@ /* -Copyright (C) 2025 QuantumNous +Copyright (C) 2025 modelstoken This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as @@ -14,7 +14,7 @@ GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . -For commercial licensing, please contact support@quantumnous.com +For commercial licensing, please contact admin@modelstoken.com */ import React from 'react'; diff --git a/web/classic/src/components/layout/headerbar/HeaderLogo.jsx b/web/classic/src/components/layout/headerbar/HeaderLogo.jsx index 73be0516b..629273bae 100644 --- a/web/classic/src/components/layout/headerbar/HeaderLogo.jsx +++ b/web/classic/src/components/layout/headerbar/HeaderLogo.jsx @@ -1,5 +1,5 @@ /* -Copyright (C) 2025 QuantumNous +Copyright (C) 2025 modelstoken This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as @@ -14,7 +14,7 @@ GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . -For commercial licensing, please contact support@quantumnous.com +For commercial licensing, please contact admin@modelstoken.com */ import React from 'react'; diff --git a/web/classic/src/components/layout/headerbar/LanguageSelector.jsx b/web/classic/src/components/layout/headerbar/LanguageSelector.jsx index ede8b5a4a..513da7d5b 100644 --- a/web/classic/src/components/layout/headerbar/LanguageSelector.jsx +++ b/web/classic/src/components/layout/headerbar/LanguageSelector.jsx @@ -1,5 +1,5 @@ /* -Copyright (C) 2025 QuantumNous +Copyright (C) 2025 modelstoken This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as @@ -14,7 +14,7 @@ GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . -For commercial licensing, please contact support@quantumnous.com +For commercial licensing, please contact admin@modelstoken.com */ import React from 'react'; @@ -32,8 +32,7 @@ const LanguageSelector = ({ currentLang, onLanguageChange, t }) => { onClick={() => onLanguageChange('zh-CN')} className={`!px-3 !py-1.5 !text-sm !text-semi-color-text-0 dark:!text-gray-200 ${currentLang === 'zh-CN' ? '!bg-semi-color-primary-light-default dark:!bg-blue-600 !font-semibold' : 'hover:!bg-semi-color-fill-1 dark:hover:!bg-gray-600'}`} > - 简体中文 - + 简体中? onLanguageChange('zh-TW')} className={`!px-3 !py-1.5 !text-sm !text-semi-color-text-0 dark:!text-gray-200 ${currentLang === 'zh-TW' ? '!bg-semi-color-primary-light-default dark:!bg-blue-600 !font-semibold' : 'hover:!bg-semi-color-fill-1 dark:hover:!bg-gray-600'}`} @@ -55,8 +54,7 @@ const LanguageSelector = ({ currentLang, onLanguageChange, t }) => { onClick={() => onLanguageChange('ja')} className={`!px-3 !py-1.5 !text-sm !text-semi-color-text-0 dark:!text-gray-200 ${currentLang === 'ja' ? '!bg-semi-color-primary-light-default dark:!bg-blue-600 !font-semibold' : 'hover:!bg-semi-color-fill-1 dark:hover:!bg-gray-600'}`} > - 日本語 - + 日本? onLanguageChange('ru')} className={`!px-3 !py-1.5 !text-sm !text-semi-color-text-0 dark:!text-gray-200 ${currentLang === 'ru' ? '!bg-semi-color-primary-light-default dark:!bg-blue-600 !font-semibold' : 'hover:!bg-semi-color-fill-1 dark:hover:!bg-gray-600'}`} diff --git a/web/classic/src/components/layout/headerbar/MobileMenuButton.jsx b/web/classic/src/components/layout/headerbar/MobileMenuButton.jsx index 7cf7e4aa9..f79b0678c 100644 --- a/web/classic/src/components/layout/headerbar/MobileMenuButton.jsx +++ b/web/classic/src/components/layout/headerbar/MobileMenuButton.jsx @@ -1,5 +1,5 @@ /* -Copyright (C) 2025 QuantumNous +Copyright (C) 2025 modelstoken This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as @@ -14,7 +14,7 @@ GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . -For commercial licensing, please contact support@quantumnous.com +For commercial licensing, please contact admin@modelstoken.com */ import React from 'react'; @@ -43,7 +43,7 @@ const MobileMenuButton = ({ ) } aria-label={ - (isMobile ? drawerOpen : collapsed) ? t('关闭侧边栏') : t('打开侧边栏') + (isMobile ? drawerOpen : collapsed) ? t('关闭侧边?) : t('打开侧边?) } onClick={onToggle} theme='borderless' diff --git a/web/classic/src/components/layout/headerbar/Navigation.jsx b/web/classic/src/components/layout/headerbar/Navigation.jsx index e2a4a696e..034835b93 100644 --- a/web/classic/src/components/layout/headerbar/Navigation.jsx +++ b/web/classic/src/components/layout/headerbar/Navigation.jsx @@ -1,5 +1,5 @@ /* -Copyright (C) 2025 QuantumNous +Copyright (C) 2025 modelstoken This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as @@ -14,7 +14,7 @@ GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . -For commercial licensing, please contact support@quantumnous.com +For commercial licensing, please contact admin@modelstoken.com */ import React from 'react'; diff --git a/web/classic/src/components/layout/headerbar/NewYearButton.jsx b/web/classic/src/components/layout/headerbar/NewYearButton.jsx index 4f007c517..e06ac2b62 100644 --- a/web/classic/src/components/layout/headerbar/NewYearButton.jsx +++ b/web/classic/src/components/layout/headerbar/NewYearButton.jsx @@ -1,5 +1,5 @@ /* -Copyright (C) 2025 QuantumNous +Copyright (C) 2025 modelstoken This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as @@ -14,7 +14,7 @@ GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . -For commercial licensing, please contact support@quantumnous.com +For commercial licensing, please contact admin@modelstoken.com */ import React from 'react'; diff --git a/web/classic/src/components/layout/headerbar/NotificationButton.jsx b/web/classic/src/components/layout/headerbar/NotificationButton.jsx index 54ab9dd94..f291a7ca7 100644 --- a/web/classic/src/components/layout/headerbar/NotificationButton.jsx +++ b/web/classic/src/components/layout/headerbar/NotificationButton.jsx @@ -1,5 +1,5 @@ /* -Copyright (C) 2025 QuantumNous +Copyright (C) 2025 modelstoken This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as @@ -14,7 +14,7 @@ GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . -For commercial licensing, please contact support@quantumnous.com +For commercial licensing, please contact admin@modelstoken.com */ import React from 'react'; diff --git a/web/classic/src/components/layout/headerbar/ThemeToggle.jsx b/web/classic/src/components/layout/headerbar/ThemeToggle.jsx index 95cf8db5f..96c90cbad 100644 --- a/web/classic/src/components/layout/headerbar/ThemeToggle.jsx +++ b/web/classic/src/components/layout/headerbar/ThemeToggle.jsx @@ -1,5 +1,5 @@ /* -Copyright (C) 2025 QuantumNous +Copyright (C) 2025 modelstoken This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as @@ -14,7 +14,7 @@ GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . -For commercial licensing, please contact support@quantumnous.com +For commercial licensing, please contact admin@modelstoken.com */ import React, { useMemo } from 'react'; @@ -87,8 +87,7 @@ const ThemeToggle = ({ theme, onThemeToggle, t }) => { <>
- {t('当前跟随系统')}: - {actualTheme === 'dark' ? t('深色') : t('浅色')} + {t('当前跟随系统')}? {actualTheme === 'dark' ? t('深色') : t('浅色')}
)} diff --git a/web/classic/src/components/layout/headerbar/UserArea.jsx b/web/classic/src/components/layout/headerbar/UserArea.jsx index 9fc011da1..97f93e692 100644 --- a/web/classic/src/components/layout/headerbar/UserArea.jsx +++ b/web/classic/src/components/layout/headerbar/UserArea.jsx @@ -1,5 +1,5 @@ /* -Copyright (C) 2025 QuantumNous +Copyright (C) 2025 modelstoken This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as @@ -14,7 +14,7 @@ GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . -For commercial licensing, please contact support@quantumnous.com +For commercial licensing, please contact admin@modelstoken.com */ import React, { useRef } from 'react'; @@ -110,7 +110,7 @@ const UserArea = ({ size='small' className='text-gray-500 dark:text-gray-400' /> - {t('退出')} + {t('退?)}
diff --git a/web/classic/src/components/layout/headerbar/index.jsx b/web/classic/src/components/layout/headerbar/index.jsx index 81b51d7fe..42c3499aa 100644 --- a/web/classic/src/components/layout/headerbar/index.jsx +++ b/web/classic/src/components/layout/headerbar/index.jsx @@ -1,5 +1,5 @@ /* -Copyright (C) 2025 QuantumNous +Copyright (C) 2025 modelstoken This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as @@ -14,7 +14,7 @@ GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . -For commercial licensing, please contact support@quantumnous.com +For commercial licensing, please contact admin@modelstoken.com */ import React from 'react'; diff --git a/web/classic/src/components/model-deployments/DeploymentAccessGuard.jsx b/web/classic/src/components/model-deployments/DeploymentAccessGuard.jsx index eef17b364..0074e3d9b 100644 --- a/web/classic/src/components/model-deployments/DeploymentAccessGuard.jsx +++ b/web/classic/src/components/model-deployments/DeploymentAccessGuard.jsx @@ -1,5 +1,5 @@ /* -Copyright (C) 2025 QuantumNous +Copyright (C) 2025 modelstoken This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as @@ -14,7 +14,7 @@ GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . -For commercial licensing, please contact support@quantumnous.com +For commercial licensing, please contact admin@modelstoken.com */ import React from 'react'; @@ -46,7 +46,7 @@ const DeploymentAccessGuard = ({
- {t('加载设置中...')} + {t('加载设置?..')}
@@ -113,7 +113,7 @@ const DeploymentAccessGuard = ({ fontWeight: '700', }} > - {t('模型部署服务未启用')} + {t('模型部署服务未启?)} - {t('启用 io.net 部署开关')} + {t('启用 io.net 部署开?)}
- {t('配置有效的 io.net API Key')} + {t('配置有效?io.net API Key')}
@@ -272,7 +272,7 @@ const DeploymentAccessGuard = ({ lineHeight: '1.5', }} > - {t('配置完成后刷新页面即可使用模型部署功能')} + {t('配置完成后刷新页面即可使用模型部署功?)}
@@ -285,7 +285,7 @@ const DeploymentAccessGuard = ({
- {t('正在检查 io.net 连接...')} + {t('正在检?io.net 连接...')}
@@ -294,10 +294,10 @@ const DeploymentAccessGuard = ({ if (connectionOk === false) { const isExpired = connectionError?.type === 'expired'; - const title = isExpired ? t('接口密钥已过期') : t('无法连接 io.net'); + const title = isExpired ? t('接口密钥已过?) : t('无法连接 io.net'); const description = isExpired - ? t('当前 API 密钥已过期,请在设置中更新。') - : t('当前配置无法连接到 io.net。'); + ? t('当前 API 密钥已过期,请在设置中更新?) + : t('当前配置无法连接?io.net?); const detail = connectionError?.message || ''; return ( diff --git a/web/classic/src/components/playground/ChatArea.jsx b/web/classic/src/components/playground/ChatArea.jsx index 2c65731f5..de444a007 100644 --- a/web/classic/src/components/playground/ChatArea.jsx +++ b/web/classic/src/components/playground/ChatArea.jsx @@ -1,5 +1,5 @@ /* -Copyright (C) 2025 QuantumNous +Copyright (C) 2025 modelstoken This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as @@ -14,7 +14,7 @@ GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . -For commercial licensing, please contact support@quantumnous.com +For commercial licensing, please contact admin@modelstoken.com */ import React from 'react'; @@ -73,7 +73,7 @@ const ChatArea = ({ {t('AI 对话')} - {inputs.model || t('选择模型开始对话')} + {inputs.model || t('选择模型开始对?)}
@@ -119,7 +119,7 @@ const ChatArea = ({ onStopGenerator={onStopGenerator} onClear={onClearMessages} className='h-full' - placeholder={t('请输入您的问题...')} + placeholder={t('请输入您的问?..')} />
diff --git a/web/classic/src/components/playground/CodeViewer.jsx b/web/classic/src/components/playground/CodeViewer.jsx index b34c647fe..c477b9dbb 100644 --- a/web/classic/src/components/playground/CodeViewer.jsx +++ b/web/classic/src/components/playground/CodeViewer.jsx @@ -1,5 +1,5 @@ /* -Copyright (C) 2025 QuantumNous +Copyright (C) 2025 modelstoken This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as @@ -14,7 +14,7 @@ GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . -For commercial licensing, please contact support@quantumnous.com +For commercial licensing, please contact admin@modelstoken.com */ import React, { useState, useMemo, useCallback } from 'react'; @@ -230,7 +230,7 @@ const CodeViewer = ({ content, title, language = 'json' }) => { const success = await copy(textToCopy); setCopied(true); - Toast.success(t('已复制到剪贴板')); + Toast.success(t('已复制到剪贴?)); setTimeout(() => setCopied(false), 2000); if (!success) { @@ -277,11 +277,11 @@ const CodeViewer = ({ content, title, language = 'json' }) => { {/* 性能警告 */} {contentMetrics.isLarge && (
- + ?/span> {contentMetrics.isVeryLarge ? t('内容较大,已启用性能优化模式') - : t('内容较大,部分功能可能受限')} + : t('内容较大,部分功能可能受?)}
)} @@ -297,7 +297,7 @@ const CodeViewer = ({ content, title, language = 'json' }) => { onMouseEnter={() => setIsHoveringCopy(true)} onMouseLeave={() => setIsHoveringCopy(false)} > - +
) : (
diff --git a/web/classic/src/components/playground/ConfigManager.jsx b/web/classic/src/components/playground/ConfigManager.jsx index 7eaa35b8a..626a64fc6 100644 --- a/web/classic/src/components/playground/ConfigManager.jsx +++ b/web/classic/src/components/playground/ConfigManager.jsx @@ -1,5 +1,5 @@ /* -Copyright (C) 2025 QuantumNous +Copyright (C) 2025 modelstoken This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as @@ -14,7 +14,7 @@ GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . -For commercial licensing, please contact support@quantumnous.com +For commercial licensing, please contact admin@modelstoken.com */ import React, { useRef } from 'react'; @@ -41,8 +41,7 @@ const ConfigManager = ({ const handleExport = () => { try { - // 在导出前先保存当前配置,确保导出的是最新内容 - const configWithTimestamp = { + // 在导出前先保存当前配置,确保导出的是最新内? const configWithTimestamp = { ...currentConfig, timestamp: new Date().toISOString(), }; @@ -53,7 +52,7 @@ const ConfigManager = ({ exportConfig(currentConfig, messages); Toast.success({ - content: t('配置已导出到下载文件夹'), + content: t('配置已导出到下载文件?), duration: 3, }); } catch (error) { @@ -115,10 +114,10 @@ const ConfigManager = ({ Modal.confirm({ title: t('重置选项'), content: t( - '是否同时重置对话消息?选择"是"将清空所有对话记录并恢复默认示例;选择"否"将保留当前对话记录。', + '是否同时重置对话消息?选择"?将清空所有对话记录并恢复默认示例;选择"?将保留当前对话记录?, ), okText: t('同时重置消息'), - cancelText: t('仅重置配置'), + cancelText: t('仅重置配?), okButtonProps: { type: 'danger', }, @@ -134,7 +133,7 @@ const ConfigManager = ({ clearConfig(); onConfigReset({ resetMessages: false }); Toast.success({ - content: t('配置已重置,对话消息已保留'), + content: t('配置已重置,对话消息已保?), duration: 3, }); }, @@ -150,9 +149,9 @@ const ConfigManager = ({ const date = new Date(timestamp); return t('上次保存: ') + date.toLocaleString(); } - return t('已有保存的配置'); + return t('已有保存的配?); } - return t('暂无保存的配置'); + return t('暂无保存的配?); }; const dropdownItems = [ @@ -224,8 +223,7 @@ const ConfigManager = ({ ); } - // 桌面端显示紧凑的按钮组 - return ( + // 桌面端显示紧凑的按钮? return (
{/* 配置状态信息和重置按钮 */}
@@ -242,7 +240,7 @@ const ConfigManager = ({ />
- {/* 导出和导入按钮 */} + {/* 导出和导入按?*/}
diff --git a/web/classic/src/components/playground/CustomRequestEditor.jsx b/web/classic/src/components/playground/CustomRequestEditor.jsx index 68f0ae871..81fa32628 100644 --- a/web/classic/src/components/playground/CustomRequestEditor.jsx +++ b/web/classic/src/components/playground/CustomRequestEditor.jsx @@ -1,5 +1,5 @@ /* -Copyright (C) 2025 QuantumNous +Copyright (C) 2025 modelstoken This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as @@ -14,7 +14,7 @@ GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . -For commercial licensing, please contact support@quantumnous.com +For commercial licensing, please contact admin@modelstoken.com */ import React, { useState, useEffect } from 'react'; @@ -40,8 +40,7 @@ const CustomRequestEditor = ({ const [errorMessage, setErrorMessage] = useState(''); const [localValue, setLocalValue] = useState(customRequestBody || ''); - // 当切换到自定义模式时,用默认payload初始化 - useEffect(() => { + // 当切换到自定义模式时,用默认payload初始? useEffect(() => { if ( customRequestMode && (!customRequestBody || customRequestBody.trim() === '') @@ -59,8 +58,7 @@ const CustomRequestEditor = ({ onCustomRequestBodyChange, ]); - // 同步外部传入的customRequestBody到本地状态 - useEffect(() => { + // 同步外部传入的customRequestBody到本地状? useEffect(() => { if (customRequestBody !== localValue) { setLocalValue(customRequestBody || ''); validateJson(customRequestBody || ''); @@ -118,7 +116,7 @@ const CustomRequestEditor = ({ return (
- {/* 自定义模式开关 */} + {/* 自定义模式开?*/}
@@ -130,7 +128,7 @@ const CustomRequestEditor = ({ checked={customRequestMode} onChange={handleModeToggle} checkedText={t('开')} - uncheckedText={t('关')} + uncheckedText={t('?)} size='small' />
@@ -141,18 +139,18 @@ const CustomRequestEditor = ({ } className='!rounded-lg' closeIcon={null} /> - {/* JSON编辑器 */} + {/* JSON编辑?*/}
- {t('请求体 JSON')} + {t('请求?JSON')}
{isValid ? ( @@ -179,7 +177,7 @@ const CustomRequestEditor = ({ disabled={!isValid} className='!rounded-lg' > - {t('格式化')} + {t('格式?)}
@@ -204,7 +202,7 @@ const CustomRequestEditor = ({ {t( - '请输入有效的JSON格式的请求体。您可以参考预览面板中的默认请求体格式。', + '请输入有效的JSON格式的请求体。您可以参考预览面板中的默认请求体格式?, )}
diff --git a/web/classic/src/components/playground/DebugPanel.jsx b/web/classic/src/components/playground/DebugPanel.jsx index 28de0153b..b533d39b6 100644 --- a/web/classic/src/components/playground/DebugPanel.jsx +++ b/web/classic/src/components/playground/DebugPanel.jsx @@ -1,5 +1,5 @@ /* -Copyright (C) 2025 QuantumNous +Copyright (C) 2025 modelstoken This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as @@ -14,7 +14,7 @@ GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . -For commercial licensing, please contact support@quantumnous.com +For commercial licensing, please contact admin@modelstoken.com */ import React, { useState, useEffect } from 'react'; @@ -85,12 +85,10 @@ const DebugPanel = ({ > {pos === 'start' ? (
- ← -
+ ?
) : (
- → -
+ ?
)} ); @@ -143,11 +141,10 @@ const DebugPanel = ({ tab={
- {t('预览请求体')} + {t('预览请求?)} {customRequestMode && ( - 自定义 - + 自定? )}
} @@ -164,7 +161,7 @@ const DebugPanel = ({ tab={
- {t('实际请求体')} + {t('实际请求?)}
} itemKey='request' @@ -211,7 +208,7 @@ const DebugPanel = ({ {activeKey === 'preview' && debugData.previewTimestamp ? `${t('预览更新')}: ${new Date(debugData.previewTimestamp).toLocaleString()}` : debugData.timestamp - ? `${t('最后请求')}: ${new Date(debugData.timestamp).toLocaleString()}` + ? `${t('最后请?)}: ${new Date(debugData.timestamp).toLocaleString()}` : ''}
diff --git a/web/classic/src/components/playground/FloatingButtons.jsx b/web/classic/src/components/playground/FloatingButtons.jsx index 3d024df4c..6be9dd2d6 100644 --- a/web/classic/src/components/playground/FloatingButtons.jsx +++ b/web/classic/src/components/playground/FloatingButtons.jsx @@ -1,5 +1,5 @@ /* -Copyright (C) 2025 QuantumNous +Copyright (C) 2025 modelstoken This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as @@ -14,7 +14,7 @@ GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . -For commercial licensing, please contact support@quantumnous.com +For commercial licensing, please contact admin@modelstoken.com */ import React from 'react'; diff --git a/web/classic/src/components/playground/ImageUrlInput.jsx b/web/classic/src/components/playground/ImageUrlInput.jsx index 28a287818..269539e7a 100644 --- a/web/classic/src/components/playground/ImageUrlInput.jsx +++ b/web/classic/src/components/playground/ImageUrlInput.jsx @@ -1,5 +1,5 @@ /* -Copyright (C) 2025 QuantumNous +Copyright (C) 2025 modelstoken This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as @@ -14,7 +14,7 @@ GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . -For commercial licensing, please contact support@quantumnous.com +For commercial licensing, please contact admin@modelstoken.com */ import React from 'react'; @@ -91,19 +91,19 @@ const ImageUrlInput = ({ {!imageEnabled ? ( {disabled - ? t('图片功能在自定义请求体模式下不可用') - : t('启用后可添加图片URL进行多模态对话')} + ? t('图片功能在自定义请求体模式下不可?) + : t('启用后可添加图片URL进行多模态对?)} ) : imageUrls.length === 0 ? ( {disabled - ? t('图片功能在自定义请求体模式下不可用') - : t('点击 + 按钮添加图片URL进行多模态对话')} + ? t('图片功能在自定义请求体模式下不可?) + : t('点击 + 按钮添加图片URL进行多模态对?)} ) : ( - {t('已添加')} {imageUrls.length} {t('张图片')} - {disabled ? ` (${t('自定义模式下不可用')})` : ''} + {t('已添?)} {imageUrls.length} {t('张图?)} + {disabled ? ` (${t('自定义模式下不可?)})` : ''} )} diff --git a/web/classic/src/components/playground/MessageActions.jsx b/web/classic/src/components/playground/MessageActions.jsx index 093700367..8b82fdb2d 100644 --- a/web/classic/src/components/playground/MessageActions.jsx +++ b/web/classic/src/components/playground/MessageActions.jsx @@ -1,5 +1,5 @@ /* -Copyright (C) 2025 QuantumNous +Copyright (C) 2025 modelstoken This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as @@ -14,7 +14,7 @@ GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . -For commercial licensing, please contact support@quantumnous.com +For commercial licensing, please contact admin@modelstoken.com */ import React from 'react'; @@ -50,7 +50,7 @@ const MessageActions = ({
{!isLoading && (
- {t('核采样,控制词汇选择的多样性')} + {t('核采样,控制词汇选择的多样?)}
. -For commercial licensing, please contact support@quantumnous.com +For commercial licensing, please contact admin@modelstoken.com */ import React, { useState, useMemo, useCallback } from 'react'; @@ -108,7 +108,7 @@ const SSEViewer = ({ sseData }) => { await copy(allData); setCopied(true); - Toast.success(t('已复制全部数据')); + Toast.success(t('已复制全部数?)); setTimeout(() => setCopied(false), 2000); } catch (err) { Toast.error(t('复制失败')); @@ -123,7 +123,7 @@ const SSEViewer = ({ sseData }) => { ? JSON.stringify(item.parsed, null, 2) : item.raw; await copy(textToCopy); - Toast.success(t('已复制')); + Toast.success(t('已复?)); } catch (err) { Toast.error(t('复制失败')); } @@ -161,7 +161,7 @@ const SSEViewer = ({ sseData }) => { return (
- {/* JSON 格式化显示 */} + {/* JSON 格式化显?*/}
             {JSON.stringify(item.parsed, null, 2)}
@@ -185,7 +185,7 @@ const SSEViewer = ({ sseData }) => {
               />
             )}
             {item.parsed.choices[0].delta?.reasoning_content && (
-              
+              
             )}
             {item.parsed.choices[0].finish_reason && (
                {
 
   return (
     
- {/* 头部工具栏 */} + {/* 头部工具?*/}
- {t('SSE数据流')} + {t('SSE数据?)} {stats.errors > 0 && ( @@ -234,7 +234,7 @@ const SSEViewer = ({ sseData }) => { onClick={handleCopyAll} theme='borderless' > - {copied ? t('已复制') : t('复制全部')} + {copied ? t('已复?) : t('复制全部')} . -For commercial licensing, please contact support@quantumnous.com +For commercial licensing, please contact admin@modelstoken.com */ import React from 'react'; @@ -67,7 +67,7 @@ const SettingsPanel = ({ flexDirection: 'column', }} > - {/* 标题区域 - 与调试面板保持一致 */} + {/* 标题区域 - 与调试面板保持一?*/}
@@ -90,7 +90,7 @@ const SettingsPanel = ({ )}
- {/* 移动端配置管理 */} + {/* 移动端配置管?*/} {styleState.isMobile && (
- {/* 自定义请求体编辑器 */} + {/* 自定义请求体编辑?*/}
- {/* 流式输出开关 */} + {/* 流式输出开?*/}
@@ -218,7 +218,7 @@ const SettingsPanel = ({ checked={inputs.stream} onChange={(checked) => onInputChange('stream', checked)} checkedText={t('开')} - uncheckedText={t('关')} + uncheckedText={t('?)} size='small' disabled={customRequestMode} /> diff --git a/web/classic/src/components/playground/ThinkingContent.jsx b/web/classic/src/components/playground/ThinkingContent.jsx index 9a0262ed5..21450e2b2 100644 --- a/web/classic/src/components/playground/ThinkingContent.jsx +++ b/web/classic/src/components/playground/ThinkingContent.jsx @@ -1,5 +1,5 @@ /* -Copyright (C) 2025 QuantumNous +Copyright (C) 2025 modelstoken This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as @@ -14,7 +14,7 @@ GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . -For commercial licensing, please contact support@quantumnous.com +For commercial licensing, please contact admin@modelstoken.com */ import React, { useEffect, useRef } from 'react'; @@ -39,7 +39,7 @@ const ThinkingContent = ({ const headerText = isThinkingStatus && !message.isThinkingComplete ? t('思考中...') - : t('思考过程'); + : t('思考过?); useEffect(() => { if ( diff --git a/web/classic/src/components/playground/configStorage.js b/web/classic/src/components/playground/configStorage.js index d201ed6af..62e0c81fc 100644 --- a/web/classic/src/components/playground/configStorage.js +++ b/web/classic/src/components/playground/configStorage.js @@ -1,5 +1,5 @@ /* -Copyright (C) 2025 QuantumNous +Copyright (C) 2025 modelstoken This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as @@ -14,7 +14,7 @@ GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . -For commercial licensing, please contact support@quantumnous.com +For commercial licensing, please contact admin@modelstoken.com */ import { @@ -25,7 +25,7 @@ import { const MESSAGES_STORAGE_KEY = 'playground_messages'; /** - * 保存配置到 localStorage + * 保存配置?localStorage * @param {Object} config - 要保存的配置对象 */ export const saveConfig = (config) => { @@ -41,7 +41,7 @@ export const saveConfig = (config) => { }; /** - * 保存消息到 localStorage + * 保存消息?localStorage * @param {Array} messages - 要保存的消息数组 */ export const saveMessages = (messages) => { @@ -57,9 +57,8 @@ export const saveMessages = (messages) => { }; /** - * 从 localStorage 加载配置 - * @returns {Object} 配置对象,如果不存在则返回默认配置 - */ + * ?localStorage 加载配置 + * @returns {Object} 配置对象,如果不存在则返回默认配? */ export const loadConfig = () => { try { const savedConfig = localStorage.getItem(STORAGE_KEYS.CONFIG); @@ -97,8 +96,8 @@ export const loadConfig = () => { }; /** - * 从 localStorage 加载消息 - * @returns {Array} 消息数组,如果不存在则返回 null + * ?localStorage 加载消息 + * @returns {Array} 消息数组,如果不存在则返?null */ export const loadMessages = () => { try { @@ -115,8 +114,7 @@ export const loadMessages = () => { }; /** - * 清除保存的配置 - */ + * 清除保存的配? */ export const clearConfig = () => { try { localStorage.removeItem(STORAGE_KEYS.CONFIG); @@ -127,8 +125,7 @@ export const clearConfig = () => { }; /** - * 清除保存的消息 - */ + * 清除保存的消? */ export const clearMessages = () => { try { localStorage.removeItem(STORAGE_KEYS.MESSAGES); @@ -138,22 +135,18 @@ export const clearMessages = () => { }; /** - * 检查是否有保存的配置 - * @returns {boolean} 是否存在保存的配置 - */ + * 检查是否有保存的配? * @returns {boolean} 是否存在保存的配? */ export const hasStoredConfig = () => { try { return localStorage.getItem(STORAGE_KEYS.CONFIG) !== null; } catch (error) { - console.error('检查配置失败:', error); + console.error('检查配置失?', error); return false; } }; /** - * 获取配置的最后保存时间 - * @returns {string|null} 最后保存时间的 ISO 字符串 - */ + * 获取配置的最后保存时? * @returns {string|null} 最后保存时间的 ISO 字符? */ export const getConfigTimestamp = () => { try { const savedConfig = localStorage.getItem(STORAGE_KEYS.CONFIG); @@ -162,13 +155,13 @@ export const getConfigTimestamp = () => { return parsedConfig.timestamp || null; } } catch (error) { - console.error('获取配置时间戳失败:', error); + console.error('获取配置时间戳失?', error); } return null; }; /** - * 导出配置为 JSON 文件(包含消息) + * 导出配置?JSON 文件(包含消息) * @param {Object} config - 要导出的配置 * @param {Array} messages - 要导出的消息 */ @@ -196,10 +189,8 @@ export const exportConfig = (config, messages = null) => { }; /** - * 从文件导入配置(包含消息) - * @param {File} file - 包含配置的 JSON 文件 - * @returns {Promise} 导入的配置对象 - */ + * 从文件导入配置(包含消息? * @param {File} file - 包含配置?JSON 文件 + * @returns {Promise} 导入的配置对? */ export const importConfig = (file) => { return new Promise((resolve, reject) => { try { @@ -209,8 +200,7 @@ export const importConfig = (file) => { const importedConfig = JSON.parse(e.target.result); if (importedConfig.inputs && importedConfig.parameterEnabled) { - // 如果导入的配置包含消息,也一起导入 - if ( + // 如果导入的配置包含消息,也一起导? if ( importedConfig.messages && Array.isArray(importedConfig.messages) ) { diff --git a/web/classic/src/components/playground/index.js b/web/classic/src/components/playground/index.js index 8c470351b..84241d4a2 100644 --- a/web/classic/src/components/playground/index.js +++ b/web/classic/src/components/playground/index.js @@ -1,5 +1,5 @@ /* -Copyright (C) 2025 QuantumNous +Copyright (C) 2025 modelstoken This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as @@ -14,7 +14,7 @@ GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . -For commercial licensing, please contact support@quantumnous.com +For commercial licensing, please contact admin@modelstoken.com */ export { default as SettingsPanel } from './SettingsPanel'; diff --git a/web/classic/src/components/settings/ChannelSelectorModal.jsx b/web/classic/src/components/settings/ChannelSelectorModal.jsx index 165aafafd..b900993e4 100644 --- a/web/classic/src/components/settings/ChannelSelectorModal.jsx +++ b/web/classic/src/components/settings/ChannelSelectorModal.jsx @@ -1,5 +1,5 @@ /* -Copyright (C) 2025 QuantumNous +Copyright (C) 2025 modelstoken This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as @@ -14,7 +14,7 @@ GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . -For commercial licensing, please contact support@quantumnous.com +For commercial licensing, please contact admin@modelstoken.com */ import React, { @@ -182,14 +182,14 @@ const ChannelSelectorModal = forwardRef( case 1: statusTag = ( - {t('已启用')} + {t('已启?)} ); break; case 2: statusTag = ( - {t('已禁用')} + {t('已禁?)} ); break; @@ -203,7 +203,7 @@ const ChannelSelectorModal = forwardRef( default: statusTag = ( - {t('未知状态')} + {t('未知状?)} ); } @@ -240,7 +240,7 @@ const ChannelSelectorModal = forwardRef( renderBaseUrlCell(record._originalData?.base_url || ''), }, { - title: t('状态'), + title: t('状?), dataIndex: '_originalData.status', render: (_, record) => renderStatusCell(record), }, diff --git a/web/classic/src/components/settings/ChatsSetting.jsx b/web/classic/src/components/settings/ChatsSetting.jsx index 9ead13525..39c7222a8 100644 --- a/web/classic/src/components/settings/ChatsSetting.jsx +++ b/web/classic/src/components/settings/ChatsSetting.jsx @@ -1,5 +1,5 @@ /* -Copyright (C) 2025 QuantumNous +Copyright (C) 2025 modelstoken This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as @@ -14,7 +14,7 @@ GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . -For commercial licensing, please contact support@quantumnous.com +For commercial licensing, please contact admin@modelstoken.com */ import React, { useEffect, useState } from 'react'; diff --git a/web/classic/src/components/settings/CustomOAuthSetting.jsx b/web/classic/src/components/settings/CustomOAuthSetting.jsx index 0912160be..17e0bc1ee 100644 --- a/web/classic/src/components/settings/CustomOAuthSetting.jsx +++ b/web/classic/src/components/settings/CustomOAuthSetting.jsx @@ -1,5 +1,5 @@ /* -Copyright (C) 2025 QuantumNous +Copyright (C) 2025 modelstoken This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as @@ -14,7 +14,7 @@ GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . -For commercial licensing, please contact support@quantumnous.com +For commercial licensing, please contact admin@modelstoken.com */ import React, { useEffect, useState } from 'react'; @@ -185,8 +185,8 @@ const ACCESS_POLICY_TEMPLATES = { }; const ACCESS_DENIED_TEMPLATES = { - level_hint: '需要等级 {{required}},你当前等级 {{current}}(字段:{{field}})', - org_hint: '仅限指定组织或角色访问。组织={{current.org}},角色={{current.roles}}', + level_hint: '需要等?{{required}},你当前等级 {{current}}(字段:{{field}}?, + org_hint: '仅限指定组织或角色访问。组?{{current.org}},角?{{current.roles}}', }; const CustomOAuthSetting = ({ serverAddress }) => { @@ -249,7 +249,7 @@ const CustomOAuthSetting = ({ serverAddress }) => { showError(res.data.message); } } catch (error) { - showError(t('获取自定义 OAuth 提供商列表失败')); + showError(t('获取自定?OAuth 提供商列表失?)); } setLoading(false); }; @@ -322,7 +322,7 @@ const CustomOAuthSetting = ({ serverAddress }) => { for (const field of requiredFields) { if (!currentValues[field]) { - showError(t(`请填写 ${field}`)); + showError(t(`请填?${field}`)); return; } } @@ -334,9 +334,9 @@ const CustomOAuthSetting = ({ serverAddress }) => { if (value && !value.startsWith('http://') && !value.startsWith('https://')) { // Check if user selected a preset but forgot to fill issuer URL if (selectedPreset && !baseUrl) { - showError(t('请先填写 Issuer URL,以自动生成完整的端点 URL')); + showError(t('请先填写 Issuer URL,以自动生成完整的端?URL')); } else { - showError(t('端点 URL 必须是完整地址(以 http:// 或 https:// 开头)')); + showError(t('端点 URL 必须是完整地址(以 http:// ?https:// 开头)')); } return; } @@ -380,7 +380,7 @@ const CustomOAuthSetting = ({ serverAddress }) => { (cleanBaseUrl ? `${cleanBaseUrl}/.well-known/openid-configuration` : ''); if (!wellKnownUrl) { - showError(t('请先填写 Discovery URL 或 Issuer URL')); + showError(t('请先填写 Discovery URL ?Issuer URL')); return; } @@ -462,7 +462,7 @@ const CustomOAuthSetting = ({ serverAddress }) => { showSuccess(t('已从 Discovery 自动填充配置')); } catch (error) { showError( - t('获取 Discovery 配置失败:') + (error?.message || t('未知错误')), + t('获取 Discovery 配置失败?) + (error?.message || t('未知错误')), ); } finally { setDiscoveryLoading(false); @@ -518,14 +518,14 @@ const CustomOAuthSetting = ({ serverAddress }) => { const template = ACCESS_POLICY_TEMPLATES[templateKey]; if (!template) return; mergeFormValues({ access_policy: template }); - showSuccess(t('已填充策略模板')); + showSuccess(t('已填充策略模?)); }; const applyDeniedTemplate = (templateKey) => { const template = ACCESS_DENIED_TEMPLATES[templateKey]; if (!template) return; mergeFormValues({ access_denied_message: template }); - showSuccess(t('已填充提示模板')); + showSuccess(t('已填充提示模?)); }; const columns = [ @@ -548,12 +548,12 @@ const CustomOAuthSetting = ({ serverAddress }) => { render: (slug) => {slug}, }, { - title: t('状态'), + title: t('状?), dataIndex: 'enabled', key: 'enabled', render: (enabled) => ( - {enabled ? t('已启用') : t('已禁用')} + {enabled ? t('已启?) : t('已禁?)} ), }, @@ -579,7 +579,7 @@ const CustomOAuthSetting = ({ serverAddress }) => { {t('编辑')} handleDelete(record.id)} > { loading={loading} rowKey="id" pagination={false} - empty={t('暂无自定义 OAuth 提供商')} + empty={t('暂无自定?OAuth 提供?)} /> { }} > - {t('启用供应商')} + {t('启用供应?)} mergeFormValues({ enabled: !!checked })} /> - {formValues.enabled ? t('已启用') : t('已禁用')} + {formValues.enabled ? t('已启?) : t('已禁?)} @@ -677,7 +677,7 @@ const CustomOAuthSetting = ({ serverAddress }) => { {t('Configuration')} - {t('先填写配置,再自动填充 OAuth 端点,能显著减少手工输入')} + {t('先填写配置,再自动填?OAuth 端点,能显著减少手工输入')} {discoveryInfo && ( { description={
- {t('已从 Discovery 获取配置,可继续手动修改所有字段。')} + {t('已从 Discovery 获取配置,可继续手动修改所有字段?)}
{discoveryAutoFilledLabels ? (
@@ -724,7 +724,7 @@ const CustomOAuthSetting = ({ serverAddress }) => { value={selectedPreset} onChange={handlePresetChange} optionList={[ - { value: '', label: t('自定义') }, + { value: '', label: t('自定?) }, ...Object.entries(OAUTH_PRESETS).map(([key, config]) => ({ value: key, label: config.name, @@ -735,14 +735,14 @@ const CustomOAuthSetting = ({ serverAddress }) => {
@@ -776,7 +776,7 @@ const CustomOAuthSetting = ({ serverAddress }) => { field="name" label={t('显示名称')} placeholder={t('例如:GitHub Enterprise')} - rules={[{ required: true, message: t('请输入显示名称') }]} + rules={[{ required: true, message: t('请输入显示名?) }]} /> @@ -784,8 +784,8 @@ const CustomOAuthSetting = ({ serverAddress }) => { field="slug" label="Slug" placeholder={t('例如:github-enterprise')} - extraText={t('URL 标识,只能包含小写字母、数字和连字符')} - rules={[{ required: true, message: t('请输入 Slug') }]} + extraText={t('URL 标识,只能包含小写字母、数字和连字?)} + rules={[{ required: true, message: t('请输?Slug') }]} /> @@ -831,7 +831,7 @@ const CustomOAuthSetting = ({ serverAddress }) => { field="client_id" label="Client ID" placeholder={t('OAuth Client ID')} - rules={[{ required: true, message: t('请输入 Client ID') }]} + rules={[{ required: true, message: t('请输?Client ID') }]} /> @@ -841,13 +841,13 @@ const CustomOAuthSetting = ({ serverAddress }) => { type="password" placeholder={ editingProvider - ? t('留空则保持原有密钥') + ? t('留空则保持原有密?) : t('OAuth Client Secret') } rules={ editingProvider ? [] - : [{ required: true, message: t('请输入 Client Secret') }] + : [{ required: true, message: t('请输?Client Secret') }] } /> @@ -869,7 +869,7 @@ const CustomOAuthSetting = ({ serverAddress }) => { : 'https://example.com/oauth/authorize' } rules={[ - { required: true, message: t('请输入 Authorization Endpoint') }, + { required: true, message: t('请输?Authorization Endpoint') }, ]} /> @@ -882,10 +882,10 @@ const CustomOAuthSetting = ({ serverAddress }) => { label={t('Token Endpoint')} placeholder={ selectedPreset && OAUTH_PRESETS[selectedPreset] - ? t('自动生成:') + OAUTH_PRESETS[selectedPreset].token_endpoint + ? t('自动生成?) + OAUTH_PRESETS[selectedPreset].token_endpoint : 'https://example.com/oauth/token' } - rules={[{ required: true, message: t('请输入 Token Endpoint') }]} + rules={[{ required: true, message: t('请输?Token Endpoint') }]} /> @@ -894,11 +894,11 @@ const CustomOAuthSetting = ({ serverAddress }) => { label={t('User Info Endpoint')} placeholder={ selectedPreset && OAUTH_PRESETS[selectedPreset] - ? t('自动生成:') + OAUTH_PRESETS[selectedPreset].user_info_endpoint + ? t('自动生成?) + OAUTH_PRESETS[selectedPreset].user_info_endpoint : 'https://example.com/api/user' } rules={[ - { required: true, message: t('请输入 User Info Endpoint') }, + { required: true, message: t('请输?User Info Endpoint') }, ]} /> @@ -912,9 +912,9 @@ const CustomOAuthSetting = ({ serverAddress }) => { placeholder="openid profile email" extraText={ discoveryInfo?.scopesSupported?.length - ? t('Discovery 建议 scopes:') + + ? t('Discovery 建议 scopes?) + discoveryInfo.scopesSupported.join(', ') - : t('可手动填写,多个 scope 用空格分隔') + : t('可手动填写,多个 scope 用空格分?) } /> @@ -924,7 +924,7 @@ const CustomOAuthSetting = ({ serverAddress }) => { {t('字段映射')} - {t('配置如何从用户信息 API 响应中提取用户数据,支持 JSONPath 语法')} + {t('配置如何从用户信?API 响应中提取用户数据,支持 JSONPath 语法')} @@ -933,7 +933,7 @@ const CustomOAuthSetting = ({ serverAddress }) => { field="user_id_field" label={t('用户 ID 字段(可选)')} placeholder={t('例如:sub、id、data.user.id')} - extraText={t('用于唯一标识用户的字段路径')} + extraText={t('用于唯一标识用户的字段路?)} /> @@ -978,9 +978,9 @@ const CustomOAuthSetting = ({ serverAddress }) => { field="auth_style" label={t('认证方式')} optionList={[ - { value: 0, label: t('自动检测') }, + { value: 0, label: t('自动检?) }, { value: 1, label: t('POST 参数') }, - { value: 2, label: t('Basic Auth 头') }, + { value: 2, label: t('Basic Auth ?) }, ]} /> @@ -990,7 +990,7 @@ const CustomOAuthSetting = ({ serverAddress }) => { {t('准入策略')} - {t('可选:基于用户信息 JSON 做组合条件准入,条件不满足时返回自定义提示')} + {t('可选:基于用户信息 JSON 做组合条件准入,条件不满足时返回自定义提?)} @@ -1007,12 +1007,12 @@ const CustomOAuthSetting = ({ serverAddress }) => { {"field": "active", "op": "eq", "value": true} ] }`} - extraText={t('支持逻辑 and/or 与嵌套 groups;操作符支持 eq/ne/gt/gte/lt/lte/in/not_in/contains/exists')} + extraText={t('支持逻辑 and/or 与嵌?groups;操作符支持 eq/ne/gt/gte/lt/lte/in/not_in/contains/exists')} showClear /> diff --git a/web/classic/src/components/settings/DashboardSetting.jsx b/web/classic/src/components/settings/DashboardSetting.jsx index 7bf424943..2c7393a2e 100644 --- a/web/classic/src/components/settings/DashboardSetting.jsx +++ b/web/classic/src/components/settings/DashboardSetting.jsx @@ -1,5 +1,5 @@ /* -Copyright (C) 2025 QuantumNous +Copyright (C) 2025 modelstoken This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as @@ -14,7 +14,7 @@ GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . -For commercial licensing, please contact support@quantumnous.com +For commercial licensing, please contact admin@modelstoken.com */ import React, { useEffect, useState, useMemo } from 'react'; @@ -51,8 +51,7 @@ const DashboardSetting = () => { }); let [loading, setLoading] = useState(false); - const [showMigrateModal, setShowMigrateModal] = useState(false); // 下个版本会删除 - + const [showMigrateModal, setShowMigrateModal] = useState(false); // 下个版本会删? const getOptions = async () => { const res = await API.get('/api/option/'); const { success, message, data } = res.data; @@ -110,7 +109,7 @@ const DashboardSetting = () => { try { setLoading(true); await API.post('/api/option/migrate_console_setting'); - showSuccess('旧配置迁移完成'); + showSuccess('旧配置迁移完?); await onRefresh(); setShowMigrateModal(false); } catch (err) { @@ -136,9 +135,8 @@ const DashboardSetting = () => { >

检测到旧版本的配置数据,是否要迁移到新的配置格式?

- 注意: - 迁移过程中会自动处理数据格式转换,迁移完成后旧配置将被清除,请在迁移前在数据库中备份好旧配置。 -

+ 注意?/strong> + 迁移过程中会自动处理数据格式转换,迁移完成后旧配置将被清除,请在迁移前在数据库中备份好旧配置?

{/* 数据看板设置 */} diff --git a/web/classic/src/components/settings/DrawingSetting.jsx b/web/classic/src/components/settings/DrawingSetting.jsx index a714b6908..9f32e703f 100644 --- a/web/classic/src/components/settings/DrawingSetting.jsx +++ b/web/classic/src/components/settings/DrawingSetting.jsx @@ -1,5 +1,5 @@ /* -Copyright (C) 2025 QuantumNous +Copyright (C) 2025 modelstoken This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as @@ -14,7 +14,7 @@ GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . -For commercial licensing, please contact support@quantumnous.com +For commercial licensing, please contact admin@modelstoken.com */ import React, { useEffect, useState } from 'react'; diff --git a/web/classic/src/components/settings/HttpStatusCodeRulesInput.jsx b/web/classic/src/components/settings/HttpStatusCodeRulesInput.jsx index 5faf93af9..f84353584 100644 --- a/web/classic/src/components/settings/HttpStatusCodeRulesInput.jsx +++ b/web/classic/src/components/settings/HttpStatusCodeRulesInput.jsx @@ -1,5 +1,5 @@ /* -Copyright (C) 2025 QuantumNous +Copyright (C) 2025 modelstoken This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as @@ -14,7 +14,7 @@ GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . -For commercial licensing, please contact support@quantumnous.com +For commercial licensing, please contact admin@modelstoken.com */ import React from 'react'; diff --git a/web/classic/src/components/settings/ModelDeploymentSetting.jsx b/web/classic/src/components/settings/ModelDeploymentSetting.jsx index c872f631d..bae6f15e9 100644 --- a/web/classic/src/components/settings/ModelDeploymentSetting.jsx +++ b/web/classic/src/components/settings/ModelDeploymentSetting.jsx @@ -1,5 +1,5 @@ /* -Copyright (C) 2025 QuantumNous +Copyright (C) 2025 modelstoken This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as @@ -14,7 +14,7 @@ GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . -For commercial licensing, please contact support@quantumnous.com +For commercial licensing, please contact admin@modelstoken.com */ import React, { useEffect, useState } from 'react'; diff --git a/web/classic/src/components/settings/ModelSetting.jsx b/web/classic/src/components/settings/ModelSetting.jsx index fb0b844a0..31d044146 100644 --- a/web/classic/src/components/settings/ModelSetting.jsx +++ b/web/classic/src/components/settings/ModelSetting.jsx @@ -1,5 +1,5 @@ /* -Copyright (C) 2025 QuantumNous +Copyright (C) 2025 modelstoken This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as @@ -14,7 +14,7 @@ GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . -For commercial licensing, please contact support@quantumnous.com +For commercial licensing, please contact admin@modelstoken.com */ import React, { useEffect, useState } from 'react'; diff --git a/web/classic/src/components/settings/OperationSetting.jsx b/web/classic/src/components/settings/OperationSetting.jsx index 8585a3e90..1b445e386 100644 --- a/web/classic/src/components/settings/OperationSetting.jsx +++ b/web/classic/src/components/settings/OperationSetting.jsx @@ -1,5 +1,5 @@ /* -Copyright (C) 2025 QuantumNous +Copyright (C) 2025 modelstoken This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as @@ -14,7 +14,7 @@ GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . -For commercial licensing, please contact support@quantumnous.com +For commercial licensing, please contact admin@modelstoken.com */ import React, { useEffect, useState } from 'react'; @@ -53,10 +53,10 @@ const OperationSetting = () => { /* 顶栏模块管理 */ HeaderNavModules: '', - /* 左侧边栏模块管理(管理员) */ + /* 左侧边栏模块管理(管理员?*/ SidebarModulesAdmin: '', - /* 敏感词设置 */ + /* 敏感词设?*/ CheckSensitiveEnabled: false, CheckSensitiveOnPromptEnabled: false, SensitiveWords: '', @@ -130,11 +130,11 @@ const OperationSetting = () => {
- {/* 左侧边栏模块管理(管理员) */} + {/* 左侧边栏模块管理(管理员?*/}
- {/* 屏蔽词过滤设置 */} + {/* 屏蔽词过滤设?*/} diff --git a/web/classic/src/components/settings/OtherSetting.jsx b/web/classic/src/components/settings/OtherSetting.jsx index 56049093b..962d5eb79 100644 --- a/web/classic/src/components/settings/OtherSetting.jsx +++ b/web/classic/src/components/settings/OtherSetting.jsx @@ -1,5 +1,5 @@ /* -Copyright (C) 2025 QuantumNous +Copyright (C) 2025 modelstoken This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as @@ -14,7 +14,7 @@ GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . -For commercial licensing, please contact support@quantumnous.com +For commercial licensing, please contact admin@modelstoken.com */ import React, { useContext, useEffect, useRef, useState } from 'react'; @@ -96,7 +96,7 @@ const OtherSetting = () => { try { setLoadingInput((loadingInput) => ({ ...loadingInput, Notice: true })); await updateOption('Notice', inputs.Notice); - showSuccess(t('公告已更新')); + showSuccess(t('公告已更?)); } catch (error) { console.error(t('公告更新失败'), error); showError(t('公告更新失败')); @@ -115,7 +115,7 @@ const OtherSetting = () => { LEGAL_USER_AGREEMENT_KEY, inputs[LEGAL_USER_AGREEMENT_KEY], ); - showSuccess(t('用户协议已更新')); + showSuccess(t('用户协议已更?)); } catch (error) { console.error(t('用户协议更新失败'), error); showError(t('用户协议更新失败')); @@ -137,7 +137,7 @@ const OtherSetting = () => { LEGAL_PRIVACY_POLICY_KEY, inputs[LEGAL_PRIVACY_POLICY_KEY], ); - showSuccess(t('隐私政策已更新')); + showSuccess(t('隐私政策已更?)); } catch (error) { console.error(t('隐私政策更新失败'), error); showError(t('隐私政策更新失败')); @@ -158,7 +158,7 @@ const OtherSetting = () => { SystemName: true, })); await updateOption('SystemName', inputs.SystemName); - showSuccess(t('系统名称已更新')); + showSuccess(t('系统名称已更?)); } catch (error) { console.error(t('系统名称更新失败'), error); showError(t('系统名称更新失败')); @@ -175,7 +175,7 @@ const OtherSetting = () => { try { setLoadingInput((loadingInput) => ({ ...loadingInput, Logo: true })); await updateOption('Logo', inputs.Logo); - showSuccess('Logo 已更新'); + showSuccess('Logo 已更?); } catch (error) { console.error('Logo 更新失败', error); showError('Logo 更新失败'); @@ -191,7 +191,7 @@ const OtherSetting = () => { HomePageContent: true, })); await updateOption(key, inputs[key]); - showSuccess('首页内容已更新'); + showSuccess('首页内容已更?); } catch (error) { console.error('首页内容更新失败', error); showError('首页内容更新失败'); @@ -207,7 +207,7 @@ const OtherSetting = () => { try { setLoadingInput((loadingInput) => ({ ...loadingInput, About: true })); await updateOption('About', inputs.About); - showSuccess('关于内容已更新'); + showSuccess('关于内容已更?); } catch (error) { console.error('关于内容更新失败', error); showError('关于内容更新失败'); @@ -220,7 +220,7 @@ const OtherSetting = () => { try { setLoadingInput((loadingInput) => ({ ...loadingInput, Footer: true })); await updateOption('Footer', inputs.Footer); - showSuccess('页脚内容已更新'); + showSuccess('页脚内容已更?); } catch (error) { console.error('页脚内容更新失败', error); showError('页脚内容更新失败'); @@ -271,7 +271,7 @@ const OtherSetting = () => { } } catch (error) { console.error('Failed to check for updates:', error); - showError('检查更新失败,请稍后再试'); + showError('检查更新失败,请稍后再?); } finally { setLoadingInput((loadingInput) => ({ ...loadingInput, @@ -282,7 +282,7 @@ const OtherSetting = () => { const switchToDefaultFrontend = () => { Modal.confirm({ - title: t('切换到新版前端'), + title: t('切换到新版前?), content: t('切换后页面会自动刷新,并进入新版前端。是否继续?'), okText: t('确认切换'), cancelText: t('取消'), @@ -301,7 +301,7 @@ const OtherSetting = () => { showError(message); return; } - showSuccess(t('已切换到新版前端,正在刷新页面')); + showSuccess(t('已切换到新版前端,正在刷新页?)); setTimeout(() => { window.location.reload(); }, 600); @@ -372,21 +372,20 @@ const OtherSetting = () => {
- {t('当前版本')}: - {statusState?.status?.version || t('未知')} + {t('当前版本')}? {statusState?.status?.version || t('未知')} @@ -411,7 +410,7 @@ const OtherSetting = () => { { { { { { fullMode={false} type='info' description={t( - '移除 One API 的版权标识必须首先获得授权,项目维护需要花费大量精力,如果本项目对你有意义,请主动支持本项目', + '移除 One API 的版权标识必须首先获得授权,项目维护需要花费大量精力,如果本项目对你有意义,请主动支持本项?, )} closeIcon={null} style={{ marginTop: 15 }} @@ -532,7 +531,7 @@ const OtherSetting = () => { { setShowUpdateModal(false)} footer={[ diff --git a/web/classic/src/components/settings/PaymentSetting.jsx b/web/classic/src/components/settings/PaymentSetting.jsx index 880001123..5100c6461 100644 --- a/web/classic/src/components/settings/PaymentSetting.jsx +++ b/web/classic/src/components/settings/PaymentSetting.jsx @@ -1,5 +1,5 @@ /* -Copyright (C) 2025 QuantumNous +Copyright (C) 2025 modelstoken This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as @@ -14,7 +14,7 @@ GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . -For commercial licensing, please contact support@quantumnous.com +For commercial licensing, please contact admin@modelstoken.com */ import React, { useEffect, useState } from 'react'; @@ -64,38 +64,38 @@ const PaymentSetting = () => { const complianceStatements = [ t('你已合法取得所接入模型 API、账号、密钥和额度的授权;'), t( - '你承诺仅在已取得上游服务商、模型服务提供方或相关权利方合法授权的范围内使用其 API、账号、密钥、额度及服务能力,不进行未经授权的转售、倒卖、分销或其他违规商业化使用。', + '你承诺仅在已取得上游服务商、模型服务提供方或相关权利方合法授权的范围内使用?API、账号、密钥、额度及服务能力,不进行未经授权的转售、倒卖、分销或其他违规商业化使用?, ), t( - '如向中华人民共和国境内公众提供生成式人工智能服务,你将依法履行备案登记、安全评估、内容安全、投诉举报、生成合成内容标识、日志留存、个人信息保护等合规义务;', + '如向中华人民共和国境内公众提供生成式人工智能服务,你将依法履行备案登记、安全评估、内容安全、投诉举报、生成合成内容标识、日志留存、个人信息保护等合规义务?, ), t( - '你承诺不会利用本系统实施、协助实施或变相实施违反适用法律法规、监管要求、平台规则、社会公共利益或第三方合法权益的行为。', + '你承诺不会利用本系统实施、协助实施或变相实施违反适用法律法规、监管要求、平台规则、社会公共利益或第三方合法权益的行为?, ), - t('你理解并自行承担部署、运营和收费行为产生的法律责任。'), + t('你理解并自行承担部署、运营和收费行为产生的法律责任?), t( - '你理解本合规提醒仅用于风险提示,不构成法律意见、合规审查结论或对你使用本系统行为合法性的保证;你应根据实际业务场景自行咨询专业法律或合规顾问。', + '你理解本合规提醒仅用于风险提示,不构成法律意见、合规审查结论或对你使用本系统行为合法性的保证;你应根据实际业务场景自行咨询专业法律或合规顾问?, ), ]; const requiredComplianceText = t( - '我已阅读并理解上述合规提醒,知悉相关法律风险,并确认自行承担部署、运营和收费行为产生的法律责任', + '我已阅读并理解上述合规提醒,知悉相关法律风险,并确认自行承担部署、运营和收费行为产生的法律责?, ); const requiredComplianceTextParts = [ { type: 'input', - text: t('我已阅读并理解上述合规提醒'), + text: t('我已阅读并理解上述合规提?), }, - { type: 'static', text: t(',') }, + { type: 'static', text: t('?) }, { type: 'input', text: t('知悉相关法律风险'), }, - { type: 'static', text: t(',') }, + { type: 'static', text: t('?) }, { type: 'input', - text: t('并确认自行承担部署'), + text: t('并确认自行承担部?), }, - { type: 'static', text: t('、') }, + { type: 'static', text: t('?) }, { type: 'input', text: t('运营和收费行为产生的法律责任'), @@ -217,12 +217,12 @@ const PaymentSetting = () => { {!complianceConfirmed ? ( {t( - '确认前,支付、兑换码、订阅计划和邀请返利功能将保持锁定。', + '确认前,支付、兑换码、订阅计划和邀请返利功能将保持锁定?, )} @@ -787,7 +777,7 @@ const SystemSetting = () => { - {t('配置服务器端请求伪造(SSRF)防护,用于保护内网资源安全')} + {t('配置服务器端请求伪?SSRF)防护,用于保护内网资源安?)} { handleCheckboxChange( 'fetch_setting.enable_ssrf_protection', @@ -826,7 +816,7 @@ const SystemSetting = () => { } > {t( - '允许访问私有IP地址(127.0.0.1、192.168.x.x等内网地址)', + '允许访问私有IP地址?27.0.0.1?92.168.x.x等内网地址?, )} @@ -849,10 +839,10 @@ const SystemSetting = () => { } style={{ marginBottom: 8 }} > - {t('对域名启用 IP 过滤(推荐开启)')} + {t('对域名启?IP 过滤(推荐开启)')} - {t(domainFilterMode ? '域名白名单' : '域名黑名单')} + {t(domainFilterMode ? '域名白名? : '域名黑名?)} { }} style={{ marginBottom: 8 }} > - {t('白名单')} - {t('黑名单')} + {t('白名?)} + {t('黑名?)} { > - {t(ipFilterMode ? 'IP白名单' : 'IP黑名单')} + {t(ipFilterMode ? 'IP白名? : 'IP黑名?)} - {t('支持CIDR格式,如:8.8.8.8, 192.168.1.0/24')} + {t('支持CIDR格式,如?.8.8.8, 192.168.1.0/24')} { }} style={{ marginBottom: 8 }} > - {t('白名单')} - {t('黑名单')} + {t('白名?)} + {t('黑名?)} { style={{ marginTop: 16 }} > - {t('允许的端口')} + {t('允许的端?)} { 'fetch_setting.allowed_ports': value, })); }} - placeholder={t('输入端口后回车,如:80 或 8000-8999')} + placeholder={t('输入端口后回车,如:80 ?8000-8999')} style={{ width: '100%' }} /> { handleCheckboxChange('EmailVerificationEnabled', e) } > - {t('通过密码注册时需要进行邮箱验证')} + {t('通过密码注册时需要进行邮箱验?)} { handleCheckboxChange('RegisterEnabled', e) } > - {t('允许新用户注册')} + {t('允许新用户注?)} { @@ -1130,7 +1120,7 @@ const SystemSetting = () => { label={t('服务显示名称')} placeholder={t('默认使用系统名称')} extraText={t( - "用户注册时看到的网站名称,比如'我的网站'", + "用户注册时看到的网站名称,比?我的网站'", )} /> @@ -1153,26 +1143,26 @@ const SystemSetting = () => { { handleCheckboxChange( 'passkey.allow_insecure_origin', @@ -1197,7 +1187,7 @@ const SystemSetting = () => { ) } > - {t('允许不安全的 Origin(HTTP)')} + {t('允许不安全的 Origin(HTTP?)} @@ -1208,10 +1198,10 @@ const SystemSetting = () => { @@ -1226,7 +1216,7 @@ const SystemSetting = () => { - + {t('用以防止恶意用户利用临时邮箱批量注册')} { ) } > - 启用邮箱域名白名单 - + 启用邮箱域名白名? { { onClick={submitEmailDomainWhitelist} style={{ marginTop: 10 }} > - {t('保存邮箱域名白名单设置')} + {t('保存邮箱域名白名单设?)} - {t('用以支持系统的邮件发送')} + {t('用以支持系统的邮件发?)} @@ -1316,7 +1305,7 @@ const SystemSetting = () => { @@ -1355,17 +1344,17 @@ const SystemSetting = () => { {t( - '用以支持通过 OIDC 登录,例如 Okta、Auth0 等兼容 OIDC 协议的 IdP', + '用以支持通过 OIDC 登录,例?Okta、Auth0 等兼?OIDC 协议?IdP', )} {t( - '若你的 OIDC Provider 支持 Discovery Endpoint,你可以仅填写 OIDC Well-Known URL,系统会自动获取 OIDC 配置', + '若你?OIDC Provider 支持 Discovery Endpoint,你可以仅填?OIDC Well-Known URL,系统会自动获取 OIDC 配置', )} { @@ -1401,7 +1390,7 @@ const SystemSetting = () => { @@ -1412,14 +1401,14 @@ const SystemSetting = () => { @@ -1434,7 +1423,7 @@ const SystemSetting = () => { {t('用以支持通过 GitHub 进行登录注册')} { {t('用以支持通过 Discord 进行登录注册')} { { @@ -1536,7 +1525,7 @@ const SystemSetting = () => { diff --git a/web/classic/src/components/settings/personal/cards/AccountManagement.jsx b/web/classic/src/components/settings/personal/cards/AccountManagement.jsx index 29249caa1..05d5cc8c6 100644 --- a/web/classic/src/components/settings/personal/cards/AccountManagement.jsx +++ b/web/classic/src/components/settings/personal/cards/AccountManagement.jsx @@ -1,5 +1,5 @@ /* -Copyright (C) 2025 QuantumNous +Copyright (C) 2025 modelstoken This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as @@ -14,7 +14,7 @@ GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . -For commercial licensing, please contact support@quantumnous.com +For commercial licensing, please contact admin@modelstoken.com */ import React from 'react'; @@ -74,7 +74,7 @@ const AccountManagement = ({ }) => { const renderAccountInfo = (accountId, label) => { if (!accountId || accountId === '') { - return {t('未绑定')}; + return {t('未绑?)}; } const popContent = ( @@ -120,7 +120,7 @@ const AccountManagement = ({ const handleUnbindCustomOAuth = async (providerId, providerName) => { Modal.confirm({ title: t('确认解绑'), - content: t('确定要解绑 {{name}} 吗?', { name: providerName }), + content: t('确定要解?{{name}} 吗?', { name: providerName }), okText: t('确认'), cancelText: t('取消'), onOk: async () => { @@ -251,10 +251,10 @@ const AccountManagement = ({
{!status.wechat_login - ? t('未启用') + ? t('未启?) : isBound(userState.user?.wechat_id) - ? t('已绑定') - : t('未绑定')} + ? t('已绑?) + : t('未绑?)}
@@ -270,7 +270,7 @@ const AccountManagement = ({ ? t('修改绑定') : status.wechat_login ? t('绑定') - : t('未启用')} + : t('未启?)} @@ -311,7 +311,7 @@ const AccountManagement = ({ !status.github_oauth } > - {status.github_oauth ? t('绑定') : t('未启用')} + {status.github_oauth ? t('绑定') : t('未启?)} @@ -352,7 +352,7 @@ const AccountManagement = ({ !status.discord_oauth } > - {status.discord_oauth ? t('绑定') : t('未启用')} + {status.discord_oauth ? t('绑定') : t('未启?)} @@ -395,7 +395,7 @@ const AccountManagement = ({ isBound(userState.user?.oidc_id) || !status.oidc_enabled } > - {status.oidc_enabled ? t('绑定') : t('未启用')} + {status.oidc_enabled ? t('绑定') : t('未启?)} @@ -432,7 +432,7 @@ const AccountManagement = ({ type='primary' theme='outline' > - {t('已绑定')} + {t('已绑?)} ) : ( )} @@ -511,13 +511,13 @@ const AccountManagement = ({ !status.linuxdo_oauth } > - {status.linuxdo_oauth ? t('绑定') : t('未启用')} + {status.linuxdo_oauth ? t('绑定') : t('未启?)} - {/* 自定义 OAuth 提供商绑定 */} + {/* 自定?OAuth 提供商绑?*/} {status.custom_oauth_providers && status.custom_oauth_providers.map((provider) => { const bound = isCustomOAuthBound(provider.id); @@ -542,7 +542,7 @@ const AccountManagement = ({ binding?.provider_user_id, t('{{name}} ID', { name: provider.name }), ) - : t('未绑定')} + : t('未绑?)} @@ -603,7 +603,7 @@ const AccountManagement = ({ {t('系统访问令牌')} - {t('用于API调用的身份验证令牌,请妥善保管')} + {t('用于API调用的身份验证令牌,请妥善保?)} {systemToken && (
@@ -642,7 +642,7 @@ const AccountManagement = ({ {t('密码管理')} - {t('定期更改密码可以提高账户安全性')} + {t('定期更改密码可以提高账户安全?)}
@@ -671,26 +671,26 @@ const AccountManagement = ({ {passkeyEnabled - ? t('已启用 Passkey,无需密码即可登录') - : t('使用 Passkey 实现免密且更安全的登录体验')} + ? t('已启?Passkey,无需密码即可登录') + : t('使用 Passkey 实现免密且更安全的登录体?)}
- {t('最后使用时间')}:{lastUsedLabel} + {t('最后使用时?)}:{lastUsedLabel}
{/*{passkeyEnabled && (*/} {/*
*/} - {/* {t('备份支持')}:*/} + {/* {t('备份支持')}?/} {/* {passkeyStatus?.backup_eligible*/} {/* ? t('支持备份')*/} - {/* : t('不支持')}*/} - {/* ,{t('备份状态')}:*/} - {/* {passkeyStatus?.backup_state ? t('已备份') : t('未备份')}*/} + {/* : t('不支?)}*/} + {/* ,{t('备份状?)}?/} + {/* {passkeyStatus?.backup_state ? t('已备?) : t('未备?)}*/} {/*
*/} {/*)}*/} {!passkeySupported && (
- {t('当前设备不支持 Passkey')} + {t('当前设备不支?Passkey')}
)}
@@ -747,7 +747,7 @@ const AccountManagement = ({ {t('删除账户')} - {t('此操作不可逆,所有数据将被永久删除')} + {t('此操作不可逆,所有数据将被永久删?)} diff --git a/web/classic/src/components/settings/personal/cards/CheckinCalendar.jsx b/web/classic/src/components/settings/personal/cards/CheckinCalendar.jsx index 2298ae94d..8cd363332 100644 --- a/web/classic/src/components/settings/personal/cards/CheckinCalendar.jsx +++ b/web/classic/src/components/settings/personal/cards/CheckinCalendar.jsx @@ -1,5 +1,5 @@ /* -Copyright (C) 2025 QuantumNous +Copyright (C) 2025 modelstoken This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as @@ -14,7 +14,7 @@ GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . -For commercial licensing, please contact support@quantumnous.com +For commercial licensing, please contact admin@modelstoken.com */ import React, { useState, useEffect, useMemo } from 'react'; @@ -57,13 +57,10 @@ const CheckinCalendar = ({ t, status, turnstileEnabled, turnstileSiteKey }) => { const [currentMonth, setCurrentMonth] = useState( new Date().toISOString().slice(0, 7), ); - // 初始加载状态,用于避免折叠状态闪烁 - const [initialLoaded, setInitialLoaded] = useState(false); - // 折叠状态:null 表示未确定(等待首次加载) - const [isCollapsed, setIsCollapsed] = useState(null); + // 初始加载状态,用于避免折叠状态闪? const [initialLoaded, setInitialLoaded] = useState(false); + // 折叠状态:null 表示未确定(等待首次加载? const [isCollapsed, setIsCollapsed] = useState(null); - // 创建日期到额度的映射,方便快速查找 - const checkinRecordsMap = useMemo(() => { + // 创建日期到额度的映射,方便快速查? const checkinRecordsMap = useMemo(() => { const map = {}; const records = checkinData.stats?.records || []; records.forEach((record) => { @@ -72,8 +69,7 @@ const CheckinCalendar = ({ t, status, turnstileEnabled, turnstileSiteKey }) => { return map; }, [checkinData.stats?.records]); - // 计算本月获得的额度 - const monthlyQuota = useMemo(() => { + // 计算本月获得的额? const monthlyQuota = useMemo(() => { const records = checkinData.stats?.records || []; return records.reduce( (sum, record) => sum + (record.quota_awarded || 0), @@ -81,8 +77,7 @@ const CheckinCalendar = ({ t, status, turnstileEnabled, turnstileSiteKey }) => { ); }, [checkinData.stats?.records]); - // 获取签到状态 - const fetchCheckinStatus = async (month) => { + // 获取签到状? const fetchCheckinStatus = async (month) => { const isFirstLoad = !initialLoaded; setLoading(true); try { @@ -90,20 +85,19 @@ const CheckinCalendar = ({ t, status, turnstileEnabled, turnstileSiteKey }) => { const { success, data, message } = res.data; if (success) { setCheckinData(data); - // 首次加载时,根据签到状态设置折叠状态 - if (isFirstLoad) { + // 首次加载时,根据签到状态设置折叠状? if (isFirstLoad) { setIsCollapsed(data.stats?.checked_in_today ?? false); setInitialLoaded(true); } } else { - showError(message || t('获取签到状态失败')); + showError(message || t('获取签到状态失?)); if (isFirstLoad) { setIsCollapsed(false); setInitialLoaded(true); } } } catch (error) { - showError(t('获取签到状态失败')); + showError(t('获取签到状态失?)); if (isFirstLoad) { setIsCollapsed(false); setInitialLoaded(true); @@ -133,10 +127,9 @@ const CheckinCalendar = ({ t, status, turnstileEnabled, turnstileSiteKey }) => { const { success, data, message } = res.data; if (success) { showSuccess( - t('签到成功!获得') + ' ' + renderQuota(data.quota_awarded), + t('签到成功!获?) + ' ' + renderQuota(data.quota_awarded), ); - // 刷新签到状态 - fetchCheckinStatus(currentMonth); + // 刷新签到状? fetchCheckinStatus(currentMonth); setTurnstileModalVisible(false); } else { if (!token && shouldTriggerTurnstile(message)) { @@ -165,16 +158,13 @@ const CheckinCalendar = ({ t, status, turnstileEnabled, turnstileSiteKey }) => { } }, [status?.checkin_enabled, currentMonth]); - // 如果签到功能未启用,不显示组件 - if (!status?.checkin_enabled) { + // 如果签到功能未启用,不显示组? if (!status?.checkin_enabled) { return null; } - // 日期渲染函数 - 显示签到状态和获得的额度 - const dateRender = (dateString) => { - // Semi Calendar 传入的 dateString 是 Date.toString() 格式 - // 需要转换为 YYYY-MM-DD 格式来匹配后端数据 - const date = new Date(dateString); + // 日期渲染函数 - 显示签到状态和获得的额? const dateRender = (dateString) => { + // Semi Calendar 传入?dateString ?Date.toString() 格式 + // 需要转换为 YYYY-MM-DD 格式来匹配后端数? const date = new Date(dateString); if (isNaN(date.getTime())) { return null; } @@ -260,12 +250,12 @@ const CheckinCalendar = ({ t, status, turnstileEnabled, turnstileSiteKey }) => {
{!initialLoaded - ? t('正在加载签到状态...') + ? t('正在加载签到状?..') : checkinData.stats?.checked_in_today ? t('今日已签到,累计签到') + ` ${checkinData.stats?.total_checkins || 0} ` + - t('天') - : t('每日签到可获得随机额度奖励')} + t('?) + : t('每日签到可获得随机额度奖?)}
@@ -279,14 +269,14 @@ const CheckinCalendar = ({ t, status, turnstileEnabled, turnstileSiteKey }) => { className='!bg-green-600 hover:!bg-green-700' > {!initialLoaded - ? t('加载中...') + ? t('加载?..') : checkinData.stats?.checked_in_today - ? t('今日已签到') + ? t('今日已签?) : t('立即签到')} - {/* 可折叠内容 */} + {/* 可折叠内?*/} {/* 签到统计 */}
@@ -370,7 +360,7 @@ const CheckinCalendar = ({ t, status, turnstileEnabled, turnstileSiteKey }) => {
    -
  • {t('每日签到可获得随机额度奖励')}
  • +
  • {t('每日签到可获得随机额度奖?)}
  • {t('签到奖励将直接添加到您的账户余额')}
  • {t('每日仅可签到一次,请勿重复签到')}
diff --git a/web/classic/src/components/settings/personal/cards/ModelsList.jsx b/web/classic/src/components/settings/personal/cards/ModelsList.jsx index 3f374fd44..c5326dbad 100644 --- a/web/classic/src/components/settings/personal/cards/ModelsList.jsx +++ b/web/classic/src/components/settings/personal/cards/ModelsList.jsx @@ -1,5 +1,5 @@ /* -Copyright (C) 2025 QuantumNous +Copyright (C) 2025 modelstoken This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as @@ -14,7 +14,7 @@ GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . -For commercial licensing, please contact support@quantumnous.com +For commercial licensing, please contact admin@modelstoken.com */ import React, { useState, useEffect } from 'react'; @@ -44,8 +44,7 @@ const ModelsList = ({ t, models, modelsLoading, copyText }) => { return savedState ? JSON.parse(savedState) : false; }); const [activeModelCategory, setActiveModelCategory] = useState('all'); - const MODELS_DISPLAY_COUNT = 25; // 默认显示的模型数量 - + const MODELS_DISPLAY_COUNT = 25; // 默认显示的模型数? // Save models expanded state to localStorage whenever it changes useEffect(() => { localStorage.setItem('modelsExpanded', JSON.stringify(isModelsExpanded)); @@ -63,7 +62,7 @@ const ModelsList = ({ t, models, modelsLoading, copyText }) => { {t('可用模型')}
- {t('查看当前可用的所有模型')} + {t('查看当前可用的所有模?)}
@@ -71,7 +70,7 @@ const ModelsList = ({ t, models, modelsLoading, copyText }) => { {/* 可用模型部分 */}
{modelsLoading ? ( - // 骨架屏加载状态 - 模拟实际加载后的布局 + // 骨架屏加载状?- 模拟实际加载后的布局
{/* 模拟分类标签 */}
{
) : ( <> - {/* 模型分类标签页 */} + {/* 模型分类标签?*/}
{ > {Object.entries(getModelCategories(t)).map( ([key, category]) => { - // 计算该分类下的模型数量 - const modelCount = + // 计算该分类下的模型数? const modelCount = key === 'all' ? models.length : models.filter((model) => @@ -175,8 +173,7 @@ const ModelsList = ({ t, models, modelsLoading, copyText }) => {
{(() => { - // 根据当前选中的分类过滤模型 - const categories = getModelCategories(t); + // 根据当前选中的分类过滤模? const categories = getModelCategories(t); const filteredModels = activeModelCategory === 'all' ? models @@ -186,8 +183,7 @@ const ModelsList = ({ t, models, modelsLoading, copyText }) => { }), ); - // 如果过滤后没有模型,显示空状态 - if (filteredModels.length === 0) { + // 如果过滤后没有模型,显示空状? if (filteredModels.length === 0) { return ( { > {t('更多')}{' '} {filteredModels.length - MODELS_DISPLAY_COUNT}{' '} - {t('个模型')} + {t('个模?)} )} diff --git a/web/classic/src/components/settings/personal/cards/NotificationSettings.jsx b/web/classic/src/components/settings/personal/cards/NotificationSettings.jsx index 5e8d4fd82..a5d7f5d2e 100644 --- a/web/classic/src/components/settings/personal/cards/NotificationSettings.jsx +++ b/web/classic/src/components/settings/personal/cards/NotificationSettings.jsx @@ -1,5 +1,5 @@ /* -Copyright (C) 2025 QuantumNous +Copyright (C) 2025 modelstoken This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as @@ -14,7 +14,7 @@ GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . -For commercial licensing, please contact support@quantumnous.com +For commercial licensing, please contact admin@modelstoken.com */ import React, { useRef, useEffect, useState, useContext } from 'react'; @@ -60,8 +60,7 @@ const NotificationSettings = ({ const [userState] = useContext(UserContext); const isAdminOrRoot = (userState?.user?.role || 0) >= 10; - // 左侧边栏设置相关状态 - const [sidebarLoading, setSidebarLoading] = useState(false); + // 左侧边栏设置相关状? const [sidebarLoading, setSidebarLoading] = useState(false); const [activeTabKey, setActiveTabKey] = useState('notification'); const [sidebarModulesUser, setSidebarModulesUser] = useState({ chat: { @@ -141,10 +140,9 @@ const NotificationSettings = ({ sidebar_modules: JSON.stringify(sidebarModulesUser), }); if (res.data.success) { - showSuccess(t('侧边栏设置保存成功')); + showSuccess(t('侧边栏设置保存成?)); - // 刷新useSidebar钩子中的用户配置,实现实时更新 - await refreshUserConfig(); + // 刷新useSidebar钩子中的用户配置,实现实时更? await refreshUserConfig(); } else { showError(res.data.message); } @@ -217,8 +215,7 @@ const NotificationSettings = ({ loadSidebarConfigs(); }, [statusState]); - // 初始化表单值 - useEffect(() => { + // 初始化表单? useEffect(() => { if (formApiRef.current && notificationSettings) { formApiRef.current.setValues(notificationSettings); } @@ -229,8 +226,7 @@ const NotificationSettings = ({ handleNotificationSettingChange(field, value); }; - // 检查功能是否被管理员允许 - const isAllowedByAdmin = (sectionKey, moduleKey = null) => { + // 检查功能是否被管理员允? const isAllowedByAdmin = (sectionKey, moduleKey = null) => { if (!adminConfig) return true; if (moduleKey) { @@ -251,7 +247,7 @@ const NotificationSettings = ({ modules: [ { key: 'playground', - title: t('操练场'), + title: t('操练?), description: t('AI模型测试环境'), }, { key: 'chat', title: t('聊天'), description: t('聊天会话管理') }, @@ -259,8 +255,8 @@ const NotificationSettings = ({ }, { key: 'console', - title: t('控制台区域'), - description: t('数据管理和日志查看'), + title: t('控制台区?), + description: t('数据管理和日志查?), modules: [ { key: 'detail', title: t('数据看板'), description: t('系统数据统计') }, { key: 'token', title: t('令牌管理'), description: t('API令牌管理') }, @@ -278,7 +274,7 @@ const NotificationSettings = ({ title: t('个人中心区域'), description: t('用户个人功能'), modules: [ - { key: 'topup', title: t('钱包管理'), description: t('余额充值管理') }, + { key: 'topup', title: t('钱包管理'), description: t('余额充值管?) }, { key: 'personal', title: t('个人设置'), @@ -289,7 +285,7 @@ const NotificationSettings = ({ // 管理员区域:根据后端权限控制显示 { key: 'admin', - title: t('管理员区域'), + title: t('管理员区?), description: t('系统管理功能'), modules: [ { key: 'channel', title: t('渠道管理'), description: t('API渠道配置') }, @@ -306,8 +302,8 @@ const NotificationSettings = ({ }, { key: 'redemption', - title: t('兑换码管理'), - description: t('兑换码生成管理'), + title: t('兑换码管?), + description: t('兑换码生成管?), }, { key: 'user', title: t('用户管理'), description: t('用户账户管理') }, { @@ -344,7 +340,7 @@ const NotificationSettings = ({ }) .catch((errors) => { console.log('表单验证失败:', errors); - Toast.error(t('请检查表单填写是否正确')); + Toast.error(t('请检查表单填写是否正?)); }); } else { saveNotificationSettings(); @@ -364,7 +360,7 @@ const NotificationSettings = ({ onClick={resetSidebarModules} className='!rounded-lg' > - {t('重置为默认')} + {t('重置为默?)}
content:{' '} - {t('通知内容,支持 {{value}} 变量占位符')} + {t('通知内容,支?{{value}} 变量占位?)}
values:{' '} - {t('按顺序替换content中的变量占位符')} + {t('按顺序替换content中的变量占位?)}
- timestamp: {t('Unix时间戳')} + timestamp: {t('Unix时间?)}
@@ -584,19 +580,19 @@ const NotificationSettings = ({ )} - {/* Bark推送设置 */} + {/* Bark推送设?*/} {notificationSettings.warningType === 'bark' && ( <> handleFormChange('barkUrl', val)} prefix={} extraText={t( - '支持HTTP和HTTPS,模板变量: {{title}} (通知标题), {{content}} (通知内容)', + '支持HTTP和HTTPS,模板变? {{title}} (通知标题), {{content}} (通知内容)', )} showClear rules={[ @@ -606,7 +602,7 @@ const NotificationSettings = ({ }, { pattern: /^https?:\/\/.+/, - message: t('Bark推送URL必须以http://或https://开头'), + message: t('Bark推送URL必须以http://或https://开?), }, ]} /> @@ -621,14 +617,14 @@ const NotificationSettings = ({
- • {'title'}: {t('通知标题')} + ?{'title'}: {t('通知标题')}
- • {'content'}: {t('通知内容')} + ?{'content'}: {t('通知内容')}
- {t('更多参数请参考')} + {t('更多参数请参?)} {' '} )} - {/* Gotify推送设置 */} + {/* Gotify推送设?*/} {notificationSettings.warningType === 'gotify' && ( <> handleFormChange('gotifyUrl', val)} prefix={} @@ -668,7 +664,7 @@ const NotificationSettings = ({ { pattern: /^https?:\/\/.+/, message: t( - 'Gotify服务器地址必须以http://或https://开头', + 'Gotify服务器地址必须以http://或https://开?, ), }, ]} @@ -695,14 +691,14 @@ const NotificationSettings = ({ handleFormChange('gotifyPriority', val) @@ -729,7 +725,7 @@ const NotificationSettings = ({
3. {t('填写Gotify服务器的完整URL地址')}
@@ -788,10 +784,10 @@ const NotificationSettings = ({ field='recordIpLog' label={t('记录请求与错误日志IP')} checkedText={t('开')} - uncheckedText={t('关')} + uncheckedText={t('?)} onChange={(value) => handleFormChange('recordIpLog', value)} extraText={t( - '开启后,仅"消费"和"错误"日志将记录您的客户端IP地址', + '开启后,仅"消费"?错误"日志将记录您的客户端IP地址', )} />
@@ -819,7 +815,7 @@ const NotificationSettings = ({ color: 'var(--semi-color-text-2)', }} > - {t('您可以个性化设置侧边栏的要显示功能')} + {t('您可以个性化设置侧边栏的要显示功?)}
{/* 边栏设置功能区域容器 */} @@ -832,7 +828,7 @@ const NotificationSettings = ({ > {sectionConfigs.map((section) => (
- {/* 区域标题和总开关 */} + {/* 区域标题和总开?*/}
. -For commercial licensing, please contact support@quantumnous.com +For commercial licensing, please contact admin@modelstoken.com */ import React, { useState, useEffect, useContext } from "react"; @@ -27,12 +27,12 @@ import { normalizeLanguage } from "../../../../i18n/language"; // Language options with native names const languageOptions = [ - { value: "zh-CN", label: "简体中文" }, + { value: "zh-CN", label: "简体中? }, { value: "zh-TW", label: "繁體中文" }, { value: "en", label: "English" }, { value: 'fr', label: 'Français'}, { value: 'ru', label: 'Русский'}, - { value: 'ja', label: '日本語'}, + { value: 'ja', label: '日本?}, { value: "vi", label: "Tiếng Việt" }, ]; @@ -81,7 +81,7 @@ const PreferencesSettings = ({ t }) => { }); if (res.data.success) { - showSuccess(t("语言偏好已保存")); + showSuccess(t("语言偏好已保?)); // Keep backend preference, context state, and local cache aligned. let settings = {}; if (userState?.user?.setting) { @@ -131,7 +131,7 @@ const PreferencesSettings = ({ t }) => { {t("偏好设置")}
- {t("界面语言和其他个人偏好")} + {t("界面语言和其他个人偏?)}
@@ -150,7 +150,7 @@ const PreferencesSettings = ({ t }) => { {t("语言偏好")} - {t("选择您的首选界面语言,设置将自动保存并同步到所有设备")} + {t("选择您的首选界面语言,设置将自动保存并同步到所有设?)} @@ -171,7 +171,7 @@ const PreferencesSettings = ({ t }) => {
{t( - "提示:语言偏好会同步到您登录的所有设备,并影响API返回的错误消息语言。", + "提示:语言偏好会同步到您登录的所有设备,并影响API返回的错误消息语言?, )}
diff --git a/web/classic/src/components/settings/personal/components/TwoFASetting.jsx b/web/classic/src/components/settings/personal/components/TwoFASetting.jsx index 10ee2373f..074064e28 100644 --- a/web/classic/src/components/settings/personal/components/TwoFASetting.jsx +++ b/web/classic/src/components/settings/personal/components/TwoFASetting.jsx @@ -1,5 +1,5 @@ /* -Copyright (C) 2025 QuantumNous +Copyright (C) 2025 modelstoken This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as @@ -14,7 +14,7 @@ GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . -For commercial licensing, please contact support@quantumnous.com +For commercial licensing, please contact admin@modelstoken.com */ import { API, showError, showSuccess, showWarning } from '../../../../helpers'; import { @@ -51,8 +51,7 @@ const TwoFASetting = ({ t }) => { backup_codes_remaining: 0, }); - // 模态框状态 - const [setupModalVisible, setSetupModalVisible] = useState(false); + // 模态框状? const [setupModalVisible, setSetupModalVisible] = useState(false); const [enableModalVisible, setEnableModalVisible] = useState(false); const [disableModalVisible, setDisableModalVisible] = useState(false); const [backupModalVisible, setBackupModalVisible] = useState(false); @@ -64,15 +63,14 @@ const TwoFASetting = ({ t }) => { const [confirmDisable, setConfirmDisable] = useState(false); const [currentStep, setCurrentStep] = useState(0); - // 获取2FA状态 - const fetchStatus = async () => { + // 获取2FA状? const fetchStatus = async () => { try { const res = await API.get('/api/user/2fa/status'); if (res.data.success) { setStatus(res.data.data); } } catch (error) { - showError(t('获取2FA状态失败')); + showError(t('获取2FA状态失?)); } }; @@ -80,7 +78,7 @@ const TwoFASetting = ({ t }) => { fetchStatus(); }, []); - // 初始化2FA设置 + // 初始?FA设置 const handleSetup2FA = async () => { setLoading(true); try { @@ -112,7 +110,7 @@ const TwoFASetting = ({ t }) => { code: verificationCode, }); if (res.data.success) { - showSuccess(t('两步验证启用成功!')); + showSuccess(t('两步验证启用成功?)); setEnableModalVisible(false); setSetupModalVisible(false); setVerificationCode(''); @@ -146,7 +144,7 @@ const TwoFASetting = ({ t }) => { code: verificationCode, }); if (res.data.success) { - showSuccess(t('两步验证已禁用')); + showSuccess(t('两步验证已禁?)); setDisableModalVisible(false); setVerificationCode(''); setConfirmDisable(false); @@ -161,8 +159,7 @@ const TwoFASetting = ({ t }) => { } }; - // 重新生成备用码 - const handleRegenerateBackupCodes = async () => { + // 重新生成备用? const handleRegenerateBackupCodes = async () => { if (!verificationCode) { showWarning(t('请输入验证码')); return; @@ -175,21 +172,21 @@ const TwoFASetting = ({ t }) => { }); if (res.data.success) { setBackupCodes(res.data.data.backup_codes); - showSuccess(t('备用码重新生成成功')); + showSuccess(t('备用码重新生成成?)); setVerificationCode(''); fetchStatus(); } else { showError(res.data.message); } } catch (error) { - showError(t('重新生成备用码失败')); + showError(t('重新生成备用码失?)); } finally { setLoading(false); } }; // 通用复制函数 - const copyTextToClipboard = (text, successMessage = t('已复制到剪贴板')) => { + const copyTextToClipboard = (text, successMessage = t('已复制到剪贴?)) => { navigator.clipboard .writeText(text) .then(() => { @@ -205,8 +202,7 @@ const TwoFASetting = ({ t }) => { copyTextToClipboard(codesText, t('备用码已复制到剪贴板')); }; - // 备用码展示组件 - const BackupCodesDisplay = ({ codes, title, onCopy }) => { + // 备用码展示组? const BackupCodesDisplay = ({ codes, title, onCopy }) => { return (
@@ -242,7 +238,7 @@ const TwoFASetting = ({ t }) => { onClick={onCopy} className='!rounded-lg !bg-slate-600 hover:!bg-slate-700 w-full' > - {t('复制所有代码')} + {t('复制所有代?)}
@@ -258,7 +254,7 @@ const TwoFASetting = ({ t }) => { onClick={() => setCurrentStep(currentStep - 1)} className='!rounded-lg' > - {t('上一步')} + {t('上一?)} )} {currentStep < 2 ? ( @@ -268,7 +264,7 @@ const TwoFASetting = ({ t }) => { onClick={() => setCurrentStep(currentStep + 1)} className='!rounded-lg !bg-slate-600 hover:!bg-slate-700' > - {t('下一步')} + {t('下一?)} ) : ( )} @@ -358,7 +354,7 @@ const TwoFASetting = ({ t }) => { onClick={handleRegenerateBackupCodes} className='!rounded-lg !bg-slate-600 hover:!bg-slate-700' > - {t('生成新的备用码')} + {t('生成新的备用?)} ); @@ -382,22 +378,22 @@ const TwoFASetting = ({ t }) => { {status.enabled ? ( - {t('已启用')} + {t('已启?)} ) : ( - {t('未启用')} + {t('未启?)} )} {status.locked && ( - {t('账户已锁定')} + {t('账户已锁?)} )} {t( - '两步验证(2FA)为您的账户提供额外的安全保护。启用后,登录时需要输入密码和验证器应用生成的验证码。', + '两步验证?FA)为您的账户提供额外的安全保护。启用后,登录时需要输入密码和验证器应用生成的验证码?, )} {status.enabled && ( @@ -405,7 +401,7 @@ const TwoFASetting = ({ t }) => { {t('剩余备用码:')} {status.backup_codes_remaining || 0} - {t('个')} + {t('?)} )} @@ -444,7 +440,7 @@ const TwoFASetting = ({ t }) => { className='!rounded-lg' icon={} > - {t('重新生成备用码')} + {t('重新生成备用?)} )} @@ -476,16 +472,16 @@ const TwoFASetting = ({ t }) => { {/* 步骤进度 */} @@ -495,7 +491,7 @@ const TwoFASetting = ({ t }) => {
{t( - '使用认证器应用(如 Google Authenticator、Microsoft Authenticator)扫描下方二维码:', + '使用认证器应用(?Google Authenticator、Microsoft Authenticator)扫描下方二维码?, )}
@@ -516,7 +512,7 @@ const TwoFASetting = ({ t }) => { {currentStep === 1 && (
- {/* 备用码展示 */} + {/* 备用码展?*/} { @@ -580,16 +576,16 @@ const TwoFASetting = ({ t }) => { strong className='block mb-2 text-slate-700 dark:text-slate-200' > - {t('禁用后的影响:')} + {t('禁用后的影响?)}
  • - {t('降低您账户的安全性')} + {t('降低您账户的安全?)}
  • - {t('需要重新完整设置才能再次启用')} + {t('需要重新完整设置才能再次启?)}
  • @@ -613,7 +609,7 @@ const TwoFASetting = ({ t }) => { {t('验证身份')} { title={
    - {t('重新生成备用码')} + {t('重新生成备用?)}
    } visible={backupModalVisible} @@ -663,7 +659,7 @@ const TwoFASetting = ({ t }) => { @@ -679,7 +675,7 @@ const TwoFASetting = ({ t }) => { {t('验证身份')} {
- {t('旧的备用码已失效,请保存新的备用码')} + {t('旧的备用码已失效,请保存新的备用?)} - {/* 备用码展示 */} + {/* 备用码展?*/} . -For commercial licensing, please contact support@quantumnous.com +For commercial licensing, please contact admin@modelstoken.com */ import React from 'react'; @@ -86,7 +86,7 @@ const UserInfoHeader = ({ t, userState }) => { shape='circle' style={{ color: 'white' }} > - {t('超级管理员')} + {t('超级管理?)} ) : isAdmin() ? ( { shape='circle' style={{ color: 'white' }} > - {t('管理员')} + {t('管理?)} ) : ( { shape='circle' style={{ color: 'white' }} > - {t('普通用户')} + {t('普通用?)} )} @@ -125,7 +125,7 @@ const UserInfoHeader = ({ t, userState }) => {
- {/* 桌面版统计信息(Semi UI 卡片) */} + {/* 桌面版统计信息(Semi UI 卡片?*/}
{
- {t('历史消耗')} + {t('历史消?)} {renderQuota(userState?.user?.used_quota)} @@ -179,7 +179,7 @@ const UserInfoHeader = ({ t, userState }) => {
- {t('历史消耗')} + {t('历史消?)}
diff --git a/web/classic/src/components/settings/personal/modals/AccountDeleteModal.jsx b/web/classic/src/components/settings/personal/modals/AccountDeleteModal.jsx index b2bc40f69..290c4841c 100644 --- a/web/classic/src/components/settings/personal/modals/AccountDeleteModal.jsx +++ b/web/classic/src/components/settings/personal/modals/AccountDeleteModal.jsx @@ -1,5 +1,5 @@ /* -Copyright (C) 2025 QuantumNous +Copyright (C) 2025 modelstoken This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as @@ -14,7 +14,7 @@ GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . -For commercial licensing, please contact support@quantumnous.com +For commercial licensing, please contact admin@modelstoken.com */ import React from 'react'; @@ -59,10 +59,10 @@ const AccountDeleteModal = ({
- {t('请输入您的用户名以确认删除')} + {t('请输入您的用户名以确认删?)} . -For commercial licensing, please contact support@quantumnous.com +For commercial licensing, please contact admin@modelstoken.com */ import React from 'react'; @@ -51,7 +51,7 @@ const ChangePasswordModal = ({
- {t('原密码')} + {t('原密?)} - {t('新密码')} + {t('新密?)} - {t('确认新密码')} + {t('确认新密?)} . -For commercial licensing, please contact support@quantumnous.com +For commercial licensing, please contact admin@modelstoken.com */ import React from 'react'; @@ -73,13 +73,13 @@ const EmailBindModal = ({ size='large' > {disableButton - ? `${t('重新发送')} (${countdown})` - : t('获取验证码')} + ? `${t('重新发?)} (${countdown})` + : t('获取验证?)}
diff --git a/web/classic/src/components/settings/personal/modals/WeChatBindModal.jsx b/web/classic/src/components/settings/personal/modals/WeChatBindModal.jsx index 1bdb5df41..72fd18e71 100644 --- a/web/classic/src/components/settings/personal/modals/WeChatBindModal.jsx +++ b/web/classic/src/components/settings/personal/modals/WeChatBindModal.jsx @@ -1,5 +1,5 @@ /* -Copyright (C) 2025 QuantumNous +Copyright (C) 2025 modelstoken This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as @@ -14,7 +14,7 @@ GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . -For commercial licensing, please contact support@quantumnous.com +For commercial licensing, please contact admin@modelstoken.com */ import React from 'react'; @@ -54,7 +54,7 @@ const WeChatBindModal = ({

handleInputChange('wechat_verification_code', v)} diff --git a/web/classic/src/components/setup/SetupWizard.jsx b/web/classic/src/components/setup/SetupWizard.jsx index 0d500fdd8..65a92bc16 100644 --- a/web/classic/src/components/setup/SetupWizard.jsx +++ b/web/classic/src/components/setup/SetupWizard.jsx @@ -1,5 +1,5 @@ /* -Copyright (C) 2025 QuantumNous +Copyright (C) 2025 modelstoken This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as @@ -14,7 +14,7 @@ GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . -For commercial licensing, please contact support@quantumnous.com +For commercial licensing, please contact admin@modelstoken.com */ import React, { useEffect, useState, useRef } from 'react'; @@ -56,19 +56,19 @@ const SetupWizard = () => { // 定义步骤内容 const steps = [ { - title: t('数据库检查'), - description: t('验证数据库连接状态'), + title: t('数据库检?), + description: t('验证数据库连接状?), }, { - title: t('管理员账号'), - description: t('设置管理员登录信息'), + title: t('管理员账?), + description: t('设置管理员登录信?), }, { title: t('使用模式'), description: t('选择系统运行模式'), }, { - title: t('完成初始化'), + title: t('完成初始?), description: t('确认设置并完成初始化'), }, ]; @@ -90,14 +90,13 @@ const SetupWizard = () => { return; } - // 设置当前步骤 - 默认从数据库检查开始 - setCurrentStep(0); + // 设置当前步骤 - 默认从数据库检查开? setCurrentStep(0); } else { - showError(t('获取初始化状态失败')); + showError(t('获取初始化状态失?)); } } catch (error) { console.error('Failed to fetch setup status:', error); - showError(t('获取初始化状态失败')); + showError(t('获取初始化状态失?)); } }; @@ -120,30 +119,26 @@ const SetupWizard = () => { setCurrentStep(current); }; - // 验证是否可以继续到下一步 - const canProceedToNext = () => { + // 验证是否可以继续到下一? const canProceedToNext = () => { switch (currentStep) { - case 0: // 数据库检查步骤 - return true; // 数据库检查总是可以继续 - case 1: // 管理员账号步骤 - if (setupStatus.root_init) { + case 0: // 数据库检查步? return true; // 数据库检查总是可以继续 + case 1: // 管理员账号步? if (setupStatus.root_init) { return true; // 如果已经初始化,可以继续 } - // 检查必填字段 - if ( + // 检查必填字? if ( !formData.username || !formData.password || !formData.confirmPassword ) { - showError(t('请填写完整的管理员账号信息')); + showError(t('请填写完整的管理员账号信?)); return false; } if (formData.password !== formData.confirmPassword) { - showError(t('两次输入的密码不一致')); + showError(t('两次输入的密码不一?)); return false; } if (formData.password.length < 8) { - showError(t('密码长度至少为8个字符')); + showError(t('密码长度至少?个字?)); return false; } return true; @@ -175,17 +170,17 @@ const SetupWizard = () => { // For root_init=false, validate admin username and password if (!setupStatus.root_init) { if (!values.username || !values.username.trim()) { - showError(t('请输入管理员用户名')); + showError(t('请输入管理员用户?)); return; } if (!values.password || values.password.length < 8) { - showError(t('密码长度至少为8个字符')); + showError(t('密码长度至少?个字?)); return; } if (values.password !== values.confirmPassword) { - showError(t('两次输入的密码不一致')); + showError(t('两次输入的密码不一?)); return; } } @@ -199,8 +194,7 @@ const SetupWizard = () => { // Remove usageMode as it's not needed by the backend delete formValues.usageMode; - // 提交表单至后端 - setLoading(true); + // 提交表单至后? setLoading(true); // Submit to backend API.post('/api/setup', formValues) @@ -213,12 +207,12 @@ const SetupWizard = () => { window.location.reload(); }, 1500); } else { - showError(message || t('初始化失败,请重试')); + showError(message || t('初始化失败,请重?)); } }) .catch((error) => { console.error('API error:', error); - showError(t('系统初始化失败,请重试')); + showError(t('系统初始化失败,请重?)); setLoading(false); }) .finally(() => { @@ -273,9 +267,9 @@ const SetupWizard = () => {
-
{t('系统初始化')}
+
{t('系统初始?)}
- {t('欢迎使用,请完成以下设置以开始使用系统')} + {t('欢迎使用,请完成以下设置以开始使用系?)}
diff --git a/web/classic/src/components/setup/components/StepNavigation.jsx b/web/classic/src/components/setup/components/StepNavigation.jsx index 0877a9754..790a3da57 100644 --- a/web/classic/src/components/setup/components/StepNavigation.jsx +++ b/web/classic/src/components/setup/components/StepNavigation.jsx @@ -1,5 +1,5 @@ /* -Copyright (C) 2025 QuantumNous +Copyright (C) 2025 modelstoken This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as @@ -14,7 +14,7 @@ GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . -For commercial licensing, please contact support@quantumnous.com +For commercial licensing, please contact admin@modelstoken.com */ import React from 'react'; @@ -36,19 +36,19 @@ const StepNavigation = ({ }) => { return (
- {/* 上一步按钮 */} + {/* 上一步按?*/} {currentStep > 0 && ( )}
- {/* 下一步按钮 */} + {/* 下一步按?*/} {currentStep < steps.length - 1 && ( )} @@ -61,7 +61,7 @@ const StepNavigation = ({ className='!rounded-lg' icon={} > - {t('初始化系统')} + {t('初始化系?)} )}
diff --git a/web/classic/src/components/setup/components/steps/AdminStep.jsx b/web/classic/src/components/setup/components/steps/AdminStep.jsx index 662196cfe..c8a744b02 100644 --- a/web/classic/src/components/setup/components/steps/AdminStep.jsx +++ b/web/classic/src/components/setup/components/steps/AdminStep.jsx @@ -1,5 +1,5 @@ /* -Copyright (C) 2025 QuantumNous +Copyright (C) 2025 modelstoken This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as @@ -14,7 +14,7 @@ GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . -For commercial licensing, please contact support@quantumnous.com +For commercial licensing, please contact admin@modelstoken.com */ import React from 'react'; @@ -22,8 +22,7 @@ import { Banner, Form } from '@douyinfe/semi-ui'; import { IconUser, IconLock } from '@douyinfe/semi-icons'; /** - * 管理员账号设置步骤组件 - * 提供管理员用户名和密码的设置界面 + * 管理员账号设置步骤组? * 提供管理员用户名和密码的设置界面 */ const AdminStep = ({ setupStatus, @@ -41,7 +40,7 @@ const AdminStep = ({ closeIcon={null} description={
- {t('管理员账号已经初始化过,请继续设置其他参数')} + {t('管理员账号已经初始化过,请继续设置其他参?)}
} className='!rounded-lg' @@ -50,13 +49,13 @@ const AdminStep = ({ <> } showClear noLabel={false} validateStatus='default' - rules={[{ required: true, message: t('请输入管理员用户名') }]} + rules={[{ required: true, message: t('请输入管理员用户?) }]} initValue={formData.username || ''} onChange={(value) => { setFormData({ ...formData, username: value }); @@ -74,7 +73,7 @@ const AdminStep = ({ validateStatus='default' rules={[ { required: true, message: t('请输入管理员密码') }, - { min: 8, message: t('密码长度至少为8个字符') }, + { min: 8, message: t('密码长度至少?个字?) }, ]} initValue={formData.password || ''} onChange={(value) => { @@ -98,7 +97,7 @@ const AdminStep = ({ if (value && formRef.current) { const password = formRef.current.getValue('password'); if (value !== password) { - return Promise.reject(t('两次输入的密码不一致')); + return Promise.reject(t('两次输入的密码不一?)); } } return Promise.resolve(); diff --git a/web/classic/src/components/setup/components/steps/CompleteStep.jsx b/web/classic/src/components/setup/components/steps/CompleteStep.jsx index 5f3265ac8..0d431fe50 100644 --- a/web/classic/src/components/setup/components/steps/CompleteStep.jsx +++ b/web/classic/src/components/setup/components/steps/CompleteStep.jsx @@ -1,5 +1,5 @@ /* -Copyright (C) 2025 QuantumNous +Copyright (C) 2025 modelstoken This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as @@ -14,7 +14,7 @@ GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . -For commercial licensing, please contact support@quantumnous.com +For commercial licensing, please contact admin@modelstoken.com */ import React from 'react'; @@ -39,24 +39,24 @@ const CompleteStep = ({ - {t('准备完成初始化')} + {t('准备完成初始?)} - {t('请确认以下设置信息,点击"初始化系统"开始配置')} + {t('请确认以下设置信息,点击"初始化系?开始配?)} - + {setupStatus.database_type === 'sqlite' ? 'SQLite' : setupStatus.database_type === 'mysql' ? 'MySQL' : 'PostgreSQL'} - + {setupStatus.root_init ? t('已初始化') - : formData.username || t('未设置')} + : formData.username || t('未设?)} {formData.usageMode === 'external' diff --git a/web/classic/src/components/setup/components/steps/DatabaseStep.jsx b/web/classic/src/components/setup/components/steps/DatabaseStep.jsx index d8d1d4f9f..5ba2d3bfb 100644 --- a/web/classic/src/components/setup/components/steps/DatabaseStep.jsx +++ b/web/classic/src/components/setup/components/steps/DatabaseStep.jsx @@ -1,5 +1,5 @@ /* -Copyright (C) 2025 QuantumNous +Copyright (C) 2025 modelstoken This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as @@ -14,40 +14,38 @@ GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . -For commercial licensing, please contact support@quantumnous.com +For commercial licensing, please contact admin@modelstoken.com */ import React from 'react'; import { Banner } from '@douyinfe/semi-ui'; /** - * 数据库检查步骤组件 - * 显示当前数据库类型和相关警告信息 + * 数据库检查步骤组? * 显示当前数据库类型和相关警告信息 */ const DatabaseStep = ({ setupStatus, renderNavigationButtons, t }) => { - // 检测是否在 Electron 环境中运行 - const isElectron = + // 检测是否在 Electron 环境中运? const isElectron = typeof window !== 'undefined' && window.electron?.isElectron; return ( <> - {/* 数据库警告 */} + {/* 数据库警?*/} {setupStatus.database_type === 'sqlite' && (

{t( - '您的数据将安全地存储在本地计算机上。所有配置、用户信息和使用记录都会自动保存,关闭应用后不会丢失。', + '您的数据将安全地存储在本地计算机上。所有配置、用户信息和使用记录都会自动保存,关闭应用后不会丢失?, )}

{window.electron?.dataDir && (

- {t('数据存储位置:')} + {t('数据存储位置?)}
{window.electron.dataDir} @@ -62,13 +60,13 @@ const DatabaseStep = ({ setupStatus, renderNavigationButtons, t }) => {

{t( - '您正在使用 SQLite 数据库。如果您在容器环境中运行,请确保已正确设置数据库文件的持久化映射,否则容器重启后所有数据将丢失!', + '您正在使?SQLite 数据库。如果您在容器环境中运行,请确保已正确设置数据库文件的持久化映射,否则容器重启后所有数据将丢失?, )}

{t( - '建议在生产环境中使用 MySQL 或 PostgreSQL 数据库,或确保 SQLite 数据库文件已映射到宿主机的持久化存储。', + '建议在生产环境中使用 MySQL ?PostgreSQL 数据库,或确?SQLite 数据库文件已映射到宿主机的持久化存储?, )}

@@ -81,17 +79,17 @@ const DatabaseStep = ({ setupStatus, renderNavigationButtons, t }) => { /> )} - {/* MySQL数据库提示 */} + {/* MySQL数据库提?*/} {setupStatus.database_type === 'mysql' && (

{t( - '您正在使用 MySQL 数据库。MySQL 是一个可靠的关系型数据库管理系统,适合生产环境使用。', + '您正在使?MySQL 数据库。MySQL 是一个可靠的关系型数据库管理系统,适合生产环境使用?, )}

@@ -102,17 +100,17 @@ const DatabaseStep = ({ setupStatus, renderNavigationButtons, t }) => { /> )} - {/* PostgreSQL数据库提示 */} + {/* PostgreSQL数据库提?*/} {setupStatus.database_type === 'postgres' && (

{t( - '您正在使用 PostgreSQL 数据库。PostgreSQL 是一个功能强大的开源关系型数据库系统,提供了出色的可靠性和数据完整性,适合生产环境使用。', + '您正在使?PostgreSQL 数据库。PostgreSQL 是一个功能强大的开源关系型数据库系统,提供了出色的可靠性和数据完整性,适合生产环境使用?, )}

diff --git a/web/classic/src/components/setup/components/steps/UsageModeStep.jsx b/web/classic/src/components/setup/components/steps/UsageModeStep.jsx index 19364430f..7cbbd1ab3 100644 --- a/web/classic/src/components/setup/components/steps/UsageModeStep.jsx +++ b/web/classic/src/components/setup/components/steps/UsageModeStep.jsx @@ -1,5 +1,5 @@ /* -Copyright (C) 2025 QuantumNous +Copyright (C) 2025 modelstoken This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as @@ -14,7 +14,7 @@ GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . -For commercial licensing, please contact support@quantumnous.com +For commercial licensing, please contact admin@modelstoken.com */ import React from 'react'; @@ -43,14 +43,14 @@ const UsageModeStep = ({ > {t('对外运营模式')} {t('自用模式')} diff --git a/web/classic/src/components/setup/index.jsx b/web/classic/src/components/setup/index.jsx index 7ce1247f2..8c6bbf2f5 100644 --- a/web/classic/src/components/setup/index.jsx +++ b/web/classic/src/components/setup/index.jsx @@ -1,5 +1,5 @@ /* -Copyright (C) 2025 QuantumNous +Copyright (C) 2025 modelstoken This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as @@ -14,7 +14,7 @@ GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . -For commercial licensing, please contact support@quantumnous.com +For commercial licensing, please contact admin@modelstoken.com */ // 主要组件导出 diff --git a/web/classic/src/components/table/channels/ChannelsActions.jsx b/web/classic/src/components/table/channels/ChannelsActions.jsx index 3f185c55d..8c7b2de09 100644 --- a/web/classic/src/components/table/channels/ChannelsActions.jsx +++ b/web/classic/src/components/table/channels/ChannelsActions.jsx @@ -1,5 +1,5 @@ /* -Copyright (C) 2025 QuantumNous +Copyright (C) 2025 modelstoken This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as @@ -14,7 +14,7 @@ GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . -For commercial licensing, please contact support@quantumnous.com +For commercial licensing, please contact admin@modelstoken.com */ import React from 'react'; @@ -60,9 +60,9 @@ const ChannelsActions = ({ }) => { return (
- {/* 第一行:批量操作按钮 + 设置开关 */} + {/* 第一行:批量操作按钮 + 设置开?*/}
- {/* 左侧:批量操作按钮 */} + {/* 左侧:批量操作按?*/}
@@ -141,7 +141,7 @@ const ChannelsActions = ({ className='w-full' onClick={() => { Modal.confirm({ - title: t('确定?'), + title: t('确定?), content: t('确定要更新所有已启用通道余额吗?'), onOk: () => updateAllChannelsBalance(), size: 'sm', @@ -159,9 +159,9 @@ const ChannelsActions = ({ className='w-full' onClick={() => { Modal.confirm({ - title: t('确定?'), + title: t('确定?), content: t( - '确定要仅检测全部渠道上游模型更新吗?(不执行新增/删除)', + '确定要仅检测全部渠道上游模型更新吗?(不执行新?删除?, ), onOk: () => detectAllUpstreamUpdates(), size: 'sm', @@ -169,7 +169,7 @@ const ChannelsActions = ({ }); }} > - {t('检测全部渠道上游更新')} + {t('检测全部渠道上游更?)} @@ -181,7 +181,7 @@ const ChannelsActions = ({ disabled={applyAllUpstreamUpdatesLoading} onClick={() => { Modal.confirm({ - title: t('确定?'), + title: t('确定?), content: t('确定要对全部渠道执行上游模型更新吗?'), onOk: () => applyAllUpstreamUpdates(), size: 'sm', @@ -199,8 +199,8 @@ const ChannelsActions = ({ className='w-full' onClick={() => { Modal.confirm({ - title: t('确定是否要删除禁用通道?'), - content: t('此修改将不可逆'), + title: t('确定是否要删除禁用通道?), + content: t('此修改将不可?), onOk: () => deleteAllDisabledChannels(), size: 'sm', centered: true, @@ -230,7 +230,7 @@ const ChannelsActions = ({ />
- {/* 右侧:设置开关区域 */} + {/* 右侧:设置开关区?*/}
@@ -266,7 +266,7 @@ const ChannelsActions = ({
- {t('开启批量操作')} + {t('开启批量操?)} - {t('状态筛选')} + {t('状态筛?)}
diff --git a/web/classic/src/components/table/channels/ChannelsColumnDefs.jsx b/web/classic/src/components/table/channels/ChannelsColumnDefs.jsx index 5d748c0f5..c6c9e5a6c 100644 --- a/web/classic/src/components/table/channels/ChannelsColumnDefs.jsx +++ b/web/classic/src/components/table/channels/ChannelsColumnDefs.jsx @@ -1,5 +1,5 @@ /* -Copyright (C) 2025 QuantumNous +Copyright (C) 2025 modelstoken This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as @@ -14,7 +14,7 @@ GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . -For commercial licensing, please contact support@quantumnous.com +For commercial licensing, please contact admin@modelstoken.com */ import React from 'react'; @@ -115,7 +115,7 @@ const renderType = (type, record = {}, t) => { content={
- {t('来源于 IO.NET 部署')} + {t('来源?IO.NET 部署')}
{ionetMeta?.deployment_id && (
@@ -164,13 +164,13 @@ const renderStatus = (status, channelInfo = undefined, t) => { case 1: return ( - {t('已启用')} + {t('已启?)} ); case 2: return ( - {t('已禁用')} + {t('已禁?)} ); case 3: @@ -182,7 +182,7 @@ const renderStatus = (status, channelInfo = undefined, t) => { default: return ( - {t('未知状态')} + {t('未知状?)} ); } @@ -193,13 +193,13 @@ const renderMultiKeyStatus = (status, keySize, enabledKeySize, t) => { case 1: return ( - {t('已启用')} {enabledKeySize}/{keySize} + {t('已启?)} {enabledKeySize}/{keySize} ); case 2: return ( - {t('已禁用')} {enabledKeySize}/{keySize} + {t('已禁?)} {enabledKeySize}/{keySize} ); case 3: @@ -211,7 +211,7 @@ const renderMultiKeyStatus = (status, keySize, enabledKeySize, t) => { default: return ( - {t('未知状态')} {enabledKeySize}/{keySize} + {t('未知状?)} {enabledKeySize}/{keySize} ); } @@ -219,11 +219,11 @@ const renderMultiKeyStatus = (status, keySize, enabledKeySize, t) => { const renderResponseTime = (responseTime, t) => { let time = responseTime / 1000; - time = time.toFixed(2) + t(' 秒'); + time = time.toFixed(2) + t(' ?); if (responseTime === 0) { return ( - {t('未测试')} + {t('未测?)} ); } else if (responseTime <= 1000) { @@ -393,7 +393,7 @@ export const getChannelsColumns = ({ {passThroughEnabled && ( { if (text === 3) { @@ -504,7 +504,7 @@ export const getChannelsColumns = ({
{renderStatus(text, record.channel_info, t)} @@ -539,11 +539,11 @@ export const getChannelsColumns = ({ { if (record.children === undefined) { @@ -657,9 +657,9 @@ export const getChannelsColumns = ({ keepFocus={true} onBlur={(e) => { Modal.warning({ - title: t('修改子渠道权重'), + title: t('修改子渠道权?), content: - t('确定要修改所有子渠道权重为 ') + + t('确定要修改所有子渠道权重?') + e.target.value + t(' 吗?'), onOk: () => { @@ -697,8 +697,8 @@ export const getChannelsColumns = ({ type: 'danger', onClick: () => { Modal.confirm({ - title: t('确定是否要删除此渠道?'), - content: t('此修改将不可逆'), + title: t('确定是否要删除此渠道?), + content: t('此修改将不可?), onOk: () => { (async () => { await manageChannel(record.id, 'delete', record); @@ -719,8 +719,8 @@ export const getChannelsColumns = ({ type: 'tertiary', onClick: () => { Modal.confirm({ - title: t('确定是否要复制此渠道?'), - content: t('复制渠道的所有信息'), + title: t('确定是否要复制此渠道?), + content: t('复制渠道的所有信?), onOk: () => copySelectedChannel(record), }); }, @@ -730,7 +730,7 @@ export const getChannelsColumns = ({ if (upstreamUpdateMeta.supported) { moreMenuItems.push({ node: 'item', - name: t('仅检测上游模型更新'), + name: t('仅检测上游模型更?), type: 'tertiary', onClick: () => { detectChannelUpstreamUpdates(record); @@ -742,14 +742,14 @@ export const getChannelsColumns = ({ type: 'tertiary', onClick: () => { if (!upstreamUpdateMeta.enabled) { - showInfo(t('该渠道未开启上游模型更新检测')); + showInfo(t('该渠道未开启上游模型更新检?)); return; } if ( upstreamUpdateMeta.pendingAddModels.length === 0 && upstreamUpdateMeta.pendingRemoveModels.length === 0 ) { - showInfo(t('该渠道暂无可处理的上游模型更新')); + showInfo(t('该渠道暂无可处理的上游模型更?)); return; } openUpstreamUpdateModal( @@ -777,7 +777,7 @@ export const getChannelsColumns = ({
@@ -100,7 +100,7 @@ const ChannelsFilters = ({ size='small' field='searchModel' prefix={} - placeholder={t('模型关键字')} + placeholder={t('模型关键?)} showClear pure /> diff --git a/web/classic/src/components/table/channels/ChannelsTable.jsx b/web/classic/src/components/table/channels/ChannelsTable.jsx index 09b486e32..020acd578 100644 --- a/web/classic/src/components/table/channels/ChannelsTable.jsx +++ b/web/classic/src/components/table/channels/ChannelsTable.jsx @@ -1,5 +1,5 @@ /* -Copyright (C) 2025 QuantumNous +Copyright (C) 2025 modelstoken This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as @@ -14,7 +14,7 @@ GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . -For commercial licensing, please contact support@quantumnous.com +For commercial licensing, please contact admin@modelstoken.com */ import React, { useMemo } from 'react'; @@ -163,7 +163,7 @@ const ChannelsTable = (channelsData) => { darkModeImage={ } - description={t('搜索无结果')} + description={t('搜索无结?)} style={{ padding: 30 }} /> } diff --git a/web/classic/src/components/table/channels/ChannelsTabs.jsx b/web/classic/src/components/table/channels/ChannelsTabs.jsx index f95d138a4..3989169ec 100644 --- a/web/classic/src/components/table/channels/ChannelsTabs.jsx +++ b/web/classic/src/components/table/channels/ChannelsTabs.jsx @@ -1,5 +1,5 @@ /* -Copyright (C) 2025 QuantumNous +Copyright (C) 2025 modelstoken This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as @@ -14,7 +14,7 @@ GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . -For commercial licensing, please contact support@quantumnous.com +For commercial licensing, please contact admin@modelstoken.com */ import React from 'react'; diff --git a/web/classic/src/components/table/channels/index.jsx b/web/classic/src/components/table/channels/index.jsx index 4a22233ce..69eace1ca 100644 --- a/web/classic/src/components/table/channels/index.jsx +++ b/web/classic/src/components/table/channels/index.jsx @@ -1,5 +1,5 @@ /* -Copyright (C) 2025 QuantumNous +Copyright (C) 2025 modelstoken This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as @@ -14,7 +14,7 @@ GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . -For commercial licensing, please contact support@quantumnous.com +For commercial licensing, please contact admin@modelstoken.com */ import React from 'react'; @@ -86,7 +86,7 @@ const ChannelsPage = () => { /> } description={channelsData.t( - '已开启全局请求透传:参数覆写、模型重定向、渠道适配等 NewAPI 内置功能将失效,非最佳实践;如因此产生问题,请勿提交 issue 反馈。', + '已开启全局请求透传:参数覆写、模型重定向、渠道适配?NewAPI 内置功能将失效,非最佳实践;如因此产生问题,请勿提交 issue 反馈?, )} style={{ marginBottom: 12 }} /> diff --git a/web/classic/src/components/table/channels/modals/BatchTagModal.jsx b/web/classic/src/components/table/channels/modals/BatchTagModal.jsx index 16bb64b08..8b74f6c0f 100644 --- a/web/classic/src/components/table/channels/modals/BatchTagModal.jsx +++ b/web/classic/src/components/table/channels/modals/BatchTagModal.jsx @@ -1,5 +1,5 @@ /* -Copyright (C) 2025 QuantumNous +Copyright (C) 2025 modelstoken This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as @@ -14,7 +14,7 @@ GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . -For commercial licensing, please contact support@quantumnous.com +For commercial licensing, please contact admin@modelstoken.com */ import React from 'react'; @@ -41,16 +41,16 @@ const BatchTagModal = ({ className='!rounded-lg' >
- {t('请输入要设置的标签名称')} + {t('请输入要设置的标签名?)}
setBatchSetTagValue(v)} />
- {t('已选择 ${count} 个渠道').replace( + {t('已选择 ${count} 个渠?).replace( '${count}', selectedChannels.length, )} diff --git a/web/classic/src/components/table/channels/modals/ChannelUpstreamUpdateModal.jsx b/web/classic/src/components/table/channels/modals/ChannelUpstreamUpdateModal.jsx index 71f2ab8eb..032e2df2b 100644 --- a/web/classic/src/components/table/channels/modals/ChannelUpstreamUpdateModal.jsx +++ b/web/classic/src/components/table/channels/modals/ChannelUpstreamUpdateModal.jsx @@ -1,5 +1,5 @@ /* -Copyright (C) 2025 QuantumNous +Copyright (C) 2025 modelstoken This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as @@ -14,7 +14,7 @@ GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . -For commercial licensing, please contact support@quantumnous.com +For commercial licensing, please contact admin@modelstoken.com */ import React, { useEffect, useMemo, useState } from 'react'; @@ -192,7 +192,7 @@ const ChannelUpstreamUpdateModal = ({ count: missingCount, }, ), - okText: t('仅提交已勾选'), + okText: t('仅提交已勾?), cancelText: t('去处理{{type}}', { type: missingType }), centered: true, onOk: () => { @@ -223,7 +223,7 @@ const ChannelUpstreamUpdateModal = ({
{t( - '可勾选需要执行的变更:新增会加入渠道模型列表,删除会从渠道模型列表移除。', + '可勾选需要执行的变更:新增会加入渠道模型列表,删除会从渠道模型列表移除?, )} @@ -236,13 +236,13 @@ const ChannelUpstreamUpdateModal = ({ />
- {t('新增已选 {{selected}} / {{total}}', { + {t('新增已?{{selected}} / {{total}}', { selected: selectedAddCount, total: normalizedAddModels.length, })} - {t('删除已选 {{selected}} / {{total}}', { + {t('删除已?{{selected}} / {{total}}', { selected: selectedRemoveCount, total: normalizedRemoveModels.length, })} @@ -301,7 +301,7 @@ const ChannelUpstreamUpdateModal = ({ handleToggleAllCurrent(e.target.checked)} />
diff --git a/web/classic/src/components/table/channels/modals/CodexOAuthModal.jsx b/web/classic/src/components/table/channels/modals/CodexOAuthModal.jsx index 7f3f349b2..337764d4f 100644 --- a/web/classic/src/components/table/channels/modals/CodexOAuthModal.jsx +++ b/web/classic/src/components/table/channels/modals/CodexOAuthModal.jsx @@ -1,5 +1,5 @@ /* -Copyright (C) 2025 QuantumNous +Copyright (C) 2025 modelstoken This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as @@ -14,7 +14,7 @@ GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . -For commercial licensing, please contact support@quantumnous.com +For commercial licensing, please contact admin@modelstoken.com */ import React, { useEffect, useState } from 'react'; @@ -92,7 +92,7 @@ const CodexOAuthModal = ({ visible, onCancel, onSuccess }) => { } onSuccess && onSuccess(key); - showSuccess(t('已生成授权凭据')); + showSuccess(t('已生成授权凭?)); onCancel && onCancel(); } catch (error) { showError(error?.message || t('授权失败')); @@ -126,7 +126,7 @@ const CodexOAuthModal = ({ visible, onCancel, onSuccess }) => { onClick={completeOAuth} loading={loading} > - {t('生成并填入')} + {t('生成并填?)} } @@ -135,7 +135,7 @@ const CodexOAuthModal = ({ visible, onCancel, onSuccess }) => { @@ -155,13 +155,13 @@ const CodexOAuthModal = ({ visible, onCancel, onSuccess }) => { setInput(value)} - placeholder={t('请粘贴完整回调 URL(包含 code 与 state)')} + placeholder={t('请粘贴完整回?URL(包?code ?state?)} showClear /> {t( - '说明:生成结果是可直接粘贴到渠道密钥里的 JSON(包含 access_token / refresh_token / account_id)。', + '说明:生成结果是可直接粘贴到渠道密钥里的 JSON(包?access_token / refresh_token / account_id)?, )} diff --git a/web/classic/src/components/table/channels/modals/CodexUsageModal.jsx b/web/classic/src/components/table/channels/modals/CodexUsageModal.jsx index 3b5ad0359..b4a06a13e 100644 --- a/web/classic/src/components/table/channels/modals/CodexUsageModal.jsx +++ b/web/classic/src/components/table/channels/modals/CodexUsageModal.jsx @@ -1,5 +1,5 @@ /* -Copyright (C) 2025 QuantumNous +Copyright (C) 2025 modelstoken This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as @@ -14,7 +14,7 @@ GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . -For commercial licensing, please contact support@quantumnous.com +For commercial licensing, please contact admin@modelstoken.com */ import React, { useCallback, useEffect, useRef, useState } from 'react'; @@ -119,8 +119,8 @@ const formatDurationSeconds = (seconds, t) => { const minutes = Math.floor((total % 3600) / 60); const secs = total % 60; if (hours > 0) return `${hours}${tt('小时')} ${minutes}${tt('分钟')}`; - if (minutes > 0) return `${minutes}${tt('分钟')} ${secs}${tt('秒')}`; - return `${secs}${tt('秒')}`; + if (minutes > 0) return `${minutes}${tt('分钟')} ${secs}${tt('?)}`; + return `${secs}${tt('?)}`; }; const formatUnixSeconds = (unixSeconds) => { @@ -187,7 +187,7 @@ const formatAccountTypeLabel = (value, t) => { case 'enterprise': return 'Enterprise'; default: - return getDisplayText(value) || tt('未识别'); + return getDisplayText(value) || tt('未识?); } }; @@ -212,7 +212,7 @@ const getAccountTypeTagColor = (value) => { const resolveUsageStatusTag = (t, rateLimit) => { const tt = typeof t === 'function' ? t : (v) => v; if (!rateLimit || Object.keys(rateLimit).length === 0) { - return {tt('待确认')}; + return {tt('待确?)}; } if (rateLimit?.allowed && !rateLimit?.limit_reached) { return {tt('可用')}; @@ -264,7 +264,7 @@ const RateLimitWindowCard = ({ t, title, windowData }) => {
{title}
- {tt('重置时间:')} + {tt('重置时间?)} {formatUnixSeconds(resetAt)}
@@ -287,11 +287,11 @@ const RateLimitWindowCard = ({ t, title, windowData }) => { {hasWindowData ? `${percent}%` : '-'}
- {tt('距离重置:')} + {tt('距离重置?)} {hasWindowData ? formatDurationSeconds(resetAfterSeconds, tt) : '-'}
- {tt('窗口:')} + {tt('窗口?)} {hasWindowData ? formatDurationSeconds(limitWindowSeconds, tt) : '-'}
@@ -421,7 +421,7 @@ const CodexUsageView = ({ t, record, payload, onCopy, onRefresh }) => { {statusTag} - {tt('上游状态码:')} + {tt('上游状态码?)} {upstreamStatus ?? '-'}
@@ -461,8 +461,8 @@ const CodexUsageView = ({ t, record, payload, onCopy, onRefresh }) => {
- {tt('渠道:')} - {record?.name || '-'} ({tt('编号:')} + {tt('渠道?)} + {record?.name || '-'} ({tt('编号?)} {record?.id || '-'})
@@ -474,7 +474,7 @@ const CodexUsageView = ({ t, record, payload, onCopy, onRefresh }) => {
{tt( - '用于观察当前帐号在 Codex 上游的基础限额与附加计费能力使用情况', + '用于观察当前帐号?Codex 上游的基础限额与附加计费能力使用情?, )}
@@ -496,7 +496,7 @@ const CodexUsageView = ({ t, record, payload, onCopy, onRefresh }) => { {tt('附加额度')}
- {tt('按模型或能力拆分的附加计费能力窗口')} + {tt('按模型或能力拆分的附加计费能力窗?)}
@@ -610,7 +610,7 @@ const CodexUsageLoader = ({ t, record, initialPayload, onCopy }) => { if (loading) { return (
- +
); } @@ -649,7 +649,7 @@ export const openCodexUsageModal = ({ t, record, payload, onCopy }) => { const layout = getCodexUsageModalLayout(); Modal.info({ - title: tt('Codex 帐号与用量'), + title: tt('Codex 帐号与用?), centered: false, width: layout.width, style: layout.style, diff --git a/web/classic/src/components/table/channels/modals/ColumnSelectorModal.jsx b/web/classic/src/components/table/channels/modals/ColumnSelectorModal.jsx index b46379ac5..3e8a17fb6 100644 --- a/web/classic/src/components/table/channels/modals/ColumnSelectorModal.jsx +++ b/web/classic/src/components/table/channels/modals/ColumnSelectorModal.jsx @@ -1,5 +1,5 @@ /* -Copyright (C) 2025 QuantumNous +Copyright (C) 2025 modelstoken This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as @@ -14,7 +14,7 @@ GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . -For commercial licensing, please contact support@quantumnous.com +For commercial licensing, please contact admin@modelstoken.com */ import React from 'react'; @@ -70,7 +70,7 @@ const ColumnSelectorModal = ({ return ( setShowColumnSelector(false)} footer={ @@ -94,7 +94,7 @@ const ColumnSelectorModal = ({ } onChange={(e) => handleSelectAll(e.target.checked)} > - {t('全选')} + {t('全?)}
. -For commercial licensing, please contact support@quantumnous.com +For commercial licensing, please contact admin@modelstoken.com */ import React, { useEffect, useState, useRef, useMemo } from 'react'; @@ -129,8 +129,7 @@ const PARAM_OVERRIDE_OPERATIONS_TEMPLATE = { const DEPRECATED_DOUBAO_CODING_PLAN_BASE_URL = 'doubao-coding-plan'; -// 支持并且已适配通过接口获取模型列表的渠道类型 -const MODEL_FETCHABLE_TYPES = new Set([ +// 支持并且已适配通过接口获取模型列表的渠道类?const MODEL_FETCHABLE_TYPES = new Set([ 1, 4, 14, 34, 17, 26, 27, 24, 47, 25, 20, 23, 31, 40, 42, 48, 43, ]); @@ -154,7 +153,7 @@ function type2secretPrompt(type) { case 51: return '按照如下格式输入: AccessKey|SecretAccessKey'; case 57: - return '请输入 JSON 格式的 OAuth 凭据(必须包含 access_token 和 account_id)'; + return '请输?JSON 格式?OAuth 凭据(必须包?access_token ?account_id?; default: return '请输入渠道对应的鉴权密钥'; } @@ -188,22 +187,18 @@ const EditChannelModal = (props) => { weight: 0, tag: '', multi_key_mode: 'random', - // 渠道额外设置的默认值 - force_format: false, + // 渠道额外设置的默认? force_format: false, thinking_to_content: false, proxy: '', pass_through_body_enabled: false, system_prompt: '', system_prompt_override: false, settings: '', - // 仅 Vertex: 密钥格式(存入 settings.vertex_key_type) - vertex_key_type: 'json', - // 仅 AWS: 密钥格式和区域(存入 settings.aws_key_type 和 settings.aws_region) - aws_key_type: 'ak_sk', + // ?Vertex: 密钥格式(存?settings.vertex_key_type? vertex_key_type: 'json', + // ?AWS: 密钥格式和区域(存入 settings.aws_key_type ?settings.aws_region? aws_key_type: 'ak_sk', // 企业账户设置 is_enterprise_account: false, - // 字段透传控制默认值 - allow_service_tier: false, + // 字段透传控制默认? allow_service_tier: false, disable_store: false, // false = 允许透传(默认开启) allow_safety_identifier: false, allow_include_obfuscation: false, @@ -248,9 +243,8 @@ const EditChannelModal = (props) => { const [isMultiKeyChannel, setIsMultiKeyChannel] = useState(false); const [channelSearchValue, setChannelSearchValue] = useState(''); const [useManualInput, setUseManualInput] = useState(false); // 是否使用手动输入模式 - const [keyMode, setKeyMode] = useState('append'); // 密钥模式:replace(覆盖)或 append(追加) - const [isEnterpriseAccount, setIsEnterpriseAccount] = useState(false); // 是否为企业账户 - const [doubaoApiEditUnlocked, setDoubaoApiEditUnlocked] = useState(false); // 豆包渠道自定义 API 地址隐藏入口 + const [keyMode, setKeyMode] = useState('append'); // 密钥模式:replace(覆盖)?append(追加) + const [isEnterpriseAccount, setIsEnterpriseAccount] = useState(false); // 是否为企业账? const [doubaoApiEditUnlocked, setDoubaoApiEditUnlocked] = useState(false); // 豆包渠道自定?API 地址隐藏入口 const redirectModelList = useMemo(() => { const mapping = inputs.model_mapping; if (typeof mapping !== 'string') return []; @@ -319,7 +313,7 @@ const EditChannelModal = (props) => { if (!keyword || modelSearchMatchedCount !== 0) { return ''; } - return t('未匹配到模型,按回车键可将「{{name}}」作为自定义模型名添加', { + return t('未匹配到模型,按回车键可将「{{name}}」作为自定义模型名添?, { name: keyword, }); }, [modelSearchMatchedCount, modelSearchValue, t]); @@ -330,7 +324,7 @@ const EditChannelModal = (props) => { : ''; if (!raw) { return { - tagLabel: t('不更改'), + tagLabel: t('不更?), tagColor: 'grey', preview: t( '此项可选,用于覆盖请求参数。不支持覆盖 stream 参数', @@ -354,20 +348,20 @@ const EditChannelModal = (props) => { Array.isArray(parsed.operations) ) { return { - tagLabel: `${t('新格式模板')} (${parsed.operations.length})`, + tagLabel: `${t('新格式模?)} (${parsed.operations.length})`, tagColor: 'cyan', preview: pretty, }; } if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) { return { - tagLabel: `${t('旧格式模板')} (${Object.keys(parsed).length})`, + tagLabel: `${t('旧格式模?)} (${Object.keys(parsed).length})`, tagColor: 'blue', preview: pretty, }; } return { - tagLabel: t('自定义 JSON'), + tagLabel: t('自定?JSON'), tagColor: 'orange', preview: pretty, }; @@ -387,14 +381,12 @@ const EditChannelModal = (props) => { const [paramOverrideEditorVisible, setParamOverrideEditorVisible] = useState(false); - // 密钥显示状态 - const [keyDisplayState, setKeyDisplayState] = useState({ + // 密钥显示状? const [keyDisplayState, setKeyDisplayState] = useState({ showModal: false, keyData: '', }); - // 专门的2FA验证状态(用于TwoFactorAuthModal) - const [show2FAVerifyModal, setShow2FAVerifyModal] = useState(false); + // 专门?FA验证状态(用于TwoFactorAuthModal? const [show2FAVerifyModal, setShow2FAVerifyModal] = useState(false); const [verifyCode, setVerifyCode] = useState(''); useEffect(() => { @@ -419,11 +411,9 @@ const EditChannelModal = (props) => { [], ); - // 剪贴板连接信息自动检测 - const [clipboardConfig, setClipboardConfig] = useState(null); + // 剪贴板连接信息自动检? const [clipboardConfig, setClipboardConfig] = useState(null); - // 高级设置折叠状态 - const [advancedSettingsOpen, setAdvancedSettingsOpen] = useState(false); + // 高级设置折叠状? const [advancedSettingsOpen, setAdvancedSettingsOpen] = useState(false); const toggleAdvancedSettings = (open) => { setAdvancedSettingsOpen(open); localStorage.setItem(ADVANCED_SETTINGS_EXPANDED_KEY, String(open)); @@ -435,7 +425,7 @@ const EditChannelModal = (props) => { const initialModelMappingRef = useRef(''); const initialStatusCodeMappingRef = useRef(''); const doubaoCodingPlanDeprecationMessage = - 'Doubao Coding Plan 不再允许新增。根据火山方舟文档,Coding 套餐额度仅适用于 AI Coding 产品内调用,不适用于单独 API 调用;在非 AI Coding 产品中使用对应的 Base URL 和 API Key 可能被视为违规,并可能导致订阅停用或账号封禁。'; + 'Doubao Coding Plan 不再允许新增。根据火山方舟文档,Coding 套餐额度仅适用?AI Coding 产品内调用,不适用于单?API 调用;在?AI Coding 产品中使用对应的 Base URL ?API Key 可能被视为违规,并可能导致订阅停用或账号封禁?; const canKeepDeprecatedDoubaoCodingPlan = initialBaseUrlRef.current === DEPRECATED_DOUBAO_CODING_PLAN_BASE_URL; const doubaoCodingPlanOptionLabel = ( @@ -446,8 +436,7 @@ const EditChannelModal = (props) => { ); - // 2FA状态更新辅助函数 - const updateTwoFAState = (updates) => { + // 2FA状态更新辅助函? const updateTwoFAState = (updates) => { setTwoFAState((prev) => ({ ...prev, ...updates })); }; // 使用通用安全验证 Hook @@ -462,8 +451,7 @@ const EditChannelModal = (props) => { switchVerificationMethod, } = useSecureVerification({ onSuccess: (result) => { - // 验证成功后显示密钥 - console.log('Verification success, result:', result); + // 验证成功后显示密? console.log('Verification success, result:', result); if (result && result.success && result.data?.key) { showSuccess(t('密钥获取成功')); setKeyDisplayState({ @@ -471,7 +459,7 @@ const EditChannelModal = (props) => { keyData: result.data.key, }); } else if (result && result.key) { - // 直接返回了 key(没有包装在 data 中) + // 直接返回?key(没有包装在 data 中) showSuccess(t('密钥获取成功')); setKeyDisplayState({ showModal: true, @@ -481,16 +469,14 @@ const EditChannelModal = (props) => { }, }); - // 重置密钥显示状态 - const resetKeyDisplayState = () => { + // 重置密钥显示状? const resetKeyDisplayState = () => { setKeyDisplayState({ showModal: false, keyData: '', }); }; - // 重置2FA验证状态 - const reset2FAVerifyState = () => { + // 重置2FA验证状? const reset2FAVerifyState = () => { setShow2FAVerifyModal(false); setVerifyCode(''); setVerifyLoading(false); @@ -510,8 +496,7 @@ const EditChannelModal = (props) => { } }; - // 渠道额外设置状态 - const [channelSettings, setChannelSettings] = useState({ + // 渠道额外设置状? const [channelSettings, setChannelSettings] = useState({ force_format: false, thinking_to_content: false, proxy: '', @@ -521,36 +506,28 @@ const EditChannelModal = (props) => { const showApiConfigCard = true; // 控制是否显示 API 配置卡片 const getInitValues = () => ({ ...originInputs }); - // 处理渠道额外设置的更新 - const handleChannelSettingsChange = (key, value) => { - // 更新内部状态 - setChannelSettings((prev) => ({ ...prev, [key]: value })); + // 处理渠道额外设置的更? const handleChannelSettingsChange = (key, value) => { + // 更新内部状? setChannelSettings((prev) => ({ ...prev, [key]: value })); - // 同步更新到表单字段 - if (formApiRef.current) { + // 同步更新到表单字? if (formApiRef.current) { formApiRef.current.setValue(key, value); } - // 同步更新inputs状态 - setInputs((prev) => ({ ...prev, [key]: value })); + // 同步更新inputs状? setInputs((prev) => ({ ...prev, [key]: value })); - // 生成setting JSON并更新 - const newSettings = { ...channelSettings, [key]: value }; + // 生成setting JSON并更? const newSettings = { ...channelSettings, [key]: value }; const settingsJson = JSON.stringify(newSettings); handleInputChange('setting', settingsJson); }; const handleChannelOtherSettingsChange = (key, value) => { - // 更新内部状态 - setChannelSettings((prev) => ({ ...prev, [key]: value })); + // 更新内部状? setChannelSettings((prev) => ({ ...prev, [key]: value })); - // 同步更新到表单字段 - if (formApiRef.current) { + // 同步更新到表单字? if (formApiRef.current) { formApiRef.current.setValue(key, value); } - // 同步更新inputs状态 - setInputs((prev) => ({ ...prev, [key]: value })); + // 同步更新inputs状? setInputs((prev) => ({ ...prev, [key]: value })); // 需要更新settings,是一个json,例如{"azure_responses_version": "preview"} let settings = {}; @@ -578,12 +555,12 @@ const EditChannelModal = (props) => { formApiRef.current.setValue('base_url', config.url); } setClipboardConfig(null); - showSuccess(t('连接信息已填入')); + showSuccess(t('连接信息已填?)); }; const pasteFromClipboard = async () => { if (!navigator?.clipboard?.readText) { - showError(t('无法读取剪贴板')); + showError(t('无法读取剪贴?)); return; } try { @@ -595,7 +572,7 @@ const EditChannelModal = (props) => { showInfo(t('剪贴板中未检测到连接信息')); } } catch { - showError(t('无法读取剪贴板')); + showError(t('无法读取剪贴?)); } }; @@ -620,7 +597,7 @@ const EditChannelModal = (props) => { Modal.confirm({ title: '警告', content: - '不需要在末尾加/v1,New API会自动处理,添加后可能导致请求失败,是否继续?', + '不需要在末尾?v1,New API会自动处理,添加后可能导致请求失败,是否继续?, onOk: () => { setInputs((inputs) => ({ ...inputs, [name]: value })); }, @@ -683,8 +660,7 @@ const EditChannelModal = (props) => { } setBasicModels(localModels); - // 重置手动输入模式状态 - setUseManualInput(false); + // 重置手动输入模式状? setUseManualInput(false); if (value === 57) { setBatch(false); @@ -727,7 +703,7 @@ const EditChannelModal = (props) => { ? inputs.param_override.trim() : ''; if (!raw) { - showInfo(t('暂无可复制 JSON')); + showInfo(t('暂无可复?JSON')); return; } @@ -742,7 +718,7 @@ const EditChannelModal = (props) => { const ok = await copy(content); if (ok) { - showSuccess(t('参数覆盖 JSON 已复制')); + showSuccess(t('参数覆盖 JSON 已复?)); } else { showError(t('复制失败')); } @@ -755,7 +731,7 @@ const EditChannelModal = (props) => { : ''; if (!raw) return null; if (!verifyJSON(raw)) { - throw new Error(t('当前参数覆盖不是合法的 JSON')); + throw new Error(t('当前参数覆盖不是合法?JSON')); } return JSON.parse(raw); }; @@ -857,8 +833,7 @@ const EditChannelModal = (props) => { setBatch(false); setMultiToSingle(false); } - // 解析渠道额外设置并合并到data中 - if (data.setting) { + // 解析渠道额外设置并合并到data? if (data.setting) { try { const parsedSettings = JSON.parse(data.setting); data.force_format = parsedSettings.force_format || false; @@ -895,8 +870,7 @@ const EditChannelModal = (props) => { parsedSettings.azure_responses_version || ''; // 读取 Vertex 密钥格式 data.vertex_key_type = parsedSettings.vertex_key_type || 'json'; - // 读取 AWS 密钥格式和区域 - data.aws_key_type = parsedSettings.aws_key_type || 'ak_sk'; + // 读取 AWS 密钥格式和区? data.aws_key_type = parsedSettings.aws_key_type || 'ak_sk'; // 读取企业账户设置 data.is_enterprise_account = parsedSettings.openrouter_enterprise === true; @@ -948,7 +922,7 @@ const EditChannelModal = (props) => { data.upstream_model_update_ignored_models = ''; } } else { - // 兼容历史数据:老渠道没有 settings 时,默认按 json 展示 + // 兼容历史数据:老渠道没?settings 时,默认?json 展示 data.vertex_key_type = 'json'; data.aws_key_type = 'ak_sk'; data.is_enterprise_account = false; @@ -984,11 +958,9 @@ const EditChannelModal = (props) => { } else { setAutoBan(true); } - // 同步企业账户状态 - setIsEnterpriseAccount(data.is_enterprise_account || false); + // 同步企业账户状? setIsEnterpriseAccount(data.is_enterprise_account || false); setBasicModels(getChannelModels(data.type)); - // 同步更新channelSettings状态显示 - setChannelSettings({ + // 同步更新channelSettings状态显? setChannelSettings({ force_format: data.force_format, thinking_to_content: data.thinking_to_content, proxy: data.proxy, @@ -1050,7 +1022,7 @@ const EditChannelModal = (props) => { const fetchUpstreamModelList = async (name, options = {}) => { const silent = !!options.silent; // if (inputs['type'] !== 1) { - // showError(t('仅支持 OpenAI 接口格式')); + // showError(t('仅支?OpenAI 接口格式')); // return; // } setLoading(true); @@ -1058,7 +1030,7 @@ const EditChannelModal = (props) => { let err = false; if (isEdit) { - // 如果是编辑模式,使用已有的 channelId 获取模型列表 + // 如果是编辑模式,使用已有?channelId 获取模型列表 const res = await API.get('/api/channel/fetch_models/' + channelId, { skipErrorHandler: true, }); @@ -1070,7 +1042,7 @@ const EditChannelModal = (props) => { } else { // 如果是新建模式,通过后端代理获取模型列表 if (!inputs?.['key']) { - showError(t('请填写密钥')); + showError(t('请填写密?)); err = true; } else { try { @@ -1200,21 +1172,19 @@ const EditChannelModal = (props) => { } }; - // 查看渠道密钥(透明验证) - const handleShow2FAModal = async () => { + // 查看渠道密钥(透明验证? const handleShow2FAModal = async () => { try { // 使用 withVerification 包装,会自动处理需要验证的情况 const result = await withVerification( createApiCalls.viewChannelKey(channelId), { title: t('查看渠道密钥'), - description: t('为了保护账户安全,请验证您的身份。'), + description: t('为了保护账户安全,请验证您的身份?), preferredMethod: 'passkey', // 优先使用 Passkey }, ); - // 如果直接返回了结果(已验证),显示密钥 - if (result && result.success && result.data?.key) { + // 如果直接返回了结果(已验证),显示密? if (result && result.success && result.data?.key) { showSuccess(t('密钥获取成功')); setKeyDisplayState({ showModal: true, @@ -1245,7 +1215,7 @@ const EditChannelModal = (props) => { if (!res?.data?.success) { throw new Error(res?.data?.message || 'Failed to refresh credential'); } - showSuccess(t('凭证已刷新')); + showSuccess(t('凭证已刷?)); } catch (error) { showError(error.message || t('刷新失败')); } finally { @@ -1343,10 +1313,8 @@ const EditChannelModal = (props) => { } catch {} } fetchModelGroups(); - // 重置手动输入模式状态 - setUseManualInput(false); - // 编辑模式下恢复用户偏好,创建模式一律折叠 - setAdvancedSettingsOpen( + // 重置手动输入模式状? setUseManualInput(false); + // 编辑模式下恢复用户偏好,创建模式一律折? setAdvancedSettingsOpen( isEdit && localStorage.getItem(ADVANCED_SETTINGS_EXPANDED_KEY) === 'true' ); } else { @@ -1376,8 +1344,7 @@ const EditChannelModal = (props) => { const resetModalState = () => { resolveStatusCodeRiskConfirm(false); formApiRef.current?.reset(); - // 重置渠道设置状态 - setChannelSettings({ + // 重置渠道设置状? setChannelSettings({ force_format: false, thinking_to_content: false, proxy: '', @@ -1385,26 +1352,19 @@ const EditChannelModal = (props) => { system_prompt: '', system_prompt_override: false, }); - // 重置密钥模式状态 - setKeyMode('append'); - // 重置企业账户状态 - setIsEnterpriseAccount(false); - // 重置豆包隐藏入口状态 - setDoubaoApiEditUnlocked(false); + // 重置密钥模式状? setKeyMode('append'); + // 重置企业账户状? setIsEnterpriseAccount(false); + // 重置豆包隐藏入口状? setDoubaoApiEditUnlocked(false); doubaoApiClickCountRef.current = 0; setModelSearchValue(''); - // 重置高级设置折叠状态 - setAdvancedSettingsOpen(false); + // 重置高级设置折叠状? setAdvancedSettingsOpen(false); // 清空表单中的key_mode字段 if (formApiRef.current) { formApiRef.current.setValue('key_mode', undefined); } - // 重置本地输入,避免下次打开残留上一次的 JSON 字段值 - setInputs(getInitValues()); - // 重置密钥显示状态 - resetKeyDisplayState(); - // 重置剪贴板检测状态 - setClipboardConfig(null); + // 重置本地输入,避免下次打开残留上一次的 JSON 字段? setInputs(getInitValues()); + // 重置密钥显示状? resetKeyDisplayState(); + // 重置剪贴板检测状? setClipboardConfig(null); }; const handleVertexUploadChange = ({ fileList }) => { @@ -1428,8 +1388,7 @@ const EditChannelModal = (props) => { } } - // 非批量模式下只保留一个文件(最新选择的),避免重复叠加 - if (!batch && validFiles.length > 1) { + // 非批量模式下只保留一个文件(最新选择的),避免重复叠? if (!batch && validFiles.length > 1) { validFiles = [validFiles[validFiles.length - 1]]; keys = [keys[keys.length - 1]]; } @@ -1467,7 +1426,7 @@ const EditChannelModal = (props) => {
{t( - '你可以在“自定义模型名称”处手动添加它们,然后点击填入后再提交,或者直接使用下方操作自动处理。', + '你可以在“自定义模型名称”处手动添加它们,然后点击填入后再提交,或者直接使用下方操作自动处理?, )}
@@ -1502,7 +1461,7 @@ const EditChannelModal = (props) => { resolve('add'); }} > - {t('添加后提交')} + {t('添加后提?)} ), @@ -1548,7 +1507,7 @@ const EditChannelModal = (props) => { if (localInputs.type === 57) { if (batch) { - showInfo(t('Codex 渠道不支持批量创建')); + showInfo(t('Codex 渠道不支持批量创?)); return; } @@ -1560,13 +1519,13 @@ const EditChannelModal = (props) => { if (rawKey !== '') { if (!verifyJSON(rawKey)) { - showInfo(t('密钥必须是合法的 JSON 格式!')); + showInfo(t('密钥必须是合法的 JSON 格式?)); return; } try { const parsed = JSON.parse(rawKey); if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) { - showInfo(t('密钥必须是 JSON 对象')); + showInfo(t('密钥必须?JSON 对象')); return; } const accessToken = String(parsed.access_token || '').trim(); @@ -1581,7 +1540,7 @@ const EditChannelModal = (props) => { } localInputs.key = JSON.stringify(parsed); } catch (error) { - showInfo(t('密钥必须是合法的 JSON 格式!')); + showInfo(t('密钥必须是合法的 JSON 格式?)); return; } } @@ -1603,7 +1562,7 @@ const EditChannelModal = (props) => { const parsedKey = JSON.parse(localInputs.key); localInputs.key = JSON.stringify(parsedKey); } catch (err) { - showError(t('密钥格式无效,请输入有效的 JSON 格式密钥')); + showError(t('密钥格式无效,请输入有效?JSON 格式密钥')); return; } } else if (!isEdit) { @@ -1652,7 +1611,7 @@ const EditChannelModal = (props) => { delete localInputs.vertex_files; if (!isEdit && (!localInputs.name || !localInputs.key)) { - showInfo(t('请填写渠道名称和渠道密钥!')); + showInfo(t('请填写渠道名称和渠道密钥?)); return; } if (!Array.isArray(localInputs.models) || localInputs.models.length === 0) { @@ -1663,7 +1622,7 @@ const EditChannelModal = (props) => { localInputs.type === 45 && (!localInputs.base_url || localInputs.base_url.trim() === '') ) { - showInfo(t('请输入API地址!')); + showInfo(t('请输入API地址?)); return; } const hasModelMapping = @@ -1672,13 +1631,13 @@ const EditChannelModal = (props) => { let parsedModelMapping = null; if (hasModelMapping) { if (!verifyJSON(localInputs.model_mapping)) { - showInfo(t('模型映射必须是合法的 JSON 格式!')); + showInfo(t('模型映射必须是合法的 JSON 格式?)); return; } try { parsedModelMapping = JSON.parse(localInputs.model_mapping); } catch (error) { - showInfo(t('模型映射必须是合法的 JSON 格式!')); + showInfo(t('模型映射必须是合法的 JSON 格式?)); return; } } @@ -1757,8 +1716,7 @@ const EditChannelModal = (props) => { }; localInputs.setting = JSON.stringify(channelExtraSettings); - // 处理 settings 字段(包括企业账户设置和字段透传控制) - let settings = {}; + // 处理 settings 字段(包括企业账户设置和字段透传控制? let settings = {}; if (localInputs.settings) { try { settings = JSON.parse(localInputs.settings); @@ -1773,22 +1731,21 @@ const EditChannelModal = (props) => { localInputs.is_enterprise_account === true; } - // type === 33 (AWS): 保存 aws_key_type 到 settings + // type === 33 (AWS): 保存 aws_key_type ?settings if (localInputs.type === 33) { settings.aws_key_type = localInputs.aws_key_type || 'ak_sk'; } - // type === 41 (Vertex): 始终保存 vertex_key_type 到 settings,避免编辑时被重置 - if (localInputs.type === 41) { + // type === 41 (Vertex): 始终保存 vertex_key_type ?settings,避免编辑时被重? if (localInputs.type === 41) { settings.vertex_key_type = localInputs.vertex_key_type || 'json'; } else if ('vertex_key_type' in settings) { delete settings.vertex_key_type; } - // type === 1 (OpenAI) 或 type === 14 (Claude): 设置字段透传控制(显式保存布尔值) + // type === 1 (OpenAI) ?type === 14 (Claude): 设置字段透传控制(显式保存布尔值) if (localInputs.type === 1 || localInputs.type === 14) { settings.allow_service_tier = localInputs.allow_service_tier === true; - // 仅 OpenAI 渠道需要 store / safety_identifier / include_obfuscation + // ?OpenAI 渠道需?store / safety_identifier / include_obfuscation if (localInputs.type === 1) { settings.disable_store = localInputs.disable_store === true; settings.allow_safety_identifier = @@ -1828,20 +1785,18 @@ const EditChannelModal = (props) => { localInputs.settings = JSON.stringify(settings); - // 清理不需要发送到后端的字段 - delete localInputs.force_format; + // 清理不需要发送到后端的字? delete localInputs.force_format; delete localInputs.thinking_to_content; delete localInputs.proxy; delete localInputs.pass_through_body_enabled; delete localInputs.system_prompt; delete localInputs.system_prompt_override; delete localInputs.is_enterprise_account; - // 顶层的 vertex_key_type 不应发送给后端 + // 顶层?vertex_key_type 不应发送给后端 delete localInputs.vertex_key_type; - // 顶层的 aws_key_type 不应发送给后端 + // 顶层?aws_key_type 不应发送给后端 delete localInputs.aws_key_type; - // 清理字段透传控制的临时字段 - delete localInputs.allow_service_tier; + // 清理字段透传控制的临时字? delete localInputs.allow_service_tier; delete localInputs.disable_store; delete localInputs.allow_safety_identifier; delete localInputs.allow_include_obfuscation; @@ -1868,8 +1823,7 @@ const EditChannelModal = (props) => { res = await API.put(`/api/channel/`, { ...localInputs, id: parseInt(channelId), - key_mode: isMultiKeyChannel ? keyMode : undefined, // 只在多key模式下传递 - }); + key_mode: isMultiKeyChannel ? keyMode : undefined, // 只在多key模式下传? }); } else { res = await API.post(`/api/channel/`, { mode: mode, @@ -1880,9 +1834,9 @@ const EditChannelModal = (props) => { const { success, message } = res.data; if (success) { if (isEdit) { - showSuccess(t('渠道更新成功!')); + showSuccess(t('渠道更新成功?)); } else { - showSuccess(t('渠道创建成功!')); + showSuccess(t('渠道创建成功?)); setInputs(originInputs); } props.refresh(); @@ -1920,15 +1874,14 @@ const EditChannelModal = (props) => { const afterCount = deduplicatedKeys.length; const deduplicatedKeyText = deduplicatedKeys.join('\n'); - // 更新表单和状态 - if (formApiRef.current) { + // 更新表单和状? if (formApiRef.current) { formApiRef.current.setValue('key', deduplicatedKeyText); } handleInputChange('key', deduplicatedKeyText); // 显示去重结果 const message = t( - '去重完成:去重前 {{before}} 个密钥,去重后 {{after}} 个密钥', + '去重完成:去重前 {{before}} 个密钥,去重?{{after}} 个密?, { before: beforeCount, after: afterCount, @@ -1936,7 +1889,7 @@ const EditChannelModal = (props) => { ); if (beforeCount === afterCount) { - showInfo(t('未发现重复密钥')); + showInfo(t('未发现重复密?)); } else { showSuccess(message); } @@ -1968,13 +1921,13 @@ const EditChannelModal = (props) => { if (addedModels.length > 0) { showSuccess( - t('已新增 {{count}} 个模型:{{list}}', { + t('已新?{{count}} 个模型:{{list}}', { count: addedModels.length, list: addedModels.join(', '), }), ); } else { - showInfo(t('未发现新增模型')); + showInfo(t('未发现新增模?)); } }; @@ -2024,8 +1977,7 @@ const EditChannelModal = (props) => { // 批量模式下禁用手动输入,并清空手动输入的内容 setUseManualInput(false); if (inputs.type === 41) { - // 清空手动输入的密钥内容 - if (formApiRef.current) { + // 清空手动输入的密钥内? if (formApiRef.current) { formApiRef.current.setValue('key', ''); } handleInputChange('key', ''); @@ -2080,8 +2032,7 @@ const EditChannelModal = (props) => { () => CHANNEL_OPTIONS.map((opt) => ({ ...opt, - // 保持 label 为纯文本以支持搜索 - label: opt.label, + // 保持 label 为纯文本以支持搜? label: opt.label, })), [], ); @@ -2220,9 +2171,9 @@ const EditChannelModal = (props) => { handleChannelOtherSettingsChange( 'upstream_model_update_check_enabled', @@ -2237,21 +2188,21 @@ const EditChannelModal = (props) => { field='upstream_model_update_auto_sync_enabled' label={t('是否自动同步上游模型更新')} checkedText={t('开')} - uncheckedText={t('关')} + uncheckedText={t('?)} disabled={!inputs.upstream_model_update_check_enabled} onChange={(value) => handleChannelOtherSettingsChange('upstream_model_update_auto_sync_enabled', value) } - extraText={t('开启后检测到新增模型会自动加入当前渠道模型列表')} + extraText={t('开启后检测到新增模型会自动加入当前渠道模型列?)} /> handleInputChange( @@ -2262,13 +2213,13 @@ const EditChannelModal = (props) => { showClear />
- {t('上次检测时间')}:  + {t('上次检测时?)}:  {formatUnixTime( inputs.upstream_model_update_last_check_time, )}
- {t('上次检测到可加入模型')}:  + {t('上次检测到可加入模?)}:  {upstreamDetectedModels.length === 0 ? ( t('暂无') ) : ( @@ -2317,14 +2268,14 @@ const EditChannelModal = (props) => { icon={} onClick={() => setParamOverrideEditorVisible(true)} > - {t('可视化编辑')} + {t('可视化编?)} applyParamOverrideTemplate('operations', 'fill') }, - { node: 'item', name: t('填充旧模板'), onClick: () => applyParamOverrideTemplate('legacy', 'fill') }, + { node: 'item', name: t('填充新模?), onClick: () => applyParamOverrideTemplate('operations', 'fill') }, + { node: 'item', name: t('填充旧模?), onClick: () => applyParamOverrideTemplate('legacy', 'fill') }, { node: 'item', name: t('清空'), onClick: clearParamOverride }, ]} > @@ -2365,11 +2316,11 @@ const EditChannelModal = (props) => { { className='!text-semi-color-primary cursor-pointer' onClick={() => formatJsonField('header_override')} > - {t('格式化')} + {t('格式?)}
- {t('支持变量:')} + {t('支持变量?)}
@@ -2424,7 +2375,7 @@ const EditChannelModal = (props) => { field='status_code_mapping' label={t('状态码复写')} placeholder={ - t('此项可选,用于复写返回的状态码,仅影响本地判断,不修改返回到上游的状态码,比如将claude渠道的400错误复写为500(用于重试),请勿滥用该功能,例如:') + + t('此项可选,用于复写返回的状态码,仅影响本地判断,不修改返回到上游的状态码,比如将claude渠道?00错误复写?00(用于重试),请勿滥用该功能,例如:') + '\n' + JSON.stringify(STATUS_CODE_MAPPING_EXAMPLE, null, 2) } @@ -2456,7 +2407,7 @@ const EditChannelModal = (props) => { handleInputChange('remark', value)} @@ -2466,8 +2417,8 @@ const EditChannelModal = (props) => {
handleInputChange('priority', value)} style={{ width: '100%' }} @@ -2490,10 +2441,10 @@ const EditChannelModal = (props) => {
{t('字段透传控制')}
- handleChannelOtherSettingsChange('allow_service_tier', value)} extraText={t('service_tier 字段用于指定服务层级,允许透传可能导致实际计费高于预期。默认关闭以避免额外费用')} /> - handleChannelOtherSettingsChange('disable_store', value)} extraText={t('store 字段用于授权 OpenAI 存储请求数据以评估和优化产品。默认关闭,开启后可能导致 Codex 无法正常使用')} /> - handleChannelOtherSettingsChange('allow_safety_identifier', value)} extraText={t('safety_identifier 字段用于帮助 OpenAI 识别可能违反使用政策的应用程序用户。默认关闭以保护用户隐私')} /> - handleChannelOtherSettingsChange('allow_include_obfuscation', value)} extraText={t('include_obfuscation 用于控制 Responses 流混淆字段。默认关闭以避免客户端关闭该安全保护')} /> + handleChannelOtherSettingsChange('allow_service_tier', value)} extraText={t('service_tier 字段用于指定服务层级,允许透传可能导致实际计费高于预期。默认关闭以避免额外费用')} /> + handleChannelOtherSettingsChange('disable_store', value)} extraText={t('store 字段用于授权 OpenAI 存储请求数据以评估和优化产品。默认关闭,开启后可能导致 Codex 无法正常使用')} /> + handleChannelOtherSettingsChange('allow_safety_identifier', value)} extraText={t('safety_identifier 字段用于帮助 OpenAI 识别可能违反使用政策的应用程序用户。默认关闭以保护用户隐私')} /> + handleChannelOtherSettingsChange('allow_include_obfuscation', value)} extraText={t('include_obfuscation 用于控制 Responses 流混淆字段。默认关闭以避免客户端关闭该安全保护')} /> )} @@ -2502,9 +2453,9 @@ const EditChannelModal = (props) => {
{t('字段透传控制')}
- handleChannelOtherSettingsChange('allow_service_tier', value)} extraText={t('service_tier 字段用于指定服务层级,允许透传可能导致实际计费高于预期。默认关闭以避免额外费用')} /> - handleChannelOtherSettingsChange('allow_inference_geo', value)} extraText={t('inference_geo 字段用于控制 Claude 数据驻留推理区域。默认关闭以避免未经授权透传地域信息')} /> - handleChannelOtherSettingsChange('allow_speed', value)} extraText={t('speed 字段用于控制 Claude 推理速度模式。默认关闭以避免意外切换到 fast 模式')} /> + handleChannelOtherSettingsChange('allow_service_tier', value)} extraText={t('service_tier 字段用于指定服务层级,允许透传可能导致实际计费高于预期。默认关闭以避免额外费用')} /> + handleChannelOtherSettingsChange('allow_inference_geo', value)} extraText={t('inference_geo 字段用于控制 Claude 数据驻留推理区域。默认关闭以避免未经授权透传地域信息')} /> + handleChannelOtherSettingsChange('allow_speed', value)} extraText={t('speed 字段用于控制 Claude 推理速度模式。默认关闭以避免意外切换?fast 模式')} /> )} @@ -2516,20 +2467,20 @@ const EditChannelModal = (props) => { {inputs.type === 14 && ( - handleChannelOtherSettingsChange('claude_beta_query', value)} extraText={t('开启后,该渠道请求 Claude 时将强制追加 ?beta=true(无需客户端手动传参)')} /> + handleChannelOtherSettingsChange('claude_beta_query', value)} extraText={t('开启后,该渠道请求 Claude 时将强制追加 ?beta=true(无需客户端手动传参)')} /> )} {inputs.type === 1 && ( - handleChannelSettingsChange('force_format', value)} extraText={t('强制将响应格式化为 OpenAI 标准格式(只适用于OpenAI渠道类型)')} /> + handleChannelSettingsChange('force_format', value)} extraText={t('强制将响应格式化?OpenAI 标准格式(只适用于OpenAI渠道类型?)} /> )} - handleChannelSettingsChange('thinking_to_content', value)} extraText={t('将 reasoning_content 转换为 标签拼接到内容中')} /> - handleChannelSettingsChange('pass_through_body_enabled', value)} extraText={t('启用请求体透传功能')} /> + handleChannelSettingsChange('thinking_to_content', value)} extraText={t('?reasoning_content 转换? 标签拼接到内容中')} /> + handleChannelSettingsChange('pass_through_body_enabled', value)} extraText={t('启用请求体透传功能')} /> - handleChannelSettingsChange('proxy', value)} showClear extraText={t('用于配置网络代理,支持 socks5 协议')} /> + handleChannelSettingsChange('proxy', value)} showClear extraText={t('用于配置网络代理,支?socks5 协议')} /> - handleChannelSettingsChange('system_prompt', value)} autosize showClear extraText={t('用户优先:如果用户在请求中指定了系统提示词,将优先使用用户的设置')} /> - handleChannelSettingsChange('system_prompt_override', value)} extraText={t('如果用户请求中包含系统提示词,则使用此设置拼接到用户的系统提示词前面')} /> + handleChannelSettingsChange('system_prompt', value)} autosize showClear extraText={t('用户优先:如果用户在请求中指定了系统提示词,将优先使用用户的设置')} /> + handleChannelSettingsChange('system_prompt_override', value)} extraText={t('如果用户请求中包含系统提示词,则使用此设置拼接到用户的系统提示词前面')} /> ); @@ -2544,7 +2495,7 @@ const EditChannelModal = (props) => { className='ec-dbcd0a3c01b55203' description={
- {t('检测到剪贴板中的连接信息')} + {t('检测到剪贴板中的连接信?)}
@@ -2593,7 +2544,7 @@ const EditChannelModal = (props) => { closeIcon={null} className='mb-4 rounded-xl' description={t( - '此渠道由 IO.NET 自动同步,类型、密钥和 API 地址已锁定。', + '此渠道由 IO.NET 自动同步,类型、密钥和 API 地址已锁定?, )} > @@ -2634,7 +2585,7 @@ const EditChannelModal = (props) => { closeIcon={null} className='mb-4 rounded-xl' description={t( - '免责声明:仅限个人使用,请勿分发或共享任何凭证。该渠道存在前置条件与使用门槛,请在充分了解流程与风险后使用,并遵守 OpenAI 的相关条款与政策。相关凭证与配置仅限接入 Codex CLI 使用,不适用于其他客户端、平台或渠道。', + '免责声明:仅限个人使用,请勿分发或共享任何凭证。该渠道存在前置条件与使用门槛,请在充分了解流程与风险后使用,并遵守 OpenAI 的相关条款与政策。相关凭证与配置仅限接入 Codex CLI 使用,不适用于其他客户端、平台或渠道?, )} /> )} @@ -2642,15 +2593,15 @@ const EditChannelModal = (props) => { {inputs.type === 20 && ( { setIsEnterpriseAccount(value); handleInputChange('is_enterprise_account', value); }} extraText={t( - '企业账户为特殊返回格式,需要特殊处理,如果非企业账户,请勿勾选', + '企业账户为特殊返回格式,需要特殊处理,如果非企业账户,请勿勾?, )} initValue={inputs.is_enterprise_account} /> @@ -2688,7 +2639,7 @@ const EditChannelModal = (props) => { ); }} extraText={t( - 'AK/SK 模式:使用 AccessKey 和 SecretAccessKey;API Key 模式:使用 API Key', + 'AK/SK 模式:使?AccessKey ?SecretAccessKey;API Key 模式:使?API Key', )} /> @@ -2711,8 +2662,7 @@ const EditChannelModal = (props) => { 'vertex_key_type', value, ); - // 切换为 api_key 时,关闭批量与手动/文件切换,并清理已选文件 - if (value === 'api_key') { + // 切换?api_key 时,关闭批量与手?文件切换,并清理已选文? if (value === 'api_key') { setBatch(false); setUseManualInput(false); setVertexKeys([]); @@ -2725,7 +2675,7 @@ const EditChannelModal = (props) => { extraText={ inputs.vertex_key_type === 'api_key' ? t('API Key 模式下不支持批量创建') - : t('JSON 模式支持手动输入或上传服务账号 JSON') + : t('JSON 模式支持手动输入或上传服务账?JSON') } /> )} @@ -2740,7 +2690,7 @@ const EditChannelModal = (props) => { draggable dragIcon={} dragMainText={t('点击上传文件或拖拽文件到这里')} - dragSubText={t('仅支持 JSON 文件,支持多文件')} + dragSubText={t('仅支?JSON 文件,支持多文件')} style={{ marginTop: 10 }} uploadTrigger='custom' beforeUpload={() => false} @@ -2752,7 +2702,7 @@ const EditChannelModal = (props) => { : [ { required: true, - message: t('请上传密钥文件'), + message: t('请上传密钥文?), }, ] } @@ -2766,17 +2716,17 @@ const EditChannelModal = (props) => { inputs.type === 33 ? inputs.aws_key_type === 'api_key' ? t( - '请输入 API Key,一行一个,格式:APIKey|Region', + '请输?API Key,一行一个,格式:APIKey|Region', ) : t( '请输入密钥,一行一个,格式:AccessKey|SecretAccessKey|Region', ) - : t('请输入密钥,一行一个') + : t('请输入密钥,一行一?) } rules={ isEdit ? [] - : [{ required: true, message: t('请输入密钥') }] + : [{ required: true, message: t('请输入密?) }] } autosize autoComplete='new-password' @@ -2789,7 +2739,7 @@ const EditChannelModal = (props) => { keyMode === 'append' && ( {t( - '追加模式:新密钥将添加到现有密钥列表的末尾', + '追加模式:新密钥将添加到现有密钥列表的末?, )} )} @@ -2817,11 +2767,11 @@ const EditChannelModal = (props) => { field='key' label={ isEdit - ? t('密钥(编辑模式下,保存的密钥不会显示)') + ? t('密钥(编辑模式下,保存的密钥不会显示?) : t('密钥') } placeholder={t( - '请输入 JSON 格式的 OAuth 凭据,例如:\n{\n "access_token": "...",\n "account_id": "..." \n}', + '请输?JSON 格式?OAuth 凭据,例如:\n{\n "access_token": "...",\n "account_id": "..." \n}', )} rules={ isEdit @@ -2829,7 +2779,7 @@ const EditChannelModal = (props) => { : [ { required: true, - message: t('请输入密钥'), + message: t('请输入密?), }, ] } @@ -2842,7 +2792,7 @@ const EditChannelModal = (props) => {
{t( - '仅支持 JSON 对象,必须包含 access_token 与 account_id', + '仅支?JSON 对象,必须包?access_token ?account_id', )} @@ -2877,7 +2827,7 @@ const EditChannelModal = (props) => { onClick={() => formatJsonField('key')} disabled={isIonetLocked} > - {t('格式化')} + {t('格式?)} {isEdit && (
@@ -472,7 +472,7 @@ const EditTagModal = (props) => { @@ -500,8 +500,8 @@ const EditTagModal = (props) => { setCustomModel(value.trim())} suffix={ + diff --git a/web/classic/src/components/table/channels/modals/MultiKeyManageModal.jsx b/web/classic/src/components/table/channels/modals/MultiKeyManageModal.jsx index fa7870dad..cee4f7f5d 100644 --- a/web/classic/src/components/table/channels/modals/MultiKeyManageModal.jsx +++ b/web/classic/src/components/table/channels/modals/MultiKeyManageModal.jsx @@ -1,5 +1,5 @@ /* -Copyright (C) 2025 QuantumNous +Copyright (C) 2025 modelstoken This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as @@ -14,7 +14,7 @@ GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . -For commercial licensing, please contact support@quantumnous.com +For commercial licensing, please contact admin@modelstoken.com */ import React, { useState, useEffect } from 'react'; @@ -111,7 +111,7 @@ const MultiKeyManageModal = ({ visible, onCancel, channel, onRefresh }) => { } } catch (error) { console.error(error); - showError(t('获取密钥状态失败')); + showError(t('获取密钥状态失?)); } finally { setLoading(false); } @@ -130,7 +130,7 @@ const MultiKeyManageModal = ({ visible, onCancel, channel, onRefresh }) => { }); if (res.data.success) { - showSuccess(t('密钥已禁用')); + showSuccess(t('密钥已禁?)); await loadKeyStatus(currentPage, pageSize); // Reload current page onRefresh && onRefresh(); // Refresh parent component } else { @@ -156,7 +156,7 @@ const MultiKeyManageModal = ({ visible, onCancel, channel, onRefresh }) => { }); if (res.data.success) { - showSuccess(t('密钥已启用')); + showSuccess(t('密钥已启?)); await loadKeyStatus(currentPage, pageSize); // Reload current page onRefresh && onRefresh(); // Refresh parent component } else { @@ -180,7 +180,7 @@ const MultiKeyManageModal = ({ visible, onCancel, channel, onRefresh }) => { }); if (res.data.success) { - showSuccess(res.data.message || t('已启用所有密钥')); + showSuccess(res.data.message || t('已启用所有密?)); // Reset to first page after bulk operation setCurrentPage(1); await loadKeyStatus(1, pageSize); @@ -189,7 +189,7 @@ const MultiKeyManageModal = ({ visible, onCancel, channel, onRefresh }) => { showError(res.data.message); } } catch (error) { - showError(t('启用所有密钥失败')); + showError(t('启用所有密钥失?)); } finally { setOperationLoading((prev) => ({ ...prev, enable_all: false })); } @@ -206,7 +206,7 @@ const MultiKeyManageModal = ({ visible, onCancel, channel, onRefresh }) => { }); if (res.data.success) { - showSuccess(res.data.message || t('已禁用所有密钥')); + showSuccess(res.data.message || t('已禁用所有密?)); // Reset to first page after bulk operation setCurrentPage(1); await loadKeyStatus(1, pageSize); @@ -215,7 +215,7 @@ const MultiKeyManageModal = ({ visible, onCancel, channel, onRefresh }) => { showError(res.data.message); } } catch (error) { - showError(t('禁用所有密钥失败')); + showError(t('禁用所有密钥失?)); } finally { setOperationLoading((prev) => ({ ...prev, disable_all: false })); } @@ -260,7 +260,7 @@ const MultiKeyManageModal = ({ visible, onCancel, channel, onRefresh }) => { }); if (res.data.success) { - showSuccess(t('密钥已删除')); + showSuccess(t('密钥已删?)); await loadKeyStatus(currentPage, pageSize); // Reload current page onRefresh && onRefresh(); // Refresh parent component } else { @@ -331,13 +331,13 @@ const MultiKeyManageModal = ({ visible, onCancel, channel, onRefresh }) => { case 1: return ( - {t('已启用')} + {t('已启?)} ); case 2: return ( - {t('已禁用')} + {t('已禁?)} ); case 3: @@ -349,7 +349,7 @@ const MultiKeyManageModal = ({ visible, onCancel, channel, onRefresh }) => { default: return ( - {t('未知状态')} + {t('未知状?)} ); } @@ -372,7 +372,7 @@ const MultiKeyManageModal = ({ visible, onCancel, channel, onRefresh }) => { // ), // }, { - title: t('状态'), + title: t('状?), dataIndex: 'status', render: (status) => renderStatusTag(status), }, @@ -434,7 +434,7 @@ const MultiKeyManageModal = ({ visible, onCancel, channel, onRefresh }) => { )} handleDeleteKey(record.index)} okType={'danger'} position={'topRight'} @@ -456,7 +456,7 @@ const MultiKeyManageModal = ({ visible, onCancel, channel, onRefresh }) => { - {t('多密钥管理')} + {t('多密钥管?)} {channel?.name && ( {channel.name} @@ -500,7 +500,7 @@ const MultiKeyManageModal = ({ visible, onCancel, channel, onRefresh }) => { >
- {t('已启用')} + {t('已启?)}
{ value={statusFilter} onChange={handleStatusFilterChange} size='small' - placeholder={t('全部状态')} + placeholder={t('全部状?)} > - {t('全部状态')} + {t('全部状?)} - {t('已启用')} + {t('已启?)} {t('手动禁用')} @@ -641,7 +641,7 @@ const MultiKeyManageModal = ({ visible, onCancel, channel, onRefresh }) => { {manualDisabledCount + autoDisabledCount > 0 && ( @@ -671,7 +671,7 @@ const MultiKeyManageModal = ({ visible, onCancel, channel, onRefresh }) => { )} . -For commercial licensing, please contact support@quantumnous.com +For commercial licensing, please contact admin@modelstoken.com */ import React, { useState, useEffect } from 'react'; @@ -296,10 +296,10 @@ const OllamaModelModal = ({ } }; - // 拉取模型 (流式,支持进度) + // 拉取模型 (流式,支持进? const pullModel = async () => { if (!pullModelName.trim()) { - showError(t('请输入模型名称')); + showError(t('请输入模型名?)); return; } @@ -317,8 +317,7 @@ const OllamaModelModal = ({ }; try { - // 关闭之前的连接 - if (eventSource) { + // 关闭之前的连? if (eventSource) { eventSource.close(); setEventSource(null); } @@ -329,8 +328,7 @@ const OllamaModelModal = ({ }; setEventSource(closable); - // 使用 fetch 请求 SSE 流 - const authHeaders = authHeader(); + // 使用 fetch 请求 SSE ? const authHeaders = authHeader(); const userId = getUserIdFromLocalStorage(); const fetchHeaders = { 'Content-Type': 'application/json', @@ -357,8 +355,7 @@ const OllamaModelModal = ({ const decoder = new TextDecoder(); let buffer = ''; - // 读取 SSE 流 - const processStream = async () => { + // 读取 SSE ? const processStream = async () => { try { while (true) { const { done, value } = await reader.read(); @@ -414,8 +411,7 @@ const OllamaModelModal = ({ } } } - // 正常结束流 - setPullLoading(false); + // 正常结束? setPullLoading(false); setPullProgress(null); setEventSource(null); await refreshModels(); @@ -461,8 +457,7 @@ const OllamaModelModal = ({ showSuccess(t('模型删除成功')); await fetchModels(); // 重新获取模型列表 if (onModelsUpdate) { - onModelsUpdate({ silent: true }); // 通知父组件更新 - } + onModelsUpdate({ silent: true }); // 通知父组件更? } } else { showError(res.data.message || t('模型删除失败')); } @@ -492,8 +487,7 @@ const OllamaModelModal = ({ } }, [visible]); - // 组件加载时获取模型列表 - useEffect(() => { + // 组件加载时获取模型列? useEffect(() => { if (!visible) { return; } @@ -510,7 +504,7 @@ const OllamaModelModal = ({ channelInfo?.ollama_base_url, ]); - // 组件卸载时清理 EventSource + // 组件卸载时清?EventSource useEffect(() => { return () => { if (eventSource) { @@ -548,10 +542,10 @@ const OllamaModelModal = ({
- {/* 拉取新模型 */} + {/* 拉取新模?*/} - {t('拉取新模型')} + {t('拉取新模?)} @@ -575,12 +569,12 @@ const OllamaModelModal = ({ icon={} block > - {pullLoading ? t('拉取中...') : t('拉取模型')} + {pullLoading ? t('拉取?..') : t('拉取模型')} - {/* 进度条显示 */} + {/* 进度条显?*/} {pullProgress && (() => { const completedBytes = Number(pullProgress.completed) || 0; @@ -598,7 +592,7 @@ const OllamaModelModal = ({ const percentText = hasTotal && safePercent !== null ? `${safePercent.toFixed(0)}%` - : pullProgress.status || t('处理中'); + : pullProgress.status || t('处理?); return (
@@ -630,7 +624,7 @@ const OllamaModelModal = ({ ) : (
- {t('准备中...')} + {t('准备?..')}
)}
@@ -670,7 +664,7 @@ const OllamaModelModal = ({ onClick={handleSelectAll} disabled={models.length === 0} > - {t('全选')} + {t('全?)}