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
21 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
020fccc032 | ||
|
|
c162ab3a54 | ||
|
|
85d12e15d8 | ||
|
|
ebffb49f52 | ||
|
|
316c1ffc0d | ||
|
|
b3e54e7f14 | ||
|
|
fe11bfb48f | ||
|
|
ee0d8f82d7 | ||
|
|
0bbb397df5 | ||
|
|
27948b3d5c | ||
|
|
dff28db227 | ||
|
|
34b16ca886 | ||
|
|
fa86f76289 | ||
|
|
41ca99978f | ||
|
|
6ef674487f | ||
|
|
2be7ced21a | ||
|
|
b61155d215 | ||
|
|
5488d6153d | ||
|
|
30f5300bb4 | ||
|
|
52169200f1 | ||
|
|
80b2597611 |
100
README.md
100
README.md
@@ -9,8 +9,10 @@ https://github.com/router-for-me/CLIProxyAPI
|
|||||||
Example URL:
|
Example URL:
|
||||||
https://remote.router-for.me/
|
https://remote.router-for.me/
|
||||||
|
|
||||||
Minimum required version: ≥ 5.0.0
|
Minimum required version: ≥ 6.0.0
|
||||||
Recommended version: ≥ 5.2.6
|
Recommended version: ≥ 6.1.3
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
@@ -18,13 +20,16 @@ Recommended version: ≥ 5.2.6
|
|||||||
- Supports management key authentication
|
- Supports management key authentication
|
||||||
- Configurable API base address
|
- Configurable API base address
|
||||||
- Real-time connection status detection
|
- Real-time connection status detection
|
||||||
|
- Auto-login with saved credentials
|
||||||
|
- Language and theme switching
|
||||||
|
|
||||||
### Basic Settings
|
### Basic Settings
|
||||||
- **Debug Mode**: Enable/disable debugging
|
- **Debug Mode**: Enable/disable debugging
|
||||||
- **Proxy Settings**: Configure proxy server URL
|
- **Proxy Settings**: Configure proxy server URL
|
||||||
- **Request Retries**: Set the number of request retries
|
- **Request Retries**: Set the number of request retries
|
||||||
- **Quota Management**: Configure behavior when the quota is exceeded
|
- **Quota Management**: Configure behavior when the quota is exceeded
|
||||||
- **Local Access**: Manage local unauthenticated access
|
- Auto-switch project when quota exceeded
|
||||||
|
- Switch to preview models when quota exceeded
|
||||||
|
|
||||||
### API Key Management
|
### API Key Management
|
||||||
- **Proxy Service Authentication Key**: Manage API keys for the proxy service
|
- **Proxy Service Authentication Key**: Manage API keys for the proxy service
|
||||||
@@ -39,13 +44,31 @@ Recommended version: ≥ 5.2.6
|
|||||||
- Delete single or all authentication files
|
- Delete single or all authentication files
|
||||||
- Display file details
|
- Display file details
|
||||||
|
|
||||||
|
### Usage Statistics
|
||||||
|
- **Real-time Analytics**: Track API usage with interactive charts
|
||||||
|
- **Request Trends**: Visualize request patterns by hour/day
|
||||||
|
- **Token Usage**: Monitor token consumption over time
|
||||||
|
- **API Details**: Detailed statistics for each API endpoint
|
||||||
|
- **Success/Failure Rates**: Track API reliability metrics
|
||||||
|
|
||||||
|
### System Information
|
||||||
|
- **Connection Status**: Real-time connection monitoring
|
||||||
|
- **Configuration Status**: Track configuration loading state
|
||||||
|
- **Server Information**: Display server address and management key
|
||||||
|
- **Last Update**: Show when data was last refreshed
|
||||||
|
|
||||||
|
|
||||||
## How to Use
|
## How to Use
|
||||||
|
|
||||||
### 1. Direct Use (Recommended)
|
### 1. Using After CLI Proxy API Program Launch (Recommended)
|
||||||
|
Once the CLI Proxy API program is up and running, you can access the WebUI at `http://your-server-IP:8317/management.html`.
|
||||||
|
|
||||||
|
### 2. Direct Use
|
||||||
Simply open the `index.html` file directly in your browser to use it.
|
Simply open the `index.html` file directly in your browser to use it.
|
||||||
|
|
||||||
### 2. Use a Local Server
|
### 3. Use a Local Server
|
||||||
|
|
||||||
|
#### Option A: Using Node.js (npm)
|
||||||
```bash
|
```bash
|
||||||
# Install dependencies
|
# Install dependencies
|
||||||
npm install
|
npm install
|
||||||
@@ -54,10 +77,19 @@ npm install
|
|||||||
npm start
|
npm start
|
||||||
```
|
```
|
||||||
|
|
||||||
### 3. Configure API Connection
|
#### Option B: Using Python
|
||||||
|
```bash
|
||||||
|
# Python 3.x
|
||||||
|
python -m http.server 8000
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
Then open `http://localhost:8000` in your browser.
|
||||||
|
|
||||||
|
### 3. Configure Connection
|
||||||
1. Open the management interface.
|
1. Open the management interface.
|
||||||
2. On the login screen, enter:
|
2. On the login screen, enter:
|
||||||
- **Remote Address**: `http://localhost:8317` (`/v0/management` will be auto-completed for you)
|
- **Remote Address**: The current version automatically picks up the remote address from where you're connecting. But you can also set your own address if you prefer.
|
||||||
- **Management Key**: Your management key
|
- **Management Key**: Your management key
|
||||||
3. Click the "Connect" button.
|
3. Click the "Connect" button.
|
||||||
4. Once connected successfully, all features will be available.
|
4. Once connected successfully, all features will be available.
|
||||||
@@ -69,8 +101,16 @@ npm start
|
|||||||
- **API Keys**: Management of keys for various API services.
|
- **API Keys**: Management of keys for various API services.
|
||||||
- **AI Providers**: Configuration for AI service providers.
|
- **AI Providers**: Configuration for AI service providers.
|
||||||
- **Auth Files**: Upload and download management for authentication files.
|
- **Auth Files**: Upload and download management for authentication files.
|
||||||
|
- **Usage Stats**: Real-time analytics and usage statistics with interactive charts.
|
||||||
- **System Info**: Connection status and system information.
|
- **System Info**: Connection status and system information.
|
||||||
|
|
||||||
|
### Login Interface
|
||||||
|
- **Auto-connection**: Automatically attempts to connect using saved credentials
|
||||||
|
- **Custom Connection**: Manual configuration of API base address
|
||||||
|
- **Current Address Detection**: Automatically detects and uses current access address
|
||||||
|
- **Language Switching**: Support for multiple languages (English/Chinese)
|
||||||
|
- **Theme Switching**: Light and dark theme support
|
||||||
|
|
||||||
## Feature Highlights
|
## Feature Highlights
|
||||||
|
|
||||||
### Modern UI
|
### Modern UI
|
||||||
@@ -78,27 +118,45 @@ npm start
|
|||||||
- Beautiful gradient colors and shadow effects
|
- Beautiful gradient colors and shadow effects
|
||||||
- Smooth animations and transition effects
|
- Smooth animations and transition effects
|
||||||
- Intuitive icons and status indicators
|
- Intuitive icons and status indicators
|
||||||
|
- Dark/Light theme support with system preference detection
|
||||||
|
- Mobile-friendly sidebar with overlay
|
||||||
|
|
||||||
### Real-time Updates
|
### Real-time Updates
|
||||||
- Configuration changes take effect immediately
|
- Configuration changes take effect immediately
|
||||||
- Real-time status feedback
|
- Real-time status feedback
|
||||||
- Automatic data refresh
|
- Automatic data refresh
|
||||||
|
- Live usage statistics with interactive charts
|
||||||
|
- Real-time connection status monitoring
|
||||||
|
|
||||||
### Security Features
|
### Security Features
|
||||||
- Masked display for keys
|
- Masked display for keys
|
||||||
|
- Secure credential storage
|
||||||
|
- Auto-login with encrypted local storage
|
||||||
|
|
||||||
### Responsive Design
|
### Responsive Design
|
||||||
- Perfectly adapts to desktop and mobile devices
|
- Perfectly adapts to desktop and mobile devices
|
||||||
- Adaptive layout
|
- Adaptive layout with collapsible sidebar
|
||||||
- Touch-friendly interactions
|
- Touch-friendly interactions
|
||||||
|
- Mobile menu with overlay
|
||||||
|
|
||||||
|
### Analytics & Monitoring
|
||||||
|
- Interactive charts powered by Chart.js
|
||||||
|
- Real-time usage statistics
|
||||||
|
- Request trend visualization
|
||||||
|
- Token consumption tracking
|
||||||
|
- API performance metrics
|
||||||
|
|
||||||
## Tech Stack
|
## Tech Stack
|
||||||
|
|
||||||
- **Frontend**: Plain HTML, CSS, JavaScript
|
- **Frontend**: Plain HTML, CSS, JavaScript (ES6+)
|
||||||
- **Styling**: CSS3 + Flexbox/Grid
|
- **Styling**: CSS3 + Flexbox/Grid with CSS Variables
|
||||||
- **Icons**: Font Awesome 6.4.0
|
- **Icons**: Font Awesome 6.4.0
|
||||||
|
- **Charts**: Chart.js for interactive data visualization
|
||||||
- **Fonts**: Segoe UI system font
|
- **Fonts**: Segoe UI system font
|
||||||
- **API**: RESTful API calls
|
- **API**: RESTful API calls with automatic authentication
|
||||||
|
- **Internationalization**: Custom i18n system with English/Chinese support
|
||||||
|
- **Theme System**: CSS custom properties for dynamic theming
|
||||||
|
- **Storage**: LocalStorage for user preferences and credentials
|
||||||
|
|
||||||
## Troubleshooting
|
## Troubleshooting
|
||||||
|
|
||||||
@@ -118,12 +176,20 @@ npm start
|
|||||||
### File Structure
|
### File Structure
|
||||||
```
|
```
|
||||||
webui/
|
webui/
|
||||||
├── index.html # Main page
|
├── index.html # Main page with responsive layout
|
||||||
├── styles.css # Stylesheet
|
├── styles.css # Stylesheet with theme support
|
||||||
├── app.js # Application logic
|
├── app.js # Application logic and API management
|
||||||
├── package.json # Project configuration
|
├── i18n.js # Internationalization support (EN/CN)
|
||||||
├── i18n.js # Internationalization support
|
├── package.json # Project configuration
|
||||||
└── README.md # README document
|
├── build.js # Build script for production
|
||||||
|
├── bundle-entry.js # Entry point for bundling
|
||||||
|
├── build-scripts/ # Build utilities
|
||||||
|
│ └── prepare-html.js # HTML preparation script
|
||||||
|
├── logo.jpg # Application logo
|
||||||
|
├── LICENSE # MIT License
|
||||||
|
├── README.md # English documentation
|
||||||
|
├── README_CN.md # Chinese documentation
|
||||||
|
└── BUILD_RELEASE.md # Build and release notes
|
||||||
```
|
```
|
||||||
|
|
||||||
### API Calls
|
### API Calls
|
||||||
|
|||||||
102
README_CN.md
102
README_CN.md
@@ -1,13 +1,17 @@
|
|||||||
# Cli-Proxy-API-Management-Center
|
# Cli-Proxy-API-Management-Center
|
||||||
这是一个用于管理 CLI Proxy API 的现代化 Web 界面。
|
这是一个用于管理 CLI Proxy API 的现代化 Web 界面。
|
||||||
|
|
||||||
主项目
|
主项目
|
||||||
https://github.com/router-for-me/CLIProxyAPI
|
https://github.com/router-for-me/CLIProxyAPI
|
||||||
|
|
||||||
示例网站:
|
示例网站:
|
||||||
https://remote.router-for.me/
|
https://remote.router-for.me/
|
||||||
|
|
||||||
最低可用版本 ≥ 5.0.0
|
最低可用版本 ≥ 6.0.0
|
||||||
推荐版本 ≥ 5.2.6
|
|
||||||
|
推荐版本 ≥ 6.1.3
|
||||||
|
|
||||||
|
自6.0.19起WebUI已经集成在主程序中 可以通过主项目开启的外部端口的`/management.html`访问
|
||||||
|
|
||||||
## 功能特点
|
## 功能特点
|
||||||
|
|
||||||
@@ -15,13 +19,16 @@ https://remote.router-for.me/
|
|||||||
- 支持管理密钥认证
|
- 支持管理密钥认证
|
||||||
- 可配置 API 基础地址
|
- 可配置 API 基础地址
|
||||||
- 实时连接状态检测
|
- 实时连接状态检测
|
||||||
|
- 自动登录保存的凭据
|
||||||
|
- 语言和主题切换
|
||||||
|
|
||||||
### 基础设置
|
### 基础设置
|
||||||
- **调试模式**: 开启/关闭调试功能
|
- **调试模式**: 开启/关闭调试功能
|
||||||
- **代理设置**: 配置代理服务器 URL
|
- **代理设置**: 配置代理服务器 URL
|
||||||
- **请求重试**: 设置请求重试次数
|
- **请求重试**: 设置请求重试次数
|
||||||
- **配额管理**: 配置超出配额时的行为
|
- **配额管理**: 配置超出配额时的行为
|
||||||
- **本地访问**: 管理本地未认证访问
|
- 超出配额时自动切换项目
|
||||||
|
- 超出配额时切换到预览模型
|
||||||
|
|
||||||
### API 密钥管理
|
### API 密钥管理
|
||||||
- **代理服务认证密钥**: 管理用于代理服务的 API 密钥
|
- **代理服务认证密钥**: 管理用于代理服务的 API 密钥
|
||||||
@@ -36,13 +43,31 @@ https://remote.router-for.me/
|
|||||||
- 删除单个或所有认证文件
|
- 删除单个或所有认证文件
|
||||||
- 显示文件详细信息
|
- 显示文件详细信息
|
||||||
|
|
||||||
|
### 使用统计
|
||||||
|
- **实时分析**: 通过交互式图表跟踪 API 使用情况
|
||||||
|
- **请求趋势**: 按小时/天可视化请求模式
|
||||||
|
- **Token 使用**: 监控 Token 消耗随时间变化
|
||||||
|
- **API 详情**: 每个 API 端点的详细统计
|
||||||
|
- **成功率/失败率**: 跟踪 API 可靠性指标
|
||||||
|
|
||||||
|
### 系统信息
|
||||||
|
- **连接状态**: 实时连接监控
|
||||||
|
- **配置状态**: 跟踪配置加载状态
|
||||||
|
- **服务器信息**: 显示服务器地址和管理密钥
|
||||||
|
- **最后更新**: 显示数据最后刷新时间
|
||||||
|
|
||||||
|
|
||||||
## 使用方法
|
## 使用方法
|
||||||
|
|
||||||
### 1. 直接使用(推荐)
|
### 1. 在CLI Proxy API程序启动后使用 (推荐)
|
||||||
|
在启动了CLI Proxy API程序后 访问`http://您的服务器IP:8317/management.html`使用
|
||||||
|
|
||||||
|
### 2. 直接使用
|
||||||
直接用浏览器打开 `index.html` 文件即可使用。
|
直接用浏览器打开 `index.html` 文件即可使用。
|
||||||
|
|
||||||
### 2. 使用本地服务器
|
### 3. 使用本地服务器
|
||||||
|
|
||||||
|
#### 方法A:使用 Node.js (npm)
|
||||||
```bash
|
```bash
|
||||||
# 安装依赖
|
# 安装依赖
|
||||||
npm install
|
npm install
|
||||||
@@ -51,10 +76,19 @@ npm install
|
|||||||
npm start
|
npm start
|
||||||
```
|
```
|
||||||
|
|
||||||
### 3. 配置 API 连接
|
#### 方法B:使用 Python
|
||||||
|
```bash
|
||||||
|
# Python 3.x
|
||||||
|
python -m http.server 8000
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
然后在浏览器中打开 `http://localhost:8000`。
|
||||||
|
|
||||||
|
### 3. 配置连接
|
||||||
1. 打开管理界面
|
1. 打开管理界面
|
||||||
2. 在登录界面上输入:
|
2. 在登录界面上输入:
|
||||||
- **远程地址**: `http://localhost:8317`/v0/management将会自动为您补全
|
- **远程地址**: 现版本远程地址将会自动从您的访问地址中获取 当然您也可以自定义
|
||||||
- **管理密钥**: 您的管理密钥
|
- **管理密钥**: 您的管理密钥
|
||||||
3. 点击"连接"按钮
|
3. 点击"连接"按钮
|
||||||
4. 连接成功后即可使用所有功能
|
4. 连接成功后即可使用所有功能
|
||||||
@@ -66,8 +100,16 @@ npm start
|
|||||||
- **API 密钥**: 各种 API 服务的密钥管理
|
- **API 密钥**: 各种 API 服务的密钥管理
|
||||||
- **AI 提供商**: AI 服务提供商配置
|
- **AI 提供商**: AI 服务提供商配置
|
||||||
- **认证文件**: 认证文件的上传下载管理
|
- **认证文件**: 认证文件的上传下载管理
|
||||||
|
- **使用统计**: 实时分析和使用统计,包含交互式图表
|
||||||
- **系统信息**: 连接状态和系统信息
|
- **系统信息**: 连接状态和系统信息
|
||||||
|
|
||||||
|
### 登录界面
|
||||||
|
- **自动连接**: 使用保存的凭据自动尝试连接
|
||||||
|
- **自定义连接**: 手动配置 API 基础地址
|
||||||
|
- **当前地址检测**: 自动检测并使用当前访问地址
|
||||||
|
- **语言切换**: 支持多种语言(英文/中文)
|
||||||
|
- **主题切换**: 支持明暗主题
|
||||||
|
|
||||||
## 特性亮点
|
## 特性亮点
|
||||||
|
|
||||||
### 现代化 UI
|
### 现代化 UI
|
||||||
@@ -75,27 +117,45 @@ npm start
|
|||||||
- 美观的渐变色彩和阴影效果
|
- 美观的渐变色彩和阴影效果
|
||||||
- 流畅的动画和过渡效果
|
- 流畅的动画和过渡效果
|
||||||
- 直观的图标和状态指示
|
- 直观的图标和状态指示
|
||||||
|
- 明暗主题支持,自动检测系统偏好
|
||||||
|
- 移动端友好的侧边栏和遮罩
|
||||||
|
|
||||||
### 实时更新
|
### 实时更新
|
||||||
- 配置更改立即生效
|
- 配置更改立即生效
|
||||||
- 实时状态反馈
|
- 实时状态反馈
|
||||||
- 自动数据刷新
|
- 自动数据刷新
|
||||||
|
- 实时使用统计和交互式图表
|
||||||
|
- 实时连接状态监控
|
||||||
|
|
||||||
### 安全特性
|
### 安全特性
|
||||||
- 密钥遮蔽显示
|
- 密钥遮蔽显示
|
||||||
|
- 安全凭据存储
|
||||||
|
- 加密本地存储自动登录
|
||||||
|
|
||||||
### 响应式设计
|
### 响应式设计
|
||||||
- 完美适配桌面和移动设备
|
- 完美适配桌面和移动设备
|
||||||
- 自适应布局
|
- 自适应布局,可折叠侧边栏
|
||||||
- 触摸友好的交互
|
- 触摸友好的交互
|
||||||
|
- 移动端菜单和遮罩
|
||||||
|
|
||||||
|
### 分析与监控
|
||||||
|
- Chart.js 驱动的交互式图表
|
||||||
|
- 实时使用统计
|
||||||
|
- 请求趋势可视化
|
||||||
|
- Token 消耗跟踪
|
||||||
|
- API 性能指标
|
||||||
|
|
||||||
## 技术栈
|
## 技术栈
|
||||||
|
|
||||||
- **前端**: 纯 HTML、CSS、JavaScript
|
- **前端**: 纯 HTML、CSS、JavaScript (ES6+)
|
||||||
- **样式**: CSS3 + Flexbox/Grid
|
- **样式**: CSS3 + Flexbox/Grid,支持 CSS 变量
|
||||||
- **图标**: Font Awesome 6.4.0
|
- **图标**: Font Awesome 6.4.0
|
||||||
|
- **图表**: Chart.js 交互式数据可视化
|
||||||
- **字体**: Segoe UI 系统字体
|
- **字体**: Segoe UI 系统字体
|
||||||
- **API**: RESTful API 调用
|
- **API**: RESTful API 调用,自动认证
|
||||||
|
- **国际化**: 自定义 i18n 系统,支持中英文
|
||||||
|
- **主题系统**: CSS 自定义属性动态主题
|
||||||
|
- **存储**: LocalStorage 用户偏好和凭据存储
|
||||||
|
|
||||||
## 故障排除
|
## 故障排除
|
||||||
|
|
||||||
@@ -115,12 +175,20 @@ npm start
|
|||||||
### 文件结构
|
### 文件结构
|
||||||
```
|
```
|
||||||
webui/
|
webui/
|
||||||
├── index.html # 主页面
|
├── index.html # 主页面,响应式布局
|
||||||
├── styles.css # 样式文件
|
├── styles.css # 样式文件,支持主题
|
||||||
├── app.js # 应用逻辑
|
├── app.js # 应用逻辑和 API 管理
|
||||||
├── package.json # 项目配置
|
├── i18n.js # 国际化支持(中英文)
|
||||||
├── i18n.js # 国际化支持
|
├── package.json # 项目配置
|
||||||
└── README.md # 说明文档
|
├── build.js # 生产环境构建脚本
|
||||||
|
├── bundle-entry.js # 打包入口文件
|
||||||
|
├── build-scripts/ # 构建工具
|
||||||
|
│ └── prepare-html.js # HTML 准备脚本
|
||||||
|
├── logo.jpg # 应用图标
|
||||||
|
├── LICENSE # MIT 许可证
|
||||||
|
├── README.md # 英文文档
|
||||||
|
├── README_CN.md # 中文文档
|
||||||
|
└── BUILD_RELEASE.md # 构建和发布说明
|
||||||
```
|
```
|
||||||
|
|
||||||
### API 调用
|
### API 调用
|
||||||
|
|||||||
132
build.js
Normal file
132
build.js
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
const projectRoot = __dirname;
|
||||||
|
const distDir = path.join(projectRoot, 'dist');
|
||||||
|
|
||||||
|
const sourceFiles = {
|
||||||
|
html: path.join(projectRoot, 'index.html'),
|
||||||
|
css: path.join(projectRoot, 'styles.css'),
|
||||||
|
i18n: path.join(projectRoot, 'i18n.js'),
|
||||||
|
app: path.join(projectRoot, 'app.js')
|
||||||
|
};
|
||||||
|
|
||||||
|
const logoCandidates = ['logo.png', 'logo.jpg', 'logo.jpeg', 'logo.svg', 'logo.webp', 'logo.gif'];
|
||||||
|
const logoMimeMap = {
|
||||||
|
'.png': 'image/png',
|
||||||
|
'.jpg': 'image/jpeg',
|
||||||
|
'.jpeg': 'image/jpeg',
|
||||||
|
'.svg': 'image/svg+xml',
|
||||||
|
'.webp': 'image/webp',
|
||||||
|
'.gif': 'image/gif'
|
||||||
|
};
|
||||||
|
|
||||||
|
function readFile(filePath) {
|
||||||
|
try {
|
||||||
|
return fs.readFileSync(filePath, 'utf8');
|
||||||
|
} catch (err) {
|
||||||
|
console.error(`读取文件失败: ${filePath}`);
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function readBinary(filePath) {
|
||||||
|
try {
|
||||||
|
return fs.readFileSync(filePath);
|
||||||
|
} catch (err) {
|
||||||
|
console.error(`读取文件失败: ${filePath}`);
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function escapeForScript(content) {
|
||||||
|
return content.replace(/<\/(script)/gi, '<\\/$1');
|
||||||
|
}
|
||||||
|
|
||||||
|
function escapeForStyle(content) {
|
||||||
|
return content.replace(/<\/(style)/gi, '<\\/$1');
|
||||||
|
}
|
||||||
|
|
||||||
|
function ensureDistDir() {
|
||||||
|
if (fs.existsSync(distDir)) {
|
||||||
|
fs.rmSync(distDir, { recursive: true, force: true });
|
||||||
|
}
|
||||||
|
fs.mkdirSync(distDir);
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadLogoDataUrl() {
|
||||||
|
for (const candidate of logoCandidates) {
|
||||||
|
const filePath = path.join(projectRoot, candidate);
|
||||||
|
if (!fs.existsSync(filePath)) continue;
|
||||||
|
|
||||||
|
const ext = path.extname(candidate).toLowerCase();
|
||||||
|
const mime = logoMimeMap[ext];
|
||||||
|
if (!mime) {
|
||||||
|
console.warn(`未知 Logo 文件类型,跳过内联: ${candidate}`);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const buffer = readBinary(filePath);
|
||||||
|
const base64 = buffer.toString('base64');
|
||||||
|
return `data:${mime};base64,${base64}`;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function build() {
|
||||||
|
ensureDistDir();
|
||||||
|
|
||||||
|
let html = readFile(sourceFiles.html);
|
||||||
|
const css = escapeForStyle(readFile(sourceFiles.css));
|
||||||
|
const i18n = escapeForScript(readFile(sourceFiles.i18n));
|
||||||
|
const app = escapeForScript(readFile(sourceFiles.app));
|
||||||
|
|
||||||
|
html = html.replace(
|
||||||
|
'<link rel="stylesheet" href="styles.css">',
|
||||||
|
`<style>
|
||||||
|
${css}
|
||||||
|
</style>`
|
||||||
|
);
|
||||||
|
|
||||||
|
html = html.replace(
|
||||||
|
'<script src="i18n.js"></script>',
|
||||||
|
`<script>
|
||||||
|
${i18n}
|
||||||
|
</script>`
|
||||||
|
);
|
||||||
|
|
||||||
|
html = html.replace(
|
||||||
|
'<script src="app.js"></script>',
|
||||||
|
`<script>
|
||||||
|
${app}
|
||||||
|
</script>`
|
||||||
|
);
|
||||||
|
|
||||||
|
const logoDataUrl = loadLogoDataUrl();
|
||||||
|
if (logoDataUrl) {
|
||||||
|
const logoScript = `<script>window.__INLINE_LOGO__ = "${logoDataUrl}";</script>`;
|
||||||
|
if (html.includes('</body>')) {
|
||||||
|
html = html.replace('</body>', `${logoScript}\n</body>`);
|
||||||
|
} else {
|
||||||
|
html += `\n${logoScript}`;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.warn('未找到可内联的 Logo 文件,将保持运行时加载。');
|
||||||
|
}
|
||||||
|
|
||||||
|
const outputPath = path.join(distDir, 'index.html');
|
||||||
|
fs.writeFileSync(outputPath, html, 'utf8');
|
||||||
|
|
||||||
|
console.log('构建完成: dist/index.html');
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
build();
|
||||||
|
} catch (error) {
|
||||||
|
console.error('构建失败:', error);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
347
i18n.js
347
i18n.js
@@ -3,7 +3,7 @@ const i18n = {
|
|||||||
// 语言配置
|
// 语言配置
|
||||||
currentLanguage: 'zh-CN',
|
currentLanguage: 'zh-CN',
|
||||||
fallbackLanguage: 'zh-CN',
|
fallbackLanguage: 'zh-CN',
|
||||||
|
|
||||||
// 语言包
|
// 语言包
|
||||||
translations: {
|
translations: {
|
||||||
'zh-CN': {
|
'zh-CN': {
|
||||||
@@ -36,30 +36,26 @@ const i18n = {
|
|||||||
'common.required': '必填',
|
'common.required': '必填',
|
||||||
'common.api_key': '密钥',
|
'common.api_key': '密钥',
|
||||||
'common.base_url': '地址',
|
'common.base_url': '地址',
|
||||||
|
'common.proxy_url': '代理',
|
||||||
|
'common.alias': '别名',
|
||||||
|
|
||||||
// 页面标题
|
// 页面标题
|
||||||
'title.main': 'CLI Proxy API Management Center',
|
'title.main': 'CLI Proxy API Management Center',
|
||||||
'title.login': 'CLI Proxy API Management Center',
|
'title.login': 'CLI Proxy API Management Center',
|
||||||
|
|
||||||
// 自动登录
|
// 自动登录
|
||||||
'auto_login.title': '正在自动登录...',
|
'auto_login.title': '正在自动登录...',
|
||||||
'auto_login.message': '正在使用本地保存的连接信息尝试连接服务器',
|
'auto_login.message': '正在使用本地保存的连接信息尝试连接服务器',
|
||||||
|
|
||||||
// 登录页面
|
// 登录页面
|
||||||
'login.subtitle': '请输入连接信息以访问管理界面',
|
'login.subtitle': '请输入连接信息以访问管理界面',
|
||||||
'login.tab_local_title': 'Local',
|
'login.connection_title': '连接地址',
|
||||||
'login.tab_local_subtitle': '在本地运行 Cli Web 服务器',
|
'login.connection_current': '当前地址',
|
||||||
'login.tab_remote_title': 'Remote',
|
'login.connection_auto_hint': '系统将自动使用当前访问地址进行连接',
|
||||||
'login.tab_remote_subtitle': '远程连接到 Cli Web 服务器',
|
'login.custom_connection_label': '自定义连接地址:',
|
||||||
'login.proxy_label': '代理服务器 (可选):',
|
'login.custom_connection_placeholder': '例如: https://example.com:8317',
|
||||||
'login.proxy_placeholder': 'http://ip:port 或 https://ip:port 或 socks5://user:pass@ip:port',
|
'login.custom_connection_hint': '默认使用当前访问地址,若需要可手动输入其他地址。',
|
||||||
'login.local_port_label': '端口号:',
|
'login.use_current_address': '使用当前地址',
|
||||||
'login.local_port_placeholder': '8317',
|
|
||||||
'login.local_url_hint': '将连接到 http://localhost:端口/v0/management',
|
|
||||||
'login.api_url_label': 'API 基础地址:',
|
|
||||||
'login.api_url_placeholder': '例如: http://localhost:8317 或 127.0.0.1:8317',
|
|
||||||
'login.remote_api_url_placeholder': '例如: https://example.com:8317',
|
|
||||||
'login.api_url_hint': '将自动补全 /v0/management',
|
|
||||||
'login.management_key_label': '管理密钥:',
|
'login.management_key_label': '管理密钥:',
|
||||||
'login.management_key_placeholder': '请输入管理密钥',
|
'login.management_key_placeholder': '请输入管理密钥',
|
||||||
'login.connect_button': '连接',
|
'login.connect_button': '连接',
|
||||||
@@ -68,18 +64,18 @@ const i18n = {
|
|||||||
'login.error_title': '登录失败',
|
'login.error_title': '登录失败',
|
||||||
'login.error_required': '请填写完整的连接信息',
|
'login.error_required': '请填写完整的连接信息',
|
||||||
'login.error_invalid': '连接失败,请检查地址和密钥',
|
'login.error_invalid': '连接失败,请检查地址和密钥',
|
||||||
|
|
||||||
// 头部导航
|
// 头部导航
|
||||||
'header.check_connection': '检查连接',
|
'header.check_connection': '检查连接',
|
||||||
'header.refresh_all': '刷新全部',
|
'header.refresh_all': '刷新全部',
|
||||||
'header.logout': '登出',
|
'header.logout': '登出',
|
||||||
|
|
||||||
// 连接信息
|
// 连接信息
|
||||||
'connection.title': '连接信息',
|
'connection.title': '连接信息',
|
||||||
'connection.server_address': '服务器地址:',
|
'connection.server_address': '服务器地址:',
|
||||||
'connection.management_key': '管理密钥:',
|
'connection.management_key': '管理密钥:',
|
||||||
'connection.status': '连接状态:',
|
'connection.status': '连接状态:',
|
||||||
|
|
||||||
// 侧边栏导航
|
// 侧边栏导航
|
||||||
'nav.basic_settings': '基础设置',
|
'nav.basic_settings': '基础设置',
|
||||||
'nav.api_keys': 'API 密钥',
|
'nav.api_keys': 'API 密钥',
|
||||||
@@ -87,7 +83,7 @@ const i18n = {
|
|||||||
'nav.auth_files': '认证文件',
|
'nav.auth_files': '认证文件',
|
||||||
'nav.usage_stats': '使用统计',
|
'nav.usage_stats': '使用统计',
|
||||||
'nav.system_info': '系统信息',
|
'nav.system_info': '系统信息',
|
||||||
|
|
||||||
// 基础设置
|
// 基础设置
|
||||||
'basic_settings.title': '基础设置',
|
'basic_settings.title': '基础设置',
|
||||||
'basic_settings.debug_title': '调试模式',
|
'basic_settings.debug_title': '调试模式',
|
||||||
@@ -103,7 +99,7 @@ const i18n = {
|
|||||||
'basic_settings.quota_title': '配额超出行为',
|
'basic_settings.quota_title': '配额超出行为',
|
||||||
'basic_settings.quota_switch_project': '自动切换项目',
|
'basic_settings.quota_switch_project': '自动切换项目',
|
||||||
'basic_settings.quota_switch_preview': '切换到预览模型',
|
'basic_settings.quota_switch_preview': '切换到预览模型',
|
||||||
|
|
||||||
// API 密钥管理
|
// API 密钥管理
|
||||||
'api_keys.title': 'API 密钥管理',
|
'api_keys.title': 'API 密钥管理',
|
||||||
'api_keys.proxy_auth_title': '代理服务认证密钥',
|
'api_keys.proxy_auth_title': '代理服务认证密钥',
|
||||||
@@ -117,7 +113,7 @@ const i18n = {
|
|||||||
'api_keys.edit_modal_title': '编辑API密钥',
|
'api_keys.edit_modal_title': '编辑API密钥',
|
||||||
'api_keys.edit_modal_key_label': 'API密钥:',
|
'api_keys.edit_modal_key_label': 'API密钥:',
|
||||||
'api_keys.delete_confirm': '确定要删除这个API密钥吗?',
|
'api_keys.delete_confirm': '确定要删除这个API密钥吗?',
|
||||||
|
|
||||||
// AI 提供商
|
// AI 提供商
|
||||||
'ai_providers.title': 'AI 提供商配置',
|
'ai_providers.title': 'AI 提供商配置',
|
||||||
'ai_providers.gemini_title': 'Gemini API 密钥',
|
'ai_providers.gemini_title': 'Gemini API 密钥',
|
||||||
@@ -131,7 +127,7 @@ const i18n = {
|
|||||||
'ai_providers.gemini_edit_modal_title': '编辑Gemini API密钥',
|
'ai_providers.gemini_edit_modal_title': '编辑Gemini API密钥',
|
||||||
'ai_providers.gemini_edit_modal_key_label': 'API密钥:',
|
'ai_providers.gemini_edit_modal_key_label': 'API密钥:',
|
||||||
'ai_providers.gemini_delete_confirm': '确定要删除这个Gemini密钥吗?',
|
'ai_providers.gemini_delete_confirm': '确定要删除这个Gemini密钥吗?',
|
||||||
|
|
||||||
'ai_providers.codex_title': 'Codex API 配置',
|
'ai_providers.codex_title': 'Codex API 配置',
|
||||||
'ai_providers.codex_add_button': '添加配置',
|
'ai_providers.codex_add_button': '添加配置',
|
||||||
'ai_providers.codex_empty_title': '暂无Codex配置',
|
'ai_providers.codex_empty_title': '暂无Codex配置',
|
||||||
@@ -142,11 +138,14 @@ const i18n = {
|
|||||||
'ai_providers.codex_add_modal_key_placeholder': '请输入Codex API密钥',
|
'ai_providers.codex_add_modal_key_placeholder': '请输入Codex API密钥',
|
||||||
'ai_providers.codex_add_modal_url_label': 'Base URL (可选):',
|
'ai_providers.codex_add_modal_url_label': 'Base URL (可选):',
|
||||||
'ai_providers.codex_add_modal_url_placeholder': '例如: https://api.example.com',
|
'ai_providers.codex_add_modal_url_placeholder': '例如: https://api.example.com',
|
||||||
|
'ai_providers.codex_add_modal_proxy_label': '代理 URL (可选):',
|
||||||
|
'ai_providers.codex_add_modal_proxy_placeholder': '例如: socks5://proxy.example.com:1080',
|
||||||
'ai_providers.codex_edit_modal_title': '编辑Codex API配置',
|
'ai_providers.codex_edit_modal_title': '编辑Codex API配置',
|
||||||
'ai_providers.codex_edit_modal_key_label': 'API密钥:',
|
'ai_providers.codex_edit_modal_key_label': 'API密钥:',
|
||||||
'ai_providers.codex_edit_modal_url_label': 'Base URL (可选):',
|
'ai_providers.codex_edit_modal_url_label': 'Base URL (可选):',
|
||||||
|
'ai_providers.codex_edit_modal_proxy_label': '代理 URL (可选):',
|
||||||
'ai_providers.codex_delete_confirm': '确定要删除这个Codex配置吗?',
|
'ai_providers.codex_delete_confirm': '确定要删除这个Codex配置吗?',
|
||||||
|
|
||||||
'ai_providers.claude_title': 'Claude API 配置',
|
'ai_providers.claude_title': 'Claude API 配置',
|
||||||
'ai_providers.claude_add_button': '添加配置',
|
'ai_providers.claude_add_button': '添加配置',
|
||||||
'ai_providers.claude_empty_title': '暂无Claude配置',
|
'ai_providers.claude_empty_title': '暂无Claude配置',
|
||||||
@@ -157,11 +156,14 @@ const i18n = {
|
|||||||
'ai_providers.claude_add_modal_key_placeholder': '请输入Claude API密钥',
|
'ai_providers.claude_add_modal_key_placeholder': '请输入Claude API密钥',
|
||||||
'ai_providers.claude_add_modal_url_label': 'Base URL (可选):',
|
'ai_providers.claude_add_modal_url_label': 'Base URL (可选):',
|
||||||
'ai_providers.claude_add_modal_url_placeholder': '例如: https://api.anthropic.com',
|
'ai_providers.claude_add_modal_url_placeholder': '例如: https://api.anthropic.com',
|
||||||
|
'ai_providers.claude_add_modal_proxy_label': '代理 URL (可选):',
|
||||||
|
'ai_providers.claude_add_modal_proxy_placeholder': '例如: socks5://proxy.example.com:1080',
|
||||||
'ai_providers.claude_edit_modal_title': '编辑Claude API配置',
|
'ai_providers.claude_edit_modal_title': '编辑Claude API配置',
|
||||||
'ai_providers.claude_edit_modal_key_label': 'API密钥:',
|
'ai_providers.claude_edit_modal_key_label': 'API密钥:',
|
||||||
'ai_providers.claude_edit_modal_url_label': 'Base URL (可选):',
|
'ai_providers.claude_edit_modal_url_label': 'Base URL (可选):',
|
||||||
|
'ai_providers.claude_edit_modal_proxy_label': '代理 URL (可选):',
|
||||||
'ai_providers.claude_delete_confirm': '确定要删除这个Claude配置吗?',
|
'ai_providers.claude_delete_confirm': '确定要删除这个Claude配置吗?',
|
||||||
|
|
||||||
'ai_providers.openai_title': 'OpenAI 兼容提供商',
|
'ai_providers.openai_title': 'OpenAI 兼容提供商',
|
||||||
'ai_providers.openai_add_button': '添加提供商',
|
'ai_providers.openai_add_button': '添加提供商',
|
||||||
'ai_providers.openai_empty_title': '暂无OpenAI兼容提供商',
|
'ai_providers.openai_empty_title': '暂无OpenAI兼容提供商',
|
||||||
@@ -173,15 +175,24 @@ const i18n = {
|
|||||||
'ai_providers.openai_add_modal_url_placeholder': '例如: https://openrouter.ai/api/v1',
|
'ai_providers.openai_add_modal_url_placeholder': '例如: https://openrouter.ai/api/v1',
|
||||||
'ai_providers.openai_add_modal_keys_label': 'API密钥 (每行一个):',
|
'ai_providers.openai_add_modal_keys_label': 'API密钥 (每行一个):',
|
||||||
'ai_providers.openai_add_modal_keys_placeholder': 'sk-key1\nsk-key2',
|
'ai_providers.openai_add_modal_keys_placeholder': 'sk-key1\nsk-key2',
|
||||||
|
'ai_providers.openai_add_modal_keys_proxy_label': '代理 URL (按行对应,可选):',
|
||||||
|
'ai_providers.openai_add_modal_keys_proxy_placeholder': 'socks5://proxy.example.com:1080\n',
|
||||||
|
'ai_providers.openai_add_modal_models_label': '模型列表 (name[, alias] 每行一个):',
|
||||||
|
'ai_providers.openai_models_hint': '示例:gpt-4o-mini 或 moonshotai/kimi-k2:free, kimi-k2',
|
||||||
|
'ai_providers.openai_model_name_placeholder': '模型名称,如 moonshotai/kimi-k2:free',
|
||||||
|
'ai_providers.openai_model_alias_placeholder': '模型别名 (可选)',
|
||||||
|
'ai_providers.openai_models_add_btn': '添加模型',
|
||||||
'ai_providers.openai_edit_modal_title': '编辑OpenAI兼容提供商',
|
'ai_providers.openai_edit_modal_title': '编辑OpenAI兼容提供商',
|
||||||
'ai_providers.openai_edit_modal_name_label': '提供商名称:',
|
'ai_providers.openai_edit_modal_name_label': '提供商名称:',
|
||||||
'ai_providers.openai_edit_modal_url_label': 'Base URL:',
|
'ai_providers.openai_edit_modal_url_label': 'Base URL:',
|
||||||
'ai_providers.openai_edit_modal_keys_label': 'API密钥 (每行一个):',
|
'ai_providers.openai_edit_modal_keys_label': 'API密钥 (每行一个):',
|
||||||
|
'ai_providers.openai_edit_modal_keys_proxy_label': '代理 URL (按行对应,可选):',
|
||||||
|
'ai_providers.openai_edit_modal_models_label': '模型列表 (name[, alias] 每行一个):',
|
||||||
'ai_providers.openai_delete_confirm': '确定要删除这个OpenAI提供商吗?',
|
'ai_providers.openai_delete_confirm': '确定要删除这个OpenAI提供商吗?',
|
||||||
'ai_providers.openai_keys_count': '密钥数量',
|
'ai_providers.openai_keys_count': '密钥数量',
|
||||||
'ai_providers.openai_models_count': '模型数量',
|
'ai_providers.openai_models_count': '模型数量',
|
||||||
|
|
||||||
|
|
||||||
// 认证文件管理
|
// 认证文件管理
|
||||||
'auth_files.title': '认证文件管理',
|
'auth_files.title': '认证文件管理',
|
||||||
'auth_files.title_section': '认证文件',
|
'auth_files.title_section': '认证文件',
|
||||||
@@ -202,17 +213,76 @@ const i18n = {
|
|||||||
'auth_files.delete_success': '文件删除成功',
|
'auth_files.delete_success': '文件删除成功',
|
||||||
'auth_files.delete_all_success': '成功删除',
|
'auth_files.delete_all_success': '成功删除',
|
||||||
'auth_files.files_count': '个文件',
|
'auth_files.files_count': '个文件',
|
||||||
|
|
||||||
// Gemini Web Token
|
|
||||||
'auth_login.gemini_web_title': 'Gemini Web Token',
|
// Codex OAuth
|
||||||
'auth_login.gemini_web_button': '保存 Gemini Web Token',
|
'auth_login.codex_oauth_title': 'Codex OAuth',
|
||||||
'auth_login.gemini_web_hint': '从浏览器开发者工具中获取 Gemini 网页版的 Cookie 值,用于直接认证访问 Gemini。',
|
'auth_login.codex_oauth_button': '开始 Codex 登录',
|
||||||
'auth_login.secure_1psid_label': '__Secure-1PSID Cookie:',
|
'auth_login.codex_oauth_hint': '通过 OAuth 流程登录 Codex 服务,自动获取并保存认证文件。',
|
||||||
'auth_login.secure_1psid_placeholder': '输入 __Secure-1PSID cookie 值',
|
'auth_login.codex_oauth_url_label': '授权链接:',
|
||||||
'auth_login.secure_1psidts_label': '__Secure-1PSIDTS Cookie:',
|
'auth_login.codex_open_link': '打开链接',
|
||||||
'auth_login.secure_1psidts_placeholder': '输入 __Secure-1PSIDTS cookie 值',
|
'auth_login.codex_copy_link': '复制链接',
|
||||||
'auth_login.gemini_web_saved': 'Gemini Web Token 保存成功',
|
'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': '检查认证状态失败:',
|
||||||
|
|
||||||
|
// 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': '使用统计',
|
'usage_stats.title': '使用统计',
|
||||||
'usage_stats.total_requests': '总请求数',
|
'usage_stats.total_requests': '总请求数',
|
||||||
@@ -232,7 +302,7 @@ const i18n = {
|
|||||||
'usage_stats.tokens_count': 'Token数量',
|
'usage_stats.tokens_count': 'Token数量',
|
||||||
'usage_stats.models': '模型统计',
|
'usage_stats.models': '模型统计',
|
||||||
'usage_stats.success_rate': '成功率',
|
'usage_stats.success_rate': '成功率',
|
||||||
|
|
||||||
// 系统信息
|
// 系统信息
|
||||||
'system_info.title': '系统信息',
|
'system_info.title': '系统信息',
|
||||||
'system_info.connection_status_title': '连接状态',
|
'system_info.connection_status_title': '连接状态',
|
||||||
@@ -243,7 +313,7 @@ const i18n = {
|
|||||||
'system_info.real_time_data': '实时数据',
|
'system_info.real_time_data': '实时数据',
|
||||||
'system_info.not_loaded': '未加载',
|
'system_info.not_loaded': '未加载',
|
||||||
'system_info.seconds_ago': '秒前',
|
'system_info.seconds_ago': '秒前',
|
||||||
|
|
||||||
// 通知消息
|
// 通知消息
|
||||||
'notification.debug_updated': '调试设置已更新',
|
'notification.debug_updated': '调试设置已更新',
|
||||||
'notification.proxy_updated': '代理设置已更新',
|
'notification.proxy_updated': '代理设置已更新',
|
||||||
@@ -263,9 +333,12 @@ const i18n = {
|
|||||||
'notification.claude_config_added': 'Claude配置添加成功',
|
'notification.claude_config_added': 'Claude配置添加成功',
|
||||||
'notification.claude_config_updated': 'Claude配置更新成功',
|
'notification.claude_config_updated': 'Claude配置更新成功',
|
||||||
'notification.claude_config_deleted': 'Claude配置删除成功',
|
'notification.claude_config_deleted': 'Claude配置删除成功',
|
||||||
|
'notification.field_required': '必填字段不能为空',
|
||||||
|
'notification.openai_provider_required': '请填写提供商名称和Base URL',
|
||||||
'notification.openai_provider_added': 'OpenAI提供商添加成功',
|
'notification.openai_provider_added': 'OpenAI提供商添加成功',
|
||||||
'notification.openai_provider_updated': 'OpenAI提供商更新成功',
|
'notification.openai_provider_updated': 'OpenAI提供商更新成功',
|
||||||
'notification.openai_provider_deleted': 'OpenAI提供商删除成功',
|
'notification.openai_provider_deleted': 'OpenAI提供商删除成功',
|
||||||
|
'notification.openai_model_name_required': '请填写模型名称',
|
||||||
'notification.data_refreshed': '数据刷新成功',
|
'notification.data_refreshed': '数据刷新成功',
|
||||||
'notification.connection_required': '请先建立连接',
|
'notification.connection_required': '请先建立连接',
|
||||||
'notification.refresh_failed': '刷新失败',
|
'notification.refresh_failed': '刷新失败',
|
||||||
@@ -282,12 +355,12 @@ const i18n = {
|
|||||||
'notification.gemini_api_key': 'Gemini API密钥',
|
'notification.gemini_api_key': 'Gemini API密钥',
|
||||||
'notification.codex_api_key': 'Codex API密钥',
|
'notification.codex_api_key': 'Codex API密钥',
|
||||||
'notification.claude_api_key': 'Claude API密钥',
|
'notification.claude_api_key': 'Claude API密钥',
|
||||||
|
|
||||||
// 语言切换
|
// 语言切换
|
||||||
'language.switch': '语言',
|
'language.switch': '语言',
|
||||||
'language.chinese': '中文',
|
'language.chinese': '中文',
|
||||||
'language.english': 'English',
|
'language.english': 'English',
|
||||||
|
|
||||||
// 主题切换
|
// 主题切换
|
||||||
'theme.switch': '主题',
|
'theme.switch': '主题',
|
||||||
'theme.light': '亮色',
|
'theme.light': '亮色',
|
||||||
@@ -295,12 +368,12 @@ const i18n = {
|
|||||||
'theme.switch_to_light': '切换到亮色模式',
|
'theme.switch_to_light': '切换到亮色模式',
|
||||||
'theme.switch_to_dark': '切换到暗色模式',
|
'theme.switch_to_dark': '切换到暗色模式',
|
||||||
'theme.auto': '跟随系统',
|
'theme.auto': '跟随系统',
|
||||||
|
|
||||||
// 页脚
|
// 页脚
|
||||||
'footer.version': '版本',
|
'footer.version': '版本',
|
||||||
'footer.author': '作者'
|
'footer.author': '作者'
|
||||||
},
|
},
|
||||||
|
|
||||||
'en-US': {
|
'en-US': {
|
||||||
// Common
|
// Common
|
||||||
'common.login': 'Login',
|
'common.login': 'Login',
|
||||||
@@ -331,50 +404,46 @@ const i18n = {
|
|||||||
'common.required': 'Required',
|
'common.required': 'Required',
|
||||||
'common.api_key': 'Key',
|
'common.api_key': 'Key',
|
||||||
'common.base_url': 'Address',
|
'common.base_url': 'Address',
|
||||||
|
'common.proxy_url': 'Proxy',
|
||||||
|
'common.alias': 'Alias',
|
||||||
|
|
||||||
// Page titles
|
// Page titles
|
||||||
'title.main': 'CLI Proxy API Management Center',
|
'title.main': 'CLI Proxy API Management Center',
|
||||||
'title.login': 'CLI Proxy API Management Center',
|
'title.login': 'CLI Proxy API Management Center',
|
||||||
|
|
||||||
// Auto login
|
// Auto login
|
||||||
'auto_login.title': 'Auto Login in Progress...',
|
'auto_login.title': 'Auto Login in Progress...',
|
||||||
'auto_login.message': 'Attempting to connect to server using locally saved connection information',
|
'auto_login.message': 'Attempting to connect to server using locally saved connection information',
|
||||||
|
|
||||||
// Login page
|
// Login page
|
||||||
'login.subtitle': 'Please enter connection information to access the management interface',
|
'login.subtitle': 'Please enter connection information to access the management interface',
|
||||||
'login.tab_local_title': 'Local',
|
'login.connection_title': 'Connection Address',
|
||||||
'login.tab_local_subtitle': 'Run Cli Web server on your local machine',
|
'login.connection_current': 'Current URL',
|
||||||
'login.tab_remote_title': 'Remote',
|
'login.connection_auto_hint': 'The system will automatically use the current URL for connection',
|
||||||
'login.tab_remote_subtitle': 'Remote connection for a remote Cli Web server',
|
'login.custom_connection_label': 'Custom Connection URL:',
|
||||||
'login.proxy_label': 'Proxy Server (Optional):',
|
'login.custom_connection_placeholder': 'Eg: https://example.com:8317',
|
||||||
'login.proxy_placeholder': 'http://ip:port or https://ip:port or socks5://user:pass@ip:port',
|
'login.custom_connection_hint': 'By default the current URL is used. Override it here if needed.',
|
||||||
'login.local_port_label': 'Port:',
|
'login.use_current_address': 'Use Current URL',
|
||||||
'login.local_port_placeholder': '8317',
|
|
||||||
'login.local_url_hint': 'Will connect to http://localhost:port/v0/management',
|
|
||||||
'login.api_url_label': 'API Base URL:',
|
|
||||||
'login.api_url_placeholder': 'e.g.: http://localhost:8317 or 127.0.0.1:8317',
|
|
||||||
'login.remote_api_url_placeholder': 'e.g.: https://example.com:8317',
|
|
||||||
'login.api_url_hint': 'Will automatically append /v0/management',
|
|
||||||
'login.management_key_label': 'Management Key:',
|
'login.management_key_label': 'Management Key:',
|
||||||
'login.management_key_placeholder': 'Please enter management key',
|
'login.management_key_placeholder': 'Enter the management key',
|
||||||
'login.connect_button': 'Connect',
|
'login.connect_button': 'Connect',
|
||||||
'login.submit_button': 'Login',
|
'login.submit_button': 'Login',
|
||||||
'login.submitting': 'Connecting...',
|
'login.submitting': 'Connecting...',
|
||||||
'login.error_title': 'Login Failed',
|
'login.error_title': 'Login Failed',
|
||||||
'login.error_required': 'Please fill in complete connection information',
|
'login.error_required': 'Please fill in complete connection information',
|
||||||
'login.error_invalid': 'Connection failed, please check address and key',
|
'login.error_invalid': 'Connection failed, please check address and key',
|
||||||
|
|
||||||
// Header navigation
|
// Header navigation
|
||||||
'header.check_connection': 'Check Connection',
|
'header.check_connection': 'Check Connection',
|
||||||
'header.refresh_all': 'Refresh All',
|
'header.refresh_all': 'Refresh All',
|
||||||
'header.logout': 'Logout',
|
'header.logout': 'Logout',
|
||||||
|
|
||||||
// Connection info
|
// Connection info
|
||||||
'connection.title': 'Connection Information',
|
'connection.title': 'Connection Information',
|
||||||
'connection.server_address': 'Server Address:',
|
'connection.server_address': 'Server Address:',
|
||||||
'connection.management_key': 'Management Key:',
|
'connection.management_key': 'Management Key:',
|
||||||
'connection.status': 'Connection Status:',
|
'connection.status': 'Connection Status:',
|
||||||
|
|
||||||
// Sidebar navigation
|
// Sidebar navigation
|
||||||
'nav.basic_settings': 'Basic Settings',
|
'nav.basic_settings': 'Basic Settings',
|
||||||
'nav.api_keys': 'API Keys',
|
'nav.api_keys': 'API Keys',
|
||||||
@@ -382,7 +451,7 @@ const i18n = {
|
|||||||
'nav.auth_files': 'Auth Files',
|
'nav.auth_files': 'Auth Files',
|
||||||
'nav.usage_stats': 'Usage Statistics',
|
'nav.usage_stats': 'Usage Statistics',
|
||||||
'nav.system_info': 'System Info',
|
'nav.system_info': 'System Info',
|
||||||
|
|
||||||
// Basic settings
|
// Basic settings
|
||||||
'basic_settings.title': 'Basic Settings',
|
'basic_settings.title': 'Basic Settings',
|
||||||
'basic_settings.debug_title': 'Debug Mode',
|
'basic_settings.debug_title': 'Debug Mode',
|
||||||
@@ -398,7 +467,7 @@ const i18n = {
|
|||||||
'basic_settings.quota_title': 'Quota Exceeded Behavior',
|
'basic_settings.quota_title': 'Quota Exceeded Behavior',
|
||||||
'basic_settings.quota_switch_project': 'Auto Switch Project',
|
'basic_settings.quota_switch_project': 'Auto Switch Project',
|
||||||
'basic_settings.quota_switch_preview': 'Switch to Preview Model',
|
'basic_settings.quota_switch_preview': 'Switch to Preview Model',
|
||||||
|
|
||||||
// API Keys management
|
// API Keys management
|
||||||
'api_keys.title': 'API Keys Management',
|
'api_keys.title': 'API Keys Management',
|
||||||
'api_keys.proxy_auth_title': 'Proxy Service Authentication Keys',
|
'api_keys.proxy_auth_title': 'Proxy Service Authentication Keys',
|
||||||
@@ -412,7 +481,7 @@ const i18n = {
|
|||||||
'api_keys.edit_modal_title': 'Edit API Key',
|
'api_keys.edit_modal_title': 'Edit API Key',
|
||||||
'api_keys.edit_modal_key_label': 'API Key:',
|
'api_keys.edit_modal_key_label': 'API Key:',
|
||||||
'api_keys.delete_confirm': 'Are you sure you want to delete this API key?',
|
'api_keys.delete_confirm': 'Are you sure you want to delete this API key?',
|
||||||
|
|
||||||
// AI Providers
|
// AI Providers
|
||||||
'ai_providers.title': 'AI Providers Configuration',
|
'ai_providers.title': 'AI Providers Configuration',
|
||||||
'ai_providers.gemini_title': 'Gemini API Keys',
|
'ai_providers.gemini_title': 'Gemini API Keys',
|
||||||
@@ -426,7 +495,7 @@ const i18n = {
|
|||||||
'ai_providers.gemini_edit_modal_title': 'Edit Gemini API Key',
|
'ai_providers.gemini_edit_modal_title': 'Edit Gemini API Key',
|
||||||
'ai_providers.gemini_edit_modal_key_label': 'API Key:',
|
'ai_providers.gemini_edit_modal_key_label': 'API Key:',
|
||||||
'ai_providers.gemini_delete_confirm': 'Are you sure you want to delete this Gemini key?',
|
'ai_providers.gemini_delete_confirm': 'Are you sure you want to delete this Gemini key?',
|
||||||
|
|
||||||
'ai_providers.codex_title': 'Codex API Configuration',
|
'ai_providers.codex_title': 'Codex API Configuration',
|
||||||
'ai_providers.codex_add_button': 'Add Configuration',
|
'ai_providers.codex_add_button': 'Add Configuration',
|
||||||
'ai_providers.codex_empty_title': 'No Codex Configuration',
|
'ai_providers.codex_empty_title': 'No Codex Configuration',
|
||||||
@@ -437,11 +506,14 @@ const i18n = {
|
|||||||
'ai_providers.codex_add_modal_key_placeholder': 'Please enter Codex API key',
|
'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_label': 'Base URL (Optional):',
|
||||||
'ai_providers.codex_add_modal_url_placeholder': 'e.g.: https://api.example.com',
|
'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_title': 'Edit Codex API Configuration',
|
||||||
'ai_providers.codex_edit_modal_key_label': 'API Key:',
|
'ai_providers.codex_edit_modal_key_label': 'API Key:',
|
||||||
'ai_providers.codex_edit_modal_url_label': 'Base URL (Optional):',
|
'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.codex_delete_confirm': 'Are you sure you want to delete this Codex configuration?',
|
||||||
|
|
||||||
'ai_providers.claude_title': 'Claude API Configuration',
|
'ai_providers.claude_title': 'Claude API Configuration',
|
||||||
'ai_providers.claude_add_button': 'Add Configuration',
|
'ai_providers.claude_add_button': 'Add Configuration',
|
||||||
'ai_providers.claude_empty_title': 'No Claude Configuration',
|
'ai_providers.claude_empty_title': 'No Claude Configuration',
|
||||||
@@ -452,11 +524,14 @@ const i18n = {
|
|||||||
'ai_providers.claude_add_modal_key_placeholder': 'Please enter Claude API key',
|
'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_label': 'Base URL (Optional):',
|
||||||
'ai_providers.claude_add_modal_url_placeholder': 'e.g.: https://api.anthropic.com',
|
'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_title': 'Edit Claude API Configuration',
|
||||||
'ai_providers.claude_edit_modal_key_label': 'API Key:',
|
'ai_providers.claude_edit_modal_key_label': 'API Key:',
|
||||||
'ai_providers.claude_edit_modal_url_label': 'Base URL (Optional):',
|
'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.claude_delete_confirm': 'Are you sure you want to delete this Claude configuration?',
|
||||||
|
|
||||||
'ai_providers.openai_title': 'OpenAI Compatible Providers',
|
'ai_providers.openai_title': 'OpenAI Compatible Providers',
|
||||||
'ai_providers.openai_add_button': 'Add Provider',
|
'ai_providers.openai_add_button': 'Add Provider',
|
||||||
'ai_providers.openai_empty_title': 'No OpenAI Compatible Providers',
|
'ai_providers.openai_empty_title': 'No OpenAI Compatible Providers',
|
||||||
@@ -468,15 +543,24 @@ const i18n = {
|
|||||||
'ai_providers.openai_add_modal_url_placeholder': 'e.g.: https://openrouter.ai/api/v1',
|
'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_label': 'API Keys (one per line):',
|
||||||
'ai_providers.openai_add_modal_keys_placeholder': 'sk-key1\nsk-key2',
|
'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_title': 'Edit OpenAI Compatible Provider',
|
||||||
'ai_providers.openai_edit_modal_name_label': 'Provider Name:',
|
'ai_providers.openai_edit_modal_name_label': 'Provider Name:',
|
||||||
'ai_providers.openai_edit_modal_url_label': 'Base URL:',
|
'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_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_delete_confirm': 'Are you sure you want to delete this OpenAI provider?',
|
||||||
'ai_providers.openai_keys_count': 'Keys Count',
|
'ai_providers.openai_keys_count': 'Keys Count',
|
||||||
'ai_providers.openai_models_count': 'Models Count',
|
'ai_providers.openai_models_count': 'Models Count',
|
||||||
|
|
||||||
|
|
||||||
// Auth files management
|
// Auth files management
|
||||||
'auth_files.title': 'Auth Files Management',
|
'auth_files.title': 'Auth Files Management',
|
||||||
'auth_files.title_section': 'Auth Files',
|
'auth_files.title_section': 'Auth Files',
|
||||||
@@ -497,17 +581,75 @@ const i18n = {
|
|||||||
'auth_files.delete_success': 'File deleted successfully',
|
'auth_files.delete_success': 'File deleted successfully',
|
||||||
'auth_files.delete_all_success': 'Successfully deleted',
|
'auth_files.delete_all_success': 'Successfully deleted',
|
||||||
'auth_files.files_count': 'files',
|
'auth_files.files_count': 'files',
|
||||||
|
|
||||||
// Gemini Web Token
|
// Codex OAuth
|
||||||
'auth_login.gemini_web_title': 'Gemini Web Token',
|
'auth_login.codex_oauth_title': 'Codex OAuth',
|
||||||
'auth_login.gemini_web_button': 'Save Gemini Web Token',
|
'auth_login.codex_oauth_button': 'Start Codex Login',
|
||||||
'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.codex_oauth_hint': 'Login to Codex service through OAuth flow, automatically obtain and save authentication files.',
|
||||||
'auth_login.secure_1psid_label': '__Secure-1PSID Cookie:',
|
'auth_login.codex_oauth_url_label': 'Authorization URL:',
|
||||||
'auth_login.secure_1psid_placeholder': 'Enter __Secure-1PSID cookie value',
|
'auth_login.codex_open_link': 'Open Link',
|
||||||
'auth_login.secure_1psidts_label': '__Secure-1PSIDTS Cookie:',
|
'auth_login.codex_copy_link': 'Copy Link',
|
||||||
'auth_login.secure_1psidts_placeholder': 'Enter __Secure-1PSIDTS cookie value',
|
'auth_login.codex_oauth_status_waiting': 'Waiting for authentication...',
|
||||||
'auth_login.gemini_web_saved': 'Gemini Web Token saved successfully',
|
'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:',
|
||||||
|
|
||||||
|
// 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 Statistics
|
||||||
'usage_stats.title': 'Usage Statistics',
|
'usage_stats.title': 'Usage Statistics',
|
||||||
'usage_stats.total_requests': 'Total Requests',
|
'usage_stats.total_requests': 'Total Requests',
|
||||||
@@ -527,7 +669,7 @@ const i18n = {
|
|||||||
'usage_stats.tokens_count': 'Token Count',
|
'usage_stats.tokens_count': 'Token Count',
|
||||||
'usage_stats.models': 'Model Statistics',
|
'usage_stats.models': 'Model Statistics',
|
||||||
'usage_stats.success_rate': 'Success Rate',
|
'usage_stats.success_rate': 'Success Rate',
|
||||||
|
|
||||||
// System info
|
// System info
|
||||||
'system_info.title': 'System Information',
|
'system_info.title': 'System Information',
|
||||||
'system_info.connection_status_title': 'Connection Status',
|
'system_info.connection_status_title': 'Connection Status',
|
||||||
@@ -538,7 +680,7 @@ const i18n = {
|
|||||||
'system_info.real_time_data': 'Real-time Data',
|
'system_info.real_time_data': 'Real-time Data',
|
||||||
'system_info.not_loaded': 'Not Loaded',
|
'system_info.not_loaded': 'Not Loaded',
|
||||||
'system_info.seconds_ago': 'seconds ago',
|
'system_info.seconds_ago': 'seconds ago',
|
||||||
|
|
||||||
// Notification messages
|
// Notification messages
|
||||||
'notification.debug_updated': 'Debug settings updated',
|
'notification.debug_updated': 'Debug settings updated',
|
||||||
'notification.proxy_updated': 'Proxy settings updated',
|
'notification.proxy_updated': 'Proxy settings updated',
|
||||||
@@ -558,9 +700,12 @@ const i18n = {
|
|||||||
'notification.claude_config_added': 'Claude configuration added successfully',
|
'notification.claude_config_added': 'Claude configuration added successfully',
|
||||||
'notification.claude_config_updated': 'Claude configuration updated successfully',
|
'notification.claude_config_updated': 'Claude configuration updated successfully',
|
||||||
'notification.claude_config_deleted': 'Claude configuration deleted 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_added': 'OpenAI provider added successfully',
|
||||||
'notification.openai_provider_updated': 'OpenAI provider updated successfully',
|
'notification.openai_provider_updated': 'OpenAI provider updated successfully',
|
||||||
'notification.openai_provider_deleted': 'OpenAI provider deleted successfully',
|
'notification.openai_provider_deleted': 'OpenAI provider deleted successfully',
|
||||||
|
'notification.openai_model_name_required': 'Model name is required',
|
||||||
'notification.data_refreshed': 'Data refreshed successfully',
|
'notification.data_refreshed': 'Data refreshed successfully',
|
||||||
'notification.connection_required': 'Please establish connection first',
|
'notification.connection_required': 'Please establish connection first',
|
||||||
'notification.refresh_failed': 'Refresh failed',
|
'notification.refresh_failed': 'Refresh failed',
|
||||||
@@ -577,12 +722,12 @@ const i18n = {
|
|||||||
'notification.gemini_api_key': 'Gemini API key',
|
'notification.gemini_api_key': 'Gemini API key',
|
||||||
'notification.codex_api_key': 'Codex API key',
|
'notification.codex_api_key': 'Codex API key',
|
||||||
'notification.claude_api_key': 'Claude API key',
|
'notification.claude_api_key': 'Claude API key',
|
||||||
|
|
||||||
// Language switch
|
// Language switch
|
||||||
'language.switch': 'Language',
|
'language.switch': 'Language',
|
||||||
'language.chinese': '中文',
|
'language.chinese': '中文',
|
||||||
'language.english': 'English',
|
'language.english': 'English',
|
||||||
|
|
||||||
// Theme switch
|
// Theme switch
|
||||||
'theme.switch': 'Theme',
|
'theme.switch': 'Theme',
|
||||||
'theme.light': 'Light',
|
'theme.light': 'Light',
|
||||||
@@ -590,25 +735,25 @@ const i18n = {
|
|||||||
'theme.switch_to_light': 'Switch to light mode',
|
'theme.switch_to_light': 'Switch to light mode',
|
||||||
'theme.switch_to_dark': 'Switch to dark mode',
|
'theme.switch_to_dark': 'Switch to dark mode',
|
||||||
'theme.auto': 'Follow system',
|
'theme.auto': 'Follow system',
|
||||||
|
|
||||||
// Footer
|
// Footer
|
||||||
'footer.version': 'Version',
|
'footer.version': 'Version',
|
||||||
'footer.author': 'Author'
|
'footer.author': 'Author'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// 获取翻译文本
|
// 获取翻译文本
|
||||||
t(key, params = {}) {
|
t(key, params = {}) {
|
||||||
const translation = this.translations[this.currentLanguage]?.[key] ||
|
const translation = this.translations[this.currentLanguage]?.[key] ||
|
||||||
this.translations[this.fallbackLanguage]?.[key] ||
|
this.translations[this.fallbackLanguage]?.[key] ||
|
||||||
key;
|
key;
|
||||||
|
|
||||||
// 简单的参数替换
|
// 简单的参数替换
|
||||||
return translation.replace(/\{(\w+)\}/g, (match, param) => {
|
return translation.replace(/\{(\w+)\}/g, (match, param) => {
|
||||||
return params[param] || match;
|
return params[param] || match;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
// 设置语言
|
// 设置语言
|
||||||
setLanguage(lang) {
|
setLanguage(lang) {
|
||||||
if (this.translations[lang]) {
|
if (this.translations[lang]) {
|
||||||
@@ -618,19 +763,19 @@ const i18n = {
|
|||||||
this.updateAllTexts();
|
this.updateAllTexts();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// 更新页面语言属性
|
// 更新页面语言属性
|
||||||
updatePageLanguage() {
|
updatePageLanguage() {
|
||||||
document.documentElement.lang = this.currentLanguage;
|
document.documentElement.lang = this.currentLanguage;
|
||||||
},
|
},
|
||||||
|
|
||||||
// 更新所有文本
|
// 更新所有文本
|
||||||
updateAllTexts() {
|
updateAllTexts() {
|
||||||
// 更新所有带有 data-i18n 属性的元素
|
// 更新所有带有 data-i18n 属性的元素
|
||||||
document.querySelectorAll('[data-i18n]').forEach(element => {
|
document.querySelectorAll('[data-i18n]').forEach(element => {
|
||||||
const key = element.getAttribute('data-i18n');
|
const key = element.getAttribute('data-i18n');
|
||||||
const text = this.t(key);
|
const text = this.t(key);
|
||||||
|
|
||||||
if (element.tagName === 'INPUT' && (element.type === 'text' || element.type === 'password')) {
|
if (element.tagName === 'INPUT' && (element.type === 'text' || element.type === 'password')) {
|
||||||
element.placeholder = text;
|
element.placeholder = text;
|
||||||
} else if (element.tagName === 'TITLE') {
|
} else if (element.tagName === 'TITLE') {
|
||||||
@@ -639,7 +784,7 @@ const i18n = {
|
|||||||
element.textContent = text;
|
element.textContent = text;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// 更新所有带有 data-i18n-html 属性的元素(支持HTML)
|
// 更新所有带有 data-i18n-html 属性的元素(支持HTML)
|
||||||
document.querySelectorAll('[data-i18n-html]').forEach(element => {
|
document.querySelectorAll('[data-i18n-html]').forEach(element => {
|
||||||
const key = element.getAttribute('data-i18n-html');
|
const key = element.getAttribute('data-i18n-html');
|
||||||
@@ -647,7 +792,7 @@ const i18n = {
|
|||||||
element.innerHTML = html;
|
element.innerHTML = html;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
// 初始化
|
// 初始化
|
||||||
init() {
|
init() {
|
||||||
// 从本地存储获取用户偏好语言
|
// 从本地存储获取用户偏好语言
|
||||||
@@ -663,7 +808,7 @@ const i18n = {
|
|||||||
this.currentLanguage = 'en-US';
|
this.currentLanguage = 'en-US';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.updatePageLanguage();
|
this.updatePageLanguage();
|
||||||
this.updateAllTexts();
|
this.updateAllTexts();
|
||||||
}
|
}
|
||||||
|
|||||||
1158
index.html
1158
index.html
File diff suppressed because it is too large
Load Diff
2074
package-lock.json
generated
2074
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
16
package.json
16
package.json
@@ -6,9 +6,7 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "npx serve .",
|
"start": "npx serve .",
|
||||||
"dev": "npx serve . --port 3000",
|
"dev": "npx serve . --port 3000",
|
||||||
"prebuild": "node build-scripts/prepare-html.js",
|
"build": "node build.js",
|
||||||
"build": "webpack --config webpack.config.js",
|
|
||||||
"postbuild": "rm -f index.build.html",
|
|
||||||
"lint": "echo '使用浏览器开发者工具检查代码'"
|
"lint": "echo '使用浏览器开发者工具检查代码'"
|
||||||
},
|
},
|
||||||
"keywords": [
|
"keywords": [
|
||||||
@@ -20,14 +18,7 @@
|
|||||||
"author": "CLI Proxy API WebUI",
|
"author": "CLI Proxy API WebUI",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"css-loader": "^6.8.1",
|
"serve": "^14.2.1"
|
||||||
"html-inline-script-webpack-plugin": "^3.2.1",
|
|
||||||
"html-loader": "^4.2.0",
|
|
||||||
"html-webpack-plugin": "^5.5.4",
|
|
||||||
"serve": "^14.2.1",
|
|
||||||
"style-loader": "^3.3.3",
|
|
||||||
"webpack": "^5.102.0",
|
|
||||||
"webpack-cli": "^5.1.4"
|
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=14.0.0"
|
"node": ">=14.0.0"
|
||||||
@@ -35,5 +26,6 @@
|
|||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "local"
|
"url": "local"
|
||||||
}
|
},
|
||||||
|
"dependencies": {}
|
||||||
}
|
}
|
||||||
|
|||||||
1976
styles.css
1976
styles.css
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user