mirror of
https://github.com/router-for-me/Cli-Proxy-API-Management-Center.git
synced 2026-02-03 03:10:50 +08:00
Compare commits
28 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
aa729914c5 | ||
|
|
f98f31f2ed | ||
|
|
1e79f918e2 | ||
|
|
257260b1d2 | ||
|
|
8372906820 | ||
|
|
5feea2e345 | ||
|
|
825ad53c2c | ||
|
|
3e9413172c | ||
|
|
89099b58ff | ||
|
|
7509a1eddc | ||
|
|
e92784f951 | ||
|
|
d26695da76 | ||
|
|
8964030ade | ||
|
|
0b9abdf9b1 | ||
|
|
a208a484ff | ||
|
|
369cf52346 | ||
|
|
dcfffc716b | ||
|
|
7de5280824 | ||
|
|
86d60aad77 | ||
|
|
020fccc032 | ||
|
|
c162ab3a54 | ||
|
|
85d12e15d8 | ||
|
|
ebffb49f52 | ||
|
|
316c1ffc0d | ||
|
|
b3e54e7f14 | ||
|
|
fe11bfb48f | ||
|
|
ee0d8f82d7 | ||
|
|
0bbb397df5 |
2
.github/workflows/release.yml
vendored
2
.github/workflows/release.yml
vendored
@@ -27,6 +27,8 @@ jobs:
|
||||
|
||||
- name: Build all-in-one HTML
|
||||
run: npm run build
|
||||
env:
|
||||
VERSION: ${{ github.ref_name }}
|
||||
|
||||
- name: Prepare release assets
|
||||
run: |
|
||||
|
||||
5
.gitignore
vendored
5
.gitignore
vendored
@@ -20,3 +20,8 @@ package-lock.json
|
||||
# OS files
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
CLAUDE.md
|
||||
.claude
|
||||
AGENTS.md
|
||||
.serena
|
||||
@@ -10,7 +10,7 @@ Example URL:
|
||||
https://remote.router-for.me/
|
||||
|
||||
Minimum required version: ≥ 6.0.0
|
||||
Recommended version: ≥ 6.0.19
|
||||
Recommended version: ≥ 6.2.32
|
||||
|
||||
Since version 6.0.19, the WebUI has been rolled into the main program. You can access it by going to `/management.html` on the external port after firing up the main project.
|
||||
|
||||
@@ -43,7 +43,6 @@ Since version 6.0.19, the WebUI has been rolled into the main program. You can a
|
||||
- Download existing authentication files
|
||||
- Delete single or all authentication files
|
||||
- Display file details
|
||||
- **Gemini Web Token**: Direct authentication using browser cookies
|
||||
|
||||
### Usage Statistics
|
||||
- **Real-time Analytics**: Track API usage with interactive charts
|
||||
|
||||
@@ -8,7 +8,9 @@ https://github.com/router-for-me/CLIProxyAPI
|
||||
https://remote.router-for.me/
|
||||
|
||||
最低可用版本 ≥ 6.0.0
|
||||
推荐版本 ≥ 6.0.19
|
||||
|
||||
推荐版本 ≥ 6.2.32
|
||||
|
||||
自6.0.19起WebUI已经集成在主程序中 可以通过主项目开启的外部端口的`/management.html`访问
|
||||
|
||||
## 功能特点
|
||||
@@ -40,7 +42,6 @@ https://remote.router-for.me/
|
||||
- 下载现有认证文件
|
||||
- 删除单个或所有认证文件
|
||||
- 显示文件详细信息
|
||||
- **Gemini Web Token**: 使用浏览器 Cookie 直接认证
|
||||
|
||||
### 使用统计
|
||||
- **实时分析**: 通过交互式图表跟踪 API 使用情况
|
||||
|
||||
34
build.js
34
build.js
@@ -49,6 +49,35 @@ function escapeForStyle(content) {
|
||||
return content.replace(/<\/(style)/gi, '<\\/$1');
|
||||
}
|
||||
|
||||
function getVersion() {
|
||||
// 1. 优先从环境变量获取(GitHub Actions 会设置)
|
||||
if (process.env.VERSION) {
|
||||
return process.env.VERSION;
|
||||
}
|
||||
|
||||
// 2. 尝试从 git tag 获取
|
||||
try {
|
||||
const { execSync } = require('child_process');
|
||||
const gitTag = execSync('git describe --tags --exact-match 2>/dev/null || git describe --tags 2>/dev/null || echo ""', { encoding: 'utf8' }).trim();
|
||||
if (gitTag) {
|
||||
return gitTag;
|
||||
}
|
||||
} catch (err) {
|
||||
console.warn('无法从 git 获取版本号');
|
||||
}
|
||||
|
||||
// 3. 回退到 package.json
|
||||
try {
|
||||
const packageJson = JSON.parse(fs.readFileSync(path.join(projectRoot, 'package.json'), 'utf8'));
|
||||
return 'v' + packageJson.version;
|
||||
} catch (err) {
|
||||
console.warn('无法从 package.json 读取版本号');
|
||||
}
|
||||
|
||||
// 4. 最后使用默认值
|
||||
return 'v0.0.0-dev';
|
||||
}
|
||||
|
||||
function ensureDistDir() {
|
||||
if (fs.existsSync(distDir)) {
|
||||
fs.rmSync(distDir, { recursive: true, force: true });
|
||||
@@ -83,6 +112,11 @@ function build() {
|
||||
const i18n = escapeForScript(readFile(sourceFiles.i18n));
|
||||
const app = escapeForScript(readFile(sourceFiles.app));
|
||||
|
||||
// 获取版本号并替换
|
||||
const version = getVersion();
|
||||
console.log(`使用版本号: ${version}`);
|
||||
html = html.replace(/__VERSION__/g, version);
|
||||
|
||||
html = html.replace(
|
||||
'<link rel="stylesheet" href="styles.css">',
|
||||
`<style>
|
||||
|
||||
352
i18n.js
352
i18n.js
@@ -38,6 +38,9 @@ const i18n = {
|
||||
'common.base_url': '地址',
|
||||
'common.proxy_url': '代理',
|
||||
'common.alias': '别名',
|
||||
'common.failure': '失败',
|
||||
'common.unknown_error': '未知错误',
|
||||
'common.copy': '复制',
|
||||
|
||||
// 页面标题
|
||||
'title.main': 'CLI Proxy API Management Center',
|
||||
@@ -82,6 +85,8 @@ const i18n = {
|
||||
'nav.ai_providers': 'AI 提供商',
|
||||
'nav.auth_files': '认证文件',
|
||||
'nav.usage_stats': '使用统计',
|
||||
'nav.config_management': '配置管理',
|
||||
'nav.logs': '日志查看',
|
||||
'nav.system_info': '系统信息',
|
||||
|
||||
// 基础设置
|
||||
@@ -99,6 +104,10 @@ const i18n = {
|
||||
'basic_settings.quota_title': '配额超出行为',
|
||||
'basic_settings.quota_switch_project': '自动切换项目',
|
||||
'basic_settings.quota_switch_preview': '切换到预览模型',
|
||||
'basic_settings.usage_statistics_title': '使用统计',
|
||||
'basic_settings.usage_statistics_enable': '启用使用统计',
|
||||
'basic_settings.logging_title': '日志记录',
|
||||
'basic_settings.logging_to_file_enable': '启用日志记录到文件',
|
||||
|
||||
// API 密钥管理
|
||||
'api_keys.title': 'API 密钥管理',
|
||||
@@ -213,18 +222,91 @@ const i18n = {
|
||||
'auth_files.delete_success': '文件删除成功',
|
||||
'auth_files.delete_all_success': '成功删除',
|
||||
'auth_files.files_count': '个文件',
|
||||
'auth_files.filter_all': '全部',
|
||||
'auth_files.filter_qwen': 'Qwen',
|
||||
'auth_files.filter_gemini': 'Gemini',
|
||||
'auth_files.filter_claude': 'Claude',
|
||||
'auth_files.filter_codex': 'Codex',
|
||||
'auth_files.filter_iflow': 'iFlow',
|
||||
'auth_files.filter_empty': '空文件',
|
||||
'auth_files.filter_unknown': '其他',
|
||||
'auth_files.type_qwen': 'Qwen',
|
||||
'auth_files.type_gemini': 'Gemini',
|
||||
'auth_files.type_claude': 'Claude',
|
||||
'auth_files.type_codex': 'Codex',
|
||||
'auth_files.type_iflow': 'iFlow',
|
||||
'auth_files.type_empty': '空文件',
|
||||
'auth_files.type_unknown': '其他',
|
||||
|
||||
// Gemini Web Token
|
||||
'auth_login.gemini_web_title': 'Gemini Web Token',
|
||||
'auth_login.gemini_web_button': '保存 Gemini Web Token',
|
||||
'auth_login.gemini_web_hint': '从浏览器开发者工具中获取 Gemini 网页版的 Cookie 值,用于直接认证访问 Gemini。',
|
||||
'auth_login.secure_1psid_label': '__Secure-1PSID Cookie:',
|
||||
'auth_login.secure_1psid_placeholder': '输入 __Secure-1PSID cookie 值',
|
||||
'auth_login.secure_1psidts_label': '__Secure-1PSIDTS Cookie:',
|
||||
'auth_login.secure_1psidts_placeholder': '输入 __Secure-1PSIDTS cookie 值',
|
||||
'auth_login.gemini_web_label_label': '标签 (可选):',
|
||||
'auth_login.gemini_web_label_placeholder': '输入标签名称 (可选)',
|
||||
'auth_login.gemini_web_saved': 'Gemini Web Token 保存成功',
|
||||
|
||||
// Codex OAuth
|
||||
'auth_login.codex_oauth_title': 'Codex OAuth',
|
||||
'auth_login.codex_oauth_button': '开始 Codex 登录',
|
||||
'auth_login.codex_oauth_hint': '通过 OAuth 流程登录 Codex 服务,自动获取并保存认证文件。',
|
||||
'auth_login.codex_oauth_url_label': '授权链接:',
|
||||
'auth_login.codex_open_link': '打开链接',
|
||||
'auth_login.codex_copy_link': '复制链接',
|
||||
'auth_login.codex_oauth_status_waiting': '等待认证中...',
|
||||
'auth_login.codex_oauth_status_success': '认证成功!',
|
||||
'auth_login.codex_oauth_status_error': '认证失败:',
|
||||
'auth_login.codex_oauth_start_error': '启动 Codex OAuth 失败:',
|
||||
'auth_login.codex_oauth_polling_error': '检查认证状态失败:',
|
||||
|
||||
// Anthropic OAuth
|
||||
'auth_login.anthropic_oauth_title': 'Anthropic OAuth',
|
||||
'auth_login.anthropic_oauth_button': '开始 Anthropic 登录',
|
||||
'auth_login.anthropic_oauth_hint': '通过 OAuth 流程登录 Anthropic (Claude) 服务,自动获取并保存认证文件。',
|
||||
'auth_login.anthropic_oauth_url_label': '授权链接:',
|
||||
'auth_login.anthropic_open_link': '打开链接',
|
||||
'auth_login.anthropic_copy_link': '复制链接',
|
||||
'auth_login.anthropic_oauth_status_waiting': '等待认证中...',
|
||||
'auth_login.anthropic_oauth_status_success': '认证成功!',
|
||||
'auth_login.anthropic_oauth_status_error': '认证失败:',
|
||||
'auth_login.anthropic_oauth_start_error': '启动 Anthropic OAuth 失败:',
|
||||
'auth_login.anthropic_oauth_polling_error': '检查认证状态失败:',
|
||||
|
||||
// Gemini CLI OAuth
|
||||
'auth_login.gemini_cli_oauth_title': 'Gemini CLI OAuth',
|
||||
'auth_login.gemini_cli_oauth_button': '开始 Gemini CLI 登录',
|
||||
'auth_login.gemini_cli_oauth_hint': '通过 OAuth 流程登录 Google Gemini CLI 服务,自动获取并保存认证文件。',
|
||||
'auth_login.gemini_cli_project_id_label': 'Google Cloud 项目 ID (可选):',
|
||||
'auth_login.gemini_cli_project_id_placeholder': '输入 Google Cloud 项目 ID (可选)',
|
||||
'auth_login.gemini_cli_project_id_hint': '如果指定了项目 ID,将使用该项目的认证信息。',
|
||||
'auth_login.gemini_cli_oauth_url_label': '授权链接:',
|
||||
'auth_login.gemini_cli_open_link': '打开链接',
|
||||
'auth_login.gemini_cli_copy_link': '复制链接',
|
||||
'auth_login.gemini_cli_oauth_status_waiting': '等待认证中...',
|
||||
'auth_login.gemini_cli_oauth_status_success': '认证成功!',
|
||||
'auth_login.gemini_cli_oauth_status_error': '认证失败:',
|
||||
'auth_login.gemini_cli_oauth_start_error': '启动 Gemini CLI OAuth 失败:',
|
||||
'auth_login.gemini_cli_oauth_polling_error': '检查认证状态失败:',
|
||||
|
||||
// Qwen OAuth
|
||||
'auth_login.qwen_oauth_title': 'Qwen OAuth',
|
||||
'auth_login.qwen_oauth_button': '开始 Qwen 登录',
|
||||
'auth_login.qwen_oauth_hint': '通过设备授权流程登录 Qwen 服务,自动获取并保存认证文件。',
|
||||
'auth_login.qwen_oauth_url_label': '授权链接:',
|
||||
'auth_login.qwen_open_link': '打开链接',
|
||||
'auth_login.qwen_copy_link': '复制链接',
|
||||
'auth_login.qwen_oauth_status_waiting': '等待认证中...',
|
||||
'auth_login.qwen_oauth_status_success': '认证成功!',
|
||||
'auth_login.qwen_oauth_status_error': '认证失败:',
|
||||
'auth_login.qwen_oauth_start_error': '启动 Qwen OAuth 失败:',
|
||||
'auth_login.qwen_oauth_polling_error': '检查认证状态失败:',
|
||||
'auth_login.missing_state': '无法获取认证状态参数',
|
||||
|
||||
// iFlow OAuth
|
||||
'auth_login.iflow_oauth_title': 'iFlow OAuth',
|
||||
'auth_login.iflow_oauth_button': '开始 iFlow 登录',
|
||||
'auth_login.iflow_oauth_hint': '通过 OAuth 流程登录 iFlow 服务,自动获取并保存认证文件。',
|
||||
'auth_login.iflow_oauth_url_label': '授权链接:',
|
||||
'auth_login.iflow_open_link': '打开链接',
|
||||
'auth_login.iflow_copy_link': '复制链接',
|
||||
'auth_login.iflow_oauth_status_waiting': '等待认证中...',
|
||||
'auth_login.iflow_oauth_status_success': '认证成功!',
|
||||
'auth_login.iflow_oauth_status_error': '认证失败:',
|
||||
'auth_login.iflow_oauth_start_error': '启动 iFlow OAuth 失败:',
|
||||
'auth_login.iflow_oauth_polling_error': '检查认证状态失败:',
|
||||
|
||||
// 使用统计
|
||||
'usage_stats.title': '使用统计',
|
||||
@@ -245,6 +327,48 @@ const i18n = {
|
||||
'usage_stats.tokens_count': 'Token数量',
|
||||
'usage_stats.models': '模型统计',
|
||||
'usage_stats.success_rate': '成功率',
|
||||
'stats.success': '成功',
|
||||
'stats.failure': '失败',
|
||||
|
||||
// 日志查看
|
||||
'logs.title': '日志查看',
|
||||
'logs.refresh_button': '刷新日志',
|
||||
'logs.clear_button': '清空日志',
|
||||
'logs.download_button': '下载日志',
|
||||
'logs.empty_title': '暂无日志记录',
|
||||
'logs.empty_desc': '当启用"日志记录到文件"功能后,日志将显示在这里',
|
||||
'logs.log_content': '日志内容',
|
||||
'logs.loading': '正在加载日志...',
|
||||
'logs.load_error': '加载日志失败',
|
||||
'logs.clear_confirm': '确定要清空所有日志吗?此操作不可恢复!',
|
||||
'logs.clear_success': '日志已清空',
|
||||
'logs.download_success': '日志下载成功',
|
||||
'logs.auto_refresh': '自动刷新',
|
||||
'logs.auto_refresh_enabled': '自动刷新已开启',
|
||||
'logs.auto_refresh_disabled': '自动刷新已关闭',
|
||||
'logs.lines': '行',
|
||||
'logs.removed': '已删除',
|
||||
'logs.upgrade_required_title': '需要升级 CLI Proxy API',
|
||||
'logs.upgrade_required_desc': '当前服务器版本不支持日志查看功能,请升级到最新版本的 CLI Proxy API 以使用此功能。',
|
||||
|
||||
// 配置管理
|
||||
'config_management.title': '配置管理',
|
||||
'config_management.editor_title': '配置文件',
|
||||
'config_management.reload': '重新加载',
|
||||
'config_management.save': '保存',
|
||||
'config_management.description': '查看并编辑服务器上的 config.yaml 配置文件。保存前请确认语法正确。',
|
||||
'config_management.status_idle': '等待操作',
|
||||
'config_management.status_loading': '加载配置中...',
|
||||
'config_management.status_loaded': '配置已加载',
|
||||
'config_management.status_dirty': '有未保存的更改',
|
||||
'config_management.status_disconnected': '请先连接服务器以加载配置',
|
||||
'config_management.status_load_failed': '加载失败',
|
||||
'config_management.status_saving': '正在保存配置...',
|
||||
'config_management.status_saved': '配置保存完成',
|
||||
'config_management.status_save_failed': '保存失败',
|
||||
'config_management.save_success': '配置已保存',
|
||||
'config_management.error_yaml_not_supported': '服务器未返回 YAML 格式,请确认 /config.yaml 接口可用',
|
||||
'config_management.editor_placeholder': 'key: value',
|
||||
|
||||
// 系统信息
|
||||
'system_info.title': '系统信息',
|
||||
@@ -264,6 +388,8 @@ const i18n = {
|
||||
'notification.retry_updated': '重试设置已更新',
|
||||
'notification.quota_switch_project_updated': '项目切换设置已更新',
|
||||
'notification.quota_switch_preview_updated': '预览模型切换设置已更新',
|
||||
'notification.usage_statistics_updated': '使用统计设置已更新',
|
||||
'notification.logging_to_file_updated': '日志记录设置已更新',
|
||||
'notification.api_key_added': 'API密钥添加成功',
|
||||
'notification.api_key_updated': 'API密钥更新成功',
|
||||
'notification.api_key_deleted': 'API密钥删除成功',
|
||||
@@ -298,6 +424,7 @@ const i18n = {
|
||||
'notification.gemini_api_key': 'Gemini API密钥',
|
||||
'notification.codex_api_key': 'Codex API密钥',
|
||||
'notification.claude_api_key': 'Claude API密钥',
|
||||
'notification.link_copied': '链接已复制到剪贴板',
|
||||
|
||||
// 语言切换
|
||||
'language.switch': '语言',
|
||||
@@ -312,6 +439,10 @@ const i18n = {
|
||||
'theme.switch_to_dark': '切换到暗色模式',
|
||||
'theme.auto': '跟随系统',
|
||||
|
||||
// 侧边栏
|
||||
'sidebar.toggle_expand': '展开侧边栏',
|
||||
'sidebar.toggle_collapse': '收起侧边栏',
|
||||
|
||||
// 页脚
|
||||
'footer.version': '版本',
|
||||
'footer.author': '作者'
|
||||
@@ -347,6 +478,11 @@ const i18n = {
|
||||
'common.required': 'Required',
|
||||
'common.api_key': 'Key',
|
||||
'common.base_url': 'Address',
|
||||
'common.proxy_url': 'Proxy',
|
||||
'common.alias': 'Alias',
|
||||
'common.failure': 'Failure',
|
||||
'common.unknown_error': 'Unknown error',
|
||||
'common.copy': 'Copy',
|
||||
|
||||
// Page titles
|
||||
'title.main': 'CLI Proxy API Management Center',
|
||||
@@ -391,6 +527,8 @@ const i18n = {
|
||||
'nav.ai_providers': 'AI Providers',
|
||||
'nav.auth_files': 'Auth Files',
|
||||
'nav.usage_stats': 'Usage Statistics',
|
||||
'nav.config_management': 'Config Management',
|
||||
'nav.logs': 'Logs Viewer',
|
||||
'nav.system_info': 'System Info',
|
||||
|
||||
// Basic settings
|
||||
@@ -408,6 +546,10 @@ const i18n = {
|
||||
'basic_settings.quota_title': 'Quota Exceeded Behavior',
|
||||
'basic_settings.quota_switch_project': 'Auto Switch Project',
|
||||
'basic_settings.quota_switch_preview': 'Switch to Preview Model',
|
||||
'basic_settings.usage_statistics_title': 'Usage Statistics',
|
||||
'basic_settings.usage_statistics_enable': 'Enable usage statistics',
|
||||
'basic_settings.logging_title': 'Logging',
|
||||
'basic_settings.logging_to_file_enable': 'Enable logging to file',
|
||||
|
||||
// API Keys management
|
||||
'api_keys.title': 'API Keys Management',
|
||||
@@ -447,9 +589,12 @@ const i18n = {
|
||||
'ai_providers.codex_add_modal_key_placeholder': 'Please enter Codex API key',
|
||||
'ai_providers.codex_add_modal_url_label': 'Base URL (Optional):',
|
||||
'ai_providers.codex_add_modal_url_placeholder': 'e.g.: https://api.example.com',
|
||||
'ai_providers.codex_add_modal_proxy_label': 'Proxy URL (Optional):',
|
||||
'ai_providers.codex_add_modal_proxy_placeholder': 'e.g.: socks5://proxy.example.com:1080',
|
||||
'ai_providers.codex_edit_modal_title': 'Edit Codex API Configuration',
|
||||
'ai_providers.codex_edit_modal_key_label': 'API Key:',
|
||||
'ai_providers.codex_edit_modal_url_label': 'Base URL (Optional):',
|
||||
'ai_providers.codex_edit_modal_proxy_label': 'Proxy URL (Optional):',
|
||||
'ai_providers.codex_delete_confirm': 'Are you sure you want to delete this Codex configuration?',
|
||||
|
||||
'ai_providers.claude_title': 'Claude API Configuration',
|
||||
@@ -462,9 +607,12 @@ const i18n = {
|
||||
'ai_providers.claude_add_modal_key_placeholder': 'Please enter Claude API key',
|
||||
'ai_providers.claude_add_modal_url_label': 'Base URL (Optional):',
|
||||
'ai_providers.claude_add_modal_url_placeholder': 'e.g.: https://api.anthropic.com',
|
||||
'ai_providers.claude_add_modal_proxy_label': 'Proxy URL (Optional):',
|
||||
'ai_providers.claude_add_modal_proxy_placeholder': 'e.g.: socks5://proxy.example.com:1080',
|
||||
'ai_providers.claude_edit_modal_title': 'Edit Claude API Configuration',
|
||||
'ai_providers.claude_edit_modal_key_label': 'API Key:',
|
||||
'ai_providers.claude_edit_modal_url_label': 'Base URL (Optional):',
|
||||
'ai_providers.claude_edit_modal_proxy_label': 'Proxy URL (Optional):',
|
||||
'ai_providers.claude_delete_confirm': 'Are you sure you want to delete this Claude configuration?',
|
||||
|
||||
'ai_providers.openai_title': 'OpenAI Compatible Providers',
|
||||
@@ -478,10 +626,19 @@ const i18n = {
|
||||
'ai_providers.openai_add_modal_url_placeholder': 'e.g.: https://openrouter.ai/api/v1',
|
||||
'ai_providers.openai_add_modal_keys_label': 'API Keys (one per line):',
|
||||
'ai_providers.openai_add_modal_keys_placeholder': 'sk-key1\nsk-key2',
|
||||
'ai_providers.openai_add_modal_keys_proxy_label': 'Proxy URL (one per line, optional):',
|
||||
'ai_providers.openai_add_modal_keys_proxy_placeholder': 'socks5://proxy.example.com:1080\n',
|
||||
'ai_providers.openai_add_modal_models_label': 'Model List (name[, alias] one per line):',
|
||||
'ai_providers.openai_models_hint': 'Example: gpt-4o-mini or moonshotai/kimi-k2:free, kimi-k2',
|
||||
'ai_providers.openai_model_name_placeholder': 'Model name, e.g. moonshotai/kimi-k2:free',
|
||||
'ai_providers.openai_model_alias_placeholder': 'Model alias (optional)',
|
||||
'ai_providers.openai_models_add_btn': 'Add Model',
|
||||
'ai_providers.openai_edit_modal_title': 'Edit OpenAI Compatible Provider',
|
||||
'ai_providers.openai_edit_modal_name_label': 'Provider Name:',
|
||||
'ai_providers.openai_edit_modal_url_label': 'Base URL:',
|
||||
'ai_providers.openai_edit_modal_keys_label': 'API Keys (one per line):',
|
||||
'ai_providers.openai_edit_modal_keys_proxy_label': 'Proxy URL (one per line, optional):',
|
||||
'ai_providers.openai_edit_modal_models_label': 'Model List (name[, alias] one per line):',
|
||||
'ai_providers.openai_delete_confirm': 'Are you sure you want to delete this OpenAI provider?',
|
||||
'ai_providers.openai_keys_count': 'Keys Count',
|
||||
'ai_providers.openai_models_count': 'Models Count',
|
||||
@@ -507,18 +664,90 @@ const i18n = {
|
||||
'auth_files.delete_success': 'File deleted successfully',
|
||||
'auth_files.delete_all_success': 'Successfully deleted',
|
||||
'auth_files.files_count': 'files',
|
||||
'auth_files.filter_all': 'All',
|
||||
'auth_files.filter_qwen': 'Qwen',
|
||||
'auth_files.filter_gemini': 'Gemini',
|
||||
'auth_files.filter_claude': 'Claude',
|
||||
'auth_files.filter_codex': 'Codex',
|
||||
'auth_files.filter_iflow': 'iFlow',
|
||||
'auth_files.filter_empty': 'Empty',
|
||||
'auth_files.filter_unknown': 'Other',
|
||||
'auth_files.type_qwen': 'Qwen',
|
||||
'auth_files.type_gemini': 'Gemini',
|
||||
'auth_files.type_claude': 'Claude',
|
||||
'auth_files.type_codex': 'Codex',
|
||||
'auth_files.type_iflow': 'iFlow',
|
||||
'auth_files.type_empty': 'Empty',
|
||||
'auth_files.type_unknown': 'Other',
|
||||
|
||||
// Gemini Web Token
|
||||
'auth_login.gemini_web_title': 'Gemini Web Token',
|
||||
'auth_login.gemini_web_button': 'Save Gemini Web Token',
|
||||
'auth_login.gemini_web_hint': 'Obtain the Cookie value of the Gemini web version from the browser\'s developer tools, used for direct authentication to access Gemini.',
|
||||
'auth_login.secure_1psid_label': '__Secure-1PSID Cookie:',
|
||||
'auth_login.secure_1psid_placeholder': 'Enter __Secure-1PSID cookie value',
|
||||
'auth_login.secure_1psidts_label': '__Secure-1PSIDTS Cookie:',
|
||||
'auth_login.secure_1psidts_placeholder': 'Enter __Secure-1PSIDTS cookie value',
|
||||
'auth_login.gemini_web_label_label': 'Label (Optional):',
|
||||
'auth_login.gemini_web_label_placeholder': 'Enter label name (optional)',
|
||||
'auth_login.gemini_web_saved': 'Gemini Web Token saved successfully',
|
||||
// Codex OAuth
|
||||
'auth_login.codex_oauth_title': 'Codex OAuth',
|
||||
'auth_login.codex_oauth_button': 'Start Codex Login',
|
||||
'auth_login.codex_oauth_hint': 'Login to Codex service through OAuth flow, automatically obtain and save authentication files.',
|
||||
'auth_login.codex_oauth_url_label': 'Authorization URL:',
|
||||
'auth_login.codex_open_link': 'Open Link',
|
||||
'auth_login.codex_copy_link': 'Copy Link',
|
||||
'auth_login.codex_oauth_status_waiting': 'Waiting for authentication...',
|
||||
'auth_login.codex_oauth_status_success': 'Authentication successful!',
|
||||
'auth_login.codex_oauth_status_error': 'Authentication failed:',
|
||||
'auth_login.codex_oauth_start_error': 'Failed to start Codex OAuth:',
|
||||
'auth_login.codex_oauth_polling_error': 'Failed to check authentication status:',
|
||||
|
||||
// Anthropic OAuth
|
||||
'auth_login.anthropic_oauth_title': 'Anthropic OAuth',
|
||||
'auth_login.anthropic_oauth_button': 'Start Anthropic Login',
|
||||
'auth_login.anthropic_oauth_hint': 'Login to Anthropic (Claude) service through OAuth flow, automatically obtain and save authentication files.',
|
||||
'auth_login.anthropic_oauth_url_label': 'Authorization URL:',
|
||||
'auth_login.anthropic_open_link': 'Open Link',
|
||||
'auth_login.anthropic_copy_link': 'Copy Link',
|
||||
'auth_login.anthropic_oauth_status_waiting': 'Waiting for authentication...',
|
||||
'auth_login.anthropic_oauth_status_success': 'Authentication successful!',
|
||||
'auth_login.anthropic_oauth_status_error': 'Authentication failed:',
|
||||
'auth_login.anthropic_oauth_start_error': 'Failed to start Anthropic OAuth:',
|
||||
'auth_login.anthropic_oauth_polling_error': 'Failed to check authentication status:',
|
||||
|
||||
// Gemini CLI OAuth
|
||||
'auth_login.gemini_cli_oauth_title': 'Gemini CLI OAuth',
|
||||
'auth_login.gemini_cli_oauth_button': 'Start Gemini CLI Login',
|
||||
'auth_login.gemini_cli_oauth_hint': 'Login to Google Gemini CLI service through OAuth flow, automatically obtain and save authentication files.',
|
||||
'auth_login.gemini_cli_project_id_label': 'Google Cloud Project ID (Optional):',
|
||||
'auth_login.gemini_cli_project_id_placeholder': 'Enter Google Cloud Project ID (optional)',
|
||||
'auth_login.gemini_cli_project_id_hint': 'If a project ID is specified, authentication information for that project will be used.',
|
||||
'auth_login.gemini_cli_oauth_url_label': 'Authorization URL:',
|
||||
'auth_login.gemini_cli_open_link': 'Open Link',
|
||||
'auth_login.gemini_cli_copy_link': 'Copy Link',
|
||||
'auth_login.gemini_cli_oauth_status_waiting': 'Waiting for authentication...',
|
||||
'auth_login.gemini_cli_oauth_status_success': 'Authentication successful!',
|
||||
'auth_login.gemini_cli_oauth_status_error': 'Authentication failed:',
|
||||
'auth_login.gemini_cli_oauth_start_error': 'Failed to start Gemini CLI OAuth:',
|
||||
'auth_login.gemini_cli_oauth_polling_error': 'Failed to check authentication status:',
|
||||
|
||||
// Qwen OAuth
|
||||
'auth_login.qwen_oauth_title': 'Qwen OAuth',
|
||||
'auth_login.qwen_oauth_button': 'Start Qwen Login',
|
||||
'auth_login.qwen_oauth_hint': 'Login to Qwen service through device authorization flow, automatically obtain and save authentication files.',
|
||||
'auth_login.qwen_oauth_url_label': 'Authorization URL:',
|
||||
'auth_login.qwen_open_link': 'Open Link',
|
||||
'auth_login.qwen_copy_link': 'Copy Link',
|
||||
'auth_login.qwen_oauth_status_waiting': 'Waiting for authentication...',
|
||||
'auth_login.qwen_oauth_status_success': 'Authentication successful!',
|
||||
'auth_login.qwen_oauth_status_error': 'Authentication failed:',
|
||||
'auth_login.qwen_oauth_start_error': 'Failed to start Qwen OAuth:',
|
||||
'auth_login.qwen_oauth_polling_error': 'Failed to check authentication status:',
|
||||
'auth_login.missing_state': 'Unable to retrieve authentication state parameter',
|
||||
|
||||
// iFlow OAuth
|
||||
'auth_login.iflow_oauth_title': 'iFlow OAuth',
|
||||
'auth_login.iflow_oauth_button': 'Start iFlow Login',
|
||||
'auth_login.iflow_oauth_hint': 'Login to iFlow service through OAuth flow, automatically obtain and save authentication files.',
|
||||
'auth_login.iflow_oauth_url_label': 'Authorization URL:',
|
||||
'auth_login.iflow_open_link': 'Open Link',
|
||||
'auth_login.iflow_copy_link': 'Copy Link',
|
||||
'auth_login.iflow_oauth_status_waiting': 'Waiting for authentication...',
|
||||
'auth_login.iflow_oauth_status_success': 'Authentication successful!',
|
||||
'auth_login.iflow_oauth_status_error': 'Authentication failed:',
|
||||
'auth_login.iflow_oauth_start_error': 'Failed to start iFlow OAuth:',
|
||||
'auth_login.iflow_oauth_polling_error': 'Failed to check authentication status:',
|
||||
|
||||
// Usage Statistics
|
||||
'usage_stats.title': 'Usage Statistics',
|
||||
@@ -539,6 +768,48 @@ const i18n = {
|
||||
'usage_stats.tokens_count': 'Token Count',
|
||||
'usage_stats.models': 'Model Statistics',
|
||||
'usage_stats.success_rate': 'Success Rate',
|
||||
'stats.success': 'Success',
|
||||
'stats.failure': 'Failure',
|
||||
|
||||
// Logs viewer
|
||||
'logs.title': 'Logs Viewer',
|
||||
'logs.refresh_button': 'Refresh Logs',
|
||||
'logs.clear_button': 'Clear Logs',
|
||||
'logs.download_button': 'Download Logs',
|
||||
'logs.empty_title': 'No Logs Available',
|
||||
'logs.empty_desc': 'When "Enable logging to file" is enabled, logs will be displayed here',
|
||||
'logs.log_content': 'Log Content',
|
||||
'logs.loading': 'Loading logs...',
|
||||
'logs.load_error': 'Failed to load logs',
|
||||
'logs.clear_confirm': 'Are you sure you want to clear all logs? This action cannot be undone!',
|
||||
'logs.clear_success': 'Logs cleared successfully',
|
||||
'logs.download_success': 'Logs downloaded successfully',
|
||||
'logs.auto_refresh': 'Auto Refresh',
|
||||
'logs.auto_refresh_enabled': 'Auto refresh enabled',
|
||||
'logs.auto_refresh_disabled': 'Auto refresh disabled',
|
||||
'logs.lines': 'lines',
|
||||
'logs.removed': 'Removed',
|
||||
'logs.upgrade_required_title': 'Please Upgrade CLI Proxy API',
|
||||
'logs.upgrade_required_desc': 'The current server version does not support the logs viewing feature. Please upgrade to the latest version of CLI Proxy API to use this feature.',
|
||||
|
||||
// Config management
|
||||
'config_management.title': 'Config Management',
|
||||
'config_management.editor_title': 'Configuration File',
|
||||
'config_management.reload': 'Reload',
|
||||
'config_management.save': 'Save',
|
||||
'config_management.description': 'View and edit the server-side config.yaml file. Validate the syntax before saving.',
|
||||
'config_management.status_idle': 'Waiting for action',
|
||||
'config_management.status_loading': 'Loading configuration...',
|
||||
'config_management.status_loaded': 'Configuration loaded',
|
||||
'config_management.status_dirty': 'Unsaved changes',
|
||||
'config_management.status_disconnected': 'Connect to the server to load the configuration',
|
||||
'config_management.status_load_failed': 'Load failed',
|
||||
'config_management.status_saving': 'Saving configuration...',
|
||||
'config_management.status_saved': 'Configuration saved',
|
||||
'config_management.status_save_failed': 'Save failed',
|
||||
'config_management.save_success': 'Configuration saved successfully',
|
||||
'config_management.error_yaml_not_supported': 'Server did not return YAML. Verify the /config.yaml endpoint is available.',
|
||||
'config_management.editor_placeholder': 'key: value',
|
||||
|
||||
// System info
|
||||
'system_info.title': 'System Information',
|
||||
@@ -558,6 +829,8 @@ const i18n = {
|
||||
'notification.retry_updated': 'Retry settings updated',
|
||||
'notification.quota_switch_project_updated': 'Project switch settings updated',
|
||||
'notification.quota_switch_preview_updated': 'Preview model switch settings updated',
|
||||
'notification.usage_statistics_updated': 'Usage statistics settings updated',
|
||||
'notification.logging_to_file_updated': 'Logging settings updated',
|
||||
'notification.api_key_added': 'API key added successfully',
|
||||
'notification.api_key_updated': 'API key updated successfully',
|
||||
'notification.api_key_deleted': 'API key deleted successfully',
|
||||
@@ -570,6 +843,8 @@ const i18n = {
|
||||
'notification.claude_config_added': 'Claude configuration added successfully',
|
||||
'notification.claude_config_updated': 'Claude configuration updated successfully',
|
||||
'notification.claude_config_deleted': 'Claude configuration deleted successfully',
|
||||
'notification.field_required': 'Required fields cannot be empty',
|
||||
'notification.openai_provider_required': 'Please fill in provider name and Base URL',
|
||||
'notification.openai_provider_added': 'OpenAI provider added successfully',
|
||||
'notification.openai_provider_updated': 'OpenAI provider updated successfully',
|
||||
'notification.openai_provider_deleted': 'OpenAI provider deleted successfully',
|
||||
@@ -590,6 +865,7 @@ const i18n = {
|
||||
'notification.gemini_api_key': 'Gemini API key',
|
||||
'notification.codex_api_key': 'Codex API key',
|
||||
'notification.claude_api_key': 'Claude API key',
|
||||
'notification.link_copied': 'Link copied to clipboard',
|
||||
|
||||
// Language switch
|
||||
'language.switch': 'Language',
|
||||
@@ -604,6 +880,10 @@ const i18n = {
|
||||
'theme.switch_to_dark': 'Switch to dark mode',
|
||||
'theme.auto': 'Follow system',
|
||||
|
||||
// Sidebar
|
||||
'sidebar.toggle_expand': 'Expand sidebar',
|
||||
'sidebar.toggle_collapse': 'Collapse sidebar',
|
||||
|
||||
// Footer
|
||||
'footer.version': 'Version',
|
||||
'footer.author': 'Author'
|
||||
@@ -613,8 +893,8 @@ const i18n = {
|
||||
// 获取翻译文本
|
||||
t(key, params = {}) {
|
||||
const translation = this.translations[this.currentLanguage]?.[key] ||
|
||||
this.translations[this.fallbackLanguage]?.[key] ||
|
||||
key;
|
||||
this.translations[this.fallbackLanguage]?.[key] ||
|
||||
key;
|
||||
|
||||
// 简单的参数替换
|
||||
return translation.replace(/\{(\w+)\}/g, (match, param) => {
|
||||
@@ -653,6 +933,30 @@ const i18n = {
|
||||
}
|
||||
});
|
||||
|
||||
// 更新所有包含 data-i18n-placeholder 的输入框占位符
|
||||
document.querySelectorAll('[data-i18n-placeholder]').forEach(element => {
|
||||
const key = element.getAttribute('data-i18n-placeholder');
|
||||
element.placeholder = this.t(key);
|
||||
});
|
||||
|
||||
// 更新 data-i18n-title
|
||||
document.querySelectorAll('[data-i18n-title]').forEach(element => {
|
||||
const key = element.getAttribute('data-i18n-title');
|
||||
element.title = this.t(key);
|
||||
});
|
||||
|
||||
// 更新 data-i18n-tooltip
|
||||
document.querySelectorAll('[data-i18n-tooltip]').forEach(element => {
|
||||
const key = element.getAttribute('data-i18n-tooltip');
|
||||
element.setAttribute('data-tooltip', this.t(key));
|
||||
});
|
||||
|
||||
// 更新 data-i18n-text(常用于按钮或标签)
|
||||
document.querySelectorAll('[data-i18n-text]').forEach(element => {
|
||||
const key = element.getAttribute('data-i18n-text');
|
||||
element.textContent = this.t(key);
|
||||
});
|
||||
|
||||
// 更新所有带有 data-i18n-html 属性的元素(支持HTML)
|
||||
document.querySelectorAll('[data-i18n-html]').forEach(element => {
|
||||
const key = element.getAttribute('data-i18n-html');
|
||||
|
||||
1139
index.html
1139
index.html
File diff suppressed because it is too large
Load Diff
1446
styles.css
1446
styles.css
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user