refactor(config): 重构配置文件路径至configs目录并更新相关引用

- 将配置文件统一迁移至configs目录
- 更新所有相关代码中对配置文件的引用路径
- 删除不再使用的run-docker脚本文件
- 更新文档中关于配置文件路径的说明
- 调整默认配置参数和路径引用方式
This commit is contained in:
hex2077 2025-12-25 16:48:42 +08:00
parent 7e16afd806
commit 8a1ccb9877
23 changed files with 92 additions and 221 deletions

View file

@ -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 <path>` パラメータを使用してプール設定ファイルのパスを指定します
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
{

View file

@ -1,6 +1,6 @@
<div align="center">
<img src="src/img/logo-min.webp" alt="logo" style="width: 128px; height: 128px;margin-bottom: 3px;">
<img src="src/img/logo-mid.webp" alt="logo" style="width: 128px; height: 128px;margin-bottom: 3px;">
# 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 <path>` 参数指定号池配置文件路径
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/用户名`
>
> **自定义路径**:可通过配置文件中的相关参数或环境变量指定自定义存储位置
---

View file

@ -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 <path>` 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
{

View file

@ -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` - 常量定义

View file

View file

@ -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",

View file

View file

@ -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

View file

@ -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 "脚本执行完成"

View file

@ -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 <address> 服务器监听地址 / Server listening address (default: localhost)
* --host <address> 服务器监听地址 / Server listening address (default: 0.0.0.0)
* --port <number> 服务器监听端口 / Server listening port (default: 3000)
* --api-key <key> 身份验证所需的 API 密钥 / Required API key for authentication (default: 123456)
* --model-provider <provider[,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 <path> Kiro OAuth 凭据 JSON 文件路径 / Path to Kiro OAuth credentials JSON file
* --qwen-oauth-creds-file <path> Qwen OAuth 凭据 JSON 文件路径 / Path to Qwen OAuth credentials JSON file
* --project-id <id> Google Cloud 项目 ID / Google Cloud Project ID (for gemini-cli provider)
* --system-prompt-file <path> 系统提示文件路径 / Path to system prompt file (default: input_system_prompt.txt)
* --system-prompt-file <path> 系统提示文件路径 / Path to system prompt file (default: configs/input_system_prompt.txt)
* --system-prompt-mode <mode> 系统提示模式 / System prompt mode: overwrite or append (default: overwrite)
* --log-prompts <mode> 提示日志模式 / Prompt logging mode: console, file, or none (default: none)
* --prompt-log-base-name <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');
})

View file

@ -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";

View file

@ -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 };
export { ALL_MODEL_PROVIDERS };

View file

@ -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}`);
}

View file

@ -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;

View file

@ -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
}
}));

View file

@ -103,7 +103,7 @@ element.textContent = t('your.translation.key');
1. 配置管理页面的表单标签和提示
2. 提供商池管理的详细信息
3. 上传配置管理的列表项
3. 配置管理的列表项
4. 用量查询的统计信息
5. 实时日志的控制按钮

View file

@ -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;

View file

@ -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 || '';

View file

@ -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',

View file

@ -1845,7 +1845,7 @@ input:checked + .toggle-slider:before {
position: relative;
}
/* 上传配置管理页面样式 */
/* 配置管理页面样式 */
.upload-config-panel {
background: var(--bg-primary);
padding: 2rem;

View file

@ -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() {
// 绑定搜索事件

View file

@ -46,7 +46,7 @@
<i class="fas fa-network-wired" aria-hidden="true"></i> <span data-i18n="nav.providers">提供商池管理</span>
</a>
<a href="#upload-config" class="nav-item" data-section="upload-config" aria-label="Upload Config Management" data-i18n-aria-label="nav.upload">
<i class="fas fa-upload" aria-hidden="true"></i> <span data-i18n="nav.upload">上传配置管理</span>
<i class="fas fa-upload" aria-hidden="true"></i> <span data-i18n="nav.upload">配置管理</span>
</a>
<a href="#usage" class="nav-item" data-section="usage" aria-label="Usage Query" data-i18n-aria-label="nav.usage">
<i class="fas fa-chart-bar" aria-hidden="true"></i> <span data-i18n="nav.usage">用量查询</span>
@ -701,7 +701,7 @@
<div class="config-row">
<div class="form-group">
<label for="systemPromptFilePath" data-i18n="config.advanced.systemPromptFile">系统提示文件路径</label>
<input type="text" id="systemPromptFilePath" class="form-control" value="input_system_prompt.txt" data-i18n-placeholder="config.advanced.systemPromptFilePlaceholder" placeholder="例如: input_system_prompt.txt">
<input type="text" id="systemPromptFilePath" class="form-control" value="configs/input_system_prompt.txt" data-i18n-placeholder="config.advanced.systemPromptFilePlaceholder" placeholder="例如: configs/input_system_prompt.txt">
</div>
<div class="form-group">
<label for="systemPromptMode" data-i18n="config.advanced.systemPromptMode">系统提示模式</label>
@ -754,7 +754,7 @@
<div class="form-group pool-section">
<label for="providerPoolsFilePath" data-i18n="config.advanced.poolFilePath">提供商池配置文件路径(不能为空)</label>
<input type="text" id="providerPoolsFilePath" class="form-control" value="" data-i18n-placeholder="config.advanced.poolFilePathPlaceholder" placeholder="默认: provider_pools.json">
<input type="text" id="providerPoolsFilePath" class="form-control" value="" data-i18n-placeholder="config.advanced.poolFilePathPlaceholder" placeholder="默认: configs/provider_pools.json">
<small class="form-text" data-i18n="config.advanced.poolNote">配置了提供商池后,默认使用提供商池的配置,提供商池配置失效降级到默认配置</small>
</div>
@ -808,7 +808,7 @@
<!-- Upload Configuration Section -->
<section id="upload-config" class="section" aria-labelledby="upload-config-title">
<h2 id="upload-config-title" data-i18n="upload.title">上传配置管理</h2>
<h2 id="upload-config-title" data-i18n="upload.title">配置管理</h2>
<div class="upload-config-panel">
<!-- 搜索和过滤区域 -->
<div class="config-search-panel">