mirror of
https://github.com/Wei-Shaw/sub2api.git
synced 2026-11-02 08:31:35 +00:00
Merge upstream/main into fix/api-double-billing
This commit is contained in:
commit
0d9c140bc2
120 files changed
+6391
-402
No files matched your search
@@ -0,0 +1,30 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
|
||||
import en from '../locales/en'
|
||||
import zh from '../locales/zh'
|
||||
|
||||
describe('OpenAI Fast/Flex policy locale keys', () => {
|
||||
it('exposes user scope copy at the runtime zh path', () => {
|
||||
expect(zh.admin.settings.openaiFastPolicy).toMatchObject({
|
||||
userIds: '指定用户',
|
||||
userIdsHint: '输入任意邮箱关键词进行模糊搜索。留空表示对全部 Sub2API 用户生效;选中用户的 API Key 请求优先匹配用户规则。',
|
||||
userSearchPlaceholder: '输入用户邮箱搜索',
|
||||
userSearchEmpty: '未找到匹配用户',
|
||||
userDeleted: '(已删除)',
|
||||
userIdFallback: '用户 #{id}',
|
||||
removeUser: '移除用户'
|
||||
})
|
||||
})
|
||||
|
||||
it('exposes user scope copy at the runtime en path', () => {
|
||||
expect(en.admin.settings.openaiFastPolicy).toMatchObject({
|
||||
userIds: 'Specific users',
|
||||
userIdsHint: 'Type any part of a user email to search. Leave empty to apply to all Sub2API users. Selected users match requests from their API keys and take precedence over global rules.',
|
||||
userSearchPlaceholder: 'Search by user email',
|
||||
userSearchEmpty: 'No matching users found',
|
||||
userDeleted: '(deleted)',
|
||||
userIdFallback: 'User #{id}',
|
||||
removeUser: 'Remove user'
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -1,5 +1,6 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import en from '@/i18n/locales/en'
|
||||
import zh from '@/i18n/locales/zh'
|
||||
|
||||
function flattenKeys(obj: Record<string, any>, prefix = ''): string[] {
|
||||
const keys: string[] = []
|
||||
@@ -35,4 +36,18 @@ describe('groups locale key completeness', () => {
|
||||
const enKeys = flattenKeys(en)
|
||||
expect(enKeys).toContain('admin.groups.failedToSave')
|
||||
})
|
||||
|
||||
const webSearchPricingKeys = [
|
||||
'admin.groups.webSearchPricing.title',
|
||||
'admin.groups.webSearchPricing.pricePerCall',
|
||||
'admin.groups.webSearchPricing.pricePerCallHint',
|
||||
'admin.groups.webSearchPricing.finalPricePreview',
|
||||
]
|
||||
|
||||
for (const key of webSearchPricingKeys) {
|
||||
it(`en and zh locales both have ${key}`, () => {
|
||||
expect(flattenKeys(en)).toContain(key)
|
||||
expect(flattenKeys(zh)).toContain(key)
|
||||
})
|
||||
}
|
||||
})
|
||||
@@ -939,6 +939,13 @@ export default {
|
||||
finalPricePreview: 'Final per-second price preview',
|
||||
notConfigured: 'Not configured'
|
||||
},
|
||||
webSearchPricing: {
|
||||
title: 'Codex Web Search Pricing',
|
||||
pricePerCall: 'Price per search call (USD)',
|
||||
pricePerCallHint:
|
||||
'Leave empty to use the default $0.01 per call (official pricing: $10 per 1,000 calls); 0 means free. The group rate multiplier is applied on top.',
|
||||
finalPricePreview: 'Per-call price after current multiplier: {price}'
|
||||
},
|
||||
peakRate: {
|
||||
enable: 'Enable peak rate multiplier',
|
||||
peakStart: 'Peak start',
|
||||
|
||||
@@ -979,11 +979,6 @@ export default {
|
||||
scopeOAuth: 'OAuth only',
|
||||
scopeAPIKey: 'API Key only',
|
||||
scopeBedrock: 'Bedrock only',
|
||||
userIds: 'Specific user IDs',
|
||||
userIdsHint: 'Leave empty to apply to all Sub2API users. Specified users match requests from their API keys and take precedence over global rules.',
|
||||
userIdPlaceholder: 'e.g., 1001',
|
||||
addUserId: 'Add user ID',
|
||||
removeUserId: 'Remove user ID',
|
||||
errorMessage: 'Error message',
|
||||
errorMessagePlaceholder: 'Custom error message when blocked',
|
||||
errorMessageHint: 'Leave empty for default message',
|
||||
@@ -1024,6 +1019,13 @@ export default {
|
||||
scopeOAuth: 'OAuth only',
|
||||
scopeAPIKey: 'API Key only',
|
||||
scopeBedrock: 'Bedrock only',
|
||||
userIds: 'Specific users',
|
||||
userIdsHint: 'Type any part of a user email to search. Leave empty to apply to all Sub2API users. Selected users match requests from their API keys and take precedence over global rules.',
|
||||
userSearchPlaceholder: 'Search by user email',
|
||||
userSearchEmpty: 'No matching users found',
|
||||
userDeleted: '(deleted)',
|
||||
userIdFallback: 'User #{id}',
|
||||
removeUser: 'Remove user',
|
||||
errorMessage: 'Error message',
|
||||
errorMessagePlaceholder: 'Custom error message when blocked',
|
||||
errorMessageHint: 'Leave empty for the default message.',
|
||||
|
||||
@@ -146,6 +146,7 @@ export default {
|
||||
geminiCli: 'Gemini CLI',
|
||||
codexCli: 'Codex CLI',
|
||||
codexCliWs: 'Codex CLI (WebSocket)',
|
||||
grokCli: 'Grok CLI',
|
||||
opencode: 'OpenCode',
|
||||
},
|
||||
antigravity: {
|
||||
@@ -160,6 +161,12 @@ export default {
|
||||
modelComment: 'If you have Gemini 3 access, you can use: gemini-3-pro-preview',
|
||||
note: 'These environment variables will be active in the current terminal session. For permanent configuration, add them to ~/.bashrc, ~/.zshrc, or the appropriate configuration file.',
|
||||
},
|
||||
grok: {
|
||||
description: 'Configure Grok Build or OpenCode to send Responses API traffic through your Sub2API Grok group.',
|
||||
configTomlHint: 'Back up an existing config.toml before merging this model entry. Run grok inspect after saving to verify the effective configuration.',
|
||||
note: 'Save the file as ~/.grok/config.toml, then run grok inspect and select sub2api-grok from /model.',
|
||||
noteWindows: 'Save the file as %USERPROFILE%\\.grok\\config.toml, then run grok inspect and select sub2api-grok from /model.',
|
||||
},
|
||||
opencode: {
|
||||
title: 'OpenCode Example',
|
||||
subtitle: 'opencode.json',
|
||||
|
||||
@@ -930,6 +930,13 @@ export default {
|
||||
finalPricePreview: '最终每秒价格预览',
|
||||
notConfigured: '未配置'
|
||||
},
|
||||
webSearchPricing: {
|
||||
title: 'Codex 网页搜索计费',
|
||||
pricePerCall: '搜索单次价格(USD/次)',
|
||||
pricePerCallHint:
|
||||
'留空使用默认价 $0.01/次(官方定价 $10/1000 次);填 0 表示免费。实际扣费会叠加分组费率倍数。',
|
||||
finalPricePreview: '应用当前倍率后的单次价格:{price}'
|
||||
},
|
||||
peakRate: {
|
||||
enable: '启用高峰倍率',
|
||||
peakStart: '高峰开始',
|
||||
|
||||
@@ -974,11 +974,6 @@ export default {
|
||||
scopeOAuth: '仅 OAuth 账号',
|
||||
scopeAPIKey: '仅 API Key 账号',
|
||||
scopeBedrock: '仅 Bedrock 账号',
|
||||
userIds: '指定用户 ID',
|
||||
userIdsHint: '留空表示对全部 Sub2API 用户生效。指定后仅匹配这些用户的 API Key 请求,且优先于全局规则。',
|
||||
userIdPlaceholder: '例如: 1001',
|
||||
addUserId: '添加用户 ID',
|
||||
removeUserId: '移除用户 ID',
|
||||
errorMessage: '错误消息',
|
||||
errorMessagePlaceholder: '拦截时返回的自定义错误消息',
|
||||
errorMessageHint: '留空则使用默认错误消息',
|
||||
@@ -1019,6 +1014,13 @@ export default {
|
||||
scopeOAuth: '仅 OAuth 账号',
|
||||
scopeAPIKey: '仅 API Key 账号',
|
||||
scopeBedrock: '仅 Bedrock 账号',
|
||||
userIds: '指定用户',
|
||||
userIdsHint: '输入任意邮箱关键词进行模糊搜索。留空表示对全部 Sub2API 用户生效;选中用户的 API Key 请求优先匹配用户规则。',
|
||||
userSearchPlaceholder: '输入用户邮箱搜索',
|
||||
userSearchEmpty: '未找到匹配用户',
|
||||
userDeleted: '(已删除)',
|
||||
userIdFallback: '用户 #{id}',
|
||||
removeUser: '移除用户',
|
||||
errorMessage: '错误消息',
|
||||
errorMessagePlaceholder: '拦截时返回的自定义错误消息',
|
||||
errorMessageHint: '留空则使用默认错误消息。',
|
||||
|
||||
@@ -147,6 +147,7 @@ export default {
|
||||
geminiCli: 'Gemini CLI',
|
||||
codexCli: 'Codex CLI',
|
||||
codexCliWs: 'Codex CLI (WebSocket)',
|
||||
grokCli: 'Grok CLI',
|
||||
opencode: 'OpenCode'
|
||||
},
|
||||
antigravity: {
|
||||
@@ -164,6 +165,12 @@ export default {
|
||||
modelComment: '如果你有 Gemini 3 权限可以填:gemini-3-pro-preview',
|
||||
note: '这些环境变量将在当前终端会话中生效。如需永久配置,请将其添加到 ~/.bashrc、~/.zshrc 或相应的配置文件中。'
|
||||
},
|
||||
grok: {
|
||||
description: '配置 Grok Build 或 OpenCode,让 Responses API 请求通过当前 Sub2API Grok 分组发送。',
|
||||
configTomlHint: '如已有 config.toml,请先备份再合并此模型配置。保存后运行 grok inspect 验证生效配置。',
|
||||
note: '保存为 ~/.grok/config.toml,然后运行 grok inspect,并在 /model 中选择 sub2api-grok。',
|
||||
noteWindows: '保存为 %USERPROFILE%\\.grok\\config.toml,然后运行 grok inspect,并在 /model 中选择 sub2api-grok。'
|
||||
},
|
||||
opencode: {
|
||||
title: 'OpenCode 配置示例',
|
||||
subtitle: 'opencode.json',
|
||||
|
||||
Reference in new issue
Block a user