sanbo110 commited on
Commit
f78578c
·
1 Parent(s): 9da15c9

update sth at 2026-01-15 15:33:59

Browse files
Files changed (38) hide show
  1. .env +28 -11
  2. .gitattributes +0 -2
  3. .github/workflows/docker.yml +0 -64
  4. .gitignore +0 -180
  5. Dockerfile +6 -9
  6. NGINX_SETUP.md +10 -10
  7. README_DOCKER.md +10 -10
  8. app/__pycache__/__init__.cpython-311.pyc +0 -0
  9. app/admin/api.py +1 -1
  10. app/core/__pycache__/__init__.cpython-311.pyc +0 -0
  11. app/core/__pycache__/config.cpython-311.pyc +0 -0
  12. app/core/__pycache__/openai.cpython-311.pyc +0 -0
  13. app/core/config.py +11 -11
  14. app/core/openai.py +5 -7
  15. app/models/__pycache__/__init__.cpython-311.pyc +0 -0
  16. app/models/__pycache__/schemas.cpython-311.pyc +0 -0
  17. app/providers/__pycache__/__init__.cpython-311.pyc +0 -0
  18. app/providers/__pycache__/base.cpython-311.pyc +0 -0
  19. app/providers/__pycache__/k2think_provider.cpython-311.pyc +0 -0
  20. app/providers/__pycache__/longcat_provider.cpython-311.pyc +0 -0
  21. app/providers/__pycache__/provider_factory.cpython-311.pyc +0 -0
  22. app/providers/__pycache__/zai_provider.cpython-311.pyc +0 -0
  23. app/providers/zai_provider.py +17 -14
  24. app/templates/config.html +1 -1
  25. app/utils/__pycache__/__init__.cpython-311.pyc +0 -0
  26. app/utils/__pycache__/fe_version.cpython-311.pyc +0 -0
  27. app/utils/__pycache__/logger.cpython-311.pyc +0 -0
  28. app/utils/__pycache__/reload_config.cpython-311.pyc +0 -0
  29. app/utils/__pycache__/signature.cpython-311.pyc +0 -0
  30. app/utils/__pycache__/token_pool.cpython-311.pyc +0 -0
  31. app/utils/__pycache__/tool_call_handler.cpython-311.pyc +0 -0
  32. app/utils/__pycache__/user_agent.cpython-311.pyc +0 -0
  33. app/utils/fe_version.py +112 -0
  34. app/utils/logger.py +0 -1
  35. docker-compose.yml +3 -3
  36. nginx.conf +0 -157
  37. nginx.conf.example +7 -7
  38. xREADME.md +0 -347
.env CHANGED
@@ -1,18 +1,35 @@
1
- # 代理服务配置文件
2
- # 匿名模式配置
 
3
 
4
- # 跳过客户端认证(启用匿名访问)
 
 
 
 
 
 
5
  SKIP_AUTH_TOKEN=true
6
 
7
- # Z.AI 匿名用户模式
8
- # false: 使用认证 Token 令牌,失败时自动降级为匿名请求
9
- # true: 自动从 Z.ai 获取临时访问令牌,避免对话历史共享
 
10
  ANONYMOUS_MODE=true
11
 
12
- # 服务监听端口
13
- LISTEN_PORT=7860
14
 
15
- # 调试日志
16
- DEBUG_LOGGING=true
 
 
 
17
 
18
- AUTH_TOKEN=sk-your-key
 
 
 
 
 
 
 
1
+ # ==============================================
2
+ # Z.AI API Server - Docker 环境变量配置示例
3
+ # ==============================================
4
 
5
+ # 管理后台密码
6
+ ADMIN_PASSWORD=admin123
7
+
8
+ # API 认证密钥 (用于验证客户端请求)
9
+ AUTH_TOKEN=sk-your-key
10
+
11
+ # 是否跳过 API Key 验证 (开发环境可设为 true)
12
  SKIP_AUTH_TOKEN=true
13
 
14
+ # 调试日志 (生产环境建议设为 false)
15
+ DEBUG_LOGGING=true
16
+
17
+ # 匿名模式 (允许无 token 访问,需要配合 SKIP_AUTH_TOKEN=true)
18
  ANONYMOUS_MODE=true
19
 
20
+ # Function Call 功能开关 (是否支持工具调用)
21
+ TOOL_SUPPORT=true
22
 
23
+ # 工具用扫描限制 (字符数)
24
+ SCAN_LIMIT=200000
25
+
26
+ # 数据库路径 (Docker 环境使用持久化卷)
27
+ DB_PATH=/app/data/tokens.db
28
 
29
+ # Token 池配置
30
+ TOKEN_FAILURE_THRESHOLD=3
31
+ TOKEN_RECOVERY_TIMEOUT=300
32
+
33
+ # 服务配置
34
+ SERVICE_NAME=Z.AI_API_Server
35
+ LISTEN_PORT=7860
.gitattributes DELETED
@@ -1,2 +0,0 @@
1
- # Auto detect text files and perform LF normalization
2
- * text=auto
 
 
 
.github/workflows/docker.yml DELETED
@@ -1,64 +0,0 @@
1
- name: Build and Push Docker Image
2
-
3
- on:
4
- push:
5
- branches:
6
- - main
7
- tags:
8
- - 'v*'
9
-
10
- env:
11
- IMAGE_NAME: z-ai2api-python
12
-
13
- jobs:
14
- docker:
15
- runs-on: ubuntu-latest
16
- permissions:
17
- contents: read
18
- packages: write
19
-
20
- steps:
21
- - name: Checkout
22
- uses: actions/checkout@v4
23
-
24
- - name: Set up Docker Buildx
25
- uses: docker/setup-buildx-action@v3
26
-
27
- - name: Login to GitHub Container Registry
28
- uses: docker/login-action@v3
29
- with:
30
- registry: ghcr.io
31
- username: ${{ github.actor }}
32
- password: ${{ secrets.GITHUB_TOKEN }}
33
-
34
- - name: Login to Docker Hub
35
- if: github.event_name != 'pull_request'
36
- uses: docker/login-action@v3
37
- with:
38
- username: ${{ secrets.DOCKERHUB_USERNAME }}
39
- password: ${{ secrets.DOCKERHUB_TOKEN }}
40
-
41
- - name: Extract metadata
42
- id: meta
43
- uses: docker/metadata-action@v5
44
- with:
45
- images: |
46
- ghcr.io/${{ github.repository }}
47
- ${{ secrets.DOCKERHUB_USERNAME }}/${{ env.IMAGE_NAME }}
48
- tags: |
49
- type=ref,event=branch
50
- type=semver,pattern={{version}}
51
- type=semver,pattern={{major}}.{{minor}}
52
- type=raw,value=latest,enable={{is_default_branch}}
53
-
54
- - name: Build and push
55
- uses: docker/build-push-action@v5
56
- with:
57
- context: .
58
- file: ./deploy/Dockerfile
59
- platforms: linux/amd64,linux/arm64
60
- push: true
61
- tags: ${{ steps.meta.outputs.tags }}
62
- labels: ${{ steps.meta.outputs.labels }}
63
- cache-from: type=gha
64
- cache-to: type=gha,mode=max
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
.gitignore DELETED
@@ -1,180 +0,0 @@
1
- # Custom
2
- .vs/
3
- .vscode/
4
- .idea/
5
- .conda/
6
- *.zip
7
- *.txt
8
- *.pid
9
- docs/
10
- output/
11
- main.build/
12
- main.dist/
13
- main.onefile-build/
14
- *report.xml
15
- *.yaml
16
- logs/
17
- backup/
18
- uv.lock
19
- AGENTS.md
20
- *.db
21
-
22
- # AI Toolset
23
- .augment/
24
- .cursor/
25
- .claude/
26
- CLAUDE.md
27
-
28
- # Byte-compiled / optimized / DLL files
29
- __pycache__/
30
- *.py[cod]
31
- *$py.class
32
-
33
- # C extensions
34
- *.so
35
-
36
- # Distribution / packaging
37
- .Python
38
- build/
39
- develop-eggs/
40
- dist/
41
- downloads/
42
- eggs/
43
- .eggs/
44
- lib/
45
- lib64/
46
- parts/
47
- sdist/
48
- var/
49
- wheels/
50
- share/python-wheels/
51
- *.egg-info/
52
- .installed.cfg
53
- *.egg
54
- MANIFEST
55
-
56
- # PyInstaller
57
- # Usually these files are written by a python script from a template
58
- # before PyInstaller builds the exe, so as to inject date/other infos into it.
59
- *.manifest
60
- *.spec
61
-
62
- # Installer logs
63
- pip-log.txt
64
- pip-delete-this-directory.txt
65
-
66
- # Unit test / coverage reports
67
- htmlcov/
68
- .tox/
69
- .nox/
70
- .coverage
71
- .coverage.*
72
- .cache
73
- nosetests.xml
74
- coverage.xml
75
- *.cover
76
- *.py,cover
77
- .hypothesis/
78
- .pytest_cache/
79
- cover/
80
-
81
- # Translations
82
- *.mo
83
- *.pot
84
-
85
- # Django stuff:
86
- *.log
87
- local_settings.py
88
- db.sqlite3
89
- db.sqlite3-journal
90
-
91
- # Flask stuff:
92
- instance/
93
- .webassets-cache
94
-
95
- # Scrapy stuff:
96
- .scrapy
97
-
98
- # Sphinx documentation
99
- docs/_build/
100
-
101
- # PyBuilder
102
- .pybuilder/
103
- target/
104
-
105
- # Jupyter Notebook
106
- .ipynb_checkpoints
107
-
108
- # IPython
109
- profile_default/
110
- ipython_config.py
111
-
112
- # pyenv
113
- # For a library or package, you might want to ignore these files since the code is
114
- # intended to run in multiple environments; otherwise, check them in:
115
- # .python-version
116
-
117
- # pipenv
118
- # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
119
- # However, in case of collaboration, if having platform-specific dependencies or dependencies
120
- # having no cross-platform support, pipenv may install dependencies that don't work, or not
121
- # install all needed dependencies.
122
- #Pipfile.lock
123
-
124
- # poetry
125
- # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
126
- # This is especially recommended for binary packages to ensure reproducibility, and is more
127
- # commonly ignored for libraries.
128
- # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
129
- #poetry.lock
130
-
131
- # pdm
132
- # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
133
- #pdm.lock
134
- # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
135
- # in version control.
136
- # https://pdm.fming.dev/#use-with-ide
137
- .pdm.toml
138
-
139
- # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
140
- __pypackages__/
141
-
142
- # Celery stuff
143
- celerybeat-schedule
144
- celerybeat.pid
145
-
146
- # SageMath parsed files
147
- *.sage.py
148
-
149
- # Environments
150
- .env
151
- .venv
152
- env/
153
- venv/
154
- ENV/
155
- env.bak/
156
- venv.bak/
157
-
158
- # Spyder project settings
159
- .spyderproject
160
- .spyproject
161
-
162
- # Rope project settings
163
- .ropeproject
164
-
165
- # mkdocs documentation
166
- /site
167
-
168
- # mypy
169
- .mypy_cache/
170
- .dmypy.json
171
- dmypy.json
172
-
173
- # Pyre type checker
174
- .pyre/
175
-
176
- # pytype static type analyzer
177
- .pytype/
178
-
179
- # Cython debug symbols
180
- cython_debug/
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
Dockerfile CHANGED
@@ -4,8 +4,9 @@ FROM python:3.12-slim
4
  WORKDIR /app
5
 
6
  # Create data and logs directories with proper permissions
7
- RUN mkdir -p /app/data /app/logs && \
8
- chmod 755 /app/data /app/logs
 
9
 
10
  # Install dependencies
11
  COPY requirements.txt .
@@ -14,18 +15,14 @@ RUN pip install --no-cache-dir -r requirements.txt
14
  # Copy application code
15
  COPY . .
16
 
17
- # Set environment variable for database path
18
  ENV DB_PATH=/app/data/tokens.db
 
19
  ENV SKIP_AUTH_TOKEN=true
20
  ENV ANONYMOUS_MODE=true
21
- # 服务监听端口
22
- ENV LISTEN_PORT=7860
23
- # 调试日志
24
- ENV DEBUG_LOGGING=true
25
 
26
- # Expose port
27
  EXPOSE 7860
28
 
29
-
30
  # Run the application
31
  CMD ["python", "main.py"]
 
4
  WORKDIR /app
5
 
6
  # Create data and logs directories with proper permissions
7
+ # HuggingFace Spaces runs as non-root user, need proper permissions
8
+ RUN mkdir -p /app/data /app/logs /app/app/static/css /app/app/static/js && \
9
+ chmod -R 777 /app/data /app/logs /app/app/static
10
 
11
  # Install dependencies
12
  COPY requirements.txt .
 
15
  # Copy application code
16
  COPY . .
17
 
18
+ # Set environment variables
19
  ENV DB_PATH=/app/data/tokens.db
20
+ ENV LISTEN_PORT=7860
21
  ENV SKIP_AUTH_TOKEN=true
22
  ENV ANONYMOUS_MODE=true
 
 
 
 
23
 
24
+ # Expose HuggingFace Spaces default port
25
  EXPOSE 7860
26
 
 
27
  # Run the application
28
  CMD ["python", "main.py"]
NGINX_SETUP.md CHANGED
@@ -37,7 +37,7 @@ server {
37
 
38
  location /ai2api {
39
  # 代理到后端服务
40
- proxy_pass http://127.0.0.1:7860;
41
 
42
  # 传递原始请求信息
43
  proxy_set_header Host $host;
@@ -72,7 +72,7 @@ services:
72
  - LISTEN_PORT=7860
73
  # ... 其他环境变量
74
  ports:
75
- - "7860:7860"
76
  ```
77
 
78
  ### 4. 重启服务
@@ -93,8 +93,8 @@ docker-compose restart
93
 
94
  配置完成后,服务访问地址如下:
95
 
96
- - **API 端点**: `http://your-domain.com/ai2api/v1/chat/completions`
97
- - **模型列表**: `http://your-domain.com/ai2api/v1/models`
98
  - **管理后台**: `http://your-domain.com/ai2api/admin/login`
99
  - **根路径**: `http://your-domain.com/ai2api/`
100
 
@@ -110,7 +110,7 @@ ROOT_PATH=/api
110
  **Nginx 配置**:
111
  ```nginx
112
  location /api {
113
- proxy_pass http://127.0.0.1:7860;
114
  # ... 其他配置
115
  }
116
  ```
@@ -127,7 +127,7 @@ ROOT_PATH=
127
  **Nginx 配置**:
128
  ```nginx
129
  location / {
130
- proxy_pass http://127.0.0.1:7860;
131
  # ... 其他配置
132
  }
133
  ```
@@ -144,7 +144,7 @@ ROOT_PATH=/services/ai/chat
144
  **Nginx 配置**:
145
  ```nginx
146
  location /services/ai/chat {
147
- proxy_pass http://127.0.0.1:7860;
148
  # ... 其他配置
149
  }
150
  ```
@@ -215,7 +215,7 @@ proxy_set_header X-Forwarded-Proto $scheme;
215
 
216
  1. **访问健康检查端点**:
217
  ```bash
218
- curl http://your-domain.com/ai2api/v1/models
219
  ```
220
 
221
  2. **访问管理后台**:
@@ -246,7 +246,7 @@ server {
246
  ssl_certificate_key /path/to/key.pem;
247
 
248
  location /ai2api {
249
- proxy_pass http://127.0.0.1:7860;
250
  proxy_set_header X-Forwarded-Proto https;
251
  # ... 其他配置
252
  }
@@ -257,7 +257,7 @@ server {
257
 
258
  ```nginx
259
  upstream ai2api_backend {
260
- server 127.0.0.1:7860;
261
  server 127.0.0.1:8081;
262
  server 127.0.0.1:8082;
263
  }
 
37
 
38
  location /ai2api {
39
  # 代理到后端服务
40
+ proxy_pass http://127.0.0.1:8080;
41
 
42
  # 传递原始请求信息
43
  proxy_set_header Host $host;
 
72
  - LISTEN_PORT=7860
73
  # ... 其他环境变量
74
  ports:
75
+ - "8080:8080"
76
  ```
77
 
78
  ### 4. 重启服务
 
93
 
94
  配置完成后,服务访问地址如下:
95
 
96
+ - **API 端点**: `http://your-domain.com/ai2api/hf/v1/chat/completions`
97
+ - **模型列表**: `http://your-domain.com/ai2api/hf/v1/models`
98
  - **管理后台**: `http://your-domain.com/ai2api/admin/login`
99
  - **根路径**: `http://your-domain.com/ai2api/`
100
 
 
110
  **Nginx 配置**:
111
  ```nginx
112
  location /api {
113
+ proxy_pass http://127.0.0.1:8080;
114
  # ... 其他配置
115
  }
116
  ```
 
127
  **Nginx 配置**:
128
  ```nginx
129
  location / {
130
+ proxy_pass http://127.0.0.1:8080;
131
  # ... 其他配置
132
  }
133
  ```
 
144
  **Nginx 配置**:
145
  ```nginx
146
  location /services/ai/chat {
147
+ proxy_pass http://127.0.0.1:8080;
148
  # ... 其他配置
149
  }
150
  ```
 
215
 
216
  1. **访问健康检查端点**:
217
  ```bash
218
+ curl http://your-domain.com/ai2api/hf/v1/models
219
  ```
220
 
221
  2. **访问管理后台**:
 
246
  ssl_certificate_key /path/to/key.pem;
247
 
248
  location /ai2api {
249
+ proxy_pass http://127.0.0.1:8080;
250
  proxy_set_header X-Forwarded-Proto https;
251
  # ... 其他配置
252
  }
 
257
 
258
  ```nginx
259
  upstream ai2api_backend {
260
+ server 127.0.0.1:8080;
261
  server 127.0.0.1:8081;
262
  server 127.0.0.1:8082;
263
  }
README_DOCKER.md CHANGED
@@ -16,7 +16,7 @@ mkdir -p data logs
16
  # 快速启动
17
  docker run -d \
18
  --name z-ai-api-server \
19
- -p 7860:7860 \
20
  -e ADMIN_PASSWORD=admin123 \
21
  -e AUTH_TOKEN=sk-your-api-key \
22
  -e ANONYMOUS_MODE=true \
@@ -48,7 +48,7 @@ docker compose up -d
48
  docker compose logs -f api-server
49
  ```
50
 
51
- 服务将在 `http://localhost:7860` 启动。
52
 
53
  ## 架构说明
54
 
@@ -222,10 +222,10 @@ docker compose config
222
 
223
  ### 端口冲突
224
 
225
- 如端口 7860 被占用,修改 `docker-compose.yml`:
226
  ```yaml
227
  ports:
228
- - "8081:7860" # 映射到宿主机 8081 端口
229
  ```
230
 
231
  ### 健康检查失败
@@ -235,7 +235,7 @@ ports:
235
  docker compose ps
236
 
237
  # 手动测试接口
238
- curl http://localhost:7860/v1/models
239
 
240
  # 进入容器排查
241
  docker exec -it z-ai-api-server bash
@@ -245,11 +245,11 @@ docker exec -it z-ai-api-server bash
245
 
246
  | 端点 | 地址 | 说明 |
247
  |------|------|------|
248
- | API 根路径 | `http://localhost:7860` | OpenAI 兼容 API |
249
- | 模型列表 | `http://localhost:7860/v1/models` | 获取可用模型 |
250
- | 管理后台 | `http://localhost:7860/admin` | Web 管理界面 |
251
- | API 文档 | `http://localhost:7860/docs` | OpenAPI/Swagger 文档 |
252
- | 健康检查 | `http://localhost:7860/v1/models` | 服务健康状态 |
253
 
254
  ## 高级配置
255
 
 
16
  # 快速启动
17
  docker run -d \
18
  --name z-ai-api-server \
19
+ -p 8080:8080 \
20
  -e ADMIN_PASSWORD=admin123 \
21
  -e AUTH_TOKEN=sk-your-api-key \
22
  -e ANONYMOUS_MODE=true \
 
48
  docker compose logs -f api-server
49
  ```
50
 
51
+ 服务将在 `http://localhost:8080` 启动。
52
 
53
  ## 架构说明
54
 
 
222
 
223
  ### 端口冲突
224
 
225
+ 如端口 8080 被占用,修改 `docker-compose.yml`:
226
  ```yaml
227
  ports:
228
+ - "8081:8080" # 映射到宿主机 8081 端口
229
  ```
230
 
231
  ### 健康检查失败
 
235
  docker compose ps
236
 
237
  # 手动测试接口
238
+ curl http://localhost:8080/hf/v1/models
239
 
240
  # 进入容器排查
241
  docker exec -it z-ai-api-server bash
 
245
 
246
  | 端点 | 地址 | 说明 |
247
  |------|------|------|
248
+ | API 根路径 | `http://localhost:8080` | OpenAI 兼容 API |
249
+ | 模型列表 | `http://localhost:8080/hf/v1/models` | 获取可用模型 |
250
+ | 管理后台 | `http://localhost:8080/admin` | Web 管理界面 |
251
+ | API 文档 | `http://localhost:8080/docs` | OpenAPI/Swagger 文档 |
252
+ | 健康检查 | `http://localhost:8080/hf/v1/models` | 服务健康状态 |
253
 
254
  ## 高级配置
255
 
app/__pycache__/__init__.cpython-311.pyc ADDED
Binary file (268 Bytes). View file
 
app/admin/api.py CHANGED
@@ -166,7 +166,7 @@ async def get_recent_logs(request: Request):
166
  logs = [
167
  {
168
  "timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
169
- "endpoint": "/v1/chat/completions",
170
  "model": "gpt-4o",
171
  "status": 200,
172
  "duration": "1.23s",
 
166
  logs = [
167
  {
168
  "timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
169
+ "endpoint": "/hf/v1/chat/completions",
170
  "model": "gpt-4o",
171
  "status": 200,
172
  "duration": "1.23s",
app/core/__pycache__/__init__.cpython-311.pyc ADDED
Binary file (267 Bytes). View file
 
app/core/__pycache__/config.cpython-311.pyc ADDED
Binary file (4.86 kB). View file
 
app/core/__pycache__/openai.cpython-311.pyc ADDED
Binary file (9.16 kB). View file
 
app/core/config.py CHANGED
@@ -24,11 +24,11 @@ class Settings(BaseSettings):
24
  GLM45_THINKING_MODEL: str = os.getenv("GLM45_THINKING_MODEL", "GLM-4.5-Thinking")
25
  GLM45_SEARCH_MODEL: str = os.getenv("GLM45_SEARCH_MODEL", "GLM-4.5-Search")
26
  GLM45_AIR_MODEL: str = os.getenv("GLM45_AIR_MODEL", "GLM-4.5-Air")
27
- GLM45V_MODEL: str = os.getenv("GLM45V_MODEL", "GLM-4.5V")
28
- GLM46_MODEL: str = os.getenv("GLM46_MODEL", "GLM-4.6")
29
- GLM46_THINKING_MODEL: str = os.getenv("GLM46_THINKING_MODEL", "GLM-4.6-Thinking")
30
- GLM46_SEARCH_MODEL: str = os.getenv("GLM46_SEARCH_MODEL", "GLM-4.6-Search")
31
- GLM46_ADVANCED_SEARCH_MODEL: str = os.getenv("GLM46_ADVANCED_SEARCH_MODEL", "GLM-4.6-advanced-search")
32
 
33
  # Provider Model Mapping
34
  @property
@@ -40,11 +40,11 @@ class Settings(BaseSettings):
40
  "GLM-4.5-Thinking": "zai",
41
  "GLM-4.5-Search": "zai",
42
  "GLM-4.5-Air": "zai",
43
- "GLM-4.5V": "zai",
44
- "GLM-4.6": "zai",
45
- "GLM-4.6-Thinking": "zai",
46
- "GLM-4.6-Search": "zai",
47
- "GLM-4.6-advanced-search": "zai",
48
  # K2Think models
49
  "MBZUAI-IFM/K2-Think": "k2think",
50
  # LongCat models
@@ -54,7 +54,7 @@ class Settings(BaseSettings):
54
  }
55
 
56
  # Server Configuration
57
- LISTEN_PORT: int = int(os.getenv("LISTEN_PORT", "7860"))
58
  DEBUG_LOGGING: bool = os.getenv("DEBUG_LOGGING", "true").lower() == "true"
59
  SERVICE_NAME: str = os.getenv("SERVICE_NAME", "z-ai2api-server")
60
  ROOT_PATH: str = os.getenv("ROOT_PATH", "") # For Nginx reverse proxy path prefix, e.g., "/api" or "/path-prefix"
 
24
  GLM45_THINKING_MODEL: str = os.getenv("GLM45_THINKING_MODEL", "GLM-4.5-Thinking")
25
  GLM45_SEARCH_MODEL: str = os.getenv("GLM45_SEARCH_MODEL", "GLM-4.5-Search")
26
  GLM45_AIR_MODEL: str = os.getenv("GLM45_AIR_MODEL", "GLM-4.5-Air")
27
+ GLM46V_MODEL: str = os.getenv("GLM46V_MODEL", "GLM-4.6V")
28
+ GLM47_MODEL: str = os.getenv("GLM47_MODEL", "GLM-4.7")
29
+ GLM47_THINKING_MODEL: str = os.getenv("GLM47_THINKING_MODEL", "GLM-4.7-Thinking")
30
+ GLM47_SEARCH_MODEL: str = os.getenv("GLM47_SEARCH_MODEL", "GLM-4.7-Search")
31
+ GLM47_ADVANCED_SEARCH_MODEL: str = os.getenv("GLM47_ADVANCED_SEARCH_MODEL", "GLM-4.7-advanced-search")
32
 
33
  # Provider Model Mapping
34
  @property
 
40
  "GLM-4.5-Thinking": "zai",
41
  "GLM-4.5-Search": "zai",
42
  "GLM-4.5-Air": "zai",
43
+ "GLM-4.6V": "zai",
44
+ "GLM-4.7": "zai",
45
+ "GLM-4.7-Thinking": "zai",
46
+ "GLM-4.7-Search": "zai",
47
+ "GLM-4.7-advanced-search": "zai",
48
  # K2Think models
49
  "MBZUAI-IFM/K2-Think": "k2think",
50
  # LongCat models
 
54
  }
55
 
56
  # Server Configuration
57
+ LISTEN_PORT: int = int(os.getenv("LISTEN_PORT", "7860")) # HuggingFace Spaces 默认端口
58
  DEBUG_LOGGING: bool = os.getenv("DEBUG_LOGGING", "true").lower() == "true"
59
  SERVICE_NAME: str = os.getenv("SERVICE_NAME", "z-ai2api-server")
60
  ROOT_PATH: str = os.getenv("ROOT_PATH", "") # For Nginx reverse proxy path prefix, e.g., "/api" or "/path-prefix"
app/core/openai.py CHANGED
@@ -92,9 +92,8 @@ async def handle_non_stream_response(stream_response, request: OpenAIRequest) ->
92
  return JSONResponse(content=response_data.model_dump(exclude_none=True))
93
 
94
 
95
- @router.get("/v1/models")
96
  @router.get("/hf/v1/models")
97
- @router.get("/api/v1/models")
98
  async def list_models():
99
  """List available models from all providers"""
100
  try:
@@ -107,18 +106,17 @@ async def list_models():
107
  current_time = int(time.time())
108
  fallback_response = ModelsResponse(
109
  data=[
110
- Model(id=settings.GLM46_MODEL, created=current_time, owned_by="z.ai"),
111
- Model(id=settings.GLM46_THINKING_MODEL, created=current_time, owned_by="z.ai"),
112
- Model(id=settings.GLM46_SEARCH_MODEL, created=current_time, owned_by="z.ai"),
113
  Model(id=settings.GLM45_AIR_MODEL, created=current_time, owned_by="z.ai"),
114
  ]
115
  )
116
  return fallback_response
117
 
118
 
119
- @router.post("/v1/chat/completions")
120
  @router.post("/hf/v1/chat/completions")
121
- @router.post("/api/v1/chat/completions")
122
  async def chat_completions(request: OpenAIRequest, authorization: str = Header(...)):
123
  """Handle chat completion requests with multi-provider architecture"""
124
  role = request.messages[0].role if request.messages else "unknown"
 
92
  return JSONResponse(content=response_data.model_dump(exclude_none=True))
93
 
94
 
 
95
  @router.get("/hf/v1/models")
96
+ @router.get("/v1/models")
97
  async def list_models():
98
  """List available models from all providers"""
99
  try:
 
106
  current_time = int(time.time())
107
  fallback_response = ModelsResponse(
108
  data=[
109
+ Model(id=settings.GLM47_MODEL, created=current_time, owned_by="z.ai"),
110
+ Model(id=settings.GLM47_THINKING_MODEL, created=current_time, owned_by="z.ai"),
111
+ Model(id=settings.GLM47_SEARCH_MODEL, created=current_time, owned_by="z.ai"),
112
  Model(id=settings.GLM45_AIR_MODEL, created=current_time, owned_by="z.ai"),
113
  ]
114
  )
115
  return fallback_response
116
 
117
 
 
118
  @router.post("/hf/v1/chat/completions")
119
+ @router.post("/v1/chat/completions")
120
  async def chat_completions(request: OpenAIRequest, authorization: str = Header(...)):
121
  """Handle chat completion requests with multi-provider architecture"""
122
  role = request.messages[0].role if request.messages else "unknown"
app/models/__pycache__/__init__.cpython-311.pyc ADDED
Binary file (239 Bytes). View file
 
app/models/__pycache__/schemas.cpython-311.pyc ADDED
Binary file (8.32 kB). View file
 
app/providers/__pycache__/__init__.cpython-311.pyc ADDED
Binary file (917 Bytes). View file
 
app/providers/__pycache__/base.cpython-311.pyc ADDED
Binary file (12.3 kB). View file
 
app/providers/__pycache__/k2think_provider.cpython-311.pyc ADDED
Binary file (26.1 kB). View file
 
app/providers/__pycache__/longcat_provider.cpython-311.pyc ADDED
Binary file (22.2 kB). View file
 
app/providers/__pycache__/provider_factory.cpython-311.pyc ADDED
Binary file (9.81 kB). View file
 
app/providers/__pycache__/zai_provider.cpython-311.pyc ADDED
Binary file (51.6 kB). View file
 
app/providers/zai_provider.py CHANGED
@@ -20,6 +20,7 @@ import random
20
  from datetime import datetime
21
  from typing import Dict, List, Any, Optional, AsyncGenerator, Union
22
  from app.utils.user_agent import get_random_user_agent
 
23
  from app.utils.signature import generate_signature
24
  from app.providers.base import BaseProvider, ProviderConfig
25
  from app.models.schemas import OpenAIRequest, Message
@@ -42,6 +43,7 @@ def get_zai_dynamic_headers(chat_id: str = "") -> Dict[str, str]:
42
  browser_choices = ["chrome", "chrome", "chrome", "edge", "edge", "firefox", "safari"]
43
  browser_type = random.choice(browser_choices)
44
  user_agent = get_random_user_agent(browser_type)
 
45
 
46
  chrome_version = "139"
47
  edge_version = "139"
@@ -70,7 +72,7 @@ def get_zai_dynamic_headers(chat_id: str = "") -> Dict[str, str]:
70
  "Cache-Control": "no-cache",
71
  "User-Agent": user_agent,
72
  "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8",
73
- "X-FE-Version": "prod-fe-1.0.106",
74
  "Origin": "https://chat.z.ai",
75
  }
76
 
@@ -141,11 +143,11 @@ class ZAIProvider(BaseProvider):
141
  settings.GLM45_THINKING_MODEL: "0727-360B-API", # GLM-4.5-Thinking
142
  settings.GLM45_SEARCH_MODEL: "0727-360B-API", # GLM-4.5-Search
143
  settings.GLM45_AIR_MODEL: "0727-106B-API", # GLM-4.5-Air
144
- settings.GLM45V_MODEL: "glm-4.5v", # GLM-4.5V多模态
145
- settings.GLM46_MODEL: "GLM-4-6-API-V1", # GLM-4.6
146
- settings.GLM46_THINKING_MODEL: "GLM-4-6-API-V1", # GLM-4.6-Thinking
147
- settings.GLM46_SEARCH_MODEL: "GLM-4-6-API-V1", # GLM-4.6-Search
148
- settings.GLM46_ADVANCED_SEARCH_MODEL: "GLM-4-6-API-V1", # GLM-4.6-advanced-search
149
  }
150
 
151
  def get_supported_models(self) -> List[str]:
@@ -155,11 +157,11 @@ class ZAIProvider(BaseProvider):
155
  settings.GLM45_THINKING_MODEL,
156
  settings.GLM45_SEARCH_MODEL,
157
  settings.GLM45_AIR_MODEL,
158
- settings.GLM45V_MODEL,
159
- settings.GLM46_MODEL,
160
- settings.GLM46_THINKING_MODEL,
161
- settings.GLM46_SEARCH_MODEL,
162
- settings.GLM46_ADVANCED_SEARCH_MODEL,
163
  ]
164
 
165
  def _get_proxy_config(self) -> Optional[str]:
@@ -528,7 +530,7 @@ class ZAIProvider(BaseProvider):
528
  requested_model = request.model
529
  is_thinking = "-thinking" in requested_model.casefold()
530
  is_search = "-search" in requested_model.casefold()
531
- is_advanced_search = requested_model == settings.GLM46_ADVANCED_SEARCH_MODEL
532
  is_air = "-air" in requested_model.casefold()
533
 
534
  # 获取上游模型ID
@@ -636,6 +638,7 @@ class ZAIProvider(BaseProvider):
636
  user_id = _extract_user_id_from_token(token)
637
  timestamp_ms = int(time.time() * 1000)
638
  request_id = generate_uuid()
 
639
  try:
640
  signing_metadata = f"requestId,{request_id},timestamp,{timestamp_ms},user_id,{user_id}"
641
  prompt_for_signature = last_user_text or ""
@@ -650,11 +653,11 @@ class ZAIProvider(BaseProvider):
650
  logger.error(f"[Z.AI] 签名生成失败: {e}")
651
  signature = ""
652
 
653
- # 构建请求头 (匹配 X-FE-Version 和 X-Signature)
654
  headers = {
655
  "Authorization": f"Bearer {token}",
656
  "Content-Type": "application/json",
657
- "X-FE-Version": "prod-fe-1.0.106",
658
  "X-Signature": signature,
659
  }
660
 
 
20
  from datetime import datetime
21
  from typing import Dict, List, Any, Optional, AsyncGenerator, Union
22
  from app.utils.user_agent import get_random_user_agent
23
+ from app.utils.fe_version import get_latest_fe_version
24
  from app.utils.signature import generate_signature
25
  from app.providers.base import BaseProvider, ProviderConfig
26
  from app.models.schemas import OpenAIRequest, Message
 
43
  browser_choices = ["chrome", "chrome", "chrome", "edge", "edge", "firefox", "safari"]
44
  browser_type = random.choice(browser_choices)
45
  user_agent = get_random_user_agent(browser_type)
46
+ fe_version = get_latest_fe_version()
47
 
48
  chrome_version = "139"
49
  edge_version = "139"
 
72
  "Cache-Control": "no-cache",
73
  "User-Agent": user_agent,
74
  "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8",
75
+ "X-FE-Version": fe_version,
76
  "Origin": "https://chat.z.ai",
77
  }
78
 
 
143
  settings.GLM45_THINKING_MODEL: "0727-360B-API", # GLM-4.5-Thinking
144
  settings.GLM45_SEARCH_MODEL: "0727-360B-API", # GLM-4.5-Search
145
  settings.GLM45_AIR_MODEL: "0727-106B-API", # GLM-4.5-Air
146
+ settings.GLM46V_MODEL: "glm-4.6v", # GLM-4.6V多模态
147
+ settings.GLM47_MODEL: "glm-4.7", # GLM-4.7
148
+ settings.GLM47_THINKING_MODEL: "glm-4.7", # GLM-4.7-Thinking
149
+ settings.GLM47_SEARCH_MODEL: "glm-4.7", # GLM-4.7-Search
150
+ settings.GLM47_ADVANCED_SEARCH_MODEL: "glm-4.7", # GLM-4.7-advanced-search
151
  }
152
 
153
  def get_supported_models(self) -> List[str]:
 
157
  settings.GLM45_THINKING_MODEL,
158
  settings.GLM45_SEARCH_MODEL,
159
  settings.GLM45_AIR_MODEL,
160
+ settings.GLM46V_MODEL,
161
+ settings.GLM47_MODEL,
162
+ settings.GLM47_THINKING_MODEL,
163
+ settings.GLM47_SEARCH_MODEL,
164
+ settings.GLM47_ADVANCED_SEARCH_MODEL,
165
  ]
166
 
167
  def _get_proxy_config(self) -> Optional[str]:
 
530
  requested_model = request.model
531
  is_thinking = "-thinking" in requested_model.casefold()
532
  is_search = "-search" in requested_model.casefold()
533
+ is_advanced_search = requested_model == settings.GLM47_ADVANCED_SEARCH_MODEL
534
  is_air = "-air" in requested_model.casefold()
535
 
536
  # 获取上游模型ID
 
638
  user_id = _extract_user_id_from_token(token)
639
  timestamp_ms = int(time.time() * 1000)
640
  request_id = generate_uuid()
641
+ fe_version = get_latest_fe_version()
642
  try:
643
  signing_metadata = f"requestId,{request_id},timestamp,{timestamp_ms},user_id,{user_id}"
644
  prompt_for_signature = last_user_text or ""
 
653
  logger.error(f"[Z.AI] 签名生成失败: {e}")
654
  signature = ""
655
 
656
+ # 构建请求头
657
  headers = {
658
  "Authorization": f"Bearer {token}",
659
  "Content-Type": "application/json",
660
+ "X-FE-Version": fe_version,
661
  "X-Signature": signature,
662
  }
663
 
app/templates/config.html CHANGED
@@ -43,7 +43,7 @@
43
  <label class="block text-sm font-medium text-gray-700">监听端口</label>
44
  <input type="number"
45
  name="listen_port"
46
- value="{{ config.LISTEN_PORT or 8000 }}"
47
  class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm">
48
  <p class="mt-1 text-sm text-gray-500">服务监听的端口号</p>
49
  </div>
 
43
  <label class="block text-sm font-medium text-gray-700">监听端口</label>
44
  <input type="number"
45
  name="listen_port"
46
+ value="{{ config.LISTEN_PORT or 7860 }}"
47
  class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm">
48
  <p class="mt-1 text-sm text-gray-500">服务监听的端口号</p>
49
  </div>
app/utils/__pycache__/__init__.cpython-311.pyc ADDED
Binary file (276 Bytes). View file
 
app/utils/__pycache__/fe_version.cpython-311.pyc ADDED
Binary file (4.65 kB). View file
 
app/utils/__pycache__/logger.cpython-311.pyc ADDED
Binary file (4.28 kB). View file
 
app/utils/__pycache__/reload_config.cpython-311.pyc ADDED
Binary file (1.13 kB). View file
 
app/utils/__pycache__/signature.cpython-311.pyc ADDED
Binary file (1.93 kB). View file
 
app/utils/__pycache__/token_pool.cpython-311.pyc ADDED
Binary file (30.3 kB). View file
 
app/utils/__pycache__/tool_call_handler.cpython-311.pyc ADDED
Binary file (13.7 kB). View file
 
app/utils/__pycache__/user_agent.cpython-311.pyc ADDED
Binary file (4.04 kB). View file
 
app/utils/fe_version.py ADDED
@@ -0,0 +1,112 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python
2
+ # -*- coding: utf-8 -*-
3
+
4
+ """
5
+ Utility helpers for resolving the latest X-FE-Version value from chat.z.ai.
6
+
7
+ The upstream service embeds the current front-end release identifier inside
8
+ its landing page static asset URLs (e.g. `prod-fe-1.0.107`). The helpers in
9
+ this module fetch the landing page, extract the version string, and cache it
10
+ with a configurable TTL so the expensive network fetch only happens when
11
+ necessary.
12
+ """
13
+
14
+ from __future__ import annotations
15
+
16
+ import re
17
+ import time
18
+ from typing import Optional
19
+
20
+ import httpx
21
+
22
+ from app.utils.logger import get_logger
23
+ from app.utils.user_agent import get_random_user_agent
24
+
25
+ # Base URL to probe for the version string.
26
+ FE_VERSION_SOURCE_URL = "https://chat.z.ai"
27
+
28
+ # Cache TTL in seconds (default: 30 minutes).
29
+ CACHE_TTL_SECONDS = 1800
30
+
31
+ _logger = get_logger()
32
+ _version_pattern = re.compile(r"prod-fe-\d+\.\d+\.\d+")
33
+
34
+ _cached_version: str = ""
35
+ _cached_at: float = 0.0
36
+
37
+
38
+ def _extract_version(page_content: str) -> Optional[str]:
39
+ """Extract the version string from the page content."""
40
+ if not page_content:
41
+ return None
42
+
43
+ matches = _version_pattern.findall(page_content)
44
+ if not matches:
45
+ return None
46
+
47
+ # Choose the highest lexical value to guard against mixed versions.
48
+ return max(matches)
49
+
50
+
51
+
52
+
53
+ def _should_use_cache(force_refresh: bool) -> bool:
54
+ """Determine whether the cached value can be reused."""
55
+ if force_refresh:
56
+ return False
57
+ if not _cached_version:
58
+ return False
59
+ if _cached_at <= 0:
60
+ return False
61
+ return (time.time() - _cached_at) < CACHE_TTL_SECONDS
62
+
63
+
64
+ def get_latest_fe_version(force_refresh: bool = False) -> str:
65
+ """
66
+ Resolve the latest X-FE-Version value from chat.z.ai.
67
+
68
+ The lookup order is:
69
+ 1. Cached value within TTL.
70
+ 2. Remote fetch from chat.z.ai.
71
+
72
+ Raises:
73
+ Exception: If unable to fetch the version from the remote source.
74
+ """
75
+ global _cached_version, _cached_at
76
+
77
+ if _should_use_cache(force_refresh):
78
+ return _cached_version
79
+
80
+ try:
81
+ headers = {"User-Agent": get_random_user_agent("chrome")}
82
+ except Exception:
83
+ headers = {
84
+ "User-Agent": (
85
+ "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
86
+ "AppleWebKit/537.36 (KHTML, like Gecko) "
87
+ "Chrome/120.0.0.0 Safari/537.36"
88
+ )
89
+ }
90
+
91
+ try:
92
+ with httpx.Client(timeout=10.0, follow_redirects=True) as client:
93
+ response = client.get(FE_VERSION_SOURCE_URL, headers=headers)
94
+ response.raise_for_status()
95
+ version = _extract_version(response.text)
96
+ if version:
97
+ if version != _cached_version:
98
+ _logger.info(f"[Z.AI] Detected X-FE-Version update: {version}")
99
+ _cached_version = version
100
+ _cached_at = time.time()
101
+ return version
102
+
103
+ _logger.error("[Z.AI] Unable to locate X-FE-Version in landing page")
104
+ raise Exception("Unable to locate X-FE-Version in landing page")
105
+ except Exception as exc:
106
+ _logger.error(f"[Z.AI] Failed to fetch X-FE-Version from {FE_VERSION_SOURCE_URL}: {exc}")
107
+ raise Exception(f"Failed to fetch X-FE-Version: {exc}")
108
+
109
+
110
+ def refresh_fe_version() -> str:
111
+ """Force refresh the cached version by bypassing the TTL."""
112
+ return get_latest_fe_version(force_refresh=True)
app/utils/logger.py CHANGED
@@ -56,7 +56,6 @@ def setup_logger(log_dir, log_retention_days=7, log_rotation="1 day", debug_mode
56
  enqueue=True,
57
  catch=True,
58
  )
59
- logger.info(f"✅ 日志文件输出已启用: {log_dir}")
60
  except (PermissionError, OSError) as e:
61
  # 如果无法创建日志目录或文件,降级为仅控制台输出
62
  logger.warning(f"⚠️ 无法创建日志文件 ({e}),将仅使用控制台输出")
 
56
  enqueue=True,
57
  catch=True,
58
  )
 
59
  except (PermissionError, OSError) as e:
60
  # 如果无法创建日志目录或文件,降级为仅控制台输出
61
  logger.warning(f"⚠️ 无法创建日志文件 ({e}),将仅使用控制台输出")
docker-compose.yml CHANGED
@@ -1,8 +1,8 @@
1
  services:
2
  api-server:
3
  build:
4
- context: ..
5
- dockerfile: deploy/Dockerfile
6
  container_name: z-ai-api-server
7
  ports:
8
  - "7860:7860"
@@ -29,7 +29,7 @@ services:
29
  - DB_PATH=/app/data/tokens.db
30
  restart: unless-stopped
31
  healthcheck:
32
- test: ["CMD", "curl", "-f", "http://localhost:7860/v1/models"]
33
  interval: 30s
34
  timeout: 10s
35
  retries: 3
 
1
  services:
2
  api-server:
3
  build:
4
+ context: .
5
+ dockerfile: Dockerfile
6
  container_name: z-ai-api-server
7
  ports:
8
  - "7860:7860"
 
29
  - DB_PATH=/app/data/tokens.db
30
  restart: unless-stopped
31
  healthcheck:
32
+ test: ["CMD", "curl", "-f", "http://localhost:7860/hf/v1/models"]
33
  interval: 30s
34
  timeout: 10s
35
  retries: 3
nginx.conf DELETED
@@ -1,157 +0,0 @@
1
- # Nginx reverse proxy configuration example for Z.AI2API
2
- # This example shows how to deploy the service behind Nginx with a custom path prefix
3
-
4
- # Example 1: Deploy at http://your-domain.com/ai2api
5
- server {
6
- listen 80;
7
- server_name your-domain.com;
8
-
9
- # Forward requests with /ai2api prefix to the backend service
10
- location /ai2api {
11
- # Remove trailing slash redirect (optional, but recommended)
12
- rewrite ^(/ai2api)$ $1/ permanent;
13
-
14
- # Proxy to the backend service
15
- proxy_pass http://127.0.0.1:7860;
16
-
17
- # Pass original host and IP information
18
- proxy_set_header Host $host;
19
- proxy_set_header X-Real-IP $remote_addr;
20
- proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
21
- proxy_set_header X-Forwarded-Proto $scheme;
22
-
23
- # IMPORTANT: Tell the backend about the path prefix
24
- # This ensures all generated URLs include the prefix
25
- proxy_set_header X-Forwarded-Prefix /ai2api;
26
-
27
- # WebSocket and SSE support (for streaming responses)
28
- proxy_http_version 1.1;
29
- proxy_set_header Upgrade $http_upgrade;
30
- proxy_set_header Connection "upgrade";
31
-
32
- # Disable buffering for streaming responses
33
- proxy_buffering off;
34
- proxy_cache off;
35
-
36
- # Timeout settings (adjust as needed)
37
- proxy_connect_timeout 60s;
38
- proxy_send_timeout 300s;
39
- proxy_read_timeout 300s;
40
- }
41
- }
42
-
43
- # Example 2: Deploy at http://your-domain.com/api/chat
44
- server {
45
- listen 80;
46
- server_name example.com;
47
-
48
- location /api/chat {
49
- # Proxy configuration
50
- proxy_pass http://127.0.0.1:7860;
51
-
52
- # Headers
53
- proxy_set_header Host $host;
54
- proxy_set_header X-Real-IP $remote_addr;
55
- proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
56
- proxy_set_header X-Forwarded-Proto $scheme;
57
- proxy_set_header X-Forwarded-Prefix /api/chat;
58
-
59
- # SSE/WebSocket support
60
- proxy_http_version 1.1;
61
- proxy_set_header Upgrade $http_upgrade;
62
- proxy_set_header Connection "upgrade";
63
- proxy_buffering off;
64
- proxy_cache off;
65
- }
66
- }
67
-
68
- # Example 3: Deploy with SSL (HTTPS)
69
- server {
70
- listen 443 ssl http2;
71
- server_name secure.example.com;
72
-
73
- # SSL configuration
74
- ssl_certificate /path/to/cert.pem;
75
- ssl_certificate_key /path/to/key.pem;
76
-
77
- location /ai2api {
78
- proxy_pass http://127.0.0.1:7860;
79
-
80
- proxy_set_header Host $host;
81
- proxy_set_header X-Real-IP $remote_addr;
82
- proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
83
- proxy_set_header X-Forwarded-Proto https;
84
- proxy_set_header X-Forwarded-Prefix /ai2api;
85
-
86
- # SSE/WebSocket support
87
- proxy_http_version 1.1;
88
- proxy_set_header Upgrade $http_upgrade;
89
- proxy_set_header Connection "upgrade";
90
- proxy_buffering off;
91
- proxy_cache off;
92
-
93
- # Security headers (optional)
94
- add_header X-Content-Type-Options nosniff;
95
- add_header X-Frame-Options DENY;
96
- add_header X-XSS-Protection "1; mode=block";
97
- }
98
- }
99
-
100
- # Example 4: Load balancing with multiple backend instances
101
- upstream ai2api_backend {
102
- # Round-robin by default
103
- server 127.0.0.1:7860;
104
- server 127.0.0.1:8081;
105
- server 127.0.0.1:8082;
106
-
107
- # Or use least connections
108
- # least_conn;
109
-
110
- # Or use IP hash for session persistence
111
- # ip_hash;
112
- }
113
-
114
- server {
115
- listen 80;
116
- server_name loadbalanced.example.com;
117
-
118
- location /ai2api {
119
- proxy_pass http://ai2api_backend;
120
-
121
- proxy_set_header Host $host;
122
- proxy_set_header X-Real-IP $remote_addr;
123
- proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
124
- proxy_set_header X-Forwarded-Proto $scheme;
125
- proxy_set_header X-Forwarded-Prefix /ai2api;
126
-
127
- proxy_http_version 1.1;
128
- proxy_set_header Upgrade $http_upgrade;
129
- proxy_set_header Connection "upgrade";
130
- proxy_buffering off;
131
- proxy_cache off;
132
- }
133
- }
134
-
135
- # Important Notes:
136
- #
137
- # 1. Set ROOT_PATH in your .env file to match the Nginx location path:
138
- # ROOT_PATH=/ai2api
139
- #
140
- # 2. Restart both Nginx and the application after configuration changes:
141
- # sudo systemctl reload nginx
142
- # docker-compose restart (or restart your application)
143
- #
144
- # 3. Access URLs will include the prefix:
145
- # - Admin panel: http://your-domain.com/ai2api/admin/login
146
- # - API endpoint: http://your-domain.com/ai2api/v1/chat/completions
147
- # - Health check: http://your-domain.com/ai2api/v1/models
148
- #
149
- # 4. For Docker deployments, make sure to:
150
- # - Add ROOT_PATH to docker-compose.yml environment variables
151
- # - Expose the container port (7860 by default)
152
- #
153
- # 5. Common issues:
154
- # - 404 errors: Check that ROOT_PATH matches the Nginx location path exactly
155
- # - CORS errors: Verify proxy headers are set correctly
156
- # - Streaming not working: Ensure proxy_buffering is off
157
- # - Admin panel CSS/JS not loading: Confirm static files are served with the prefix
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
nginx.conf.example CHANGED
@@ -12,7 +12,7 @@ server {
12
  rewrite ^(/ai2api)$ $1/ permanent;
13
 
14
  # Proxy to the backend service
15
- proxy_pass http://127.0.0.1:7860;
16
 
17
  # Pass original host and IP information
18
  proxy_set_header Host $host;
@@ -47,7 +47,7 @@ server {
47
 
48
  location /api/chat {
49
  # Proxy configuration
50
- proxy_pass http://127.0.0.1:7860;
51
 
52
  # Headers
53
  proxy_set_header Host $host;
@@ -75,7 +75,7 @@ server {
75
  ssl_certificate_key /path/to/key.pem;
76
 
77
  location /ai2api {
78
- proxy_pass http://127.0.0.1:7860;
79
 
80
  proxy_set_header Host $host;
81
  proxy_set_header X-Real-IP $remote_addr;
@@ -100,7 +100,7 @@ server {
100
  # Example 4: Load balancing with multiple backend instances
101
  upstream ai2api_backend {
102
  # Round-robin by default
103
- server 127.0.0.1:7860;
104
  server 127.0.0.1:8081;
105
  server 127.0.0.1:8082;
106
 
@@ -143,12 +143,12 @@ server {
143
  #
144
  # 3. Access URLs will include the prefix:
145
  # - Admin panel: http://your-domain.com/ai2api/admin/login
146
- # - API endpoint: http://your-domain.com/ai2api/v1/chat/completions
147
- # - Health check: http://your-domain.com/ai2api/v1/models
148
  #
149
  # 4. For Docker deployments, make sure to:
150
  # - Add ROOT_PATH to docker-compose.yml environment variables
151
- # - Expose the container port (7860 by default)
152
  #
153
  # 5. Common issues:
154
  # - 404 errors: Check that ROOT_PATH matches the Nginx location path exactly
 
12
  rewrite ^(/ai2api)$ $1/ permanent;
13
 
14
  # Proxy to the backend service
15
+ proxy_pass http://127.0.0.1:8080;
16
 
17
  # Pass original host and IP information
18
  proxy_set_header Host $host;
 
47
 
48
  location /api/chat {
49
  # Proxy configuration
50
+ proxy_pass http://127.0.0.1:8080;
51
 
52
  # Headers
53
  proxy_set_header Host $host;
 
75
  ssl_certificate_key /path/to/key.pem;
76
 
77
  location /ai2api {
78
+ proxy_pass http://127.0.0.1:8080;
79
 
80
  proxy_set_header Host $host;
81
  proxy_set_header X-Real-IP $remote_addr;
 
100
  # Example 4: Load balancing with multiple backend instances
101
  upstream ai2api_backend {
102
  # Round-robin by default
103
+ server 127.0.0.1:8080;
104
  server 127.0.0.1:8081;
105
  server 127.0.0.1:8082;
106
 
 
143
  #
144
  # 3. Access URLs will include the prefix:
145
  # - Admin panel: http://your-domain.com/ai2api/admin/login
146
+ # - API endpoint: http://your-domain.com/ai2api/hf/v1/chat/completions
147
+ # - Health check: http://your-domain.com/ai2api/hf/v1/models
148
  #
149
  # 4. For Docker deployments, make sure to:
150
  # - Add ROOT_PATH to docker-compose.yml environment variables
151
+ # - Expose the container port (8080 by default)
152
  #
153
  # 5. Common issues:
154
  # - 404 errors: Check that ROOT_PATH matches the Nginx location path exactly
xREADME.md DELETED
@@ -1,347 +0,0 @@
1
- # OpenAI 代理服务
2
-
3
- ![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)
4
- ![Python: 3.9-3.12](https://img.shields.io/badge/python-3.9--3.12-green.svg)
5
- ![FastAPI](https://img.shields.io/badge/framework-FastAPI-009688.svg)
6
-
7
- 基于 FastAPI 的高性能 OpenAI API 兼容代理服务,采用多提供商架构设计,支持 Z.AI(GLM-4.5/4.6 系列)、K2Think、LongCat 等多种 AI 模型。
8
-
9
- ## ✨ 核心特性
10
-
11
- - 🔌 **OpenAI API 兼容** - 无缝对接现有 OpenAI 客户端
12
- - 🏗️ **多提供商架构** - 统一接口支持 Z.AI、K2Think、LongCat
13
- - 🧬 **数据库管理** - SQLite + Web 后台统一管理 Token
14
- - 🚀 **流式响应** - 高性能 SSE 实时流式输出
15
- - 🧠 **思考模式** - 支持 Thinking 模型的推理过程展示
16
- - 🐳 **容器化部署** - Docker/Docker Compose 一键部署
17
- - 🔄 **Token 池** - 智能轮询、容错恢复、健康检查
18
- - 📊 **管理后台** - 实时监控、配置管理
19
- - 🔐 **安全认证** - 密码保护的管理后台访问
20
-
21
- ❤️ 感谢各位的反馈推动项目改进!
22
-
23
- ## 🚀 快速开始
24
-
25
- ### 环境要求
26
-
27
- - Python 3.9-3.12
28
- - pip 或 uv (推荐)
29
-
30
- ### 本地运行
31
-
32
- ```bash
33
- # 1. 克隆项目
34
- git clone https://github.com/ZyphrZero/z.ai2api_python.git
35
- cd z.ai2api_python
36
-
37
- # 2. 安装依赖(使用 uv 推荐)
38
- curl -LsSf https://astral.sh/uv/install.sh | sh
39
- uv sync
40
-
41
- # 或使用 pip
42
- pip install -r requirements.txt
43
-
44
- # 3. 配置环境变量
45
- cp .env.example .env
46
- # 编辑 .env 文件,设置 AUTH_TOKEN 等配置
47
-
48
- # 4. 启动服务
49
- uv run python main.py # 或 python main.py
50
- ```
51
-
52
- **首次运行会自动初始化数据库**,访问以下地址:
53
- - API 文档:http://localhost:7860/docs
54
- - 管理后台:http://localhost:7860/admin(**需要登录**)
55
- - Token 管理:http://localhost:7860/admin/tokens
56
-
57
- > ⚠️ **重要**:
58
- > - 请妥善保管 `AUTH_TOKEN`,不要泄露给他人
59
- > - 管理后台默认密码为 `admin123`,**首次使用后请立即修改**
60
-
61
- ### Docker 部署
62
-
63
- 从 Docker Hub 拉取镜像:
64
-
65
- ```bash
66
- # 拉取最新镜像
67
- docker pull zyphrzero/z-ai2api-python:latest
68
-
69
- # 快速启动(创建数据目录)
70
- mkdir -p data logs
71
-
72
- # 运行容器
73
- docker run -d \
74
- --name z-ai-api-server \
75
- -p 7860:7860 \
76
- -e ADMIN_PASSWORD=admin123 \
77
- -e AUTH_TOKEN=sk-your-api-key \
78
- -e ANONYMOUS_MODE=true \
79
- -e DB_PATH=/app/data/tokens.db \
80
- -v $(pwd)/data:/app/data \
81
- -v $(pwd)/logs:/app/logs \
82
- --restart unless-stopped \
83
- zyphrzero/z-ai2api-python:latest
84
- ```
85
-
86
- 启动服务:
87
-
88
- ```bash
89
- docker compose up -d
90
- ```
91
-
92
- #### 方式二:本地构建
93
-
94
- ```bash
95
- # 进入部署目录
96
- cd deploy
97
-
98
- # 启动服务(会自动构建镜像)
99
- docker compose up -d
100
-
101
- # 查看日志
102
- docker compose logs -f api-server
103
- ```
104
-
105
- #### 数据持久化
106
-
107
- 容器使用卷映射自动持久化数据:
108
-
109
- ```
110
- data/ # 数据库文件存储目录
111
- ├── tokens.db # SQLite 数据库(自动创建)
112
- logs/ # 日志文件存储目录
113
- ```
114
-
115
- 数据在容器重启或重建后仍然保留,无需担心丢失。
116
-
117
- > 📖 **详细文档**:[Docker 部署指南](deploy/README_DOCKER.md)
118
-
119
- ## 📖 支持的模型
120
-
121
- ### Z.AI 提供商(GLM 系列)
122
-
123
- | 模型 | 上游 ID | 特性 |
124
- |------|---------|------|
125
- | `GLM-4.5` | 0727-360B-API | 标准模型,通用对话 |
126
- | `GLM-4.5-Thinking` | 0727-360B-API | 思考模型,显示推理过程 |
127
- | `GLM-4.5-Search` | 0727-360B-API | 搜索模型,实时联网 |
128
- | `GLM-4.5-Air` | 0727-106B-API | 轻量模型,快速响应 |
129
- | `GLM-4.5V` | glm-4.5v | 多模态模型,支持图像理解 |
130
- | `GLM-4.6` | GLM-4-6-API-V1 | 新版标准模型,200K 上下文 |
131
- | `GLM-4.6-Thinking` | GLM-4-6-API-V1 | 新版思考模型,增强推理 |
132
- | `GLM-4.6-Search` | GLM-4-6-API-V1 | 新版搜索模型,改进联网能力 |
133
- | `GLM-4.6-advanced-search` | GLM-4-6-API-V1 | 高级搜索模型,深度研究 |
134
-
135
- ### K2Think 提供商
136
-
137
- | 模型 | 特性 |
138
- |------|------|
139
- | `MBZUAI-IFM/K2-Think` | 高质量推理模型 |
140
-
141
- ### LongCat 提供商
142
-
143
- | 模型 | 特性 |
144
- |------|------|
145
- | `LongCat-Flash` | 快速响应 |
146
- | `LongCat` | 标准模型 |
147
- | `LongCat-Search` | 搜索增强 |
148
-
149
- ## ⚙️ 配置说明
150
-
151
- ### 核心环境变量
152
-
153
- | 变量名 | 默认值 | 说明 |
154
- |--------|--------|------|
155
- | `AUTH_TOKEN` | `sk-your-api-key` | 客户端访问密钥(必填) |
156
- | `ADMIN_PASSWORD` | `admin123` | 管理后台登录密码(**强烈建议修改**) |
157
- | `LISTEN_PORT` | `7860` | 服务监听端口 |
158
- | `DEBUG_LOGGING` | `false` | 调试日志(支持热重载) |
159
- | `ANONYMOUS_MODE` | `true` | Z.AI 匿名模式 |
160
- | `TOOL_SUPPORT` | `true` | Function Call 开关 |
161
- | `SKIP_AUTH_TOKEN` | `false` | 跳过认证(仅开发) |
162
- | `DB_PATH` | `tokens.db` | 数据库文件路径(Docker: `/app/data/tokens.db`) |
163
-
164
- ### Token 配置
165
-
166
- | 变量名 | 说明 |
167
- |--------|------|
168
- | `LONGCAT_TOKEN` | LongCat 认证 Token(可选) |
169
- | `TOKEN_FAILURE_THRESHOLD` | Token 失败阈值(默认 3) |
170
- | `TOKEN_RECOVERY_TIMEOUT` | Token 恢复超时(默认 1800 秒) |
171
-
172
- > 💡 详细配置请参考 [.env.example](.env.example) 或 [deploy/.env.example](deploy/.env.example)
173
-
174
- ## 🔐 管理后台登录
175
-
176
- ### 首次登录
177
-
178
- 1. 启动服务后访问:http://localhost:7860/admin
179
- 2. 自动跳转到登录页面
180
- 3. 输入管理密码(默认:`admin123`)
181
- 4. 登录成功后进入仪表盘
182
-
183
- ### 修改密码
184
-
185
- 在 `.env` 文件中修改 `ADMIN_PASSWORD`:
186
-
187
- ```bash
188
- # 使用强密码(推荐 12 位以上)
189
- ADMIN_PASSWORD=Your_Secure_Password_2025!
190
- ```
191
-
192
- 重启服务后生效。
193
-
194
- ### 安全特性
195
-
196
- - ✅ **Session 管理**:基于 Cookie 的安全 Session
197
- - ✅ **自动过期**:登录后 24 小时自动失效
198
- - ✅ **HttpOnly Cookie**:防止 XSS 攻击
199
- - ✅ **SameSite 保护**:防止 CSRF 攻击
200
- - ✅ **随机 Token**:使用加密安全的随机数生成
201
-
202
- > 💡 详细文档:[管理后台登录功能使用说明](管理后台登录功能使用说明.md)
203
-
204
- ## 🔄 Token 管理
205
-
206
- ### 数据库方式(推荐)
207
-
208
- 项目使用 SQLite 数据库统一管理 Token,首次运行会自动初始化:
209
-
210
- ```bash
211
- # 首次运行自动创建 tokens.db
212
- python main.py
213
-
214
- # 访问 Web 管理后台
215
- http://localhost:7860/admin
216
- ```
217
-
218
- ### 管理后台功能
219
-
220
- - ✅ **密码保护** - 安全的登录认证
221
- - ✅ Token 增删改查
222
- - ✅ 批量导入/导出
223
- - ✅ 启用/禁用 Token
224
- - ✅ Token 有效性检测
225
- - ✅ 多提供商支持(Z.AI/K2Think/LongCat)
226
-
227
- ### Token 池机制
228
-
229
- - **负载均衡**:轮询使用多个 Token 分散请求
230
- - **自动容错**:Token 失败时自动切换
231
- - **自动恢复**:失败 Token 超时后重试
232
- - **智能去重**:自动检测重复 Token
233
- - **回退机制**:认证失败自动降级匿名模式
234
-
235
- ## ❓ 常见问题
236
-
237
- ### Q: 如何获取 AUTH_TOKEN?
238
- A: `AUTH_TOKEN` 是自定义的 API 密钥,用于客户端访问本服务,需在 `.env` 文件或 `docker-compose.yml` 中配置,确保客户端与服务端一致。
239
-
240
- ### Q: 匿名模式是什么?
241
- A: 匿名模式使用临时 Token 访问 Z.AI,避免对话历史共享,保护隐私。设置 `ANONYMOUS_MODE=true` 启用。
242
-
243
- ### Q: 如何管理 Token?
244
- A: 访问 Web 管理后台 http://localhost:7860/admin/tokens(需要先登录)即可增删改查 Token,支持批量导入导出。
245
-
246
- ### Q: 忘记管理后台密码怎么办?
247
- A: 在 `.env` 文件或 `docker-compose.yml` 中修改 `ADMIN_PASSWORD` 为新密码,然后重启服务即可。
248
-
249
- ### Q: Docker 部署时数据库初始化失败?
250
- A: 错误提示 `unable to open database file` 通常是权限问题。解决方案:
251
- ```bash
252
- cd deploy
253
- mkdir -p ./data ./logs
254
- chmod 755 ./data ./logs
255
- docker compose down && docker compose up -d --build
256
- ```
257
- 详见 [Docker 部署指南](deploy/README_DOCKER.md#故障排查)
258
-
259
- ### Q: 如何禁用管理后台登录?
260
- A: 当前版本暂不支持禁用登录功能。如有需要,请手动移除路由中的 `dependencies=[Depends(require_auth)]`。
261
-
262
-
263
- ## 🔑 获取 Token
264
-
265
- ### Z.AI Token
266
-
267
- 1. 访问 [Z.AI 官网](https://chat.z.ai) 并登录
268
- 2. 按 F12 打开开发者工具
269
- 3. 进入 Application → Local Storage → Cookies
270
- 4. 复制 `token` 值
271
-
272
- > ⚠️ 多模态功能需要非匿名 Token
273
-
274
- ### LongCat Token
275
-
276
- 1. 访问 [LongCat 官网](https://longcat.chat/) 并登录美团账号
277
- 2. 按 F12 打开开发者工具
278
- 3. 进入 "Application" -> "Local Storage" -> "Cookie"列表中找到名为`passport_token_key`的值
279
- 4. 复制 `passport_token_key` 值
280
-
281
- ## 🛠️ 技术栈
282
-
283
- | 组件 | 技术 | 版本 | 说明 |
284
- |------|------|------|------|
285
- | Web 框架 | [FastAPI](https://fastapi.tiangolo.com/) | 0.116.1 | 高性能异步框架 |
286
- | ASGI 服务器 | [Granian](https://github.com/emmett-framework/granian) | 2.5.2 | Rust 高性能服务器 |
287
- | HTTP 客户端 | [HTTPX](https://www.python-httpx.org/) | 0.28.1 | 异步 HTTP 客户端 |
288
- | 数据验证 | [Pydantic](https://pydantic.dev/) | 2.11.7 | 类型安全验证 |
289
- | 数据库 | SQLite (aiosqlite) | 0.20.0 | Token 存储 |
290
- | 模板引擎 | Jinja2 | 3.1.4 | Web 后台模板 |
291
- | 日志系统 | [Loguru](https://loguru.readthedocs.io/) | 0.7.3 | 结构化日志 |
292
-
293
- ## 🏗️ 系统架构
294
-
295
- ```
296
- ┌─────────────┐ ┌────────────────────────────────┐ ┌──────────────┐
297
- │ OpenAI │ │ FastAPI Server │ │ Z.AI API │
298
- │ Client │─────▶│ │─────▶│ (GLM-4.x) │
299
- └─────────────┘ │ ┌──────────────────────────┐ │ └──────────────┘
300
- │ │ Provider Router │ │
301
- │ │ ┌────────┬────────────┐ │ �� ┌──────────────┐
302
- │ │ │ Z.AI │ K2Think │ │ │ │ K2Think API │
303
- │ │ │Provider│ Provider │ │ │─────▶│ │
304
- │ │ └────────┴────────────┘ │ │ └──────────────┘
305
- │ │ ┌────────────┐ │ │
306
- │ │ │ LongCat │ │ │ ┌──────────────┐
307
- │ │ │ Provider │ │ │ │ LongCat API │
308
- │ │ └────────────┘ │ │─────▶│ │
309
- │ └──────────────────────────┘ │ └──────────────┘
310
- │ │
311
- │ ┌──────────────────────────┐ │
312
- │ │ Web Admin Dashboard │ │
313
- │ │ (Token/Stats/Monitor) │ │
314
- │ └──────────────────────────┘ │
315
- └────────────────────────────────┘
316
-
317
- ┌─────────┐
318
- │SQLite DB│
319
- │(tokens) │
320
- └─────────┘
321
- ```
322
-
323
- ## 🤝 贡献指南
324
-
325
- 欢迎提交 Issue 和 Pull Request!请确保代码符合 PEP 8 规范。
326
-
327
- ## ⭐ Star History
328
-
329
- [![Star History Chart](https://api.star-history.com/svg?repos=ZyphrZero/z.ai2api_python&type=Date)](https://star-history.com/#ZyphrZero/z.ai2api_python&Date)
330
-
331
- ## 📄 许可证
332
-
333
- 本项目采用 MIT 许可证 - 详见 [LICENSE](LICENSE) 文件。
334
-
335
- ## ⚠️ 免责声明
336
-
337
- - 本项目与 Z.AI、K2Think、LongCat 等 AI 提供商官方无关
338
- - 使用前请确保遵守各提供商的服务条款
339
- - 请勿用于商业用途或违反使用条款的场景
340
- - 项目仅供学习和研究使用
341
- - 用户需自行承担使用风险
342
-
343
- ---
344
-
345
- <div align="center">
346
- Made with ❤️ by the community
347
- </div>