|
@@ -90,12 +90,12 @@
|
|
|
"apiKeyPlaceholder": "Enter API key",
|
|
"apiKeyPlaceholder": "Enter API key",
|
|
|
"apiKeyOptional": "Leave empty to keep existing key",
|
|
"apiKeyOptional": "Leave empty to keep existing key",
|
|
|
"weight": "Weight",
|
|
"weight": "Weight",
|
|
|
- "weightDesc": "Weighted random probability. Higher weight means higher probability of selection within the same priority.",
|
|
|
|
|
|
|
+ "weightDesc": "Weighted random probability. Within same priority, higher weight = higher selection probability. E.g. weights 1:2:3 = probabilities 16%:33%:50%",
|
|
|
"priority": "Priority",
|
|
"priority": "Priority",
|
|
|
- "priorityDesc": "Within the same priority, sort by cost multiplier from low to high",
|
|
|
|
|
|
|
+ "priorityDesc": "Lower number = higher priority (0 is highest). System only selects from highest priority providers. Recommendation: Main=0, Backup=1, Emergency=2",
|
|
|
"enabled": "Enabled",
|
|
"enabled": "Enabled",
|
|
|
"costMultiplier": "Cost Multiplier",
|
|
"costMultiplier": "Cost Multiplier",
|
|
|
- "costMultiplierDesc": "e.g. A (cost 1.0x), C (cost 0.8x)",
|
|
|
|
|
|
|
+ "costMultiplierDesc": "Cost calculation multiplier. Official=1.0, 20% cheaper=0.8, 20% more expensive=1.2 (up to 4 decimal places)",
|
|
|
"limitConcurrent": "Concurrent Session Limit",
|
|
"limitConcurrent": "Concurrent Session Limit",
|
|
|
"limitConcurrentDesc": "e.g. Provider C has limit of 2, currently 2 active sessions",
|
|
"limitConcurrentDesc": "e.g. Provider C has limit of 2, currently 2 active sessions",
|
|
|
"limitAmount5h": "5-Hour Spending Limit (USD)",
|
|
"limitAmount5h": "5-Hour Spending Limit (USD)",
|
|
@@ -103,7 +103,7 @@
|
|
|
"limitAmountWeekly": "Weekly Spending Limit (USD)",
|
|
"limitAmountWeekly": "Weekly Spending Limit (USD)",
|
|
|
"limitAmountMonthly": "Monthly Spending Limit (USD)",
|
|
"limitAmountMonthly": "Monthly Spending Limit (USD)",
|
|
|
"modelRedirects": "Model Redirects",
|
|
"modelRedirects": "Model Redirects",
|
|
|
- "modelRedirectsDesc": "Redirect Claude model requests to other provider-supported models",
|
|
|
|
|
|
|
+ "modelRedirectsDesc": "Redirect Claude Code client model requests (e.g. claude-sonnet-4.5) to upstream provider supported models (e.g. glm-4.6, gemini-pro). For cost optimization or third-party AI integration.",
|
|
|
"sourceModel": "Source Model Name",
|
|
"sourceModel": "Source Model Name",
|
|
|
"sourceModelPlaceholder": "e.g. claude-sonnet-4-5-20250929",
|
|
"sourceModelPlaceholder": "e.g. claude-sonnet-4-5-20250929",
|
|
|
"sourceModelRequired": "Source model name cannot be empty",
|
|
"sourceModelRequired": "Source model name cannot be empty",
|
|
@@ -117,7 +117,7 @@
|
|
|
"proxyUrl": "Proxy Address",
|
|
"proxyUrl": "Proxy Address",
|
|
|
"proxyUrlPlaceholder": "e.g. http://proxy.example.com:8080 or socks5://127.0.0.1:1080",
|
|
"proxyUrlPlaceholder": "e.g. http://proxy.example.com:8080 or socks5://127.0.0.1:1080",
|
|
|
"proxyFallback": "Proxy Fallback",
|
|
"proxyFallback": "Proxy Fallback",
|
|
|
- "proxyFallbackDesc": "Fallback to direct connection when proxy fails",
|
|
|
|
|
|
|
+ "proxyFallbackDesc": "When enabled, auto try direct connection on proxy failure",
|
|
|
"testProxy": "Test Connection",
|
|
"testProxy": "Test Connection",
|
|
|
"testProxySuccess": "Proxy connection successful",
|
|
"testProxySuccess": "Proxy connection successful",
|
|
|
"testProxyFailed": "Failed to test proxy connection",
|
|
"testProxyFailed": "Failed to test proxy connection",
|
|
@@ -145,7 +145,145 @@
|
|
|
"searchPlaceholder": "Search provider name, URL, remark...",
|
|
"searchPlaceholder": "Search provider name, URL, remark...",
|
|
|
"clearSearch": "Clear search",
|
|
"clearSearch": "Clear search",
|
|
|
"limit0Means": "0 means unlimited",
|
|
"limit0Means": "0 means unlimited",
|
|
|
- "leaveEmpty": "Leave empty for unlimited"
|
|
|
|
|
|
|
+ "leaveEmpty": "Leave empty for unlimited",
|
|
|
|
|
+ "providerName": "Provider Name",
|
|
|
|
|
+ "providerNameRequired": "Provider Name *",
|
|
|
|
|
+ "providerNamePlaceholder": "e.g. Zhipu",
|
|
|
|
|
+ "apiAddress": "API Address",
|
|
|
|
|
+ "apiAddressRequired": "API Address *",
|
|
|
|
|
+ "apiAddressPlaceholder": "e.g. https://open.bigmodel.cn/api/anthropic",
|
|
|
|
|
+ "apiKeyRequired": "API Key *",
|
|
|
|
|
+ "apiKeyLeaveEmpty": "(Leave empty to keep unchanged)",
|
|
|
|
|
+ "apiKeyLeaveEmptyDesc": "Leave empty to keep existing key",
|
|
|
|
|
+ "apiKeyCurrent": "Current key:",
|
|
|
|
|
+ "websiteUrl": "Provider Website URL",
|
|
|
|
|
+ "websiteUrlPlaceholder": "https://example.com",
|
|
|
|
|
+ "websiteUrlDesc": "Provider website URL for quick access",
|
|
|
|
|
+ "websiteUrlInvalid": "Please enter a valid provider website URL",
|
|
|
|
|
+ "expandAll": "Expand All Advanced Configuration",
|
|
|
|
|
+ "collapseAll": "Collapse All Advanced Configuration",
|
|
|
|
|
+ "routingConfig": "Routing Configuration",
|
|
|
|
|
+ "routingConfigSummary": "{models} model whitelist, {redirects} redirects",
|
|
|
|
|
+ "routingConfigNone": "Not configured",
|
|
|
|
|
+ "providerTypeDesc": "Select the API format type for the provider.",
|
|
|
|
|
+ "providerTypeDisabledNote": "Note: Gemini CLI and OpenAI Compatible types are under development",
|
|
|
|
|
+ "modelRedirectsLabel": "Model Redirects Configuration",
|
|
|
|
|
+ "modelRedirectsOptional": "(Optional)",
|
|
|
|
|
+ "modelRedirectsEmpty": "No redirect rules yet. System will auto-rewrite model names after adding rules.",
|
|
|
|
|
+ "modelRedirectsCurrentRules": "Current Rules ({count})",
|
|
|
|
|
+ "modelRedirectsAddNew": "Add New Rule",
|
|
|
|
|
+ "modelRedirectsSourceModel": "User Requested Model",
|
|
|
|
|
+ "modelRedirectsSourcePlaceholder": "e.g. claude-sonnet-4-5-20250929",
|
|
|
|
|
+ "modelRedirectsTargetModel": "Actual Forwarded Model",
|
|
|
|
|
+ "modelRedirectsTargetPlaceholder": "e.g. glm-4.6",
|
|
|
|
|
+ "modelRedirectsSourceRequired": "Source model name cannot be empty",
|
|
|
|
|
+ "modelRedirectsTargetRequired": "Target model name cannot be empty",
|
|
|
|
|
+ "modelRedirectsExists": "Model \"{model}\" already has a redirect rule",
|
|
|
|
|
+ "joinClaudePool": "Join Claude Scheduling Pool",
|
|
|
|
|
+ "joinClaudePoolDesc": "When enabled, this provider will participate in load balancing with Claude type providers",
|
|
|
|
|
+ "joinClaudePoolHelp": "Only available when model redirect config contains mappings to claude-* models. When enabled, this provider will also participate in scheduling when users request claude-* models.",
|
|
|
|
|
+ "modelWhitelist": "Model Whitelist",
|
|
|
|
|
+ "modelWhitelistDesc": "Limit models this provider can handle. By default, provider can handle all models of its type.",
|
|
|
|
|
+ "modelWhitelistLabel": "Allowed Models",
|
|
|
|
|
+ "modelWhitelistSelected": "Selected {count} models",
|
|
|
|
|
+ "modelWhitelistLoading": "Loading...",
|
|
|
|
|
+ "modelWhitelistNotFound": "Model not found",
|
|
|
|
|
+ "modelWhitelistSearchPlaceholder": "Search model name...",
|
|
|
|
|
+ "modelWhitelistSelectAll": "Select All ({count})",
|
|
|
|
|
+ "modelWhitelistClear": "Clear",
|
|
|
|
|
+ "modelWhitelistManualAdd": "Manually Add Model",
|
|
|
|
|
+ "modelWhitelistManualPlaceholder": "Enter model name (e.g. gpt-5-turbo)",
|
|
|
|
|
+ "modelWhitelistManualDesc": "Support adding any model name (not limited to price table)",
|
|
|
|
|
+ "modelWhitelistAllowAll": "Allow all {type} models",
|
|
|
|
|
+ "modelWhitelistAllowAllClause": "Allow all Claude models",
|
|
|
|
|
+ "modelWhitelistAllowAllOpenAI": "Allow all OpenAI models",
|
|
|
|
|
+ "modelWhitelistSelectedOnly": "Only allow selected {count} models. Requests for other models won't be routed to this provider.",
|
|
|
|
|
+ "scheduleParams": "Scheduling Parameters",
|
|
|
|
|
+ "priorityLabel": "Priority",
|
|
|
|
|
+ "priorityPlaceholder": "0",
|
|
|
|
|
+ "weightLabel": "Weight",
|
|
|
|
|
+ "weightPlaceholder": "1",
|
|
|
|
|
+ "costMultiplierLabel": "Cost Multiplier",
|
|
|
|
|
+ "costMultiplierPlaceholder": "1.0",
|
|
|
|
|
+ "providerGroupLabel": "Provider Group",
|
|
|
|
|
+ "providerGroupPlaceholder": "e.g. premium, economy",
|
|
|
|
|
+ "providerGroupDesc": "Provider group tag. Only users with matching providerGroup can use this provider. Example: Set to \"premium\" to allow only providerGroup=\"premium\" users",
|
|
|
|
|
+ "rateLimitConfig": "Rate Limit Configuration",
|
|
|
|
|
+ "rateLimitConfigSummary": "5h: ${fiveHour}, Weekly: ${weekly}, Monthly: ${monthly}, Concurrent: {concurrent}",
|
|
|
|
|
+ "rateLimitConfigNone": "Unlimited",
|
|
|
|
|
+ "limit5hLabel": "5-Hour Spending Limit (USD)",
|
|
|
|
|
+ "limitWeeklyLabel": "Weekly Spending Limit (USD)",
|
|
|
|
|
+ "limitMonthlyLabel": "Monthly Spending Limit (USD)",
|
|
|
|
|
+ "limitConcurrentLabel": "Concurrent Session Limit",
|
|
|
|
|
+ "limitPlaceholderUnlimited": "Leave empty for unlimited",
|
|
|
|
|
+ "limitPlaceholder0": "0 means unlimited",
|
|
|
|
|
+ "circuitBreakerConfig": "Circuit Breaker Configuration",
|
|
|
|
|
+ "circuitBreakerConfigSummary": "{failureThreshold} failures / {openDuration} min circuit break / {successThreshold} successes to recover",
|
|
|
|
|
+ "circuitBreakerDesc": "Auto circuit break on consecutive failures to avoid overall service quality impact",
|
|
|
|
|
+ "failureThreshold": "Failure Threshold (times)",
|
|
|
|
|
+ "failureThresholdPlaceholder": "5",
|
|
|
|
|
+ "failureThresholdDesc": "How many consecutive failures trigger circuit break",
|
|
|
|
|
+ "openDuration": "Circuit Break Duration (minutes)",
|
|
|
|
|
+ "openDurationPlaceholder": "30",
|
|
|
|
|
+ "openDurationDesc": "How long before auto entering half-open state",
|
|
|
|
|
+ "successThreshold": "Recovery Threshold (times)",
|
|
|
|
|
+ "successThresholdPlaceholder": "2",
|
|
|
|
|
+ "successThresholdDesc": "How many successes in half-open state to fully recover",
|
|
|
|
|
+ "proxyConfig": "Proxy Configuration",
|
|
|
|
|
+ "proxyConfigSummary": "Proxy configured",
|
|
|
|
|
+ "proxyConfigSummaryFallback": " (fallback enabled)",
|
|
|
|
|
+ "proxyConfigNone": "Not configured",
|
|
|
|
|
+ "proxyConfigDesc": "Configure proxy server to improve provider connectivity (supports HTTP, HTTPS, SOCKS4, SOCKS5)",
|
|
|
|
|
+ "proxyAddressLabel": "Proxy Address",
|
|
|
|
|
+ "proxyAddressOptional": "(Optional)",
|
|
|
|
|
+ "proxyAddressPlaceholder": "e.g. http://proxy.example.com:8080 or socks5://127.0.0.1:1080",
|
|
|
|
|
+ "proxyAddressFormats": "Supported formats:",
|
|
|
|
|
+ "proxyFallbackLabel": "Fallback to direct on proxy failure",
|
|
|
|
|
+ "proxyTestLabel": "Connection Test",
|
|
|
|
|
+ "proxyTestButton": "Test Connection",
|
|
|
|
|
+ "proxyTestTesting": "Testing...",
|
|
|
|
|
+ "proxyTestSuccess": "Connection Successful",
|
|
|
|
|
+ "proxyTestFailed": "Connection Failed",
|
|
|
|
|
+ "proxyTestDesc": "Test provider URL access via configured proxy (uses HEAD request, no quota consumption)",
|
|
|
|
|
+ "proxyTestFillUrl": "Please fill in provider URL first",
|
|
|
|
|
+ "proxyTestResultSuccess": "Connection successful {via}",
|
|
|
|
|
+ "proxyTestViaProxy": "(via proxy)",
|
|
|
|
|
+ "proxyTestViaDirect": "(direct)",
|
|
|
|
|
+ "proxyTestResponseTime": "Response time: {time}",
|
|
|
|
|
+ "proxyTestStatusCode": "| Status code: {code}",
|
|
|
|
|
+ "proxyTestResultFailed": "Connection failed",
|
|
|
|
|
+ "proxyTestTimeout": "Connection timeout (5s). Please check:\n1. Is proxy server accessible\n2. Are proxy address and port correct\n3. Are proxy credentials correct",
|
|
|
|
|
+ "proxyTestProxyError": "Proxy error: {error}",
|
|
|
|
|
+ "proxyTestNetworkError": "Network error: {error}",
|
|
|
|
|
+ "proxyTestResultMessage": "{message}",
|
|
|
|
|
+ "proxyTestResultStatusCode": "Status code: {code}",
|
|
|
|
|
+ "proxyTestResultResponseTime": "Response time: {time}ms",
|
|
|
|
|
+ "proxyTestResultConnectionMethod": "Connection method: {via}",
|
|
|
|
|
+ "proxyTestResultConnectionMethodProxy": "Proxy",
|
|
|
|
|
+ "proxyTestResultConnectionMethodDirect": "Direct",
|
|
|
|
|
+ "proxyTestResultErrorType": "Error type: {type}",
|
|
|
|
|
+ "codexStrategyConfig": "Codex Instructions Strategy",
|
|
|
|
|
+ "codexStrategyConfigAuto": "Auto (Recommended)",
|
|
|
|
|
+ "codexStrategyConfigForce": "Force Official",
|
|
|
|
|
+ "codexStrategyConfigKeep": "Keep Original",
|
|
|
|
|
+ "codexStrategyDesc": "Control how to handle Codex request instructions field, affects upstream gateway compatibility",
|
|
|
|
|
+ "codexStrategySelect": "Strategy Selection",
|
|
|
|
|
+ "codexStrategyAutoLabel": "Auto (Recommended)",
|
|
|
|
|
+ "codexStrategyAutoDesc": "Pass through client instructions, auto retry with official prompt on 400 error",
|
|
|
|
|
+ "codexStrategyForceLabel": "Force Official",
|
|
|
|
|
+ "codexStrategyForceDesc": "Always use official Codex CLI instructions (~4000+ chars)",
|
|
|
|
|
+ "codexStrategyKeepLabel": "Keep Original",
|
|
|
|
|
+ "codexStrategyKeepDesc": "Always pass through client instructions, no auto retry (for lenient gateways)",
|
|
|
|
|
+ "codexStrategyHint": "Hint: Some strict Codex gateways (e.g. 88code, foxcode) require official instructions. Choose \"Auto\" or \"Force Official\" strategy",
|
|
|
|
|
+ "confirmAdd": "Confirm Add",
|
|
|
|
|
+ "confirmUpdate": "Confirm Update",
|
|
|
|
|
+ "confirmAddPending": "Adding...",
|
|
|
|
|
+ "confirmUpdatePending": "Updating...",
|
|
|
|
|
+ "deleteButton": "Delete",
|
|
|
|
|
+ "validUrlRequired": "Please enter a valid API address",
|
|
|
|
|
+ "filterProvider": "Filter by Provider Type",
|
|
|
|
|
+ "filterAllProviders": "All Providers",
|
|
|
|
|
+ "searchClear": "Clear search"
|
|
|
},
|
|
},
|
|
|
"scheduling": "Scheduling Strategy Details",
|
|
"scheduling": "Scheduling Strategy Details",
|
|
|
"schedulingDesc": "Understand how provider selection works with priority layering, session reuse, load balancing and failover",
|
|
"schedulingDesc": "Understand how provider selection works with priority layering, session reuse, load balancing and failover",
|
|
@@ -193,32 +331,180 @@
|
|
|
"circuitBreakerRecovery": "A automatically recovers to half-open after 60 seconds",
|
|
"circuitBreakerRecovery": "A automatically recovers to half-open after 60 seconds",
|
|
|
"circuitBreakerRecovery5h": "Auto recovery after 5-hour sliding window",
|
|
"circuitBreakerRecovery5h": "Auto recovery after 5-hour sliding window",
|
|
|
"reset": "Manual Circuit Breaker Reset",
|
|
"reset": "Manual Circuit Breaker Reset",
|
|
|
- "resetSuccess": "Circuit breaker reset"
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ "resetSuccess": "Circuit breaker reset",
|
|
|
|
|
+ "title": "Core Principles",
|
|
|
|
|
+ "priorityFirst": "1️⃣ Priority First: Select only from highest priority (lowest number) providers",
|
|
|
|
|
+ "costOptimize": "2️⃣ Cost Optimization: Within same priority, lower cost multiplier has higher probability",
|
|
|
|
|
+ "healthFilter": "3️⃣ Health Filtering: Auto skip circuit-broken or over-limit providers",
|
|
|
|
|
+ "sessionReuse": "4️⃣ Session Reuse: Consecutive chats reuse same provider, saving context costs",
|
|
|
|
|
+ "scenariosTitle": "Interactive Scenario Demos",
|
|
|
|
|
+ "bestPracticesTitle": "Best Practices",
|
|
|
|
|
+ "bestPracticesPriority": "• Priority Settings: Core providers=0, Backup=1-3",
|
|
|
|
|
+ "bestPracticesWeight": "• Weight Config: Set weight by capacity (higher capacity = higher weight)",
|
|
|
|
|
+ "bestPracticesCost": "• Cost Multiplier: Official=1.0, Self-hosted can be 0.8-1.2",
|
|
|
|
|
+ "bestPracticesLimit": "• Limit Settings: Set 5h, 7d, 30d limits based on budget",
|
|
|
|
|
+ "bestPracticesConcurrent": "• Concurrent Control: Set session concurrency by provider API limits",
|
|
|
|
|
+ "scenario1Title": "Priority Layering",
|
|
|
|
|
+ "scenario1Desc": "System first filters by priority, selecting only from highest priority providers",
|
|
|
|
|
+ "scenario1Step1": "Initial State",
|
|
|
|
|
+ "scenario1Step1Desc": "4 enabled providers with different priorities",
|
|
|
|
|
+ "scenario1Step1Before": "Provider A (priority 0), B (priority 1), C (priority 0), D (priority 2)",
|
|
|
|
|
+ "scenario1Step1After": "Filtered to highest priority (0) providers: A, C",
|
|
|
|
|
+ "scenario1Step1Decision": "Select only from A and C, B and D filtered out",
|
|
|
|
|
+ "scenario1Step2": "Cost Sorting",
|
|
|
|
|
+ "scenario1Step2Desc": "Within same priority, sort by cost multiplier low to high",
|
|
|
|
|
+ "scenario1Step2Before": "A (cost 1.0x), C (cost 0.8x)",
|
|
|
|
|
+ "scenario1Step2After": "After sorting: C (0.8x), A (1.0x)",
|
|
|
|
|
+ "scenario1Step2Decision": "Lower cost C has higher selection probability",
|
|
|
|
|
+ "scenario1Step3": "Weighted Random",
|
|
|
|
|
+ "scenario1Step3Desc": "Use weight for random selection, higher weight = higher probability",
|
|
|
|
|
+ "scenario1Step3Before": "C (weight 3), A (weight 1)",
|
|
|
|
|
+ "scenario1Step3After": "C has 75% probability, A has 25%",
|
|
|
|
|
+ "scenario1Step3Decision": "Finally randomly selected C",
|
|
|
|
|
+ "scenario2Title": "User Group Filtering",
|
|
|
|
|
+ "scenario2Desc": "If user has provider group specified, system prioritizes selection from that group",
|
|
|
|
|
+ "scenario2Step1": "Check User Group",
|
|
|
|
|
+ "scenario2Step1Desc": "User configured providerGroup = 'premium'",
|
|
|
|
|
+ "scenario2Step1Before": "All providers: A (default), B (premium), C (premium), D (economy)",
|
|
|
|
|
+ "scenario2Step1After": "Filtered to 'premium' group: B, C",
|
|
|
|
|
+ "scenario2Step1Decision": "Select only from B and C",
|
|
|
|
|
+ "scenario2Step2": "Group Fallback",
|
|
|
|
|
+ "scenario2Step2Desc": "If no available providers in user group, fallback to all providers",
|
|
|
|
|
+ "scenario2Step2Before": "All providers in user group 'vip' disabled or over limit",
|
|
|
|
|
+ "scenario2Step2After": "Fallback to all enabled providers: A, B, C, D",
|
|
|
|
|
+ "scenario2Step2Decision": "Log warning and select from global provider pool",
|
|
|
|
|
+ "scenario3Title": "Health Filtering (Circuit Breaker + Rate Limit)",
|
|
|
|
|
+ "scenario3Desc": "System auto filters circuit-broken or over-limit providers",
|
|
|
|
|
+ "scenario3Step1": "Circuit Breaker Check",
|
|
|
|
|
+ "scenario3Step1Desc": "Circuit breaker opens after 5 consecutive failures, unavailable for 60s",
|
|
|
|
|
+ "scenario3Step1Before": "Provider A failed 5 times, circuit breaker: open",
|
|
|
|
|
+ "scenario3Step1After": "A filtered, remaining: B, C, D",
|
|
|
|
|
+ "scenario3Step1Decision": "A auto recovers to half-open after 60s",
|
|
|
|
|
+ "scenario3Step2": "Amount Rate Limit",
|
|
|
|
|
+ "scenario3Step2Desc": "Check if spending exceeds limits (5h, 7d, 30d)",
|
|
|
|
|
+ "scenario3Step2Before": "Provider B 5h limit $10, consumed $9.8",
|
|
|
|
|
+ "scenario3Step2After": "B filtered (near limit), remaining: C, D",
|
|
|
|
|
+ "scenario3Step2Decision": "Auto recovery after 5h sliding window",
|
|
|
|
|
+ "scenario3Step3": "Concurrent Session Limit",
|
|
|
|
|
+ "scenario3Step3Desc": "Check if active session count exceeds configured concurrent limit",
|
|
|
|
|
+ "scenario3Step3Before": "Provider C concurrent limit 2, currently 2 active sessions",
|
|
|
|
|
+ "scenario3Step3After": "C filtered (full), remaining: D",
|
|
|
|
|
+ "scenario3Step3Decision": "Auto release after session expiry (5 min)",
|
|
|
|
|
+ "scenario4Title": "Session Reuse Mechanism",
|
|
|
|
|
+ "scenario4Desc": "Consecutive chats prioritize using same provider, leveraging Claude context cache",
|
|
|
|
|
+ "scenario4Step1": "Check Request History",
|
|
|
|
|
+ "scenario4Step1Desc": "Query providers used by this API Key in last 10 seconds",
|
|
|
|
|
+ "scenario4Step1Before": "Last request used provider B",
|
|
|
|
|
+ "scenario4Step1After": "Check if B is enabled and healthy",
|
|
|
|
|
+ "scenario4Step1Decision": "B available, reuse directly, skip random selection",
|
|
|
|
|
+ "scenario4Step2": "Reuse Invalidation",
|
|
|
|
|
+ "scenario4Step2Desc": "If last used provider unavailable, reselect",
|
|
|
|
|
+ "scenario4Step2Before": "Last used provider B disabled or circuit-broken",
|
|
|
|
|
+ "scenario4Step2After": "Enter normal selection flow",
|
|
|
|
|
+ "scenario4Step2Decision": "Select from other available providers",
|
|
|
|
|
+ "step": "Step",
|
|
|
|
|
+ "before": "Before:",
|
|
|
|
|
+ "after": "After:",
|
|
|
|
|
+ "decision": "Decision:"
|
|
|
|
|
+ },
|
|
|
|
|
+ "section": {
|
|
|
|
|
+ "title": "Provider Management",
|
|
|
|
|
+ "description": "Configure upstream provider rate limiting and concurrent session limits. Leave empty for unlimited."
|
|
|
|
|
+ },
|
|
|
|
|
+ "addProvider": "Add Provider",
|
|
|
|
|
+ "editProvider": "Edit Provider",
|
|
|
|
|
+ "createProvider": "Add Provider",
|
|
|
|
|
+ "updateFailed": "Failed to update provider",
|
|
|
|
|
+ "deleteSuccess": "Deleted successfully",
|
|
|
|
|
+ "confirmDeleteDesc": "Are you sure you want to delete provider \"{name}\"? This action cannot be undone.",
|
|
|
|
|
+ "confirmDeleteProvider": "Confirm Delete Provider?",
|
|
|
|
|
+ "confirmDeleteProviderDesc": "Are you sure you want to delete provider \"{name}\"? This action is irreversible.",
|
|
|
|
|
+ "noProviders": "No providers configured",
|
|
|
|
|
+ "noProvidersDesc": "Add your first API provider",
|
|
|
|
|
+ "toggleSuccess": "Provider {status}",
|
|
|
|
|
+ "toggleSuccessDesc": "Provider \"{name}\" status updated",
|
|
|
|
|
+ "toggleFailed": "Toggle failed",
|
|
|
|
|
+ "enabledStatus": "enabled",
|
|
|
|
|
+ "disabledStatus": "disabled",
|
|
|
|
|
+ "searchResults": "Found {count} matching providers",
|
|
|
|
|
+ "searchNoResults": "No matching providers found",
|
|
|
|
|
+ "displayCount": "Showing {filtered} / {total} providers",
|
|
|
|
|
+ "todayUsage": "Today's Usage",
|
|
|
|
|
+ "todayUsageCount": "{count} times",
|
|
|
|
|
+ "circuitBroken": "Circuit Broken",
|
|
|
|
|
+ "official": "Official",
|
|
|
|
|
+ "viewKey": "View Complete API Key",
|
|
|
|
|
+ "viewKeyDesc": "Please keep it safe and don't share it with others",
|
|
|
|
|
+ "keyLoading": "Loading...",
|
|
|
|
|
+ "resetCircuit": "Circuit breaker reset",
|
|
|
|
|
+ "resetCircuitDesc": "Provider \"{name}\" circuit breaker status cleared",
|
|
|
|
|
+ "resetCircuitFailed": "Failed to reset circuit breaker"
|
|
|
},
|
|
},
|
|
|
"prices": {
|
|
"prices": {
|
|
|
"title": "Pricing",
|
|
"title": "Pricing",
|
|
|
"description": "Manage platform basic configuration and model pricing",
|
|
"description": "Manage platform basic configuration and model pricing",
|
|
|
"subtitle": "Model Pricing",
|
|
"subtitle": "Model Pricing",
|
|
|
"subtitleDesc": "Manage AI model pricing configuration",
|
|
"subtitleDesc": "Manage AI model pricing configuration",
|
|
|
- "search": "Search model name...",
|
|
|
|
|
- "sync": "Sync LiteLLM Prices",
|
|
|
|
|
|
|
+ "search": {
|
|
|
|
|
+ "placeholder": "Search model name...",
|
|
|
|
|
+ "totalModels": "{total} total model prices",
|
|
|
|
|
+ "searchResults": "(Search results: {count})",
|
|
|
|
|
+ "lastUpdated": "Last updated:"
|
|
|
|
|
+ },
|
|
|
|
|
+ "sync": {
|
|
|
|
|
+ "button": "Sync LiteLLM Prices",
|
|
|
|
|
+ "syncing": "Syncing...",
|
|
|
|
|
+ "successWithChanges": "Sync successful: Added {added}, Updated {updated}, Unchanged {unchanged}",
|
|
|
|
|
+ "successNoChanges": "All {unchanged} model prices are up to date",
|
|
|
|
|
+ "noModels": "No supported model prices found",
|
|
|
|
|
+ "failed": "Sync failed",
|
|
|
|
|
+ "failedError": "Sync failed, please retry",
|
|
|
|
|
+ "failedNoResult": "Sync successful but no result returned",
|
|
|
|
|
+ "partialFailure": "{failed} models failed to process"
|
|
|
|
|
+ },
|
|
|
"syncing": "Syncing...",
|
|
"syncing": "Syncing...",
|
|
|
"syncSuccess": "Price table updated successfully",
|
|
"syncSuccess": "Price table updated successfully",
|
|
|
"syncFailed": "Sync failed",
|
|
"syncFailed": "Sync failed",
|
|
|
"syncFailedError": "Sync failed:",
|
|
"syncFailedError": "Sync failed:",
|
|
|
"syncNoResult": "Price table updated but no result returned",
|
|
"syncNoResult": "Price table updated but no result returned",
|
|
|
- "upload": "Update Model Price Table",
|
|
|
|
|
|
|
+ "upload": {
|
|
|
|
|
+ "button": "Update Price Table",
|
|
|
|
|
+ "updating": "Updating...",
|
|
|
|
|
+ "dialogTitle": "Update Model Price Table",
|
|
|
|
|
+ "dialogDescription": "Select a JSON file containing model price data to update the price table",
|
|
|
|
|
+ "selectFile": "Click to select JSON file or drag and drop here",
|
|
|
|
|
+ "fileSizeLimit": "File size must not exceed 10MB",
|
|
|
|
|
+ "selectFileButton": "Select File",
|
|
|
|
|
+ "invalidFileType": "Please select a JSON file",
|
|
|
|
|
+ "fileTooLarge": "File size must not exceed 10MB",
|
|
|
|
|
+ "success": "Price table updated successfully",
|
|
|
|
|
+ "failed": "Update failed, please retry",
|
|
|
|
|
+ "failedError": "Update failed:",
|
|
|
|
|
+ "noResult": "Price table updated successfully but no result returned",
|
|
|
|
|
+ "updateInProgress": "Updating model prices...",
|
|
|
|
|
+ "enterDashboard": "Enter Dashboard",
|
|
|
|
|
+ "completed": "Completed"
|
|
|
|
|
+ },
|
|
|
"uploadSuccess": "Price table updated successfully",
|
|
"uploadSuccess": "Price table updated successfully",
|
|
|
"uploadFailed": "Failed to get pricing data:",
|
|
"uploadFailed": "Failed to get pricing data:",
|
|
|
"noData": "System has built-in price table. Use buttons above to sync or update.",
|
|
"noData": "System has built-in price table. Use buttons above to sync or update.",
|
|
|
"noModels": "No model prices found",
|
|
"noModels": "No model prices found",
|
|
|
"table": {
|
|
"table": {
|
|
|
- "model": "Model",
|
|
|
|
|
- "inputPrice": "Input Price",
|
|
|
|
|
- "outputPrice": "Output Price",
|
|
|
|
|
- "cachePrice": "Cache Price",
|
|
|
|
|
- "updatedAt": "Updated At"
|
|
|
|
|
|
|
+ "modelName": "Model Name",
|
|
|
|
|
+ "type": "Type",
|
|
|
|
|
+ "provider": "Provider",
|
|
|
|
|
+ "inputPrice": "Input Price ($/M)",
|
|
|
|
|
+ "outputPrice": "Output Price ($/M)",
|
|
|
|
|
+ "updatedAt": "Updated At",
|
|
|
|
|
+ "typeChat": "Chat",
|
|
|
|
|
+ "typeImageGen": "Image Generation",
|
|
|
|
|
+ "typeCompletion": "Completion",
|
|
|
|
|
+ "typeUnknown": "Unknown",
|
|
|
|
|
+ "imagePrice": "${price}/img",
|
|
|
|
|
+ "loading": "Loading...",
|
|
|
|
|
+ "noResults": "No matching models found",
|
|
|
|
|
+ "noData": "No price data available",
|
|
|
|
|
+ "noDataHint": "Built-in price table available. Use buttons above to sync or update"
|
|
|
},
|
|
},
|
|
|
"dialog": {
|
|
"dialog": {
|
|
|
"title": "Update Model Price Table",
|
|
"title": "Update Model Price Table",
|
|
@@ -230,6 +516,33 @@
|
|
|
"uploading": "Uploading...",
|
|
"uploading": "Uploading...",
|
|
|
"readError": "Failed to get key",
|
|
"readError": "Failed to get key",
|
|
|
"getError": "Failed to get key"
|
|
"getError": "Failed to get key"
|
|
|
|
|
+ },
|
|
|
|
|
+ "section": {
|
|
|
|
|
+ "title": "Model Pricing",
|
|
|
|
|
+ "description": "Manage AI model pricing configuration"
|
|
|
|
|
+ },
|
|
|
|
|
+ "pagination": {
|
|
|
|
|
+ "perPage": "Per page:",
|
|
|
|
|
+ "showing": "Showing {start} - {end} of {total} records",
|
|
|
|
|
+ "previous": "Previous",
|
|
|
|
|
+ "next": "Next"
|
|
|
|
|
+ },
|
|
|
|
|
+ "uploadDialog": {
|
|
|
|
|
+ "notes": {
|
|
|
|
|
+ "litellm": "• Built-in LiteLLM price table. Use 'Sync LiteLLM Prices' button on the left to update",
|
|
|
|
|
+ "manual": "• You can also manually download",
|
|
|
|
|
+ "link": "latest price table",
|
|
|
|
|
+ "linkAnd": "and update via this button",
|
|
|
|
|
+ "support": "• Supports Claude and OpenAI models (claude-, gpt-, o1-, o3- prefix)"
|
|
|
|
|
+ },
|
|
|
|
|
+ "result": {
|
|
|
|
|
+ "total": "Total Processed",
|
|
|
|
|
+ "added": "Models Added ({count})",
|
|
|
|
|
+ "updated": "Models Updated ({count})",
|
|
|
|
|
+ "unchanged": "Unchanged ({count})",
|
|
|
|
|
+ "failed": "Failed ({count})",
|
|
|
|
|
+ "showMore": "and {count} more"
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
},
|
|
},
|
|
|
"sensitiveWords": {
|
|
"sensitiveWords": {
|
|
@@ -276,6 +589,43 @@
|
|
|
"totalChecks": "Total Checks",
|
|
"totalChecks": "Total Checks",
|
|
|
"cacheSize": "Cache Size",
|
|
"cacheSize": "Cache Size",
|
|
|
"lastUpdated": "Last Updated"
|
|
"lastUpdated": "Last Updated"
|
|
|
|
|
+ },
|
|
|
|
|
+ "section": {
|
|
|
|
|
+ "title": "Sensitive Words List",
|
|
|
|
|
+ "description": "Requests blocked by sensitive words will not be forwarded upstream and will not be charged. Supports contains matching, exact matching, and regex patterns."
|
|
|
|
|
+ },
|
|
|
|
|
+ "refreshCacheSuccess": "Cache refreshed successfully, loaded {count} sensitive words",
|
|
|
|
|
+ "refreshCacheFailed": "Failed to refresh cache",
|
|
|
|
|
+ "cacheStats": "Cache stats: Contains({containsCount}) Exact({exactCount}) Regex({regexCount})",
|
|
|
|
|
+ "emptyState": "No sensitive words yet. Click 'Add Sensitive Word' in the top right to start configuration.",
|
|
|
|
|
+ "confirmDelete": "Are you sure you want to delete the sensitive word \"{word}\"?",
|
|
|
|
|
+ "dialog": {
|
|
|
|
|
+ "addTitle": "Add Sensitive Word",
|
|
|
|
|
+ "addDescription": "Configure sensitive word filtering rules. Matched requests will not be forwarded upstream.",
|
|
|
|
|
+ "editTitle": "Edit Sensitive Word",
|
|
|
|
|
+ "editDescription": "Modify sensitive word configuration. Changes will automatically refresh the cache.",
|
|
|
|
|
+ "wordLabel": "Sensitive Word *",
|
|
|
|
|
+ "wordPlaceholder": "Enter sensitive word...",
|
|
|
|
|
+ "wordRequired": "Please enter a sensitive word",
|
|
|
|
|
+ "matchTypeLabel": "Match Type *",
|
|
|
|
|
+ "matchTypeContains": "Contains Match - Block if text contains this word",
|
|
|
|
|
+ "matchTypeExact": "Exact Match - Block only if exact match",
|
|
|
|
|
+ "matchTypeRegex": "Regular Expression - Support complex pattern matching",
|
|
|
|
|
+ "descriptionLabel": "Description",
|
|
|
|
|
+ "descriptionPlaceholder": "Optional: Add description...",
|
|
|
|
|
+ "creating": "Creating...",
|
|
|
|
|
+ "saving": "Saving..."
|
|
|
|
|
+ },
|
|
|
|
|
+ "table": {
|
|
|
|
|
+ "word": "Sensitive Word",
|
|
|
|
|
+ "matchType": "Match Type",
|
|
|
|
|
+ "matchTypeContains": "Contains Match",
|
|
|
|
|
+ "matchTypeExact": "Exact Match",
|
|
|
|
|
+ "matchTypeRegex": "Regular Expression",
|
|
|
|
|
+ "description": "Description",
|
|
|
|
|
+ "status": "Status",
|
|
|
|
|
+ "createdAt": "Created At",
|
|
|
|
|
+ "actions": "Actions"
|
|
|
}
|
|
}
|
|
|
},
|
|
},
|
|
|
"logs": {
|
|
"logs": {
|
|
@@ -343,21 +693,52 @@
|
|
|
"clientVersions": {
|
|
"clientVersions": {
|
|
|
"title": "Client Update Reminder",
|
|
"title": "Client Update Reminder",
|
|
|
"description": "Manage client version requirements to ensure users use latest stable version. VSCode plugin and CLI are managed separately.",
|
|
"description": "Manage client version requirements to ensure users use latest stable version. VSCode plugin and CLI are managed separately.",
|
|
|
|
|
+ "section": {
|
|
|
|
|
+ "settings": {
|
|
|
|
|
+ "title": "Update Reminder Settings",
|
|
|
|
|
+ "description": "When enabled, system automatically detects client version and blocks old version users."
|
|
|
|
|
+ },
|
|
|
|
|
+ "distribution": {
|
|
|
|
|
+ "title": "Client Version Distribution",
|
|
|
|
|
+ "description": "Shows client version info for active users in past 7 days. Each client type independently tracks GA versions."
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ "empty": {
|
|
|
|
|
+ "title": "No client data available",
|
|
|
|
|
+ "description": "No active users using recognizable clients in past 7 days"
|
|
|
|
|
+ },
|
|
|
"toggle": {
|
|
"toggle": {
|
|
|
- "title": "Update Reminder Settings",
|
|
|
|
|
- "description": "When enabled, system automatically detects client version and blocks old version users.",
|
|
|
|
|
- "note": "Note: VSCode plugin (claude-vscode) and CLI (claude-cli) use independent version detection strategies.",
|
|
|
|
|
- "enable": "Enable Client Version Check",
|
|
|
|
|
- "disable": "Disable Client Version Check",
|
|
|
|
|
|
|
+ "enable": "Enable Update Reminder",
|
|
|
|
|
+ "description": "When enabled, system will block requests from old version clients",
|
|
|
"enableSuccess": "Client version check enabled",
|
|
"enableSuccess": "Client version check enabled",
|
|
|
"disableSuccess": "Client version check disabled",
|
|
"disableSuccess": "Client version check disabled",
|
|
|
- "toggleFailed": "Toggle failed"
|
|
|
|
|
|
|
+ "toggleFailed": "Update failed"
|
|
|
|
|
+ },
|
|
|
|
|
+ "features": {
|
|
|
|
|
+ "title": "Feature Description",
|
|
|
|
|
+ "whatHappens": "What happens when enabled:",
|
|
|
|
|
+ "autoDetect": "System automatically detects the latest stable version (GA version) for each client type",
|
|
|
|
|
+ "gaRule": "GA Rule: ",
|
|
|
|
|
+ "gaRuleDesc": "A version is considered GA when used by more than 1 user",
|
|
|
|
|
+ "activeWindow": "Active Window: ",
|
|
|
|
|
+ "activeWindowDesc": "Only counts users with requests in the past 7 days",
|
|
|
|
|
+ "blockOldVersion": "Users with old versions will receive HTTP 400 error and cannot continue using the service",
|
|
|
|
|
+ "errorMessage": "Error message includes current version and required upgrade version",
|
|
|
|
|
+ "recommendation": "Recommendation: ",
|
|
|
|
|
+ "recommendationDesc": "Monitor the version distribution below and confirm new version stability before enabling."
|
|
|
},
|
|
},
|
|
|
- "stats": {
|
|
|
|
|
- "title": "Client Version Distribution",
|
|
|
|
|
- "description": "Shows client version info for active users in past 7 days. Each client type independently tracks GA versions.",
|
|
|
|
|
- "noData": "No client data available",
|
|
|
|
|
- "noDataDesc": "No active users using recognizable clients in past 7 days"
|
|
|
|
|
|
|
+ "table": {
|
|
|
|
|
+ "internalType": "Internal Type: ",
|
|
|
|
|
+ "currentGA": "Current GA Version: ",
|
|
|
|
|
+ "usersCount": "{count} users",
|
|
|
|
|
+ "user": "User",
|
|
|
|
|
+ "version": "Current Version",
|
|
|
|
|
+ "lastActive": "Last Active",
|
|
|
|
|
+ "status": "Status",
|
|
|
|
|
+ "noUsers": "No user data available",
|
|
|
|
|
+ "latest": "Latest",
|
|
|
|
|
+ "needsUpgrade": "Needs Upgrade",
|
|
|
|
|
+ "unknown": "Unknown"
|
|
|
}
|
|
}
|
|
|
},
|
|
},
|
|
|
"notifications": {
|
|
"notifications": {
|
|
@@ -433,4 +814,4 @@
|
|
|
"loadFailed": "Failed to load notification settings",
|
|
"loadFailed": "Failed to load notification settings",
|
|
|
"unknownError": "An error occurred during operation"
|
|
"unknownError": "An error occurred during operation"
|
|
|
}
|
|
}
|
|
|
-}
|
|
|
|
|
|
|
+}
|