feat: DashScope 模型代理服务初始提交

支持 Anthropic 和 OpenAI 兼容协议的模型池反代,自动切换免费额度耗尽的模型。
This commit is contained in:
oy-paddy
2026-06-11 15:05:25 +08:00
commit d1021a00a0
18 changed files with 3140 additions and 0 deletions
+163
View File
@@ -0,0 +1,163 @@
import { chmodSync, cpSync, existsSync, mkdirSync, rmSync, writeFileSync } from 'node:fs'
import { dirname, join, resolve } from 'node:path'
import { fileURLToPath } from 'node:url'
const scriptDir = dirname(fileURLToPath(import.meta.url))
const projectRoot = resolve(scriptDir, '..')
const releaseDir = join(projectRoot, 'release')
rmSync(releaseDir, { recursive: true, force: true })
mkdirSync(releaseDir, { recursive: true })
mkdirSync(join(releaseDir, 'data'), { recursive: true })
mkdirSync(join(releaseDir, 'docs'), { recursive: true })
copyRequiredPath('dist')
copyRequiredPath('package.json')
copyRequiredPath('pnpm-lock.yaml')
copyRequiredPath('.env.example')
copyRequiredPath('LLM.md')
copyRequiredPath('docs/usage.md')
copyRequiredPath('docs/state-file.md')
writeFileSync(join(releaseDir, 'data', '.gitkeep'), '\n')
writeFileSync(join(releaseDir, '.npmrc'), 'production=true\n')
writeFileSync(join(releaseDir, 'start.sh'), buildStartScript())
chmodSync(join(releaseDir, 'start.sh'), 0o755)
writeFileSync(join(releaseDir, 'start.cmd'), toWindowsLineEndings(buildWindowsStartScript()))
writeFileSync(join(releaseDir, '使用方式.txt'), buildReadme())
console.log(`[release] prepared at ${releaseDir}`)
function copyRequiredPath(relativePath) {
const source = join(projectRoot, relativePath)
const target = join(releaseDir, relativePath)
if (!existsSync(source)) {
throw new Error(`Missing required path: ${relativePath}`)
}
cpSync(source, target, {
recursive: true,
force: true,
dereference: true,
filter: (currentSource) => {
const normalized = currentSource.replace(/\\/g, '/')
if (normalized.endsWith('/data/proxy-state.json')) return false
if (normalized.includes('/data/proxy-state.json.')) return false
return true
},
})
}
function buildStartScript() {
return `#!/bin/sh
set -eu
SCRIPT_DIR="$(CDPATH= cd -- "$(dirname "$0")" && pwd)"
cd "$SCRIPT_DIR"
if [ ! -f ".env" ]; then
cp .env.example .env
echo "已生成 .env,请先填写 PROXY_API_KEY、DASHSCOPE_API_KEYS、MODEL_IDS 后再重新运行 ./start.sh"
exit 1
fi
mkdir -p data
if [ ! -d "node_modules" ]; then
if command -v pnpm >/dev/null 2>&1; then
pnpm install --prod --frozen-lockfile
elif command -v corepack >/dev/null 2>&1; then
corepack pnpm install --prod --frozen-lockfile
else
echo "未找到 pnpm 或 corepack,请先安装 Node.js 20+(含 corepack)或 pnpm"
exit 1
fi
fi
exec node dist/index.js
`
}
function buildReadme() {
return `1. 确认机器已安装 Node.js 20 或更高版本。
2. 首次运行:
- Windows:双击 start.cmd,或在 cmd/PowerShell 里执行 start.cmd
- macOS / Linux:执行 ./start.sh
3. 如果当前目录没有 .env,会自动从 .env.example 生成一份模板。
4. 打开 .env,至少填写:
- PROXY_API_KEY
- DASHSCOPE_API_KEYS
- MODEL_IDS
5. 再次运行启动脚本:
- Windowsstart.cmd
- macOS / Linux./start.sh
说明:
- 首次真正启动时会自动安装运行时依赖
- 首次启动会自动创建新的 data/proxy-state.json
- 运行时依赖不包含原生编译模块,Windows 上不需要额外安装 C++ 编译环境
`
}
function buildWindowsStartScript() {
return `@echo off
setlocal
cd /d "%~dp0"
if not exist ".env" (
copy /Y ".env.example" ".env" >nul
echo Created .env from .env.example
echo Fill PROXY_API_KEY, DASHSCOPE_API_KEYS and MODEL_IDS
echo Then run start.cmd again
echo.
pause
exit /b 1
)
if not exist "data" mkdir data
if not exist "node_modules" (
where pnpm >nul 2>nul
if not errorlevel 1 (
call pnpm install --prod --frozen-lockfile
if errorlevel 1 goto :install_failed
goto :run
)
where corepack >nul 2>nul
if not errorlevel 1 (
call corepack pnpm install --prod --frozen-lockfile
if errorlevel 1 goto :install_failed
goto :run
)
echo pnpm or corepack was not found
echo Install Node.js 20+ or pnpm first
echo.
pause
exit /b 1
)
:run
call node dist\\index.js
set EXIT_CODE=%errorlevel%
if not "%EXIT_CODE%"=="0" (
echo.
echo Service exited with code %EXIT_CODE%
pause
)
exit /b %EXIT_CODE%
:install_failed
echo.
echo Dependency install failed
echo Check Node.js, pnpm and build tools
pause
exit /b 1
`
}
function toWindowsLineEndings(value) {
return value.replace(/\n/g, '\r\n')
}