diff --git a/.dockerignore b/.dockerignore index e82f928..3fc3934 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,50 +1,50 @@ -# Git -.git -.gitignore - -# Python -__pycache__ -*.py[cod] -*$py.class -*.so -.Python -.venv -venv -ENV - -# IDE -.idea -.vscode -*.swp -*.swo - -# Node -webui/node_modules -webui/.vite - -# Build artifacts (前端构建产物在 Docker 中重新生成) -static/admin - -# 配置和敏感文件 -.env -.env.* -config.json - -# 日志和临时文件 -*.log -logs/ -tmp/ -temp/ - -# 测试 -tests/ -*.test.py - -# 文档和截图 -*.md -截图/ -docs/ - -# Claude Code -.claude/ -CLAUDE*.md +# Git +.git +.gitignore + +# Python +__pycache__ +*.py[cod] +*$py.class +*.so +.Python +.venv +venv +ENV + +# IDE +.idea +.vscode +*.swp +*.swo + +# Node +webui/node_modules +webui/.vite + +# Build artifacts (前端构建产物在 Docker 中重新生成) +static/admin + +# 配置和敏感文件 +.env +.env.* +config.json + +# 日志和临时文件 +*.log +logs/ +tmp/ +temp/ + +# 测试 +tests/ +*.test.py + +# 文档和截图 +*.md +截图/ +docs/ + +# Claude Code +.claude/ +CLAUDE*.md diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index cdc141f..22c8204 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,24 +1,20 @@ -#### 💻 变更类型 | Change Type - - - -- [ ] ✨ feat -- [ ] 🐛 fix -- [ ] ♻️ refactor -- [ ] 💄 style -- [ ] 👷 build -- [ ] ⚡️ perf -- [ ] 📝 docs -- [ ] 🔨 chore - -#### 🔀 变更说明 | Description of Change - - - -#### 📝 补充信息 | Additional Information - - - ---- - -> 💡 **提示**:如果修改了 `webui/` 目录下的文件,PR 合并后 CI 会自动构建并提交产物,无需手动构建。 \ No newline at end of file +#### 💻 变更类型 | Change Type + + + +- [ ] ✨ feat +- [ ] 🐛 fix +- [ ] ♻️ refactor +- [ ] 💄 style +- [ ] 👷 build +- [ ] ⚡️ perf +- [ ] 📝 docs +- [ ] 🔨 chore + +#### 🔀 变更说明 | Description of Change + + + +#### 📝 补充信息 | Additional Information + + \ No newline at end of file diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 8186c1c..8b7cbc1 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,128 +1,128 @@ -name: Release to Aliyun CR - -on: - workflow_dispatch: - inputs: - version_type: - description: '版本类型' - required: true - default: 'patch' - type: choice - options: - - patch - - minor - - major - -permissions: - contents: write - -jobs: - release: - runs-on: ubuntu-latest - steps: - - name: Checkout code - uses: actions/checkout@v5 - with: - fetch-depth: 0 - token: ${{ secrets.GITHUB_TOKEN }} - - - name: Get current version - id: get_version - run: | - LATEST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "v0.0.0") - TAG_VERSION=${LATEST_TAG#v} - - if [ -f VERSION ]; then - FILE_VERSION=$(cat VERSION | tr -d '[:space:]') - else - FILE_VERSION="0.0.0" - fi - - function version_gt() { test "$(printf '%s\n' "$@" | sort -V | head -n 1)" != "$1"; } - - if version_gt "$FILE_VERSION" "$TAG_VERSION"; then - VERSION="$FILE_VERSION" - else - VERSION="$TAG_VERSION" - fi - - echo "Current version: $VERSION" - echo "current_version=$VERSION" >> $GITHUB_OUTPUT - - - name: Calculate next version - id: next_version - env: - VERSION_TYPE: ${{ github.event.inputs.version_type }} - run: | - VERSION="${{ steps.get_version.outputs.current_version }}" - BASE_VERSION=$(echo "$VERSION" | sed 's/-.*$//') - - IFS='.' read -r -a version_parts <<< "$BASE_VERSION" - MAJOR="${version_parts[0]:-0}" - MINOR="${version_parts[1]:-0}" - PATCH="${version_parts[2]:-0}" - - case "$VERSION_TYPE" in - major) - NEW_VERSION="$((MAJOR + 1)).0.0" - ;; - minor) - NEW_VERSION="${MAJOR}.$((MINOR + 1)).0" - ;; - *) - NEW_VERSION="${MAJOR}.${MINOR}.$((PATCH + 1))" - ;; - esac - - echo "New version: $NEW_VERSION" - echo "new_version=$NEW_VERSION" >> $GITHUB_OUTPUT - echo "new_tag=v$NEW_VERSION" >> $GITHUB_OUTPUT - - - name: Update VERSION file - run: | - echo "${{ steps.next_version.outputs.new_version }}" > VERSION - - - name: Commit VERSION and create tag - run: | - git config user.name "github-actions[bot]" - git config user.email "github-actions[bot]@users.noreply.github.com" - - git add VERSION - if ! git diff --cached --quiet; then - git commit -m "chore: bump version to ${{ steps.next_version.outputs.new_tag }} [skip ci]" - fi - - NEW_TAG="${{ steps.next_version.outputs.new_tag }}" - git tag -a "$NEW_TAG" -m "Release $NEW_TAG" - git push origin HEAD:main "$NEW_TAG" - - # Docker 构建并推送到阿里云 - - name: Set up QEMU - uses: docker/setup-qemu-action@v3 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 - - - name: Log in to Aliyun Container Registry - uses: docker/login-action@v3 - with: - registry: ${{ secrets.ALIYUN_REGISTRY }} - username: ${{ secrets.ALIYUN_REGISTRY_USER }} - password: ${{ secrets.ALIYUN_REGISTRY_PASSWORD }} - - - name: Build and push Docker image - uses: docker/build-push-action@v6 - with: - context: . - file: ./docker/Dockerfile - platforms: linux/amd64,linux/arm64 - push: true - tags: | - ${{ secrets.ALIYUN_REGISTRY }}/${{ secrets.ALIYUN_REGISTRY_NAMESPACE }}/ds2api:${{ steps.next_version.outputs.new_tag }} - ${{ secrets.ALIYUN_REGISTRY }}/${{ secrets.ALIYUN_REGISTRY_NAMESPACE }}/ds2api:${{ steps.next_version.outputs.new_version }} - ${{ secrets.ALIYUN_REGISTRY }}/${{ secrets.ALIYUN_REGISTRY_NAMESPACE }}/ds2api:latest - labels: | - org.opencontainers.image.version=${{ steps.next_version.outputs.new_version }} - org.opencontainers.image.revision=${{ github.sha }} - cache-from: type=gha - cache-to: type=gha,mode=max +name: Release to Aliyun CR + +on: + workflow_dispatch: + inputs: + version_type: + description: '版本类型' + required: true + default: 'patch' + type: choice + options: + - patch + - minor + - major + +permissions: + contents: write + +jobs: + release: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v5 + with: + fetch-depth: 0 + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Get current version + id: get_version + run: | + LATEST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "v0.0.0") + TAG_VERSION=${LATEST_TAG#v} + + if [ -f VERSION ]; then + FILE_VERSION=$(cat VERSION | tr -d '[:space:]') + else + FILE_VERSION="0.0.0" + fi + + function version_gt() { test "$(printf '%s\n' "$@" | sort -V | head -n 1)" != "$1"; } + + if version_gt "$FILE_VERSION" "$TAG_VERSION"; then + VERSION="$FILE_VERSION" + else + VERSION="$TAG_VERSION" + fi + + echo "Current version: $VERSION" + echo "current_version=$VERSION" >> $GITHUB_OUTPUT + + - name: Calculate next version + id: next_version + env: + VERSION_TYPE: ${{ github.event.inputs.version_type }} + run: | + VERSION="${{ steps.get_version.outputs.current_version }}" + BASE_VERSION=$(echo "$VERSION" | sed 's/-.*$//') + + IFS='.' read -r -a version_parts <<< "$BASE_VERSION" + MAJOR="${version_parts[0]:-0}" + MINOR="${version_parts[1]:-0}" + PATCH="${version_parts[2]:-0}" + + case "$VERSION_TYPE" in + major) + NEW_VERSION="$((MAJOR + 1)).0.0" + ;; + minor) + NEW_VERSION="${MAJOR}.$((MINOR + 1)).0" + ;; + *) + NEW_VERSION="${MAJOR}.${MINOR}.$((PATCH + 1))" + ;; + esac + + echo "New version: $NEW_VERSION" + echo "new_version=$NEW_VERSION" >> $GITHUB_OUTPUT + echo "new_tag=v$NEW_VERSION" >> $GITHUB_OUTPUT + + - name: Update VERSION file + run: | + echo "${{ steps.next_version.outputs.new_version }}" > VERSION + + - name: Commit VERSION and create tag + run: | + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + + git add VERSION + if ! git diff --cached --quiet; then + git commit -m "chore: bump version to ${{ steps.next_version.outputs.new_tag }} [skip ci]" + fi + + NEW_TAG="${{ steps.next_version.outputs.new_tag }}" + git tag -a "$NEW_TAG" -m "Release $NEW_TAG" + git push origin HEAD:main "$NEW_TAG" + + # Docker 构建并推送到阿里云 + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log in to Aliyun Container Registry + uses: docker/login-action@v3 + with: + registry: ${{ secrets.ALIYUN_REGISTRY }} + username: ${{ secrets.ALIYUN_REGISTRY_USER }} + password: ${{ secrets.ALIYUN_REGISTRY_PASSWORD }} + + - name: Build and push Docker image + uses: docker/build-push-action@v6 + with: + context: . + file: ./docker/Dockerfile + platforms: linux/amd64,linux/arm64 + push: true + tags: | + ${{ secrets.ALIYUN_REGISTRY }}/${{ secrets.ALIYUN_REGISTRY_NAMESPACE }}/ds2api:${{ steps.next_version.outputs.new_tag }} + ${{ secrets.ALIYUN_REGISTRY }}/${{ secrets.ALIYUN_REGISTRY_NAMESPACE }}/ds2api:${{ steps.next_version.outputs.new_version }} + ${{ secrets.ALIYUN_REGISTRY }}/${{ secrets.ALIYUN_REGISTRY_NAMESPACE }}/ds2api:latest + labels: | + org.opencontainers.image.version=${{ steps.next_version.outputs.new_version }} + org.opencontainers.image.revision=${{ github.sha }} + cache-from: type=gha + cache-to: type=gha,mode=max diff --git a/.gitignore b/.gitignore index 1c77a62..7c56b63 100644 --- a/.gitignore +++ b/.gitignore @@ -1,82 +1,81 @@ -*.bak -config.json -.env - -# Python -__pycache__/ -*.py[cod] -*$py.class -*.so -.Python -build/ -develop-eggs/ -dist/ -downloads/ -eggs/ -.eggs/ -lib/ -lib64/ -parts/ -sdist/ -var/ -wheels/ -pip-wheel-metadata/ -share/python-wheels/ -*.egg-info/ -.installed.cfg -*.egg -MANIFEST - -# Virtual environments -venv/ -ENV/ -env/ -.venv - -# IDE -.vscode/ -.idea/ -*.swp -*.swo -*~ -.DS_Store - -# Logs -*.log -logs/ -uvicorn.log - -# Vercel -.vercel - -# Node.js / Frontend -node_modules/ -webui/node_modules/ -webui/dist/ -.npm -.pnpm-store/ -# 保留 webui/package-lock.json 用于 CI 缓存 -# package-lock.json # 如果有根目录的可以忽略 -yarn.lock -pnpm-lock.yaml - -# Build artifacts -*.tsbuildinfo -.cache/ -.parcel-cache/ - -# Environment -.env.local -.env.*.local - -# Testing -.coverage -htmlcov/ -.pytest_cache/ -.tox/ - -# Misc -*.pyc -*.pyo -.git/ -Thumbs.db +*.bak +config.json +.env + +# Python +__pycache__/ +*.py[cod] +*$py.class +*.so +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +pip-wheel-metadata/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# Virtual environments +venv/ +ENV/ +env/ +.venv + +# IDE +.vscode/ +.idea/ +*.swp +*.swo +*~ +.DS_Store + +# Logs +*.log +logs/ +uvicorn.log + +# Vercel +.vercel + +# Node.js / Frontend +node_modules/ +webui/node_modules/ +webui/dist/ +.npm +.pnpm-store/ +package-lock.json +yarn.lock +pnpm-lock.yaml + +# Build artifacts +*.tsbuildinfo +.cache/ +.parcel-cache/ + +# Environment +.env.local +.env.*.local + +# Testing +.coverage +htmlcov/ +.pytest_cache/ +.tox/ + +# Misc +*.pyc +*.pyo +.git/ +Thumbs.db diff --git a/DEPLOY.md b/DEPLOY.md index ff13005..09a6462 100644 --- a/DEPLOY.md +++ b/DEPLOY.md @@ -1,340 +1,319 @@ -# DS2API 部署指南 - -本文档详细介绍 DS2API 的各种部署方式。 - ---- - -## 目录 - -- [Vercel 部署(推荐)](#vercel-部署推荐) -- [本地开发](#本地开发) -- [生产环境部署](#生产环境部署) -- [常见问题](#常见问题) - ---- - -## Vercel 部署(推荐) - -### 一键部署 - -[](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2FCJackHwang%2Fds2api&env=DS2API_ADMIN_KEY&envDescription=管理面板访问密码(必填)&envLink=https%3A%2F%2Fgithub.com%2FCJackHwang%2Fds2api%23环境变量&project-name=ds2api&repository-name=ds2api) - -### 部署步骤 - -1. **点击部署按钮** - - 登录你的 GitHub 账号 - - 授权 Vercel 访问 - -2. **设置环境变量** - - `DS2API_ADMIN_KEY`: 管理面板密码(**必填**) - -3. **等待部署完成** - - Vercel 会自动构建并部署项目 - - 部署完成后获得访问 URL - -4. **配置账号** - - 访问 `https://your-project.vercel.app/admin` - - 输入管理密码登录 - - 添加 DeepSeek 账号 - - 设置自定义 API Key - -5. **同步配置** - - 点击「同步到 Vercel」按钮 - - 首次需要输入 Vercel Token 和 Project ID - - 同步成功后配置会持久化 - -### 获取 Vercel 凭证 - -**Vercel Token**: -1. 访问 https://vercel.com/account/tokens -2. 点击 "Create Token" -3. 设置名称和有效期 -4. 复制生成的 Token - -**Project ID**: -1. 进入 Vercel 项目页面 -2. 点击 Settings -> General -3. 复制 "Project ID" - ---- - -## 本地开发 - -### 环境要求 - -- Python 3.9+ -- Node.js 18+ (WebUI 开发) -- pip - -### 快速开始 - -```bash -# 1. 克隆项目 -git clone https://github.com/CJackHwang/ds2api.git -cd ds2api - -# 2. 安装 Python 依赖 -pip install -r requirements.txt - -# 3. 配置账号 -cp config.example.json config.json -# 编辑 config.json,填入 DeepSeek 账号信息 - -# 4. 启动服务 -python dev.py -``` - -### 配置文件示例 - -```json -{ - "keys": ["my-api-key-1", "my-api-key-2"], - "accounts": [ - { - "email": "your-email@example.com", - "password": "your-password", - "token": "" - }, - { - "mobile": "12345678901", - "password": "your-password", - "token": "" - } - ] -} -``` - -**说明**: -- `keys`: 自定义 API Key,用于调用本服务的接口 -- `accounts`: DeepSeek 网页版账号 - - 支持 `email` 或 `mobile` 登录 - - `token` 留空,系统会自动获取 - -### WebUI 开发 - -```bash -# 进入 WebUI 目录 -cd webui - -# 安装依赖 -npm install - -# 启动开发服务器 -npm run dev -``` - -WebUI 开发服务器会启动在 `http://localhost:5173`,并自动代理 API 请求到后端 `http://localhost:5001`。 - -### WebUI 构建 - -WebUI 构建产物位于 `static/admin/` 目录。 - -**自动构建(推荐)**: -- 当 `webui/` 目录下的文件变更并推送到 `main` 分支时,GitHub Actions 会自动构建并提交产物 -- PR 合并时会自动触发构建 - -**手动构建**: -```bash -# 方式1:使用脚本 -./scripts/build-webui.sh - -# 方式2:直接执行 -cd webui -npm install -npm run build -``` - -> **贡献者注意**:修改 WebUI 后无需手动构建,CI 会自动处理。 - ---- - -## 生产环境部署 - -### 使用 systemd (Linux) - -1. **创建服务文件** - -```bash -sudo nano /etc/systemd/system/ds2api.service -``` - -```ini -[Unit] -Description=DS2API Service -After=network.target - -[Service] -Type=simple -User=www-data -WorkingDirectory=/opt/ds2api -ExecStart=/usr/bin/python3 app.py -Restart=always -RestartSec=10 -Environment=PORT=5001 -Environment=DS2API_ADMIN_KEY=your-admin-key - -[Install] -WantedBy=multi-user.target -``` - -2. **启动服务** - -```bash -sudo systemctl daemon-reload -sudo systemctl enable ds2api -sudo systemctl start ds2api -``` - -3. **查看状态** - -```bash -sudo systemctl status ds2api -sudo journalctl -u ds2api -f -``` - -### Nginx 反向代理 - -```nginx -server { - listen 80; - server_name api.yourdomain.com; - - # SSL 配置(推荐) - # listen 443 ssl http2; - # ssl_certificate /path/to/cert.pem; - # ssl_certificate_key /path/to/key.pem; - - location / { - proxy_pass http://127.0.0.1:5001; - proxy_http_version 1.1; - - # 关闭缓冲,支持 SSE - proxy_buffering off; - proxy_cache off; - - # 连接设置 - proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Proto $scheme; - - # SSE 超时设置 - proxy_read_timeout 300s; - proxy_send_timeout 300s; - - # 分块传输 - chunked_transfer_encoding on; - tcp_nopush on; - tcp_nodelay on; - keepalive_timeout 120; - } -} -``` - -### Docker 部署(可选) - -```dockerfile -# Dockerfile -FROM python:3.11-slim - -WORKDIR /app -COPY requirements.txt . -RUN pip install --no-cache-dir -r requirements.txt - -COPY . . - -EXPOSE 5001 -CMD ["python", "app.py"] -``` - -```bash -# 构建镜像 -docker build -t ds2api . - -# 运行容器 -docker run -d \ - --name ds2api \ - -p 5001:5001 \ - -e DS2API_ADMIN_KEY=your-admin-key \ - -e DS2API_CONFIG_JSON='{"keys":["api-key"],"accounts":[...]}' \ - ds2api -``` - -### Docker Compose - -```yaml -# docker-compose.yml -version: '3.8' - -services: - ds2api: - build: . - ports: - - "5001:5001" - environment: - - DS2API_ADMIN_KEY=${DS2API_ADMIN_KEY} - - DS2API_CONFIG_JSON=${DS2API_CONFIG_JSON} - restart: unless-stopped -``` - ---- - -## 常见问题 - -### Q: 账号验证失败怎么办? - -**A**: 检查以下几点: -1. 确认 DeepSeek 账号密码正确 -2. 检查账号是否被封禁或需要验证 -3. 尝试在浏览器中手动登录一次 -4. 查看日志获取详细错误信息 - -### Q: 流式响应断开怎么办? - -**A**: -1. 检查 Nginx/反向代理配置,确保关闭了 `proxy_buffering` -2. 增加 `proxy_read_timeout` 超时时间 -3. 检查网络连接稳定性 - -### Q: Vercel 部署后配置丢失? - -**A**: -1. 确保点击了「同步到 Vercel」按钮 -2. 检查 Vercel Token 是否正确且未过期 -3. 确认 Project ID 正确 - -### Q: 如何更新到新版本? - -**本地部署**: -```bash -git pull origin main -pip install -r requirements.txt -# 重启服务 -``` - -**Vercel 部署**: -- 项目会自动从 GitHub 同步更新 -- 或在 Vercel 控制台手动触发重新部署 - -### Q: 如何查看日志? - -**本地开发**: -```bash -# 设置日志级别 -export LOG_LEVEL=DEBUG -python dev.py -``` - -**Vercel**: -- 访问 Vercel 控制台 -> 项目 -> Deployments -> Logs - -### Q: Token 计数不准确? - -**A**: DS2API 使用估算方式计算 token 数量(字符数 / 4),与 OpenAI 官方的 tokenizer 可能有差异,仅供参考。 - ---- - -## 获取帮助 - -- **GitHub Issues**: https://github.com/CJackHwang/ds2api/issues -- **文档**: https://github.com/CJackHwang/ds2api +# DS2API 部署指南 + +本文档详细介绍 DS2API 的各种部署方式。 + +--- + +## 目录 + +- [Vercel 部署(推荐)](#vercel-部署推荐) +- [本地开发](#本地开发) +- [生产环境部署](#生产环境部署) +- [常见问题](#常见问题) + +--- + +## Vercel 部署(推荐) + +### 一键部署 + +[](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2FCJackHwang%2Fds2api&env=DS2API_ADMIN_KEY&envDescription=管理面板访问密码(必填)&envLink=https%3A%2F%2Fgithub.com%2FCJackHwang%2Fds2api%23环境变量&project-name=ds2api&repository-name=ds2api) + +### 部署步骤 + +1. **点击部署按钮** + - 登录你的 GitHub 账号 + - 授权 Vercel 访问 + +2. **设置环境变量** + - `DS2API_ADMIN_KEY`: 管理面板密码(**必填**) + +3. **等待部署完成** + - Vercel 会自动构建并部署项目 + - 部署完成后获得访问 URL + +4. **配置账号** + - 访问 `https://your-project.vercel.app/admin` + - 输入管理密码登录 + - 添加 DeepSeek 账号 + - 设置自定义 API Key + +5. **同步配置** + - 点击「同步到 Vercel」按钮 + - 首次需要输入 Vercel Token 和 Project ID + - 同步成功后配置会持久化 + +### 获取 Vercel 凭证 + +**Vercel Token**: +1. 访问 https://vercel.com/account/tokens +2. 点击 "Create Token" +3. 设置名称和有效期 +4. 复制生成的 Token + +**Project ID**: +1. 进入 Vercel 项目页面 +2. 点击 Settings -> General +3. 复制 "Project ID" + +--- + +## 本地开发 + +### 环境要求 + +- Python 3.9+ +- Node.js 18+ (WebUI 开发) +- pip + +### 快速开始 + +```bash +# 1. 克隆项目 +git clone https://github.com/CJackHwang/ds2api.git +cd ds2api + +# 2. 安装 Python 依赖 +pip install -r requirements.txt + +# 3. 配置账号 +cp config.example.json config.json +# 编辑 config.json,填入 DeepSeek 账号信息 + +# 4. 启动服务 +python dev.py +``` + +### 配置文件示例 + +```json +{ + "keys": ["my-api-key-1", "my-api-key-2"], + "accounts": [ + { + "email": "your-email@example.com", + "password": "your-password", + "token": "" + }, + { + "mobile": "12345678901", + "password": "your-password", + "token": "" + } + ] +} +``` + +**说明**: +- `keys`: 自定义 API Key,用于调用本服务的接口 +- `accounts`: DeepSeek 网页版账号 + - 支持 `email` 或 `mobile` 登录 + - `token` 留空,系统会自动获取 + +### WebUI 开发 + +```bash +# 进入 WebUI 目录 +cd webui + +# 安装依赖 +npm install + +# 启动开发服务器 +npm run dev +``` + +WebUI 开发服务器会启动在 `http://localhost:5173`,并自动代理 API 请求到后端 `http://localhost:5001`。 + +--- + +## 生产环境部署 + +### 使用 systemd (Linux) + +1. **创建服务文件** + +```bash +sudo nano /etc/systemd/system/ds2api.service +``` + +```ini +[Unit] +Description=DS2API Service +After=network.target + +[Service] +Type=simple +User=www-data +WorkingDirectory=/opt/ds2api +ExecStart=/usr/bin/python3 app.py +Restart=always +RestartSec=10 +Environment=PORT=5001 +Environment=DS2API_ADMIN_KEY=your-admin-key + +[Install] +WantedBy=multi-user.target +``` + +2. **启动服务** + +```bash +sudo systemctl daemon-reload +sudo systemctl enable ds2api +sudo systemctl start ds2api +``` + +3. **查看状态** + +```bash +sudo systemctl status ds2api +sudo journalctl -u ds2api -f +``` + +### Nginx 反向代理 + +```nginx +server { + listen 80; + server_name api.yourdomain.com; + + # SSL 配置(推荐) + # listen 443 ssl http2; + # ssl_certificate /path/to/cert.pem; + # ssl_certificate_key /path/to/key.pem; + + location / { + proxy_pass http://127.0.0.1:5001; + proxy_http_version 1.1; + + # 关闭缓冲,支持 SSE + proxy_buffering off; + proxy_cache off; + + # 连接设置 + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + + # SSE 超时设置 + proxy_read_timeout 300s; + proxy_send_timeout 300s; + + # 分块传输 + chunked_transfer_encoding on; + tcp_nopush on; + tcp_nodelay on; + keepalive_timeout 120; + } +} +``` + +### Docker 部署(可选) + +```dockerfile +# Dockerfile +FROM python:3.11-slim + +WORKDIR /app +COPY requirements.txt . +RUN pip install --no-cache-dir -r requirements.txt + +COPY . . + +EXPOSE 5001 +CMD ["python", "app.py"] +``` + +```bash +# 构建镜像 +docker build -t ds2api . + +# 运行容器 +docker run -d \ + --name ds2api \ + -p 5001:5001 \ + -e DS2API_ADMIN_KEY=your-admin-key \ + -e DS2API_CONFIG_JSON='{"keys":["api-key"],"accounts":[...]}' \ + ds2api +``` + +### Docker Compose + +```yaml +# docker-compose.yml +version: '3.8' + +services: + ds2api: + build: . + ports: + - "5001:5001" + environment: + - DS2API_ADMIN_KEY=${DS2API_ADMIN_KEY} + - DS2API_CONFIG_JSON=${DS2API_CONFIG_JSON} + restart: unless-stopped +``` + +--- + +## 常见问题 + +### Q: 账号验证失败怎么办? + +**A**: 检查以下几点: +1. 确认 DeepSeek 账号密码正确 +2. 检查账号是否被封禁或需要验证 +3. 尝试在浏览器中手动登录一次 +4. 查看日志获取详细错误信息 + +### Q: 流式响应断开怎么办? + +**A**: +1. 检查 Nginx/反向代理配置,确保关闭了 `proxy_buffering` +2. 增加 `proxy_read_timeout` 超时时间 +3. 检查网络连接稳定性 + +### Q: Vercel 部署后配置丢失? + +**A**: +1. 确保点击了「同步到 Vercel」按钮 +2. 检查 Vercel Token 是否正确且未过期 +3. 确认 Project ID 正确 + +### Q: 如何更新到新版本? + +**本地部署**: +```bash +git pull origin main +pip install -r requirements.txt +# 重启服务 +``` + +**Vercel 部署**: +- 项目会自动从 GitHub 同步更新 +- 或在 Vercel 控制台手动触发重新部署 + +### Q: 如何查看日志? + +**本地开发**: +```bash +# 设置日志级别 +export LOG_LEVEL=DEBUG +python dev.py +``` + +**Vercel**: +- 访问 Vercel 控制台 -> 项目 -> Deployments -> Logs + +### Q: Token 计数不准确? + +**A**: DS2API 使用估算方式计算 token 数量(字符数 / 4),与 OpenAI 官方的 tokenizer 可能有差异,仅供参考。 + +--- + +## 获取帮助 + +- **GitHub Issues**: https://github.com/CJackHwang/ds2api/issues +- **文档**: https://github.com/CJackHwang/ds2api diff --git a/VERSION b/VERSION index 6e8bf73..7ecf123 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.1.0 +0.1.0 diff --git a/docker-compose.yml b/docker-compose.yml index 54cec15..3e6b605 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,14 +1,14 @@ -services: - ds2api: - image: crpi-cnazxqmg4avmg4fq.cn-beijing.personal.cr.aliyuncs.com/ronghuaxueleng/ds2api:latest - container_name: ds2api - restart: always - ports: - - "6011:5001" - volumes: - - ./config.json:/app/config.json # 配置文件 - - ./.env:/app/.env # 环境变量 - environment: - - TZ=Asia/Shanghai - - LOG_LEVEL=INFO - - DS2API_ADMIN_KEY=${DS2API_ADMIN_KEY:-ds2api} +services: + ds2api: + image: crpi-cnazxqmg4avmg4fq.cn-beijing.personal.cr.aliyuncs.com/ronghuaxueleng/ds2api:latest + container_name: ds2api + restart: always + ports: + - "6011:5001" + volumes: + - ./config.json:/app/config.json # 配置文件 + - ./.env:/app/.env # 环境变量 + environment: + - TZ=Asia/Shanghai + - LOG_LEVEL=INFO + - DS2API_ADMIN_KEY=${DS2API_ADMIN_KEY:-ds2api} diff --git a/docker/Dockerfile b/docker/Dockerfile index 66d71e0..ccac75f 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -1,70 +1,70 @@ -# ========== 阶段1: 构建前端 ========== -FROM node:20-slim AS frontend-builder - -WORKDIR /app/webui - -# 复制前端依赖文件 -COPY webui/package.json webui/package-lock.json ./ - -# 安装依赖 -RUN npm ci - -# 复制前端源码 -COPY webui/ ./ - -# 构建前端 -RUN npm run build - -# ========== 阶段2: 构建后端 ========== -FROM python:3.11-slim - -WORKDIR /app - -# 设置环境变量 -ENV PYTHONDONTWRITEBYTECODE=1 -ENV PYTHONUNBUFFERED=1 -ENV TZ=Asia/Shanghai - -# 安装系统依赖 -# curl_cffi 需要 libcurl 和编译工具 -RUN apt-get update && apt-get install -y --no-install-recommends \ - gcc \ - g++ \ - libffi-dev \ - libcurl4-openssl-dev \ - libssl-dev \ - curl \ - && ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone \ - && rm -rf /var/lib/apt/lists/* - -# 复制并安装 Python 依赖 -COPY requirements.txt . -RUN pip install --no-cache-dir -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple - -# 复制后端代码 -COPY app.py . -COPY core/ ./core/ -COPY routes/ ./routes/ - -# 创建 templates 目录(预留扩展用) -RUN mkdir -p ./templates - -# 复制 WASM 文件和 Tokenizer 相关文件 -COPY sha3_wasm_bg.7b9ca65ddd.wasm ./ -COPY tokenizer.json tokenizer_config.json ./ - -# 从前端构建阶段复制构建产物到 static/admin -COPY --from=frontend-builder /app/webui/dist ./static/admin - -# 创建配置文件目录(运行时挂载) -RUN mkdir -p /app/data - -# 暴露端口 -EXPOSE 5001 - -# 健康检查 -HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \ - CMD curl -f http://localhost:5001/ || exit 1 - -# 启动命令 -CMD ["python", "-m", "uvicorn", "app:app", "--host", "0.0.0.0", "--port", "5001"] +# ========== 阶段1: 构建前端 ========== +FROM node:20-slim AS frontend-builder + +WORKDIR /app/webui + +# 复制前端依赖文件 +COPY webui/package.json webui/package-lock.json ./ + +# 安装依赖 +RUN npm ci + +# 复制前端源码 +COPY webui/ ./ + +# 构建前端 +RUN npm run build + +# ========== 阶段2: 构建后端 ========== +FROM python:3.11-slim + +WORKDIR /app + +# 设置环境变量 +ENV PYTHONDONTWRITEBYTECODE=1 +ENV PYTHONUNBUFFERED=1 +ENV TZ=Asia/Shanghai + +# 安装系统依赖 +# curl_cffi 需要 libcurl 和编译工具 +RUN apt-get update && apt-get install -y --no-install-recommends \ + gcc \ + g++ \ + libffi-dev \ + libcurl4-openssl-dev \ + libssl-dev \ + curl \ + && ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone \ + && rm -rf /var/lib/apt/lists/* + +# 复制并安装 Python 依赖 +COPY requirements.txt . +RUN pip install --no-cache-dir -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple + +# 复制后端代码 +COPY app.py . +COPY core/ ./core/ +COPY routes/ ./routes/ + +# 创建 templates 目录(预留扩展用) +RUN mkdir -p ./templates + +# 复制 WASM 文件和 Tokenizer 相关文件 +COPY sha3_wasm_bg.7b9ca65ddd.wasm ./ +COPY tokenizer.json tokenizer_config.json ./ + +# 从前端构建阶段复制构建产物到 static/admin +COPY --from=frontend-builder /app/webui/dist ./static/admin + +# 创建配置文件目录(运行时挂载) +RUN mkdir -p /app/data + +# 暴露端口 +EXPOSE 5001 + +# 健康检查 +HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \ + CMD curl -f http://localhost:5001/ || exit 1 + +# 启动命令 +CMD ["python", "-m", "uvicorn", "app:app", "--host", "0.0.0.0", "--port", "5001"] diff --git a/routes/home.py b/routes/home.py index dad0fb8..4105302 100644 --- a/routes/home.py +++ b/routes/home.py @@ -1,303 +1,301 @@ -# -*- coding: utf-8 -*- -"""首页和 WebUI 路由""" -import os -from fastapi import APIRouter, Request -from fastapi.responses import HTMLResponse, FileResponse - -from core.config import STATIC_ADMIN_DIR - -router = APIRouter() - -# 首页 HTML(内嵌避免依赖模板目录) -WELCOME_HTML = """ - -
- - -DeepSeek to OpenAI & Claude Compatible API Interface
-完美适配 OpenAI 与 Claude API 格式,无缝集成现有工具。
-内置智能轮询机制,支持多账号并发,稳定高效。
-完整支持 推理过程输出,让思考可见。
-集成 DeepSeek 原生搜索能力,获取最新实时资讯。
-Run cd webui && npm run build first.
DeepSeek to OpenAI & Claude Compatible API Interface
+完美适配 OpenAI 与 Claude API 格式,无缝集成现有工具。
+内置智能轮询机制,支持多账号并发,稳定高效。
+完整支持 推理过程输出,让思考可见。
+集成 DeepSeek 原生搜索能力,获取最新实时资讯。
+Run cd webui && npm run build first.