diff --git a/README-JA.md b/README-JA.md index c777be5..03a9185 100644 --- a/README-JA.md +++ b/README-JA.md @@ -40,7 +40,7 @@ > - **2025.09.01** - Qwen Code CLIを統合、`qwen3-coder-plus`モデルサポートを追加 > - **2025.08.29** - アカウントプール管理機能をリリース、マルチアカウントポーリング、自動フェイルオーバー、自動ダウングレード戦略をサポート > - 設定方法:config.jsonに`PROVIDER_POOLS_FILE_PATH`パラメータを追加 -> - 参考設定:[provider_pools.json](./provider_pools.json.example) +> - 参考設定:[provider_pools.json](./configs/provider_pools.json.example) > - **開発済み履歴** > - Gemini CLI、Kiroなどのクライアント2APIをサポート > - OpenAI、Claude、Geminiの3つのプロトコル相互変換、自動インテリジェント切り替え @@ -156,7 +156,7 @@ AIClient-2-APIを使い始める最も推奨される方法は、自動起動ス 画像、ドキュメントなど様々なタイプの入力をサポートし、よりリッチなインタラクティブ体験とより強力なアプリケーションシナリオを提供します。 #### 最新モデルサポート -以下の最新大規模モデルをシームレスにサポート、Web UIまたは[`config.json`](./config.json)で対応するエンドポイントを設定するだけで使用可能: +以下の最新大規模モデルをシームレスにサポート、Web UIまたは[`config.json`](./configs/config.json)で対応するエンドポイントを設定するだけで使用可能: * **Claude 4.5 Opus** - Anthropic史上最強モデル、Kiro、Antigravity経由でサポート * **Gemini 3 Pro** - Google次世代アーキテクチャプレビュー版、Gemini、Antigravity経由でサポート * **Qwen3 Coder Plus** - アリババ通義千問の最新コード専用モデル、Qwen Code経由でサポート @@ -202,7 +202,7 @@ Web UI管理インターフェースでは、極めて迅速に認証設定を 4. **重要なお知らせ**:Kiroサービス使用ポリシーが更新されました、最新の使用制限と条件については公式ウェブサイトをご確認ください。 #### アカウントプール管理設定 -1. **プール設定ファイルの作成**:[provider_pools.json.example](./provider_pools.json.example) を参考に設定ファイルを作成します +1. **プール設定ファイルの作成**:[provider_pools.json.example](./configs/provider_pools.json.example) を参考に設定ファイルを作成します 2. **プールパラメータの設定**:config.json で `PROVIDER_POOLS_FILE_PATH` を設定し、プール設定ファイルを指定します 3. **起動パラメータ設定**:`--provider-pools-file ` パラメータを使用してプール設定ファイルのパスを指定します 4. **ヘルスチェック**:システムは定期的にヘルスチェックを自動実行し、健全でないプロバイダーを使用しません @@ -239,7 +239,7 @@ Web UI管理インターフェースでは、極めて迅速に認証設定を あるProvider Type(例:`gemini-cli-oauth`)のすべてのアカウントが429割り当て制限により枯渇したり、unhealthyとマークされた場合、システムは直接エラーを返すのではなく、互換性のある別のProvider Type(例:`gemini-antigravity`)に自動的にフォールバックできます。 -**設定方法**:`config.json` に `providerFallbackChain` 設定を追加: +**設定方法**:`configs/config.json` に `providerFallbackChain` 設定を追加: ```json { diff --git a/README-ZH.md b/README-ZH.md index d1b2d1a..813406d 100644 --- a/README-ZH.md +++ b/README-ZH.md @@ -1,6 +1,6 @@
-logo +logo # AIClient-2-API 🚀 @@ -39,8 +39,8 @@ > - **2025.10.18** - Kiro 开放注册,新用户赠送 500 额度,已完整支持 Claude Sonnet 4.5 > - **2025.09.01** - 集成 Qwen Code CLI,新增 `qwen3-coder-plus` 模型支持 > - **2025.08.29** - 发布账号池管理功能,支持多账号轮询、智能故障转移和自动降级策略 -> - 配置方式:在 config.json 中添加 `PROVIDER_POOLS_FILE_PATH` 参数 -> - 参考配置:[provider_pools.json](./provider_pools.json.example) +> - 配置方式:在 `configs/config.json` 中添加 `PROVIDER_POOLS_FILE_PATH` 参数 +> - 参考配置:[provider_pools.json](./configs/provider_pools.json.example) > - **历史已开发** > - 支持 Gemini CLI、Kiro 等客户端2API > - OpenAI ,Claude ,Gemini 三协议互转,自动智能切换 @@ -155,7 +155,7 @@ 支持图片、文档等多种类型的输入,为您提供更丰富的交互体验和更强大的应用场景。 #### 最新模型支持 -无缝支持以下最新大模型,仅需在 Web UI 或 [`config.json`](./config.json) 中配置相应的端点: +无缝支持以下最新大模型,仅需在 Web UI 或 [`configs/config.json`](./configs/config.json) 中配置相应的端点: * **Claude 4.5 Opus** - Anthropic 史上最强模型,现已通过 Kiro, Antigravity 支持 * **Gemini 3 Pro** - Google 下一代架构预览版,现已通过 Gemini, Antigravity 支持 * **Qwen3 Coder Plus** - 阿里通义千问最新代码专用模型,现已通过Qwen Code 支持 @@ -201,8 +201,8 @@ 4. **重要提示**:Kiro 服务使用政策已更新,请访问官方网站查看最新使用限制和条款 #### 账号池管理配置 -1. **创建号池配置文件**:参考 [provider_pools.json.example](./provider_pools.json.example) 创建配置文件 -2. **配置号池参数**:在 config.json 中设置 `PROVIDER_POOLS_FILE_PATH` 指向号池配置文件 +1. **创建号池配置文件**:参考 [provider_pools.json.example](./configs/provider_pools.json.example) 创建配置文件 +2. **配置号池参数**:在 `configs/config.json` 中设置 `PROVIDER_POOLS_FILE_PATH` 指向号池配置文件 3. **启动参数配置**:使用 `--provider-pools-file ` 参数指定号池配置文件路径 4. **健康检查**:系统会定期自动执行健康检查,不使用不健康的提供商 @@ -212,7 +212,7 @@ 支持通过 `notSupportedModels` 配置排除不支持的模型,系统会自动跳过这些提供商。 -**配置方式**:在 `provider_pools.json` 中为提供商添加 `notSupportedModels` 字段: +**配置方式**:在 `configs/provider_pools.json` 中为提供商添加 `notSupportedModels` 字段: ```json { @@ -238,7 +238,7 @@ 当某一 Provider Type(如 `gemini-cli-oauth`)下的所有账号都因 429 配额耗尽或被标记为 unhealthy 时,系统能够自动 fallback 到另一个兼容的 Provider Type(如 `gemini-antigravity`),而不是直接返回错误。 -**配置方式**:在 `config.json` 中添加 `providerFallbackChain` 配置: +**配置方式**:在 `configs/config.json` 中添加 `providerFallbackChain` 配置: ```json { @@ -282,7 +282,7 @@ | **Antigravity** | `~/.antigravity/oauth_creds.json` | Antigravity OAuth 凭据 (支持 Claude 4.5 Opus) | > **说明**:`~` 表示用户主目录(Windows: `C:\Users\用户名`,Linux/macOS: `/home/用户名` 或 `/Users/用户名`) -> + > **自定义路径**:可通过配置文件中的相关参数或环境变量指定自定义存储位置 --- diff --git a/README.md b/README.md index f418c0d..2f65874 100644 --- a/README.md +++ b/README.md @@ -39,8 +39,8 @@ > - **2025.10.18** - Kiro open registration, new accounts get 500 credits, full support for Claude Sonnet 4.5 > - **2025.09.01** - Integrated Qwen Code CLI, added `qwen3-coder-plus` model support > - **2025.08.29** - Released account pool management feature, supporting multi-account polling, intelligent failover, and automatic degradation strategies -> - Configuration: Add `PROVIDER_POOLS_FILE_PATH` parameter in config.json -> - Reference configuration: [provider_pools.json](./provider_pools.json.example) +> - Configuration: Add `PROVIDER_POOLS_FILE_PATH` parameter in `configs/config.json` +> - Reference configuration: [provider_pools.json](./configs/provider_pools.json.example) > - **History Developed** > - Support Gemini CLI, Kiro and other client2API > - OpenAI, Claude, Gemini three-protocol mutual conversion, automatic intelligent switching @@ -156,7 +156,7 @@ Access: `http://localhost:3000` → Login → Sidebar navigation → Take effect Supports various input types such as images and documents, providing you with a richer interaction experience and more powerful application scenarios. #### Latest Model Support -Seamlessly support the following latest large models, just configure the corresponding endpoint in Web UI or [`config.json`](./config.json): +Seamlessly support the following latest large models, just configure the corresponding endpoint in Web UI or [`configs/config.json`](./configs/config.json): * **Claude 4.5 Opus** - Anthropic's strongest model ever, now supported via Kiro, Antigravity * **Gemini 3 Pro** - Google's next-generation architecture preview, now supported via Gemini, Antigravity * **Qwen3 Coder Plus** - Alibaba Tongyi Qianwen's latest code-specific model, now supported via Qwen Code @@ -202,8 +202,8 @@ In the Web UI management interface, you can complete authorization configuration 4. **Important Notice**: Kiro service usage policy has been updated, please visit the official website for the latest usage restrictions and terms #### Account Pool Management Configuration -1. **Create Pool Configuration File**: Create a configuration file referencing [provider_pools.json.example](./provider_pools.json.example) -2. **Configure Pool Parameters**: Set `PROVIDER_POOLS_FILE_PATH` in config.json to point to the pool configuration file +1. **Create Pool Configuration File**: Create a configuration file referencing [provider_pools.json.example](./configs/provider_pools.json.example) +2. **Configure Pool Parameters**: Set `PROVIDER_POOLS_FILE_PATH` in `configs/config.json` to point to the pool configuration file 3. **Startup Parameter Configuration**: Use the `--provider-pools-file ` parameter to specify the pool configuration file path 4. **Health Check**: The system will automatically perform periodic health checks and avoid using unhealthy providers @@ -213,7 +213,7 @@ In the Web UI management interface, you can complete authorization configuration Support excluding unsupported models through `notSupportedModels` configuration, the system will automatically skip these providers. -**Configuration**: Add `notSupportedModels` field for providers in `provider_pools.json`: +**Configuration**: Add `notSupportedModels` field for providers in `configs/provider_pools.json`: ```json { @@ -239,7 +239,7 @@ Support excluding unsupported models through `notSupportedModels` configuration, When all accounts under a Provider Type (e.g., `gemini-cli-oauth`) are exhausted due to 429 quota limits or marked as unhealthy, the system can automatically fallback to another compatible Provider Type (e.g., `gemini-antigravity`) instead of returning an error directly. -**Configuration**: Add `providerFallbackChain` configuration in `config.json`: +**Configuration**: Add `providerFallbackChain` configuration in `configs/config.json`: ```json { diff --git a/UI_README.md b/UI_README.md index e878704..707b11f 100644 --- a/UI_README.md +++ b/UI_README.md @@ -34,7 +34,7 @@ AIClient2API 现在包含一个功能完整的可视化 Web UI 管理控制台 - OAuth令牌自动刷新设置 - 提供商池配置文件路径 -### 🔧 上传配置管理 +### 🔧 配置管理 - 搜索配置文件功能 - 按关联状态过滤(已关联/未关联) - 配置文件列表展示 @@ -88,7 +88,7 @@ node src/api-server.js --port 3000 --api-key 123456 1. **仪表盘** - 系统概览、统计信息和路径路由示例 2. **配置管理** - 修改服务器配置和提供商设置 3. **提供商池管理** - 管理多个API提供商账户 -4. **上传配置管理** - 管理配置文件和搜索过滤 +4. **配置管理** - 管理配置文件和搜索过滤 5. **实时日志** - 查看服务器运行日志 ## API 端点 @@ -122,7 +122,7 @@ node src/api-server.js --port 3000 --api-key 123456 - `GET /app/navigation.js` - 导航逻辑 - `GET /app/modal.js` - 模态框组件 - `GET /app/file-upload.js` - 文件上传 -- `GET /app/upload-config-manager.js` - 上传配置管理 +- `GET /app/upload-config-manager.js` - 配置管理 - `GET /app/routing-examples.js` - 路由示例 - `GET /app/constants.js` - 常量定义 diff --git a/configs/0 b/configs/0 deleted file mode 100644 index e69de29..0000000 diff --git a/config.json.example b/configs/config.json.example similarity index 93% rename from config.json.example rename to configs/config.json.example index 9a1e3ae..180d4db 100644 --- a/config.json.example +++ b/configs/config.json.example @@ -14,7 +14,7 @@ "KIRO_OAUTH_CREDS_BASE64": null, "KIRO_OAUTH_CREDS_FILE_PATH": null, "QWEN_OAUTH_CREDS_FILE_PATH": null, - "SYSTEM_PROMPT_FILE_PATH": "input_system_prompt.txt", + "SYSTEM_PROMPT_FILE_PATH": "configs/input_system_prompt.txt", "SYSTEM_PROMPT_MODE": "overwrite", "PROMPT_LOG_BASE_NAME": "prompt_log", "PROMPT_LOG_MODE": "none", @@ -22,7 +22,7 @@ "REQUEST_BASE_DELAY": 1000, "CRON_NEAR_MINUTES": 1, "CRON_REFRESH_TOKEN": false, - "PROVIDER_POOLS_FILE_PATH": "provider_pools.json", + "PROVIDER_POOLS_FILE_PATH": "configs/provider_pools.json", "MAX_ERROR_COUNT": 3, "QWEN_BASE_URL": "https://portal.qwen.ai/v1", "QWEN_OAUTH_BASE_URL": "https://chat.qwen.ai", diff --git a/provider_pools.json.example b/configs/provider_pools.json.example similarity index 100% rename from provider_pools.json.example rename to configs/provider_pools.json.example diff --git a/pwd b/configs/pwd similarity index 100% rename from pwd rename to configs/pwd diff --git a/run-docker.bat b/run-docker.bat deleted file mode 100644 index 1a2aab6..0000000 --- a/run-docker.bat +++ /dev/null @@ -1,68 +0,0 @@ -@echo off -:: run-docker-with-credentials.bat -:: 生成指定的Docker运行命令,使用USERPROFILE环境变量构建路径 - -setlocal enabledelayedexpansion - -echo 正在生成指定的Docker运行命令... - -:: 设置配置文件路径,使用USERPROFILE环境变量 -set "AWS_SSO_CACHE_PATH=%USERPROFILE%\.aws\sso\cache" -set "GEMINI_CONFIG_PATH=%USERPROFILE%\.gemini\oauth_creds.json" - -:: 检查AWS SSO缓存目录是否存在 -if exist "%AWS_SSO_CACHE_PATH%" ( - echo 发现AWS SSO缓存目录: %AWS_SSO_CACHE_PATH% -) else ( - echo 未找到AWS SSO缓存目录: %AWS_SSO_CACHE_PATH% - echo 注意:AWS SSO缓存目录不存在,Docker容器可能无法访问AWS凭证 -) - -:: 检查Gemini配置文件是否存在 -if exist "%GEMINI_CONFIG_PATH%" ( - echo 发现Gemini配置文件: %GEMINI_CONFIG_PATH% -) else ( - echo 未找到Gemini配置文件: %GEMINI_CONFIG_PATH% - echo 注意:Gemini配置文件不存在,Docker容器可能无法访问Gemini API -) - -:: 构建Docker运行命令,使用USERPROFILE环境变量构建的路径 -set "DOCKER_CMD=docker run -d ^" -set "DOCKER_CMD=!DOCKER_CMD! -u "$(id -u):$(id -g)" ^" -set "DOCKER_CMD=!DOCKER_CMD! --restart=always ^" -set "DOCKER_CMD=!DOCKER_CMD! --privileged=true ^" -set "DOCKER_CMD=!DOCKER_CMD! -p 3000:3000 ^" -set "DOCKER_CMD=!DOCKER_CMD! -e ARGS="--api-key 123456 --host 0.0.0.0" ^" -set "DOCKER_CMD=!DOCKER_CMD! -v "%AWS_SSO_CACHE_PATH%:/root/.aws/sso/cache" ^" -set "DOCKER_CMD=!DOCKER_CMD! -v "%GEMINI_CONFIG_PATH%:/root/.gemini/oauth_creds.json" ^" -set "DOCKER_CMD=!DOCKER_CMD! --name aiclient2api ^" -set "DOCKER_CMD=!DOCKER_CMD! aiclient2api" - -:: 显示将要执行的命令 -echo. -echo 生成的Docker命令: -echo !DOCKER_CMD! -echo. - -:: 将命令保存到文件中 -echo !DOCKER_CMD! > docker-run-command.txt -echo 命令已保存到 docker-run-command.txt 文件中,您可以从该文件复制完整的命令。 - -:: 询问用户是否要执行该命令 -echo. -set /p EXECUTE_CMD="是否要立即执行该Docker命令?(y/n): " -if /i "!EXECUTE_CMD!"=="y" ( - echo 正在执行Docker命令... - !DOCKER_CMD! - if !errorlevel! equ 0 ( - echo Docker容器已成功启动! - echo 您可以通过 http://localhost:3000 访问API服务 - ) else ( - echo Docker命令执行失败,请检查错误信息 - ) -) else ( - echo 命令未执行,您可以手动从docker-run-command.txt文件复制并执行命令 -) - -echo 脚本执行完成 -pause \ No newline at end of file diff --git a/run-docker.sh b/run-docker.sh deleted file mode 100644 index c0a0b49..0000000 --- a/run-docker.sh +++ /dev/null @@ -1,65 +0,0 @@ -#!/bin/bash -# run-docker-with-credentials.sh -# 生成指定的Docker运行命令,使用HOME环境变量构建路径 - -echo "正在生成指定的Docker运行命令..." - -# 设置配置文件路径,使用HOME环境变量 -AWS_SSO_CACHE_PATH="$HOME/.aws/sso/cache" -GEMINI_CONFIG_PATH="$HOME/.gemini/oauth_creds.json" - -# 检查AWS SSO缓存目录是否存在 -if [ -d "$AWS_SSO_CACHE_PATH" ]; then - echo "发现AWS SSO缓存目录: $AWS_SSO_CACHE_PATH" -else - echo "未找到AWS SSO缓存目录: $AWS_SSO_CACHE_PATH" - echo "注意:AWS SSO缓存目录不存在,Docker容器可能无法访问AWS凭证" -fi - -# 检查Gemini配置文件是否存在 -if [ -f "$GEMINI_CONFIG_PATH" ]; then - echo "发现Gemini配置文件: $GEMINI_CONFIG_PATH" -else - echo "未找到Gemini配置文件: $GEMINI_CONFIG_PATH" - echo "注意:Gemini配置文件不存在,Docker容器可能无法访问Gemini API" -fi - -# 构建Docker运行命令,使用HOME环境变量构建的路径 -DOCKER_CMD="docker run -d \\ - -u "$(id -u):$(id -g)" \\ - --restart=always \\ - --privileged=true \\ - -p 3000:3000 \\ - -e ARGS=\"--api-key 123456 --host 0.0.0.0\" \\ - -v $AWS_SSO_CACHE_PATH:/root/.aws/sso/cache \\ - -v $GEMINI_CONFIG_PATH:/root/.gemini/oauth_creds.json \\ - --name aiclient2api \\ - aiclient2api" - -# 显示将要执行的命令 -echo -echo "生成的Docker命令:" -echo "$DOCKER_CMD" -echo - -# 将命令保存到文件中 -echo "$DOCKER_CMD" > docker-run-command.txt -echo "命令已保存到 docker-run-command.txt 文件中,您可以从该文件复制完整的命令。" - -# 询问用户是否要执行该命令 -echo -read -p "是否要立即执行该Docker命令?(y/n): " EXECUTE_CMD -if [ "$EXECUTE_CMD" = "y" ] || [ "$EXECUTE_CMD" = "Y" ]; then - echo "正在执行Docker命令..." - eval "$DOCKER_CMD" - if [ $? -eq 0 ]; then - echo "Docker容器已成功启动!" - echo "您可以通过 http://localhost:3000 访问API服务" - else - echo "Docker命令执行失败,请检查错误信息" - fi -else - echo "命令未执行,您可以手动从docker-run-command.txt文件复制并执行命令" -fi - -echo "脚本执行完成" \ No newline at end of file diff --git a/src/api-server.js b/src/api-server.js index e9fca5d..5b7051b 100644 --- a/src/api-server.js +++ b/src/api-server.js @@ -31,7 +31,7 @@ import { createRequestHandler } from './request-handler.js'; * - 动态系统提示管理 / Dynamic System Prompt Management: * - 文件注入:通过 `--system-prompt-file` 从外部文件加载系统提示,并通过 `--system-prompt-mode` 控制其行为(覆盖或追加)。 * File Injection: Loads system prompts from external files via `--system-prompt-file` and controls their behavior (overwrite or append) with `--system-prompt-mode`. - * - 实时同步:能够将请求中包含的系统提示实时写入 `fetch_system_prompt.txt` 文件,便于开发者观察和调试。 + * - 实时同步:能够将请求中包含的系统提示实时写入 `configs/fetch_system_prompt.txt` 文件,便于开发者观察和调试。 * Real-time Synchronization: Capable of writing system prompts included in requests to the `fetch_system_prompt.txt` file in real-time, facilitating developer observation and debugging. * * - 智能请求转换和修复:自动将 OpenAI 格式的请求转换为 Gemini 格式,包括角色映射(`assistant` -> `model`)、合并来自同一角色的连续消息以及修复缺失的 `role` 字段。 @@ -84,7 +84,7 @@ import { createRequestHandler } from './request-handler.js'; * --prompt-log-base-name api-logs * * 命令行参数 / Command Line Parameters: - * --host
服务器监听地址 / Server listening address (default: localhost) + * --host
服务器监听地址 / Server listening address (default: 0.0.0.0) * --port 服务器监听端口 / Server listening port (default: 3000) * --api-key 身份验证所需的 API 密钥 / Required API key for authentication (default: 123456) * --model-provider AI 模型提供商 / AI model provider: openai-custom, claude-custom, gemini-cli-oauth, claude-kiro-oauth @@ -98,7 +98,7 @@ import { createRequestHandler } from './request-handler.js'; * --kiro-oauth-creds-file Kiro OAuth 凭据 JSON 文件路径 / Path to Kiro OAuth credentials JSON file * --qwen-oauth-creds-file Qwen OAuth 凭据 JSON 文件路径 / Path to Qwen OAuth credentials JSON file * --project-id Google Cloud 项目 ID / Google Cloud Project ID (for gemini-cli provider) - * --system-prompt-file 系统提示文件路径 / Path to system prompt file (default: input_system_prompt.txt) + * --system-prompt-file 系统提示文件路径 / Path to system prompt file (default: configs/input_system_prompt.txt) * --system-prompt-mode 系统提示模式 / System prompt mode: overwrite or append (default: overwrite) * --log-prompts 提示日志模式 / Prompt logging mode: console, file, or none (default: none) * --prompt-log-base-name 提示日志文件基础名称 / Base name for prompt log files (default: prompt_log) @@ -117,7 +117,7 @@ import { getProviderPoolManager } from './service-manager.js'; // --- Server Initialization --- async function startServer() { // Initialize configuration - await initializeConfig(); + await initializeConfig(process.argv.slice(2), 'configs/config.json'); // 自动关联 configs 目录中的配置文件到对应的提供商 console.log('[Initialization] Checking for unlinked provider configs...'); @@ -162,12 +162,16 @@ async function startServer() { console.log(` • Health check: /health`); console.log(` • UI Management Console: http://${CONFIG.HOST}:${CONFIG.SERVER_PORT}/`); - // Auto-open browser to UI (only if host is localhost or 127.0.0.1) - // if (CONFIG.HOST === 'localhost' || CONFIG.HOST === '127.0.0.1') { + // Auto-open browser to UI (only if host is 0.0.0.0 or 127.0.0.1) + // if (CONFIG.HOST === '0.0.0.0' || CONFIG.HOST === '127.0.0.1') { try { const open = (await import('open')).default; setTimeout(() => { - open(`http://${CONFIG.HOST}:${CONFIG.SERVER_PORT}/login.html`) + let openUrl = `http://${CONFIG.HOST}:${CONFIG.SERVER_PORT}/login.html`; + if(CONFIG.HOST === '0.0.0.0'){ + openUrl = `http://localhost:${CONFIG.SERVER_PORT}/login.html`; + } + open(openUrl) .then(() => { console.log('[UI] Opened login page in default browser'); }) diff --git a/src/common.js b/src/common.js index e4f866f..da68d58 100644 --- a/src/common.js +++ b/src/common.js @@ -53,8 +53,8 @@ export const ENDPOINT_TYPE = { GEMINI_MODEL_LIST: 'gemini_model_list', }; -export const FETCH_SYSTEM_PROMPT_FILE = path.join(process.cwd(), 'fetch_system_prompt.txt'); -export const INPUT_SYSTEM_PROMPT_FILE = path.join(process.cwd(), 'input_system_prompt.txt'); +export const FETCH_SYSTEM_PROMPT_FILE = path.join(process.cwd(), 'configs', 'fetch_system_prompt.txt'); +export const INPUT_SYSTEM_PROMPT_FILE = path.join(process.cwd(), 'configs', 'input_system_prompt.txt'); export function formatExpiryTime(expiryTimestamp) { if (!expiryTimestamp || typeof expiryTimestamp !== 'number') return "No expiry date available"; diff --git a/src/config-manager.js b/src/config-manager.js index 21f161c..d54841c 100644 --- a/src/config-manager.js +++ b/src/config-manager.js @@ -49,23 +49,23 @@ function normalizeConfiguredProviders(config) { /** * Initializes the server configuration from config.json and command-line arguments. * @param {string[]} args - Command-line arguments. - * @param {string} [configFilePath='config.json'] - Path to the configuration file. + * @param {string} [configFilePath='configs/config.json'] - Path to the configuration file. * @returns {Object} The initialized configuration object. */ -export async function initializeConfig(args = process.argv.slice(2), configFilePath = 'config.json') { +export async function initializeConfig(args = process.argv.slice(2), configFilePath = 'configs/config.json') { let currentConfig = {}; try { const configData = fs.readFileSync(configFilePath, 'utf8'); currentConfig = JSON.parse(configData); - console.log('[Config] Loaded configuration from config.json'); + console.log('[Config] Loaded configuration from configs/config.json'); } catch (error) { - console.error('[Config Error] Failed to load config.json:', error.message); + console.error('[Config Error] Failed to load configs/config.json:', error.message); // Fallback to default values if config.json is not found or invalid currentConfig = { REQUIRED_API_KEY: "123456", SERVER_PORT: 3000, - HOST: 'localhost', + HOST: '0.0.0.0', MODEL_PROVIDER: MODEL_PROVIDER.GEMINI_CLI, OPENAI_API_KEY: null, OPENAI_BASE_URL: null, @@ -323,7 +323,7 @@ export async function initializeConfig(args = process.argv.slice(2), configFileP // 加载号池配置 if (!currentConfig.PROVIDER_POOLS_FILE_PATH) { - currentConfig.PROVIDER_POOLS_FILE_PATH = 'provider_pools.json'; + currentConfig.PROVIDER_POOLS_FILE_PATH = 'configs/provider_pools.json'; } if (currentConfig.PROVIDER_POOLS_FILE_PATH) { try { @@ -425,4 +425,4 @@ export function logProviderSpecificDetails(provider, config) { } } -export { ALL_MODEL_PROVIDERS }; \ No newline at end of file +export { ALL_MODEL_PROVIDERS }; diff --git a/src/provider-pool-manager.js b/src/provider-pool-manager.js index 7705a79..4798a49 100644 --- a/src/provider-pool-manager.js +++ b/src/provider-pool-manager.js @@ -670,7 +670,7 @@ export class ProviderPoolManager { this.saveTimer = null; try { - const filePath = this.globalConfig.PROVIDER_POOLS_FILE_PATH || 'provider_pools.json'; + const filePath = this.globalConfig.PROVIDER_POOLS_FILE_PATH || 'configs/provider_pools.json'; let currentPools = {}; // 一次性读取文件 @@ -679,7 +679,7 @@ export class ProviderPoolManager { currentPools = JSON.parse(fileContent); } catch (readError) { if (readError.code === 'ENOENT') { - this._log('info', 'provider_pools.json does not exist, creating new file.'); + this._log('info', 'configs/provider_pools.json does not exist, creating new file.'); } else { throw readError; } @@ -709,7 +709,7 @@ export class ProviderPoolManager { // 一次性写入文件 await fs.promises.writeFile(filePath, JSON.stringify(currentPools, null, 2), 'utf8'); - this._log('info', `provider_pools.json updated successfully for types: ${typesToSave.join(', ')}`); + this._log('info', `configs/provider_pools.json updated successfully for types: ${typesToSave.join(', ')}`); } catch (error) { this._log('error', `Failed to write provider_pools.json: ${error.message}`); } diff --git a/src/service-manager.js b/src/service-manager.js index 50f2efd..1043312 100644 --- a/src/service-manager.js +++ b/src/service-manager.js @@ -72,7 +72,7 @@ export async function autoLinkProviderConfigs(config) { // 如果有新的配置文件需要关联,保存更新后的 provider_pools.json if (totalNewProviders > 0) { - const filePath = config.PROVIDER_POOLS_FILE_PATH || 'provider_pools.json'; + const filePath = config.PROVIDER_POOLS_FILE_PATH || 'configs/provider_pools.json'; try { await pfs.writeFile(filePath, JSON.stringify(config.providerPools, null, 2), 'utf8'); console.log(`[Auto-Link] Added ${totalNewProviders} new config(s) to provider pools:`); @@ -311,7 +311,7 @@ export function markProviderUnhealthy(provider, providerInfo) { */ export async function getProviderStatus(config, options = {}) { let providerPools = {}; - const filePath = config.PROVIDER_POOLS_FILE_PATH || 'provider_pools.json'; + const filePath = config.PROVIDER_POOLS_FILE_PATH || 'configs/provider_pools.json'; try { if (providerPoolManager && providerPoolManager.providerPools) { providerPools = providerPoolManager.providerPools; diff --git a/src/ui-manager.js b/src/ui-manager.js index e2a675f..ae8b9e4 100644 --- a/src/ui-manager.js +++ b/src/ui-manager.js @@ -25,10 +25,10 @@ import { import { formatKiroUsage, formatGeminiUsage, formatAntigravityUsage } from './usage-service.js'; // Token存储到本地文件中 -const TOKEN_STORE_FILE = 'token-store.json'; +const TOKEN_STORE_FILE = path.join(process.cwd(), 'configs', 'token-store.json'); // 用量缓存文件路径 -const USAGE_CACHE_FILE = 'usage-cache.json'; +const USAGE_CACHE_FILE = path.join(process.cwd(), 'configs', 'usage-cache.json'); /** * 读取用量缓存文件 @@ -205,7 +205,7 @@ async function cleanupExpiredTokens() { */ async function readPasswordFile() { try { - const password = await fs.readFile('./pwd', 'utf8'); + const password = await fs.readFile(path.join(process.cwd(), 'configs', 'pwd'), 'utf8'); return password.trim(); } catch (error) { console.error('读取密码文件失败:', error); @@ -408,7 +408,7 @@ async function reloadConfig(providerPoolManager) { const { initializeConfig } = await import('./config-manager.js'); // Reload main config - const newConfig = await initializeConfig(process.argv.slice(2), 'config.json'); + const newConfig = await initializeConfig(process.argv.slice(2), 'configs/config.json'); // Update provider pool manager if available if (providerPoolManager) { providerPoolManager.providerPools = newConfig.providerPools; @@ -565,7 +565,7 @@ export async function handleUIApiRequests(method, pathParam, req, res, currentCo } // 写入密码到 pwd 文件 - const pwdFilePath = path.join(process.cwd(), 'pwd'); + const pwdFilePath = path.join(process.cwd(), 'configs', 'pwd'); await fs.writeFile(pwdFilePath, password.trim(), 'utf8'); console.log('[UI API] Admin password updated successfully'); @@ -653,7 +653,7 @@ export async function handleUIApiRequests(method, pathParam, req, res, currentCo // Handle system prompt update if (newConfig.systemPrompt !== undefined) { - const promptPath = currentConfig.SYSTEM_PROMPT_FILE_PATH || 'input_system_prompt.txt'; + const promptPath = currentConfig.SYSTEM_PROMPT_FILE_PATH || 'configs/input_system_prompt.txt'; try { const relativePath = path.relative(process.cwd(), promptPath); writeFileSync(promptPath, newConfig.systemPrompt, 'utf-8'); @@ -674,7 +674,7 @@ export async function handleUIApiRequests(method, pathParam, req, res, currentCo // Update config.json file try { - const configPath = 'config.json'; + const configPath = 'configs/config.json'; // Create a clean config object for saving (exclude runtime-only properties) const configToSave = { @@ -717,12 +717,12 @@ export async function handleUIApiRequests(method, pathParam, req, res, currentCo }; writeFileSync(configPath, JSON.stringify(configToSave, null, 2), 'utf-8'); - console.log('[UI API] Configuration saved to config.json'); + console.log('[UI API] Configuration saved to configs/config.json'); // 广播更新事件 broadcastEvent('config_update', { action: 'update', - filePath: 'config.json', + filePath: 'configs/config.json', type: 'main_config', timestamp: new Date().toISOString() }); @@ -784,7 +784,7 @@ export async function handleUIApiRequests(method, pathParam, req, res, currentCo // Get provider pools summary if (method === 'GET' && pathParam === '/api/providers') { let providerPools = {}; - const filePath = currentConfig.PROVIDER_POOLS_FILE_PATH || 'provider_pools.json'; + const filePath = currentConfig.PROVIDER_POOLS_FILE_PATH || 'configs/provider_pools.json'; try { if (providerPoolManager && providerPoolManager.providerPools) { providerPools = providerPoolManager.providerPools; @@ -806,7 +806,7 @@ export async function handleUIApiRequests(method, pathParam, req, res, currentCo if (method === 'GET' && providerTypeMatch) { const providerType = decodeURIComponent(providerTypeMatch[1]); let providerPools = {}; - const filePath = currentConfig.PROVIDER_POOLS_FILE_PATH || 'provider_pools.json'; + const filePath = currentConfig.PROVIDER_POOLS_FILE_PATH || 'configs/provider_pools.json'; try { if (providerPoolManager && providerPoolManager.providerPools) { providerPools = providerPoolManager.providerPools; @@ -951,7 +951,7 @@ export async function handleUIApiRequests(method, pathParam, req, res, currentCo return true; } - const filePath = currentConfig.PROVIDER_POOLS_FILE_PATH || 'provider_pools.json'; + const filePath = currentConfig.PROVIDER_POOLS_FILE_PATH || 'configs/provider_pools.json'; let providerPools = {}; // Load existing pools @@ -1029,7 +1029,7 @@ export async function handleUIApiRequests(method, pathParam, req, res, currentCo const providerUuid = updateProviderMatch[2]; try { - const filePath = currentConfig.PROVIDER_POOLS_FILE_PATH || 'provider_pools.json'; + const filePath = currentConfig.PROVIDER_POOLS_FILE_PATH || 'configs/provider_pools.json'; let providerPools = {}; // Load existing pools @@ -1103,7 +1103,7 @@ export async function handleUIApiRequests(method, pathParam, req, res, currentCo const action = disableEnableProviderMatch[3]; try { - const filePath = currentConfig.PROVIDER_POOLS_FILE_PATH || 'provider_pools.json'; + const filePath = currentConfig.PROVIDER_POOLS_FILE_PATH || 'configs/provider_pools.json'; let providerPools = {}; // Load existing pools @@ -1177,7 +1177,7 @@ export async function handleUIApiRequests(method, pathParam, req, res, currentCo const providerType = decodeURIComponent(resetHealthMatch[1]); try { - const filePath = currentConfig.PROVIDER_POOLS_FILE_PATH || 'provider_pools.json'; + const filePath = currentConfig.PROVIDER_POOLS_FILE_PATH || 'configs/provider_pools.json'; let providerPools = {}; // Load existing pools @@ -1316,7 +1316,7 @@ export async function handleUIApiRequests(method, pathParam, req, res, currentCo } // 保存更新后的状态到文件 - const filePath = currentConfig.PROVIDER_POOLS_FILE_PATH || 'provider_pools.json'; + const filePath = currentConfig.PROVIDER_POOLS_FILE_PATH || 'configs/provider_pools.json'; // 从 providerStatus 构建 providerPools 对象并保存 const providerPools = {}; @@ -1671,7 +1671,7 @@ export async function handleUIApiRequests(method, pathParam, req, res, currentCo } const { providerType, credPathKey, defaultCheckModel, displayName } = providerMapping; - const poolsFilePath = currentConfig.PROVIDER_POOLS_FILE_PATH || 'provider_pools.json'; + const poolsFilePath = currentConfig.PROVIDER_POOLS_FILE_PATH || 'configs/provider_pools.json'; // Load existing pools let providerPools = {}; @@ -1855,7 +1855,7 @@ export async function handleUIApiRequests(method, pathParam, req, res, currentCo // 广播更新事件 broadcastEvent('config_update', { action: 'reload', - filePath: 'config.json', + filePath: 'configs/config.json', providerPoolsPath: newConfig.PROVIDER_POOLS_FILE_PATH || null, timestamp: new Date().toISOString() }); @@ -1866,7 +1866,7 @@ export async function handleUIApiRequests(method, pathParam, req, res, currentCo message: '配置文件重新加载成功', details: { configReloaded: true, - configPath: 'config.json', + configPath: 'configs/config.json', providerPoolsPath: newConfig.PROVIDER_POOLS_FILE_PATH || null } })); diff --git a/static/app/I18N_GUIDE.md b/static/app/I18N_GUIDE.md index 6595649..b14271c 100644 --- a/static/app/I18N_GUIDE.md +++ b/static/app/I18N_GUIDE.md @@ -103,7 +103,7 @@ element.textContent = t('your.translation.key'); 1. 配置管理页面的表单标签和提示 2. 提供商池管理的详细信息 -3. 上传配置管理的列表项 +3. 配置管理的列表项 4. 用量查询的统计信息 5. 实时日志的控制按钮 diff --git a/static/app/app.js b/static/app/app.js index 633c60e..06d6483 100644 --- a/static/app/app.js +++ b/static/app/app.js @@ -107,7 +107,7 @@ function initApp() { initEventStream(); initFileUpload(); // 初始化文件上传功能 initRoutingExamples(); // 初始化路径路由示例功能 - initUploadConfigManager(); // 初始化上传配置管理功能 + initUploadConfigManager(); // 初始化配置管理功能 initUsageManager(); // 初始化用量管理功能 initImageZoom(); // 初始化图片放大功能 loadInitialData(); @@ -151,7 +151,7 @@ window.refreshProviderConfig = refreshProviderConfig; window.fileUploadHandler = fileUploadHandler; window.showAuthModal = showAuthModal; -// 上传配置管理相关全局函数 +// 配置管理相关全局函数 window.viewConfig = viewConfig; window.deleteConfig = deleteConfig; window.loadConfigList = loadConfigList; diff --git a/static/app/config-manager.js b/static/app/config-manager.js index 42c8286..40ae07d 100644 --- a/static/app/config-manager.js +++ b/static/app/config-manager.js @@ -95,7 +95,7 @@ async function loadConfiguration() { const maxErrorCountEl = document.getElementById('maxErrorCount'); const providerFallbackChainEl = document.getElementById('providerFallbackChain'); - if (systemPromptFilePathEl) systemPromptFilePathEl.value = data.SYSTEM_PROMPT_FILE_PATH || 'input_system_prompt.txt'; + if (systemPromptFilePathEl) systemPromptFilePathEl.value = data.SYSTEM_PROMPT_FILE_PATH || 'configs/input_system_prompt.txt'; if (systemPromptModeEl) systemPromptModeEl.value = data.SYSTEM_PROMPT_MODE || 'append'; if (promptLogBaseNameEl) promptLogBaseNameEl.value = data.PROMPT_LOG_BASE_NAME || 'prompt_log'; if (promptLogModeEl) promptLogModeEl.value = data.PROMPT_LOG_MODE || 'none'; @@ -223,7 +223,7 @@ async function saveConfiguration() { } // 保存高级配置参数 - config.SYSTEM_PROMPT_FILE_PATH = document.getElementById('systemPromptFilePath')?.value || 'input_system_prompt.txt'; + config.SYSTEM_PROMPT_FILE_PATH = document.getElementById('systemPromptFilePath')?.value || 'configs/input_system_prompt.txt'; config.SYSTEM_PROMPT_MODE = document.getElementById('systemPromptMode')?.value || 'append'; config.PROMPT_LOG_BASE_NAME = document.getElementById('promptLogBaseName')?.value || ''; config.PROMPT_LOG_MODE = document.getElementById('promptLogMode')?.value || ''; diff --git a/static/app/i18n.js b/static/app/i18n.js index 90c73fc..db09b79 100644 --- a/static/app/i18n.js +++ b/static/app/i18n.js @@ -14,7 +14,7 @@ const translations = { 'nav.dashboard': '仪表盘', 'nav.config': '配置管理', 'nav.providers': '提供商池管理', - 'nav.upload': '上传配置管理', + 'nav.upload': '配置管理', 'nav.usage': '用量查询', 'nav.logs': '实时日志', @@ -147,7 +147,7 @@ const translations = { 'config.qwen.credsFilePathPlaceholder': '例如: ~/.qwen/oauth_creds.json', 'config.advanced.title': '高级配置', 'config.advanced.systemPromptFile': '系统提示文件路径', - 'config.advanced.systemPromptFilePlaceholder': '例如: input_system_prompt.txt', + 'config.advanced.systemPromptFilePlaceholder': '例如: configs/input_system_prompt.txt', 'config.advanced.systemPromptMode': '系统提示模式', 'config.advanced.systemPromptMode.append': '追加 (append)', 'config.advanced.systemPromptMode.overwrite': '覆盖 (overwrite)', @@ -162,7 +162,7 @@ const translations = { 'config.advanced.cronInterval': 'OAuth令牌刷新间隔(分钟)', 'config.advanced.cronEnabled': '启用OAuth令牌自动刷新(需重启服务)', 'config.advanced.poolFilePath': '提供商池配置文件路径(不能为空)', - 'config.advanced.poolFilePathPlaceholder': '默认: provider_pools.json', + 'config.advanced.poolFilePathPlaceholder': '默认: configs/provider_pools.json', 'config.advanced.poolNote': '配置了提供商池后,默认使用提供商池的配置,提供商池配置失效降级到默认配置', 'config.advanced.maxErrorCount': '提供商最大错误次数', 'config.advanced.maxErrorCountPlaceholder': '默认: 3', @@ -182,7 +182,7 @@ const translations = { 'config.placeholder.model': '例如: gpt-3.5-turbo', // Upload Config - 'upload.title': '上传配置管理', + 'upload.title': '配置管理', 'upload.search': '搜索配置', 'upload.searchPlaceholder': '输入文件名', 'upload.statusFilter': '关联状态', @@ -386,7 +386,7 @@ const translations = { 'nav.dashboard': 'Dashboard', 'nav.config': 'Configuration', 'nav.providers': 'Provider Pools', - 'nav.upload': 'Upload Config', + 'nav.upload': 'Config Management', 'nav.usage': 'Usage Query', 'nav.logs': 'Real-time Logs', @@ -519,7 +519,7 @@ const translations = { 'config.qwen.credsFilePathPlaceholder': 'e.g.: ~/.qwen/oauth_creds.json', 'config.advanced.title': 'Advanced Configuration', 'config.advanced.systemPromptFile': 'System Prompt File Path', - 'config.advanced.systemPromptFilePlaceholder': 'e.g.: input_system_prompt.txt', + 'config.advanced.systemPromptFilePlaceholder': 'e.g.: configs/input_system_prompt.txt', 'config.advanced.systemPromptMode': 'System Prompt Mode', 'config.advanced.systemPromptMode.append': 'Append', 'config.advanced.systemPromptMode.overwrite': 'Overwrite', @@ -534,7 +534,7 @@ const translations = { 'config.advanced.cronInterval': 'OAuth Token Refresh Interval (minutes)', 'config.advanced.cronEnabled': 'Enable OAuth Token Auto Refresh (requires restart)', 'config.advanced.poolFilePath': 'Provider Pool Config File Path (required)', - 'config.advanced.poolFilePathPlaceholder': 'Default: provider_pools.json', + 'config.advanced.poolFilePathPlaceholder': 'Default: configs/provider_pools.json', 'config.advanced.poolNote': 'When provider pool is configured, it will be used by default. Falls back to default config if pool config fails', 'config.advanced.maxErrorCount': 'Provider Max Error Count', 'config.advanced.maxErrorCountPlaceholder': 'Default: 3', @@ -554,7 +554,7 @@ const translations = { 'config.placeholder.model': 'e.g.: gpt-3.5-turbo', // Upload Config - 'upload.title': 'Upload Configuration Management', + 'upload.title': 'Config Management', 'upload.search': 'Search Config', 'upload.searchPlaceholder': 'Enter filename', 'upload.statusFilter': 'Association Status', diff --git a/static/app/styles.css b/static/app/styles.css index 1470120..66ae319 100644 --- a/static/app/styles.css +++ b/static/app/styles.css @@ -1845,7 +1845,7 @@ input:checked + .toggle-slider:before { position: relative; } -/* 上传配置管理页面样式 */ +/* 配置管理页面样式 */ .upload-config-panel { background: var(--bg-primary); padding: 2rem; diff --git a/static/app/upload-config-manager.js b/static/app/upload-config-manager.js index 84e002f..494a73f 100644 --- a/static/app/upload-config-manager.js +++ b/static/app/upload-config-manager.js @@ -1,4 +1,4 @@ -// 上传配置管理功能模块 +// 配置管理功能模块 import { showToast } from './utils.js'; import { t } from './i18n.js'; @@ -320,7 +320,7 @@ function generateMockConfigData() { return [ { name: 'provider_pools.json', - path: './provider_pools.json', + path: './configs/provider_pools.json', type: 'provider-pool', size: 2048, modified: '2025-11-11T04:30:00.000Z', @@ -336,7 +336,7 @@ function generateMockConfigData() { }, { name: 'config.json', - path: './config.json', + path: './configs/config.json', type: 'other', size: 1024, modified: '2025-11-10T12:00:00.000Z', @@ -357,7 +357,7 @@ function generateMockConfigData() { }, { name: 'input_system_prompt.txt', - path: './input_system_prompt.txt', + path: './configs/input_system_prompt.txt', type: 'system-prompt', size: 256, modified: '2025-11-08T15:20:00.000Z', @@ -698,7 +698,7 @@ async function deleteConfig(path) { } /** - * 初始化上传配置管理页面 + * 初始化配置管理页面 */ function initUploadConfigManager() { // 绑定搜索事件 diff --git a/static/index.html b/static/index.html index 5b491f4..1a5b64d 100644 --- a/static/index.html +++ b/static/index.html @@ -46,7 +46,7 @@ 提供商池管理 - 上传配置管理 + 配置管理 用量查询 @@ -701,7 +701,7 @@
- +
@@ -754,7 +754,7 @@
- + 配置了提供商池后,默认使用提供商池的配置,提供商池配置失效降级到默认配置
@@ -808,7 +808,7 @@
-

上传配置管理

+

配置管理