diff --git a/internal/admin/handler_accounts_crud.go b/internal/admin/handler_accounts_crud.go
index a0d64df..768e59e 100644
--- a/internal/admin/handler_accounts_crud.go
+++ b/internal/admin/handler_accounts_crud.go
@@ -1,115 +1,128 @@
-package admin
-
-import (
- "encoding/json"
- "fmt"
- "net/http"
- "strings"
-
- "github.com/go-chi/chi/v5"
-
- "ds2api/internal/config"
-)
-
-func (h *Handler) listAccounts(w http.ResponseWriter, r *http.Request) {
- page := intFromQuery(r, "page", 1)
- pageSize := intFromQuery(r, "page_size", 10)
- if page < 1 {
- page = 1
- }
- if pageSize < 1 {
- pageSize = 1
- }
- if pageSize > 100 {
- pageSize = 100
- }
- accounts := h.Store.Snapshot().Accounts
- total := len(accounts)
- reverseAccounts(accounts)
- totalPages := 1
- if total > 0 {
- totalPages = (total + pageSize - 1) / pageSize
- }
- start := (page - 1) * pageSize
- if start > total {
- start = total
- }
- end := start + pageSize
- if end > total {
- end = total
- }
- items := make([]map[string]any, 0, end-start)
- for _, acc := range accounts[start:end] {
- token := strings.TrimSpace(acc.Token)
- preview := ""
- if token != "" {
- if len(token) > 20 {
- preview = token[:20] + "..."
- } else {
- preview = token
- }
- }
- items = append(items, map[string]any{
- "identifier": acc.Identifier(),
- "email": acc.Email,
- "mobile": acc.Mobile,
- "has_password": acc.Password != "",
- "has_token": token != "",
- "token_preview": preview,
- "test_status": acc.TestStatus,
- })
- }
- writeJSON(w, http.StatusOK, map[string]any{"items": items, "total": total, "page": page, "page_size": pageSize, "total_pages": totalPages})
-}
-
-func (h *Handler) addAccount(w http.ResponseWriter, r *http.Request) {
- var req map[string]any
- _ = json.NewDecoder(r.Body).Decode(&req)
- acc := toAccount(req)
- if acc.Identifier() == "" {
- writeJSON(w, http.StatusBadRequest, map[string]any{"detail": "需要 email 或 mobile"})
- return
- }
- err := h.Store.Update(func(c *config.Config) error {
- for _, a := range c.Accounts {
- if acc.Email != "" && a.Email == acc.Email {
- return fmt.Errorf("邮箱已存在")
- }
- if acc.Mobile != "" && a.Mobile == acc.Mobile {
- return fmt.Errorf("手机号已存在")
- }
- }
- c.Accounts = append(c.Accounts, acc)
- return nil
- })
- if err != nil {
- writeJSON(w, http.StatusBadRequest, map[string]any{"detail": err.Error()})
- return
- }
- h.Pool.Reset()
- writeJSON(w, http.StatusOK, map[string]any{"success": true, "total_accounts": len(h.Store.Snapshot().Accounts)})
-}
-
-func (h *Handler) deleteAccount(w http.ResponseWriter, r *http.Request) {
- identifier := chi.URLParam(r, "identifier")
- err := h.Store.Update(func(c *config.Config) error {
- idx := -1
- for i, a := range c.Accounts {
- if accountMatchesIdentifier(a, identifier) {
- idx = i
- break
- }
- }
- if idx < 0 {
- return fmt.Errorf("账号不存在")
- }
- c.Accounts = append(c.Accounts[:idx], c.Accounts[idx+1:]...)
- return nil
- })
- if err != nil {
- writeJSON(w, http.StatusNotFound, map[string]any{"detail": err.Error()})
- return
- }
- h.Pool.Reset()
- writeJSON(w, http.StatusOK, map[string]any{"success": true, "total_accounts": len(h.Store.Snapshot().Accounts)})
-}
+package admin
+
+import (
+ "encoding/json"
+ "fmt"
+ "net/http"
+ "strings"
+
+ "github.com/go-chi/chi/v5"
+
+ "ds2api/internal/config"
+)
+
+func (h *Handler) listAccounts(w http.ResponseWriter, r *http.Request) {
+ page := intFromQuery(r, "page", 1)
+ pageSize := intFromQuery(r, "page_size", 10)
+ if page < 1 {
+ page = 1
+ }
+ if pageSize < 1 {
+ pageSize = 1
+ }
+ if pageSize > 100 {
+ pageSize = 100
+ }
+ accounts := h.Store.Snapshot().Accounts
+ reverseAccounts(accounts)
+ q := strings.TrimSpace(strings.ToLower(r.URL.Query().Get("q")))
+ if q != "" {
+ filtered := make([]config.Account, 0, len(accounts))
+ for _, acc := range accounts {
+ id := strings.ToLower(acc.Identifier())
+ if strings.Contains(id, q) ||
+ strings.Contains(strings.ToLower(acc.Email), q) ||
+ strings.Contains(strings.ToLower(acc.Mobile), q) {
+ filtered = append(filtered, acc)
+ }
+ }
+ accounts = filtered
+ }
+ total := len(accounts)
+ totalPages := 1
+ if total > 0 {
+ totalPages = (total + pageSize - 1) / pageSize
+ }
+ start := (page - 1) * pageSize
+ if start > total {
+ start = total
+ }
+ end := start + pageSize
+ if end > total {
+ end = total
+ }
+ items := make([]map[string]any, 0, end-start)
+ for _, acc := range accounts[start:end] {
+ token := strings.TrimSpace(acc.Token)
+ preview := ""
+ if token != "" {
+ if len(token) > 20 {
+ preview = token[:20] + "..."
+ } else {
+ preview = token
+ }
+ }
+ items = append(items, map[string]any{
+ "identifier": acc.Identifier(),
+ "email": acc.Email,
+ "mobile": acc.Mobile,
+ "has_password": acc.Password != "",
+ "has_token": token != "",
+ "token_preview": preview,
+ "test_status": acc.TestStatus,
+ })
+ }
+ writeJSON(w, http.StatusOK, map[string]any{"items": items, "total": total, "page": page, "page_size": pageSize, "total_pages": totalPages})
+}
+
+func (h *Handler) addAccount(w http.ResponseWriter, r *http.Request) {
+ var req map[string]any
+ _ = json.NewDecoder(r.Body).Decode(&req)
+ acc := toAccount(req)
+ if acc.Identifier() == "" {
+ writeJSON(w, http.StatusBadRequest, map[string]any{"detail": "需要 email 或 mobile"})
+ return
+ }
+ err := h.Store.Update(func(c *config.Config) error {
+ for _, a := range c.Accounts {
+ if acc.Email != "" && a.Email == acc.Email {
+ return fmt.Errorf("邮箱已存在")
+ }
+ if acc.Mobile != "" && a.Mobile == acc.Mobile {
+ return fmt.Errorf("手机号已存在")
+ }
+ }
+ c.Accounts = append(c.Accounts, acc)
+ return nil
+ })
+ if err != nil {
+ writeJSON(w, http.StatusBadRequest, map[string]any{"detail": err.Error()})
+ return
+ }
+ h.Pool.Reset()
+ writeJSON(w, http.StatusOK, map[string]any{"success": true, "total_accounts": len(h.Store.Snapshot().Accounts)})
+}
+
+func (h *Handler) deleteAccount(w http.ResponseWriter, r *http.Request) {
+ identifier := chi.URLParam(r, "identifier")
+ err := h.Store.Update(func(c *config.Config) error {
+ idx := -1
+ for i, a := range c.Accounts {
+ if accountMatchesIdentifier(a, identifier) {
+ idx = i
+ break
+ }
+ }
+ if idx < 0 {
+ return fmt.Errorf("账号不存在")
+ }
+ c.Accounts = append(c.Accounts[:idx], c.Accounts[idx+1:]...)
+ return nil
+ })
+ if err != nil {
+ writeJSON(w, http.StatusNotFound, map[string]any{"detail": err.Error()})
+ return
+ }
+ h.Pool.Reset()
+ writeJSON(w, http.StatusOK, map[string]any{"success": true, "total_accounts": len(h.Store.Snapshot().Accounts)})
+}
diff --git a/webui/src/features/account/AccountManagerContainer.jsx b/webui/src/features/account/AccountManagerContainer.jsx
index 558739d..9da3616 100644
--- a/webui/src/features/account/AccountManagerContainer.jsx
+++ b/webui/src/features/account/AccountManagerContainer.jsx
@@ -1,117 +1,121 @@
-import { useI18n } from '../../i18n'
-import { useAccountsData } from './useAccountsData'
-import { useAccountActions } from './useAccountActions'
-import QueueCards from './QueueCards'
-import ApiKeysPanel from './ApiKeysPanel'
-import AccountsTable from './AccountsTable'
-import AddKeyModal from './AddKeyModal'
-import AddAccountModal from './AddAccountModal'
-
-export default function AccountManagerContainer({ config, onRefresh, onMessage, authFetch }) {
- const { t } = useI18n()
- const apiFetch = authFetch || fetch
-
- const {
- queueStatus,
- keysExpanded,
- setKeysExpanded,
- accounts,
- page,
- pageSize,
- totalPages,
- totalAccounts,
- loadingAccounts,
- fetchAccounts,
- changePageSize,
- resolveAccountIdentifier,
- } = useAccountsData({ apiFetch })
-
- const {
- showAddKey,
- setShowAddKey,
- showAddAccount,
- setShowAddAccount,
- newKey,
- setNewKey,
- copiedKey,
- setCopiedKey,
- newAccount,
- setNewAccount,
- loading,
- testing,
- testingAll,
- batchProgress,
- addKey,
- deleteKey,
- addAccount,
- deleteAccount,
- testAccount,
- testAllAccounts,
- } = useAccountActions({
- apiFetch,
- t,
- onMessage,
- onRefresh,
- config,
- fetchAccounts,
- resolveAccountIdentifier,
- })
-
- return (
-
-
-
-
-
-
setShowAddAccount(true)}
- onTestAccount={testAccount}
- onDeleteAccount={deleteAccount}
- onPrevPage={() => fetchAccounts(page - 1)}
- onNextPage={() => fetchAccounts(page + 1)}
- onPageSizeChange={changePageSize}
- />
-
- setShowAddKey(false)}
- onAdd={addKey}
- />
-
- setShowAddAccount(false)}
- onAdd={addAccount}
- />
-
- )
-}
+import { useI18n } from '../../i18n'
+import { useAccountsData } from './useAccountsData'
+import { useAccountActions } from './useAccountActions'
+import QueueCards from './QueueCards'
+import ApiKeysPanel from './ApiKeysPanel'
+import AccountsTable from './AccountsTable'
+import AddKeyModal from './AddKeyModal'
+import AddAccountModal from './AddAccountModal'
+
+export default function AccountManagerContainer({ config, onRefresh, onMessage, authFetch }) {
+ const { t } = useI18n()
+ const apiFetch = authFetch || fetch
+
+ const {
+ queueStatus,
+ keysExpanded,
+ setKeysExpanded,
+ accounts,
+ page,
+ pageSize,
+ totalPages,
+ totalAccounts,
+ loadingAccounts,
+ fetchAccounts,
+ changePageSize,
+ resolveAccountIdentifier,
+ searchQuery,
+ handleSearchChange,
+ } = useAccountsData({ apiFetch })
+
+ const {
+ showAddKey,
+ setShowAddKey,
+ showAddAccount,
+ setShowAddAccount,
+ newKey,
+ setNewKey,
+ copiedKey,
+ setCopiedKey,
+ newAccount,
+ setNewAccount,
+ loading,
+ testing,
+ testingAll,
+ batchProgress,
+ addKey,
+ deleteKey,
+ addAccount,
+ deleteAccount,
+ testAccount,
+ testAllAccounts,
+ } = useAccountActions({
+ apiFetch,
+ t,
+ onMessage,
+ onRefresh,
+ config,
+ fetchAccounts,
+ resolveAccountIdentifier,
+ })
+
+ return (
+
+
+
+
+
+
setShowAddAccount(true)}
+ onTestAccount={testAccount}
+ onDeleteAccount={deleteAccount}
+ onPrevPage={() => fetchAccounts(page - 1)}
+ onNextPage={() => fetchAccounts(page + 1)}
+ onPageSizeChange={changePageSize}
+ searchQuery={searchQuery}
+ onSearchChange={handleSearchChange}
+ />
+
+ setShowAddKey(false)}
+ onAdd={addKey}
+ />
+
+ setShowAddAccount(false)}
+ onAdd={addAccount}
+ />
+
+ )
+}
diff --git a/webui/src/features/account/AccountsTable.jsx b/webui/src/features/account/AccountsTable.jsx
index 7f7c960..d7be383 100644
--- a/webui/src/features/account/AccountsTable.jsx
+++ b/webui/src/features/account/AccountsTable.jsx
@@ -1,182 +1,191 @@
-import { useState } from 'react'
-import { ChevronLeft, ChevronRight, Check, Copy, Play, Plus, Trash2 } from 'lucide-react'
-import clsx from 'clsx'
-
-export default function AccountsTable({
- t,
- accounts,
- loadingAccounts,
- testing,
- testingAll,
- batchProgress,
- totalAccounts,
- page,
- pageSize,
- totalPages,
- resolveAccountIdentifier,
- onTestAll,
- onShowAddAccount,
- onTestAccount,
- onDeleteAccount,
- onPrevPage,
- onNextPage,
- onPageSizeChange,
-}) {
- const [copiedId, setCopiedId] = useState(null)
-
- const copyId = (id) => {
- navigator.clipboard.writeText(id).then(() => {
- setCopiedId(id)
- setTimeout(() => setCopiedId(null), 1500)
- })
- }
- return (
-
-
-
-
{t('accountManager.accountsTitle')}
-
{t('accountManager.accountsDesc')}
-
-
-
-
-
-
-
- {testingAll && batchProgress.total > 0 && (
-
-
- {t('accountManager.testingAllAccounts')}
- {batchProgress.current} / {batchProgress.total}
-
-
- {batchProgress.results.length > 0 && (
-
- {batchProgress.results.map((r, i) => (
-
- {r.success ? '✓' : '✗'} {r.id}
-
- ))}
-
- )}
-
- )}
-
-
- {loadingAccounts ? (
-
{t('actions.loading')}
- ) : accounts.length > 0 ? (
- accounts.map((acc, i) => {
- const id = resolveAccountIdentifier(acc)
- return (
-
-
-
-
-
copyId(id)}
- >
- {id || '-'}
- {copiedId === id
- ?
- :
- }
-
-
- {acc.test_status === 'failed' ? t('accountManager.testStatusFailed') : (acc.test_status === 'ok' || acc.has_token) ? t('accountManager.sessionActive') : t('accountManager.reauthRequired')}
- {acc.token_preview && (
-
- {acc.token_preview}
-
- )}
-
-
-
-
-
-
-
-
- )
- })
- ) : (
-
{t('accountManager.noAccounts')}
- )}
-
-
- {totalPages > 1 && (
-
-
-
- {t('accountManager.pageInfo', { current: page, total: totalPages, count: totalAccounts })}
-
-
-
-
-
- {page} / {totalPages}
-
-
-
- )}
-
- )
-}
+import { useState } from 'react'
+import { ChevronLeft, ChevronRight, Check, Copy, Play, Plus, Trash2 } from 'lucide-react'
+import clsx from 'clsx'
+
+export default function AccountsTable({
+ t,
+ accounts,
+ loadingAccounts,
+ testing,
+ testingAll,
+ batchProgress,
+ totalAccounts,
+ page,
+ pageSize,
+ totalPages,
+ resolveAccountIdentifier,
+ onTestAll,
+ onShowAddAccount,
+ onTestAccount,
+ onDeleteAccount,
+ onPrevPage,
+ onNextPage,
+ onPageSizeChange,
+ searchQuery,
+ onSearchChange,
+}) {
+ const [copiedId, setCopiedId] = useState(null)
+
+ const copyId = (id) => {
+ navigator.clipboard.writeText(id).then(() => {
+ setCopiedId(id)
+ setTimeout(() => setCopiedId(null), 1500)
+ })
+ }
+ return (
+
+
+
+
{t('accountManager.accountsTitle')}
+
{t('accountManager.accountsDesc')}
+
+
+
onSearchChange(e.target.value)}
+ placeholder={t('accountManager.searchPlaceholder')}
+ className="px-3 py-1.5 text-sm bg-muted border border-border rounded-lg focus:outline-none focus:ring-1 focus:ring-ring placeholder:text-muted-foreground"
+ />
+
+
+
+
+
+ {testingAll && batchProgress.total > 0 && (
+
+
+ {t('accountManager.testingAllAccounts')}
+ {batchProgress.current} / {batchProgress.total}
+
+
+ {batchProgress.results.length > 0 && (
+
+ {batchProgress.results.map((r, i) => (
+
+ {r.success ? '✓' : '✗'} {r.id}
+
+ ))}
+
+ )}
+
+ )}
+
+
+ {loadingAccounts ? (
+
{t('actions.loading')}
+ ) : accounts.length > 0 ? (
+ accounts.map((acc, i) => {
+ const id = resolveAccountIdentifier(acc)
+ return (
+
+
+
+
+
copyId(id)}
+ >
+ {id || '-'}
+ {copiedId === id
+ ?
+ :
+ }
+
+
+ {acc.test_status === 'failed' ? t('accountManager.testStatusFailed') : (acc.test_status === 'ok' || acc.has_token) ? t('accountManager.sessionActive') : t('accountManager.reauthRequired')}
+ {acc.token_preview && (
+
+ {acc.token_preview}
+
+ )}
+
+
+
+
+
+
+
+
+ )
+ })
+ ) : (
+
{searchQuery ? t('accountManager.searchNoResults') : t('accountManager.noAccounts')}
+ )}
+
+
+ {totalPages > 1 && (
+
+
+
+ {t('accountManager.pageInfo', { current: page, total: totalPages, count: totalAccounts })}
+
+
+
+
+
+ {page} / {totalPages}
+
+
+
+ )}
+
+ )
+}
diff --git a/webui/src/features/account/useAccountsData.js b/webui/src/features/account/useAccountsData.js
index 90c56e0..3c904f3 100644
--- a/webui/src/features/account/useAccountsData.js
+++ b/webui/src/features/account/useAccountsData.js
@@ -1,75 +1,86 @@
-import { useEffect, useState } from 'react'
-
-export function useAccountsData({ apiFetch }) {
- const [queueStatus, setQueueStatus] = useState(null)
- const [keysExpanded, setKeysExpanded] = useState(false)
-
- const [accounts, setAccounts] = useState([])
- const [page, setPage] = useState(1)
- const [pageSize, setPageSize] = useState(10)
- const [totalPages, setTotalPages] = useState(1)
- const [totalAccounts, setTotalAccounts] = useState(0)
- const [loadingAccounts, setLoadingAccounts] = useState(false)
-
- const resolveAccountIdentifier = (acc) => {
- if (!acc || typeof acc !== 'object') return ''
- return String(acc.identifier || acc.email || acc.mobile || '').trim()
- }
-
- const fetchAccounts = async (targetPage = page, targetPageSize = pageSize) => {
- setLoadingAccounts(true)
- try {
- const res = await apiFetch(`/admin/accounts?page=${targetPage}&page_size=${targetPageSize}`)
- if (res.ok) {
- const data = await res.json()
- setAccounts(data.items || [])
- setTotalPages(data.total_pages || 1)
- setTotalAccounts(data.total || 0)
- setPage(data.page || 1)
- }
- } catch (e) {
- console.error('Failed to fetch accounts:', e)
- } finally {
- setLoadingAccounts(false)
- }
- }
-
- const changePageSize = (newSize) => {
- setPageSize(newSize)
- fetchAccounts(1, newSize)
- }
-
- const fetchQueueStatus = async () => {
- try {
- const res = await apiFetch('/admin/queue/status')
- if (res.ok) {
- const data = await res.json()
- setQueueStatus(data)
- }
- } catch (e) {
- console.error('Failed to fetch queue status:', e)
- }
- }
-
- useEffect(() => {
- fetchAccounts()
- fetchQueueStatus()
- const interval = setInterval(fetchQueueStatus, 5000)
- return () => clearInterval(interval)
- }, [])
-
- return {
- queueStatus,
- keysExpanded,
- setKeysExpanded,
- accounts,
- page,
- pageSize,
- totalPages,
- totalAccounts,
- loadingAccounts,
- fetchAccounts,
- changePageSize,
- resolveAccountIdentifier,
- }
-}
+import { useEffect, useState } from 'react'
+
+export function useAccountsData({ apiFetch }) {
+ const [queueStatus, setQueueStatus] = useState(null)
+ const [keysExpanded, setKeysExpanded] = useState(false)
+
+ const [accounts, setAccounts] = useState([])
+ const [page, setPage] = useState(1)
+ const [pageSize, setPageSize] = useState(10)
+ const [totalPages, setTotalPages] = useState(1)
+ const [totalAccounts, setTotalAccounts] = useState(0)
+ const [loadingAccounts, setLoadingAccounts] = useState(false)
+
+ const resolveAccountIdentifier = (acc) => {
+ if (!acc || typeof acc !== 'object') return ''
+ return String(acc.identifier || acc.email || acc.mobile || '').trim()
+ }
+
+ const [searchQuery, setSearchQuery] = useState('')
+
+ const fetchAccounts = async (targetPage = page, targetPageSize = pageSize, targetQuery = searchQuery) => {
+ setLoadingAccounts(true)
+ try {
+ let url = `/admin/accounts?page=${targetPage}&page_size=${targetPageSize}`
+ if (targetQuery.trim()) url += `&q=${encodeURIComponent(targetQuery.trim())}`
+ const res = await apiFetch(url)
+ if (res.ok) {
+ const data = await res.json()
+ setAccounts(data.items || [])
+ setTotalPages(data.total_pages || 1)
+ setTotalAccounts(data.total || 0)
+ setPage(data.page || 1)
+ }
+ } catch (e) {
+ console.error('Failed to fetch accounts:', e)
+ } finally {
+ setLoadingAccounts(false)
+ }
+ }
+
+ const changePageSize = (newSize) => {
+ setPageSize(newSize)
+ fetchAccounts(1, newSize)
+ }
+
+ const handleSearchChange = (query) => {
+ setSearchQuery(query)
+ fetchAccounts(1, pageSize, query)
+ }
+
+ const fetchQueueStatus = async () => {
+ try {
+ const res = await apiFetch('/admin/queue/status')
+ if (res.ok) {
+ const data = await res.json()
+ setQueueStatus(data)
+ }
+ } catch (e) {
+ console.error('Failed to fetch queue status:', e)
+ }
+ }
+
+ useEffect(() => {
+ fetchAccounts()
+ fetchQueueStatus()
+ const interval = setInterval(fetchQueueStatus, 5000)
+ return () => clearInterval(interval)
+ }, [])
+
+ return {
+ queueStatus,
+ keysExpanded,
+ setKeysExpanded,
+ accounts,
+ page,
+ pageSize,
+ totalPages,
+ totalAccounts,
+ loadingAccounts,
+ fetchAccounts,
+ changePageSize,
+ resolveAccountIdentifier,
+ searchQuery,
+ handleSearchChange,
+ }
+}
diff --git a/webui/src/locales/en.json b/webui/src/locales/en.json
index bd38fd0..499509e 100644
--- a/webui/src/locales/en.json
+++ b/webui/src/locales/en.json
@@ -1,295 +1,297 @@
-{
- "language": {
- "label": "Language",
- "english": "English",
- "chinese": "中文"
- },
- "nav": {
- "accounts": {
- "label": "Account Management",
- "desc": "Manage the DeepSeek account pool"
- },
- "test": {
- "label": "API Test",
- "desc": "Test API connectivity and responses"
- },
- "import": {
- "label": "Batch Import",
- "desc": "Bulk import account configuration"
- },
- "vercel": {
- "label": "Vercel Sync",
- "desc": "Sync configuration to Vercel"
- },
- "settings": {
- "label": "Settings",
- "desc": "Edit runtime and security settings online"
- }
- },
- "sidebar": {
- "onlineAdminConsole": "Online Admin Console",
- "systemStatus": "System Status",
- "statusOnline": "Online",
- "accounts": "Accounts",
- "keys": "Keys",
- "signOut": "Sign out"
- },
- "auth": {
- "expired": "Authentication expired. Please sign in again.",
- "checking": "Checking authentication status..."
- },
- "errors": {
- "fetchConfig": "Failed to fetch configuration: {error}"
- },
- "actions": {
- "cancel": "Cancel",
- "add": "Add",
- "delete": "Delete",
- "copy": "Copy",
- "generate": "Generate",
- "test": "Test",
- "testing": "Testing...",
- "loading": "Loading..."
- },
- "messages": {
- "deleted": "Deleted successfully",
- "deleteFailed": "Delete failed",
- "failedToAdd": "Failed to add",
- "networkError": "Network error.",
- "requestFailed": "Request failed.",
- "generationStopped": "Generation stopped.",
- "invalidJson": "Invalid JSON format.",
- "importFailed": "Import failed.",
- "copyFailed": "Copy failed."
- },
- "landing": {
- "adminConsole": "Admin Console",
- "apiStatus": "API Status",
- "features": {
- "compatibility": {
- "title": "Full Compatibility",
- "desc": "OpenAI & Claude format support"
- },
- "loadBalancing": {
- "title": "Load Balancing",
- "desc": "Smart rotation with stable throughput"
- },
- "reasoning": {
- "title": "Deep Reasoning",
- "desc": "Expose reasoning traces when enabled"
- },
- "search": {
- "title": "Web Search",
- "desc": "Integrated native web search"
- }
- }
- },
- "accountManager": {
- "addKeySuccess": "API key added successfully.",
- "addAccountSuccess": "Account added successfully.",
- "requiredFields": "Password and email/mobile are required.",
- "deleteKeyConfirm": "Are you sure you want to delete this API key?",
- "deleteAccountConfirm": "Are you sure you want to delete this account?",
- "invalidIdentifier": "Invalid account identifier. Operation aborted.",
- "testAllConfirm": "Test API connectivity for all accounts?",
- "testAllCompleted": "Completed: {success}/{total} available",
- "testFailed": "Test failed: {error}",
- "available": "Available",
- "inUse": "In use",
- "totalPool": "Total pool",
- "accountsUnit": "accounts",
- "threadsUnit": "threads",
- "apiKeysTitle": "API Keys",
- "apiKeysDesc": "Manage the API access key pool",
- "addKey": "Add key",
- "copied": "Copied",
- "copyKeyTitle": "Copy key",
- "deleteKeyTitle": "Delete key",
- "noApiKeys": "No API keys found.",
- "accountsTitle": "DeepSeek Accounts",
- "accountsDesc": "Manage the DeepSeek account pool",
- "testAll": "Test all",
- "addAccount": "Add account",
- "testingAllAccounts": "Testing all accounts...",
- "sessionActive": "Session active",
- "reauthRequired": "Re-auth required",
- "testStatusFailed": "Last test failed",
- "noAccounts": "No accounts found.",
- "modalAddKeyTitle": "Add API key",
- "newKeyLabel": "New key value",
- "newKeyPlaceholder": "Enter a custom API key",
- "generate": "Generate",
- "generateHint": "Click Generate to create a random key.",
- "addKeyLoading": "Adding...",
- "addKeyAction": "Add key",
- "modalAddAccountTitle": "Add DeepSeek account",
- "emailOptional": "Email (optional)",
- "mobileOptional": "Mobile (optional)",
- "passwordLabel": "Password",
- "passwordPlaceholder": "Account password",
- "addAccountLoading": "Adding...",
- "addAccountAction": "Add account",
- "pageInfo": "Page {current}/{total}, {count} accounts total"
- },
- "apiTester": {
- "defaultMessage": "Hello, please introduce yourself in one sentence.",
- "models": {
- "chat": "Non-reasoning model",
- "reasoner": "Reasoning model",
- "chatSearch": "Non-reasoning model (with search)",
- "reasonerSearch": "Reasoning model (with search)"
- },
- "missingApiKey": "Please provide an API key.",
- "requestFailed": "Request failed.",
- "networkError": "Network error: {error}",
- "testSuccess": "{account}: Test successful ({time}ms)",
- "config": "Configuration",
- "modelLabel": "Model",
- "streamMode": "Streaming",
- "accountSelector": "Account",
- "autoRandom": "🤖 Auto / Random",
- "apiKeyOptional": "API Key (optional)",
- "apiKeyDefault": "Default: ...{suffix}",
- "apiKeyPlaceholder": "Enter a custom key",
- "modeManaged": "Managed key mode (uses account pool).",
- "modeDirect": "Direct token mode (requires a valid DeepSeek token).",
- "statusError": "Error",
- "reasoningTrace": "Reasoning Trace",
- "generating": "Generating response...",
- "enterMessage": "Enter a message...",
- "adminConsoleLabel": "DeepSeek admin console"
- },
- "batchImport": {
- "templates": {
- "full": {
- "name": "Full configuration template",
- "desc": "Includes keys, accounts, and model mapping"
- },
- "emailOnly": {
- "name": "Email-only accounts",
- "desc": "Batch import accounts using email login"
- },
- "mobileOnly": {
- "name": "Mobile-only accounts",
- "desc": "Batch import accounts using mobile login"
- },
- "keysOnly": {
- "name": "API keys only",
- "desc": "Add API access keys only"
- }
- },
- "enterJson": "Please provide JSON configuration content.",
- "importSuccess": "Import successful: {keys} keys, {accounts} accounts",
- "templateLoaded": "Template loaded: {name}",
- "currentConfigLoaded": "Current configuration loaded.",
- "fetchConfigFailed": "Failed to fetch configuration.",
- "copySuccess": "Base64 configuration copied to clipboard.",
- "quickTemplates": "Quick Templates",
- "dataExport": "Data Export",
- "dataExportDesc": "Copy the Base64-encoded configuration for Vercel environment variables.",
- "copyBase64": "Copy Base64 config",
- "copied": "Copied",
- "variableName": "Variable name",
- "jsonEditor": "JSON Editor",
- "loadCurrentConfig": "Load current config",
- "applyConfig": "Apply config",
- "importing": "Importing...",
- "importComplete": "Import complete",
- "importSummary": "Imported {keys} API keys and updated {accounts} accounts."
- },
- "settings": {
- "loadFailed": "Failed to load settings.",
- "nonJsonResponse": "Unexpected non-JSON response from server (status: {status}).",
- "save": "Save settings",
- "saving": "Saving...",
- "saveSuccess": "Settings saved and hot reloaded.",
- "saveFailed": "Failed to save settings.",
- "securityTitle": "Security",
- "jwtExpireHours": "JWT expiry (hours)",
- "newPassword": "New admin password",
- "newPasswordPlaceholder": "Enter new password (min 4 chars)",
- "updatePassword": "Update password",
- "updating": "Updating...",
- "passwordTooShort": "Password must be at least 4 characters.",
- "passwordUpdated": "Password updated. Please sign in again.",
- "passwordUpdateFailed": "Failed to update password.",
- "runtimeTitle": "Concurrency & Queue",
- "accountMaxInflight": "Per-account max inflight",
- "accountMaxQueue": "Account max queue size",
- "globalMaxInflight": "Global max inflight",
- "behaviorTitle": "Behavior",
- "toolcallMode": "Toolcall mode",
- "earlyEmitConfidence": "Early emit confidence",
- "responsesTTL": "Responses store TTL (seconds)",
- "embeddingsProvider": "Embeddings provider",
- "modelTitle": "Model mapping",
- "claudeMapping": "Claude mapping (JSON)",
- "modelAliases": "Model aliases (JSON)",
- "backupTitle": "Backup & Restore",
- "loadExport": "Load current export",
- "importModeMerge": "Merge import (default)",
- "importModeReplace": "Replace all import",
- "importNow": "Import now",
- "importing": "Importing...",
- "importPlaceholder": "Paste config JSON to import",
- "importEmpty": "Please input import JSON.",
- "importInvalidJson": "Import JSON is invalid.",
- "importFailed": "Import failed.",
- "importSuccess": "Config imported (mode: {mode}).",
- "exportFailed": "Export failed.",
- "exportLoaded": "Current export loaded.",
- "exportJson": "Export JSON",
- "invalidJsonField": "{field} is not a valid JSON object.",
- "defaultPasswordWarning": "You are using the default admin password \"admin\". Please change it.",
- "vercelSyncHint": "Configuration changed. For Vercel deployments, sync manually in Vercel Sync and redeploy.",
- "autoFetchPaused": "Auto loading paused after {count} failures: {error}",
- "retryLoad": "Retry now"
- },
- "login": {
- "welcome": "Welcome back",
- "subtitle": "Enter your admin key to continue",
- "adminKeyLabel": "Admin key",
- "adminKeyPlaceholder": "Enter your admin key...",
- "rememberSession": "Remember this session",
- "signIn": "Sign in",
- "secureConnection": "Secure connection",
- "adminPortal": "DS2API admin portal",
- "signInFailed": "Sign-in failed.",
- "networkError": "Network error: {error}"
- },
- "vercel": {
- "tokenRequired": "Vercel access token is required.",
- "projectRequired": "Project ID is required.",
- "syncFailed": "Sync failed.",
- "networkError": "Network error.",
- "title": "Vercel Deployment",
- "description": "Sync the current keys and accounts directly to Vercel environment variables.",
- "tokenLabel": "Vercel Access Token",
- "getToken": "Get token",
- "tokenPlaceholderPreconfig": "Using preconfigured token",
- "tokenPlaceholder": "Enter Vercel access token",
- "projectIdLabel": "Project ID",
- "projectIdHint": "Find it in Project Settings → General.",
- "teamIdLabel": "Team ID",
- "optional": "optional",
- "syncing": "Syncing...",
- "syncRedeploy": "Sync & redeploy",
- "redeployHint": "This triggers a Vercel redeploy and usually takes 30–60 seconds.",
- "syncSucceeded": "Sync succeeded",
- "syncFailedLabel": "Sync failed",
- "openDeployment": "Open deployment",
- "statusSynced": "Synced",
- "statusNotSynced": "Not synced",
- "statusNeverSynced": "Never synced",
- "lastSyncTime": "Last sync: {time}",
- "pollPaused": "Status polling paused after {count} failures.",
- "manualRefresh": "Refresh manually",
- "howItWorks": "How it works",
- "steps": {
- "one": "The current configuration (keys and accounts) is exported as JSON.",
- "two": "The JSON is Base64-encoded for safe formatting.",
- "three": "Update the env var in Vercel:",
- "four": "Trigger a redeploy to apply the updated environment variables."
- }
- }
-}
+{
+ "language": {
+ "label": "Language",
+ "english": "English",
+ "chinese": "中文"
+ },
+ "nav": {
+ "accounts": {
+ "label": "Account Management",
+ "desc": "Manage the DeepSeek account pool"
+ },
+ "test": {
+ "label": "API Test",
+ "desc": "Test API connectivity and responses"
+ },
+ "import": {
+ "label": "Batch Import",
+ "desc": "Bulk import account configuration"
+ },
+ "vercel": {
+ "label": "Vercel Sync",
+ "desc": "Sync configuration to Vercel"
+ },
+ "settings": {
+ "label": "Settings",
+ "desc": "Edit runtime and security settings online"
+ }
+ },
+ "sidebar": {
+ "onlineAdminConsole": "Online Admin Console",
+ "systemStatus": "System Status",
+ "statusOnline": "Online",
+ "accounts": "Accounts",
+ "keys": "Keys",
+ "signOut": "Sign out"
+ },
+ "auth": {
+ "expired": "Authentication expired. Please sign in again.",
+ "checking": "Checking authentication status..."
+ },
+ "errors": {
+ "fetchConfig": "Failed to fetch configuration: {error}"
+ },
+ "actions": {
+ "cancel": "Cancel",
+ "add": "Add",
+ "delete": "Delete",
+ "copy": "Copy",
+ "generate": "Generate",
+ "test": "Test",
+ "testing": "Testing...",
+ "loading": "Loading..."
+ },
+ "messages": {
+ "deleted": "Deleted successfully",
+ "deleteFailed": "Delete failed",
+ "failedToAdd": "Failed to add",
+ "networkError": "Network error.",
+ "requestFailed": "Request failed.",
+ "generationStopped": "Generation stopped.",
+ "invalidJson": "Invalid JSON format.",
+ "importFailed": "Import failed.",
+ "copyFailed": "Copy failed."
+ },
+ "landing": {
+ "adminConsole": "Admin Console",
+ "apiStatus": "API Status",
+ "features": {
+ "compatibility": {
+ "title": "Full Compatibility",
+ "desc": "OpenAI & Claude format support"
+ },
+ "loadBalancing": {
+ "title": "Load Balancing",
+ "desc": "Smart rotation with stable throughput"
+ },
+ "reasoning": {
+ "title": "Deep Reasoning",
+ "desc": "Expose reasoning traces when enabled"
+ },
+ "search": {
+ "title": "Web Search",
+ "desc": "Integrated native web search"
+ }
+ }
+ },
+ "accountManager": {
+ "addKeySuccess": "API key added successfully.",
+ "addAccountSuccess": "Account added successfully.",
+ "requiredFields": "Password and email/mobile are required.",
+ "deleteKeyConfirm": "Are you sure you want to delete this API key?",
+ "deleteAccountConfirm": "Are you sure you want to delete this account?",
+ "invalidIdentifier": "Invalid account identifier. Operation aborted.",
+ "testAllConfirm": "Test API connectivity for all accounts?",
+ "testAllCompleted": "Completed: {success}/{total} available",
+ "testFailed": "Test failed: {error}",
+ "available": "Available",
+ "inUse": "In use",
+ "totalPool": "Total pool",
+ "accountsUnit": "accounts",
+ "threadsUnit": "threads",
+ "apiKeysTitle": "API Keys",
+ "apiKeysDesc": "Manage the API access key pool",
+ "addKey": "Add key",
+ "copied": "Copied",
+ "copyKeyTitle": "Copy key",
+ "deleteKeyTitle": "Delete key",
+ "noApiKeys": "No API keys found.",
+ "accountsTitle": "DeepSeek Accounts",
+ "accountsDesc": "Manage the DeepSeek account pool",
+ "testAll": "Test all",
+ "addAccount": "Add account",
+ "testingAllAccounts": "Testing all accounts...",
+ "sessionActive": "Session active",
+ "reauthRequired": "Re-auth required",
+ "testStatusFailed": "Last test failed",
+ "noAccounts": "No accounts found.",
+ "modalAddKeyTitle": "Add API key",
+ "newKeyLabel": "New key value",
+ "newKeyPlaceholder": "Enter a custom API key",
+ "generate": "Generate",
+ "generateHint": "Click Generate to create a random key.",
+ "addKeyLoading": "Adding...",
+ "addKeyAction": "Add key",
+ "modalAddAccountTitle": "Add DeepSeek account",
+ "emailOptional": "Email (optional)",
+ "mobileOptional": "Mobile (optional)",
+ "passwordLabel": "Password",
+ "passwordPlaceholder": "Account password",
+ "addAccountLoading": "Adding...",
+ "addAccountAction": "Add account",
+ "pageInfo": "Page {current}/{total}, {count} accounts total",
+ "searchPlaceholder": "Search accounts...",
+ "searchNoResults": "No accounts match your search"
+ },
+ "apiTester": {
+ "defaultMessage": "Hello, please introduce yourself in one sentence.",
+ "models": {
+ "chat": "Non-reasoning model",
+ "reasoner": "Reasoning model",
+ "chatSearch": "Non-reasoning model (with search)",
+ "reasonerSearch": "Reasoning model (with search)"
+ },
+ "missingApiKey": "Please provide an API key.",
+ "requestFailed": "Request failed.",
+ "networkError": "Network error: {error}",
+ "testSuccess": "{account}: Test successful ({time}ms)",
+ "config": "Configuration",
+ "modelLabel": "Model",
+ "streamMode": "Streaming",
+ "accountSelector": "Account",
+ "autoRandom": "🤖 Auto / Random",
+ "apiKeyOptional": "API Key (optional)",
+ "apiKeyDefault": "Default: ...{suffix}",
+ "apiKeyPlaceholder": "Enter a custom key",
+ "modeManaged": "Managed key mode (uses account pool).",
+ "modeDirect": "Direct token mode (requires a valid DeepSeek token).",
+ "statusError": "Error",
+ "reasoningTrace": "Reasoning Trace",
+ "generating": "Generating response...",
+ "enterMessage": "Enter a message...",
+ "adminConsoleLabel": "DeepSeek admin console"
+ },
+ "batchImport": {
+ "templates": {
+ "full": {
+ "name": "Full configuration template",
+ "desc": "Includes keys, accounts, and model mapping"
+ },
+ "emailOnly": {
+ "name": "Email-only accounts",
+ "desc": "Batch import accounts using email login"
+ },
+ "mobileOnly": {
+ "name": "Mobile-only accounts",
+ "desc": "Batch import accounts using mobile login"
+ },
+ "keysOnly": {
+ "name": "API keys only",
+ "desc": "Add API access keys only"
+ }
+ },
+ "enterJson": "Please provide JSON configuration content.",
+ "importSuccess": "Import successful: {keys} keys, {accounts} accounts",
+ "templateLoaded": "Template loaded: {name}",
+ "currentConfigLoaded": "Current configuration loaded.",
+ "fetchConfigFailed": "Failed to fetch configuration.",
+ "copySuccess": "Base64 configuration copied to clipboard.",
+ "quickTemplates": "Quick Templates",
+ "dataExport": "Data Export",
+ "dataExportDesc": "Copy the Base64-encoded configuration for Vercel environment variables.",
+ "copyBase64": "Copy Base64 config",
+ "copied": "Copied",
+ "variableName": "Variable name",
+ "jsonEditor": "JSON Editor",
+ "loadCurrentConfig": "Load current config",
+ "applyConfig": "Apply config",
+ "importing": "Importing...",
+ "importComplete": "Import complete",
+ "importSummary": "Imported {keys} API keys and updated {accounts} accounts."
+ },
+ "settings": {
+ "loadFailed": "Failed to load settings.",
+ "nonJsonResponse": "Unexpected non-JSON response from server (status: {status}).",
+ "save": "Save settings",
+ "saving": "Saving...",
+ "saveSuccess": "Settings saved and hot reloaded.",
+ "saveFailed": "Failed to save settings.",
+ "securityTitle": "Security",
+ "jwtExpireHours": "JWT expiry (hours)",
+ "newPassword": "New admin password",
+ "newPasswordPlaceholder": "Enter new password (min 4 chars)",
+ "updatePassword": "Update password",
+ "updating": "Updating...",
+ "passwordTooShort": "Password must be at least 4 characters.",
+ "passwordUpdated": "Password updated. Please sign in again.",
+ "passwordUpdateFailed": "Failed to update password.",
+ "runtimeTitle": "Concurrency & Queue",
+ "accountMaxInflight": "Per-account max inflight",
+ "accountMaxQueue": "Account max queue size",
+ "globalMaxInflight": "Global max inflight",
+ "behaviorTitle": "Behavior",
+ "toolcallMode": "Toolcall mode",
+ "earlyEmitConfidence": "Early emit confidence",
+ "responsesTTL": "Responses store TTL (seconds)",
+ "embeddingsProvider": "Embeddings provider",
+ "modelTitle": "Model mapping",
+ "claudeMapping": "Claude mapping (JSON)",
+ "modelAliases": "Model aliases (JSON)",
+ "backupTitle": "Backup & Restore",
+ "loadExport": "Load current export",
+ "importModeMerge": "Merge import (default)",
+ "importModeReplace": "Replace all import",
+ "importNow": "Import now",
+ "importing": "Importing...",
+ "importPlaceholder": "Paste config JSON to import",
+ "importEmpty": "Please input import JSON.",
+ "importInvalidJson": "Import JSON is invalid.",
+ "importFailed": "Import failed.",
+ "importSuccess": "Config imported (mode: {mode}).",
+ "exportFailed": "Export failed.",
+ "exportLoaded": "Current export loaded.",
+ "exportJson": "Export JSON",
+ "invalidJsonField": "{field} is not a valid JSON object.",
+ "defaultPasswordWarning": "You are using the default admin password \"admin\". Please change it.",
+ "vercelSyncHint": "Configuration changed. For Vercel deployments, sync manually in Vercel Sync and redeploy.",
+ "autoFetchPaused": "Auto loading paused after {count} failures: {error}",
+ "retryLoad": "Retry now"
+ },
+ "login": {
+ "welcome": "Welcome back",
+ "subtitle": "Enter your admin key to continue",
+ "adminKeyLabel": "Admin key",
+ "adminKeyPlaceholder": "Enter your admin key...",
+ "rememberSession": "Remember this session",
+ "signIn": "Sign in",
+ "secureConnection": "Secure connection",
+ "adminPortal": "DS2API admin portal",
+ "signInFailed": "Sign-in failed.",
+ "networkError": "Network error: {error}"
+ },
+ "vercel": {
+ "tokenRequired": "Vercel access token is required.",
+ "projectRequired": "Project ID is required.",
+ "syncFailed": "Sync failed.",
+ "networkError": "Network error.",
+ "title": "Vercel Deployment",
+ "description": "Sync the current keys and accounts directly to Vercel environment variables.",
+ "tokenLabel": "Vercel Access Token",
+ "getToken": "Get token",
+ "tokenPlaceholderPreconfig": "Using preconfigured token",
+ "tokenPlaceholder": "Enter Vercel access token",
+ "projectIdLabel": "Project ID",
+ "projectIdHint": "Find it in Project Settings → General.",
+ "teamIdLabel": "Team ID",
+ "optional": "optional",
+ "syncing": "Syncing...",
+ "syncRedeploy": "Sync & redeploy",
+ "redeployHint": "This triggers a Vercel redeploy and usually takes 30–60 seconds.",
+ "syncSucceeded": "Sync succeeded",
+ "syncFailedLabel": "Sync failed",
+ "openDeployment": "Open deployment",
+ "statusSynced": "Synced",
+ "statusNotSynced": "Not synced",
+ "statusNeverSynced": "Never synced",
+ "lastSyncTime": "Last sync: {time}",
+ "pollPaused": "Status polling paused after {count} failures.",
+ "manualRefresh": "Refresh manually",
+ "howItWorks": "How it works",
+ "steps": {
+ "one": "The current configuration (keys and accounts) is exported as JSON.",
+ "two": "The JSON is Base64-encoded for safe formatting.",
+ "three": "Update the env var in Vercel:",
+ "four": "Trigger a redeploy to apply the updated environment variables."
+ }
+ }
+}
diff --git a/webui/src/locales/zh.json b/webui/src/locales/zh.json
index 1206f89..27150b4 100644
--- a/webui/src/locales/zh.json
+++ b/webui/src/locales/zh.json
@@ -1,295 +1,297 @@
-{
- "language": {
- "label": "语言",
- "english": "English",
- "chinese": "中文"
- },
- "nav": {
- "accounts": {
- "label": "账号管理",
- "desc": "管理 DeepSeek 账号池"
- },
- "test": {
- "label": "API 测试",
- "desc": "测试 API 连接与响应"
- },
- "import": {
- "label": "批量导入",
- "desc": "批量导入账号配置"
- },
- "vercel": {
- "label": "Vercel 同步",
- "desc": "同步配置到 Vercel"
- },
- "settings": {
- "label": "设置中心",
- "desc": "在线修改系统设置与配置"
- }
- },
- "sidebar": {
- "onlineAdminConsole": "在线管理面板",
- "systemStatus": "系统状态",
- "statusOnline": "在线",
- "accounts": "账号",
- "keys": "密钥",
- "signOut": "退出登录"
- },
- "auth": {
- "expired": "认证已过期,请重新登录",
- "checking": "正在检查登录状态..."
- },
- "errors": {
- "fetchConfig": "获取配置失败: {error}"
- },
- "actions": {
- "cancel": "取消",
- "add": "添加",
- "delete": "删除",
- "copy": "复制",
- "generate": "生成",
- "test": "测试",
- "testing": "正在测试...",
- "loading": "加载中..."
- },
- "messages": {
- "deleted": "删除成功",
- "deleteFailed": "删除失败",
- "failedToAdd": "添加失败",
- "networkError": "网络错误",
- "requestFailed": "请求失败",
- "generationStopped": "已停止生成",
- "invalidJson": "无效的 JSON 格式",
- "importFailed": "导入失败",
- "copyFailed": "复制失败"
- },
- "landing": {
- "adminConsole": "管理面板",
- "apiStatus": "API 状态",
- "features": {
- "compatibility": {
- "title": "全面兼容",
- "desc": "适配 OpenAI 与 Claude 格式"
- },
- "loadBalancing": {
- "title": "负载均衡",
- "desc": "智能轮询,稳定高效"
- },
- "reasoning": {
- "title": "深度思考",
- "desc": "支持推理过程输出"
- },
- "search": {
- "title": "联网搜索",
- "desc": "集成原生网页搜索能力"
- }
- }
- },
- "accountManager": {
- "addKeySuccess": "API 密钥添加成功",
- "addAccountSuccess": "账号添加成功",
- "requiredFields": "需要填写密码以及邮箱或手机号",
- "deleteKeyConfirm": "确定要删除此 API 密钥吗?",
- "deleteAccountConfirm": "确定要删除此账号吗?",
- "invalidIdentifier": "账号标识无效,无法执行操作",
- "testAllConfirm": "测试所有账号的 API 连通性?",
- "testAllCompleted": "完成:{success}/{total} 可用",
- "testFailed": "测试失败: {error}",
- "available": "可用",
- "inUse": "正在使用",
- "totalPool": "账号池总数",
- "accountsUnit": "个账号",
- "threadsUnit": "线程",
- "apiKeysTitle": "API 密钥",
- "apiKeysDesc": "管理 API 访问密钥池",
- "addKey": "添加密钥",
- "copied": "已复制",
- "copyKeyTitle": "复制密钥",
- "deleteKeyTitle": "删除密钥",
- "noApiKeys": "未找到 API 密钥",
- "accountsTitle": "DeepSeek 账号",
- "accountsDesc": "管理 DeepSeek 账号池",
- "testAll": "测试全部",
- "addAccount": "添加账号",
- "testingAllAccounts": "正在测试所有账号...",
- "sessionActive": "已建立会话",
- "reauthRequired": "需重新登录",
- "testStatusFailed": "上次测试失败",
- "noAccounts": "未找到任何账号",
- "modalAddKeyTitle": "添加 API 密钥",
- "newKeyLabel": "新密钥值",
- "newKeyPlaceholder": "输入自定义 API 密钥",
- "generate": "生成",
- "generateHint": "点击「生成」自动创建随机密钥",
- "addKeyLoading": "添加中...",
- "addKeyAction": "添加密钥",
- "modalAddAccountTitle": "添加 DeepSeek 账号",
- "emailOptional": "邮箱 (可选)",
- "mobileOptional": "手机号 (可选)",
- "passwordLabel": "密码",
- "passwordPlaceholder": "账号密码",
- "addAccountLoading": "添加中...",
- "addAccountAction": "添加账号",
- "pageInfo": "第 {current}/{total} 页,共 {count} 个账号"
- },
- "apiTester": {
- "defaultMessage": "你好,请用一句话介绍你自己。",
- "models": {
- "chat": "非思考模型",
- "reasoner": "思考模型",
- "chatSearch": "非思考模型 (带搜索)",
- "reasonerSearch": "思考模型 (带搜索)"
- },
- "missingApiKey": "请提供 API 密钥",
- "requestFailed": "请求失败",
- "networkError": "网络错误: {error}",
- "testSuccess": "{account}: 测试成功 ({time}ms)",
- "config": "配置",
- "modelLabel": "模型",
- "streamMode": "流式模式",
- "accountSelector": "选择账号",
- "autoRandom": "🤖 自动 / 随机",
- "apiKeyOptional": "API 密钥 (可选)",
- "apiKeyDefault": "默认: ...{suffix}",
- "apiKeyPlaceholder": "输入自定义密钥",
- "modeManaged": "当前使用托管 key 模式(会走账号池)。",
- "modeDirect": "当前使用直通 token 模式(需填写有效 DeepSeek token)。",
- "statusError": "错误",
- "reasoningTrace": "思维链过程",
- "generating": "正在生成响应...",
- "enterMessage": "输入消息...",
- "adminConsoleLabel": "DeepSeek 管理员界面"
- },
- "batchImport": {
- "templates": {
- "full": {
- "name": "全量配置模板",
- "desc": "包含密钥、账号及模型映射"
- },
- "emailOnly": {
- "name": "仅邮箱账号",
- "desc": "批量导入邮箱格式账号"
- },
- "mobileOnly": {
- "name": "仅手机号账号",
- "desc": "批量导入手机号格式账号"
- },
- "keysOnly": {
- "name": "仅 API 密钥",
- "desc": "仅添加 API 访问密钥"
- }
- },
- "enterJson": "请输入 JSON 配置内容",
- "importSuccess": "导入成功: {keys} 个密钥, {accounts} 个账号",
- "templateLoaded": "已加载模板: {name}",
- "currentConfigLoaded": "当前配置已加载",
- "fetchConfigFailed": "获取配置失败",
- "copySuccess": "Base64 配置已复制到剪贴板",
- "quickTemplates": "快速模板",
- "dataExport": "数据导出",
- "dataExportDesc": "获取配置的 Base64 字符串,用于 Vercel 环境变量。",
- "copyBase64": "复制 Base64 配置",
- "copied": "已复制",
- "variableName": "变量名",
- "jsonEditor": "JSON 编辑器",
- "loadCurrentConfig": "加载当前配置",
- "applyConfig": "应用配置",
- "importing": "正在导入...",
- "importComplete": "导入操作已完成",
- "importSummary": "成功导入了 {keys} 个 API 密钥,并更新了 {accounts} 个账号。"
- },
- "settings": {
- "loadFailed": "加载设置失败",
- "nonJsonResponse": "服务端返回了非 JSON 响应(状态码:{status})",
- "save": "保存设置",
- "saving": "保存中...",
- "saveSuccess": "设置已保存并热更新生效",
- "saveFailed": "保存设置失败",
- "securityTitle": "安全设置",
- "jwtExpireHours": "JWT 有效期(小时)",
- "newPassword": "面板新密码",
- "newPasswordPlaceholder": "输入新密码(至少 4 位)",
- "updatePassword": "修改密码",
- "updating": "更新中...",
- "passwordTooShort": "新密码至少 4 位",
- "passwordUpdated": "密码已更新,需重新登录",
- "passwordUpdateFailed": "密码更新失败",
- "runtimeTitle": "并发与队列",
- "accountMaxInflight": "每账号并发上限",
- "accountMaxQueue": "账号等待队列上限",
- "globalMaxInflight": "全局并发上限",
- "behaviorTitle": "行为设置",
- "toolcallMode": "Toolcall 模式",
- "earlyEmitConfidence": "早发置信度",
- "responsesTTL": "Responses 缓存 TTL(秒)",
- "embeddingsProvider": "Embeddings Provider",
- "modelTitle": "模型映射",
- "claudeMapping": "Claude 映射(JSON)",
- "modelAliases": "模型别名(JSON)",
- "backupTitle": "备份与恢复",
- "loadExport": "加载当前导出",
- "importModeMerge": "合并导入(默认)",
- "importModeReplace": "全量覆盖导入",
- "importNow": "立即导入",
- "importing": "导入中...",
- "importPlaceholder": "粘贴要导入的 JSON 配置",
- "importEmpty": "请先输入导入 JSON",
- "importInvalidJson": "导入 JSON 格式无效",
- "importFailed": "导入失败",
- "importSuccess": "配置导入成功(模式:{mode})",
- "exportFailed": "导出失败",
- "exportLoaded": "已加载当前配置导出",
- "exportJson": "导出 JSON",
- "invalidJsonField": "{field} 不是有效 JSON 对象",
- "defaultPasswordWarning": "当前使用默认密码 admin,请尽快在此修改。",
- "vercelSyncHint": "当前配置已更新。Vercel 部署请到 Vercel 同步页面手动同步并重部署。",
- "autoFetchPaused": "自动加载已暂停:连续失败 {count} 次({error})",
- "retryLoad": "立即重试"
- },
- "login": {
- "welcome": "欢迎回来",
- "subtitle": "请输入管理员密钥以继续",
- "adminKeyLabel": "管理员密钥",
- "adminKeyPlaceholder": "输入您的管理员密钥...",
- "rememberSession": "记住登录状态",
- "signIn": "登录",
- "secureConnection": "安全连接",
- "adminPortal": "DS2API 管理员门户",
- "signInFailed": "登录失败",
- "networkError": "网络错误: {error}"
- },
- "vercel": {
- "tokenRequired": "需要 Vercel 访问令牌",
- "projectRequired": "需要项目 ID",
- "syncFailed": "同步失败",
- "networkError": "网络错误",
- "title": "Vercel 部署",
- "description": "将当前密钥和账号配置直接同步到 Vercel 环境变量中。",
- "tokenLabel": "Vercel 访问令牌",
- "getToken": "获取令牌",
- "tokenPlaceholderPreconfig": "正在使用预配置的令牌",
- "tokenPlaceholder": "输入 Vercel 访问令牌",
- "projectIdLabel": "项目 ID",
- "projectIdHint": "可在项目设置 (Project Settings) → 常规 (General) 中找到",
- "teamIdLabel": "团队 ID",
- "optional": "可选",
- "syncing": "正在同步...",
- "syncRedeploy": "同步并重新部署",
- "redeployHint": "这将触发 Vercel 的重新部署,大约需要 30-60 秒。",
- "syncSucceeded": "同步成功",
- "syncFailedLabel": "同步失败",
- "openDeployment": "访问部署地址",
- "statusSynced": "已同步",
- "statusNotSynced": "未同步",
- "statusNeverSynced": "从未同步",
- "lastSyncTime": "上次同步: {time}",
- "pollPaused": "状态轮询已暂停:连续失败 {count} 次。",
- "manualRefresh": "手动刷新",
- "howItWorks": "工作原理",
- "steps": {
- "one": "当前配置 (密钥和账号) 被导出为 JSON 字符串。",
- "two": "JSON 被编码为 Base64 以确保格式兼容性。",
- "three": "更新 Vercel 项目中的环境变量:",
- "four": "触发重新部署以应用新的环境变量。"
- }
- }
-}
+{
+ "language": {
+ "label": "语言",
+ "english": "English",
+ "chinese": "中文"
+ },
+ "nav": {
+ "accounts": {
+ "label": "账号管理",
+ "desc": "管理 DeepSeek 账号池"
+ },
+ "test": {
+ "label": "API 测试",
+ "desc": "测试 API 连接与响应"
+ },
+ "import": {
+ "label": "批量导入",
+ "desc": "批量导入账号配置"
+ },
+ "vercel": {
+ "label": "Vercel 同步",
+ "desc": "同步配置到 Vercel"
+ },
+ "settings": {
+ "label": "设置中心",
+ "desc": "在线修改系统设置与配置"
+ }
+ },
+ "sidebar": {
+ "onlineAdminConsole": "在线管理面板",
+ "systemStatus": "系统状态",
+ "statusOnline": "在线",
+ "accounts": "账号",
+ "keys": "密钥",
+ "signOut": "退出登录"
+ },
+ "auth": {
+ "expired": "认证已过期,请重新登录",
+ "checking": "正在检查登录状态..."
+ },
+ "errors": {
+ "fetchConfig": "获取配置失败: {error}"
+ },
+ "actions": {
+ "cancel": "取消",
+ "add": "添加",
+ "delete": "删除",
+ "copy": "复制",
+ "generate": "生成",
+ "test": "测试",
+ "testing": "正在测试...",
+ "loading": "加载中..."
+ },
+ "messages": {
+ "deleted": "删除成功",
+ "deleteFailed": "删除失败",
+ "failedToAdd": "添加失败",
+ "networkError": "网络错误",
+ "requestFailed": "请求失败",
+ "generationStopped": "已停止生成",
+ "invalidJson": "无效的 JSON 格式",
+ "importFailed": "导入失败",
+ "copyFailed": "复制失败"
+ },
+ "landing": {
+ "adminConsole": "管理面板",
+ "apiStatus": "API 状态",
+ "features": {
+ "compatibility": {
+ "title": "全面兼容",
+ "desc": "适配 OpenAI 与 Claude 格式"
+ },
+ "loadBalancing": {
+ "title": "负载均衡",
+ "desc": "智能轮询,稳定高效"
+ },
+ "reasoning": {
+ "title": "深度思考",
+ "desc": "支持推理过程输出"
+ },
+ "search": {
+ "title": "联网搜索",
+ "desc": "集成原生网页搜索能力"
+ }
+ }
+ },
+ "accountManager": {
+ "addKeySuccess": "API 密钥添加成功",
+ "addAccountSuccess": "账号添加成功",
+ "requiredFields": "需要填写密码以及邮箱或手机号",
+ "deleteKeyConfirm": "确定要删除此 API 密钥吗?",
+ "deleteAccountConfirm": "确定要删除此账号吗?",
+ "invalidIdentifier": "账号标识无效,无法执行操作",
+ "testAllConfirm": "测试所有账号的 API 连通性?",
+ "testAllCompleted": "完成:{success}/{total} 可用",
+ "testFailed": "测试失败: {error}",
+ "available": "可用",
+ "inUse": "正在使用",
+ "totalPool": "账号池总数",
+ "accountsUnit": "个账号",
+ "threadsUnit": "线程",
+ "apiKeysTitle": "API 密钥",
+ "apiKeysDesc": "管理 API 访问密钥池",
+ "addKey": "添加密钥",
+ "copied": "已复制",
+ "copyKeyTitle": "复制密钥",
+ "deleteKeyTitle": "删除密钥",
+ "noApiKeys": "未找到 API 密钥",
+ "accountsTitle": "DeepSeek 账号",
+ "accountsDesc": "管理 DeepSeek 账号池",
+ "testAll": "测试全部",
+ "addAccount": "添加账号",
+ "testingAllAccounts": "正在测试所有账号...",
+ "sessionActive": "已建立会话",
+ "reauthRequired": "需重新登录",
+ "testStatusFailed": "上次测试失败",
+ "noAccounts": "未找到任何账号",
+ "modalAddKeyTitle": "添加 API 密钥",
+ "newKeyLabel": "新密钥值",
+ "newKeyPlaceholder": "输入自定义 API 密钥",
+ "generate": "生成",
+ "generateHint": "点击「生成」自动创建随机密钥",
+ "addKeyLoading": "添加中...",
+ "addKeyAction": "添加密钥",
+ "modalAddAccountTitle": "添加 DeepSeek 账号",
+ "emailOptional": "邮箱 (可选)",
+ "mobileOptional": "手机号 (可选)",
+ "passwordLabel": "密码",
+ "passwordPlaceholder": "账号密码",
+ "addAccountLoading": "添加中...",
+ "addAccountAction": "添加账号",
+ "pageInfo": "第 {current}/{total} 页,共 {count} 个账号",
+ "searchPlaceholder": "搜索账号...",
+ "searchNoResults": "未找到匹配的账号"
+ },
+ "apiTester": {
+ "defaultMessage": "你好,请用一句话介绍你自己。",
+ "models": {
+ "chat": "非思考模型",
+ "reasoner": "思考模型",
+ "chatSearch": "非思考模型 (带搜索)",
+ "reasonerSearch": "思考模型 (带搜索)"
+ },
+ "missingApiKey": "请提供 API 密钥",
+ "requestFailed": "请求失败",
+ "networkError": "网络错误: {error}",
+ "testSuccess": "{account}: 测试成功 ({time}ms)",
+ "config": "配置",
+ "modelLabel": "模型",
+ "streamMode": "流式模式",
+ "accountSelector": "选择账号",
+ "autoRandom": "🤖 自动 / 随机",
+ "apiKeyOptional": "API 密钥 (可选)",
+ "apiKeyDefault": "默认: ...{suffix}",
+ "apiKeyPlaceholder": "输入自定义密钥",
+ "modeManaged": "当前使用托管 key 模式(会走账号池)。",
+ "modeDirect": "当前使用直通 token 模式(需填写有效 DeepSeek token)。",
+ "statusError": "错误",
+ "reasoningTrace": "思维链过程",
+ "generating": "正在生成响应...",
+ "enterMessage": "输入消息...",
+ "adminConsoleLabel": "DeepSeek 管理员界面"
+ },
+ "batchImport": {
+ "templates": {
+ "full": {
+ "name": "全量配置模板",
+ "desc": "包含密钥、账号及模型映射"
+ },
+ "emailOnly": {
+ "name": "仅邮箱账号",
+ "desc": "批量导入邮箱格式账号"
+ },
+ "mobileOnly": {
+ "name": "仅手机号账号",
+ "desc": "批量导入手机号格式账号"
+ },
+ "keysOnly": {
+ "name": "仅 API 密钥",
+ "desc": "仅添加 API 访问密钥"
+ }
+ },
+ "enterJson": "请输入 JSON 配置内容",
+ "importSuccess": "导入成功: {keys} 个密钥, {accounts} 个账号",
+ "templateLoaded": "已加载模板: {name}",
+ "currentConfigLoaded": "当前配置已加载",
+ "fetchConfigFailed": "获取配置失败",
+ "copySuccess": "Base64 配置已复制到剪贴板",
+ "quickTemplates": "快速模板",
+ "dataExport": "数据导出",
+ "dataExportDesc": "获取配置的 Base64 字符串,用于 Vercel 环境变量。",
+ "copyBase64": "复制 Base64 配置",
+ "copied": "已复制",
+ "variableName": "变量名",
+ "jsonEditor": "JSON 编辑器",
+ "loadCurrentConfig": "加载当前配置",
+ "applyConfig": "应用配置",
+ "importing": "正在导入...",
+ "importComplete": "导入操作已完成",
+ "importSummary": "成功导入了 {keys} 个 API 密钥,并更新了 {accounts} 个账号。"
+ },
+ "settings": {
+ "loadFailed": "加载设置失败",
+ "nonJsonResponse": "服务端返回了非 JSON 响应(状态码:{status})",
+ "save": "保存设置",
+ "saving": "保存中...",
+ "saveSuccess": "设置已保存并热更新生效",
+ "saveFailed": "保存设置失败",
+ "securityTitle": "安全设置",
+ "jwtExpireHours": "JWT 有效期(小时)",
+ "newPassword": "面板新密码",
+ "newPasswordPlaceholder": "输入新密码(至少 4 位)",
+ "updatePassword": "修改密码",
+ "updating": "更新中...",
+ "passwordTooShort": "新密码至少 4 位",
+ "passwordUpdated": "密码已更新,需重新登录",
+ "passwordUpdateFailed": "密码更新失败",
+ "runtimeTitle": "并发与队列",
+ "accountMaxInflight": "每账号并发上限",
+ "accountMaxQueue": "账号等待队列上限",
+ "globalMaxInflight": "全局并发上限",
+ "behaviorTitle": "行为设置",
+ "toolcallMode": "Toolcall 模式",
+ "earlyEmitConfidence": "早发置信度",
+ "responsesTTL": "Responses 缓存 TTL(秒)",
+ "embeddingsProvider": "Embeddings Provider",
+ "modelTitle": "模型映射",
+ "claudeMapping": "Claude 映射(JSON)",
+ "modelAliases": "模型别名(JSON)",
+ "backupTitle": "备份与恢复",
+ "loadExport": "加载当前导出",
+ "importModeMerge": "合并导入(默认)",
+ "importModeReplace": "全量覆盖导入",
+ "importNow": "立即导入",
+ "importing": "导入中...",
+ "importPlaceholder": "粘贴要导入的 JSON 配置",
+ "importEmpty": "请先输入导入 JSON",
+ "importInvalidJson": "导入 JSON 格式无效",
+ "importFailed": "导入失败",
+ "importSuccess": "配置导入成功(模式:{mode})",
+ "exportFailed": "导出失败",
+ "exportLoaded": "已加载当前配置导出",
+ "exportJson": "导出 JSON",
+ "invalidJsonField": "{field} 不是有效 JSON 对象",
+ "defaultPasswordWarning": "当前使用默认密码 admin,请尽快在此修改。",
+ "vercelSyncHint": "当前配置已更新。Vercel 部署请到 Vercel 同步页面手动同步并重部署。",
+ "autoFetchPaused": "自动加载已暂停:连续失败 {count} 次({error})",
+ "retryLoad": "立即重试"
+ },
+ "login": {
+ "welcome": "欢迎回来",
+ "subtitle": "请输入管理员密钥以继续",
+ "adminKeyLabel": "管理员密钥",
+ "adminKeyPlaceholder": "输入您的管理员密钥...",
+ "rememberSession": "记住登录状态",
+ "signIn": "登录",
+ "secureConnection": "安全连接",
+ "adminPortal": "DS2API 管理员门户",
+ "signInFailed": "登录失败",
+ "networkError": "网络错误: {error}"
+ },
+ "vercel": {
+ "tokenRequired": "需要 Vercel 访问令牌",
+ "projectRequired": "需要项目 ID",
+ "syncFailed": "同步失败",
+ "networkError": "网络错误",
+ "title": "Vercel 部署",
+ "description": "将当前密钥和账号配置直接同步到 Vercel 环境变量中。",
+ "tokenLabel": "Vercel 访问令牌",
+ "getToken": "获取令牌",
+ "tokenPlaceholderPreconfig": "正在使用预配置的令牌",
+ "tokenPlaceholder": "输入 Vercel 访问令牌",
+ "projectIdLabel": "项目 ID",
+ "projectIdHint": "可在项目设置 (Project Settings) → 常规 (General) 中找到",
+ "teamIdLabel": "团队 ID",
+ "optional": "可选",
+ "syncing": "正在同步...",
+ "syncRedeploy": "同步并重新部署",
+ "redeployHint": "这将触发 Vercel 的重新部署,大约需要 30-60 秒。",
+ "syncSucceeded": "同步成功",
+ "syncFailedLabel": "同步失败",
+ "openDeployment": "访问部署地址",
+ "statusSynced": "已同步",
+ "statusNotSynced": "未同步",
+ "statusNeverSynced": "从未同步",
+ "lastSyncTime": "上次同步: {time}",
+ "pollPaused": "状态轮询已暂停:连续失败 {count} 次。",
+ "manualRefresh": "手动刷新",
+ "howItWorks": "工作原理",
+ "steps": {
+ "one": "当前配置 (密钥和账号) 被导出为 JSON 字符串。",
+ "two": "JSON 被编码为 Base64 以确保格式兼容性。",
+ "three": "更新 Vercel 项目中的环境变量:",
+ "four": "触发重新部署以应用新的环境变量。"
+ }
+ }
+}