deepseek-proxy 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- deepseek_proxy-0.1.0/PKG-INFO +409 -0
- deepseek_proxy-0.1.0/README.md +393 -0
- deepseek_proxy-0.1.0/deepseek_proxy/__init__.py +381 -0
- deepseek_proxy-0.1.0/deepseek_proxy/__main__.py +2 -0
- deepseek_proxy-0.1.0/deepseek_proxy.egg-info/PKG-INFO +409 -0
- deepseek_proxy-0.1.0/deepseek_proxy.egg-info/SOURCES.txt +10 -0
- deepseek_proxy-0.1.0/deepseek_proxy.egg-info/dependency_links.txt +1 -0
- deepseek_proxy-0.1.0/deepseek_proxy.egg-info/entry_points.txt +2 -0
- deepseek_proxy-0.1.0/deepseek_proxy.egg-info/requires.txt +4 -0
- deepseek_proxy-0.1.0/deepseek_proxy.egg-info/top_level.txt +1 -0
- deepseek_proxy-0.1.0/pyproject.toml +31 -0
- deepseek_proxy-0.1.0/setup.cfg +4 -0
|
@@ -0,0 +1,409 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: deepseek-proxy
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Translate OpenAI Responses API ↔ DeepSeek Chat Completions API for codex
|
|
5
|
+
Author: peinibiancheng
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/peinibiancheng/deepseek-proxy
|
|
8
|
+
Project-URL: Source, https://github.com/peinibiancheng/deepseek-proxy
|
|
9
|
+
Keywords: deepseek,claude-code,codex,proxy,responses-api
|
|
10
|
+
Requires-Python: >=3.8
|
|
11
|
+
Description-Content-Type: text/markdown
|
|
12
|
+
Requires-Dist: flask>=3.0
|
|
13
|
+
Requires-Dist: requests>=2.31
|
|
14
|
+
Requires-Dist: uvicorn>=0.27
|
|
15
|
+
Requires-Dist: asgiref>=3.7
|
|
16
|
+
|
|
17
|
+
<p align="center">
|
|
18
|
+
<a href="#english">English</a> | <a href="#chinese">中文</a>
|
|
19
|
+
</p>
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
<h1 align="center">DeepSeek Proxy</h1>
|
|
24
|
+
|
|
25
|
+
<p align="center">
|
|
26
|
+
A lightweight proxy that translates <strong>OpenAI Responses API</strong> requests into <strong>DeepSeek Chat Completions API</strong> calls.
|
|
27
|
+
<br/>
|
|
28
|
+
Designed for use with <a href="https://claude.ai/code">Claude Code</a> as a backend model provider.
|
|
29
|
+
</p>
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
<a name="english"></a>
|
|
34
|
+
|
|
35
|
+
# English
|
|
36
|
+
|
|
37
|
+
## Motivation
|
|
38
|
+
|
|
39
|
+
**codex** (Claude Code CLI) uses the OpenAI **Responses API** (`/v1/responses`) natively, with SSE streaming and a specific event lifecycle. DeepSeek only provides a standard **Chat Completions API** (`/v1/chat/completions`). These two protocols are incompatible — you cannot simply point codex at a DeepSeek endpoint and expect it to work.
|
|
40
|
+
|
|
41
|
+
This proxy solves that problem by translating between the two protocols in real time, allowing codex to use DeepSeek as its backend model.
|
|
42
|
+
|
|
43
|
+
## Overview
|
|
44
|
+
|
|
45
|
+
DeepSeek Proxy is a single-file Flask application that sits between codex and the DeepSeek API. It accepts requests in the Responses API streaming format, translates them into DeepSeek's chat completions format, and converts the streaming SSE output back into the Responses API event protocol.
|
|
46
|
+
|
|
47
|
+
## Architecture
|
|
48
|
+
|
|
49
|
+
```
|
|
50
|
+
┌─────────────┐ Responses API SSE ┌────────────────┐ DeepSeek Chat API ┌────────────┐
|
|
51
|
+
│ codex │ ───────────────────────→ │ ds_proxy.py │ ──────────────────────→ │ DeepSeek │
|
|
52
|
+
│ (CLI Client)│ ←─────────────────────── │ (Flask Proxy) │ ←────────────────────── │ API │
|
|
53
|
+
└─────────────┘ SSE Events (7 types) └────────────────┘ SSE stream chunks └────────────┘
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### Components
|
|
57
|
+
|
|
58
|
+
| Layer | Technology | Role |
|
|
59
|
+
|---|---|---|
|
|
60
|
+
| **Server** | Flask + uvicorn (ASGI) | HTTP server, SSE streaming |
|
|
61
|
+
| **Adapter** | `asgiref.wsgi.WsgiToAsgi` | WSGI → ASGI wrapper for uvicorn |
|
|
62
|
+
| **Translator** | Custom logic in `ds_proxy.py` | Responses API ↔ Chat API conversion |
|
|
63
|
+
| **Client** | `requests` (streaming) | HTTP client to DeepSeek API |
|
|
64
|
+
|
|
65
|
+
### Endpoints
|
|
66
|
+
|
|
67
|
+
| Route | Method | Purpose |
|
|
68
|
+
|---|---|---|
|
|
69
|
+
| `/v1/responses` | POST | Accept Responses API request, return SSE stream |
|
|
70
|
+
| `/v1/models` | GET | List available model (`deepseek-v4-flash`) |
|
|
71
|
+
| `/v1/models/<id>` | GET | Get model capabilities |
|
|
72
|
+
|
|
73
|
+
## Design Approach
|
|
74
|
+
|
|
75
|
+
The proxy follows a **stream-through** architecture:
|
|
76
|
+
|
|
77
|
+
1. **No buffering** — as DeepSeek streams tokens, the proxy immediately forwards them as SSE events
|
|
78
|
+
2. **Minimal transformation** — only the necessary field mappings are applied, keeping latency low
|
|
79
|
+
3. **Fail-fast** — errors from DeepSeek are propagated back as SSE error events
|
|
80
|
+
4. **Single-file** — the entire proxy is one Python file for easy deployment and modification
|
|
81
|
+
|
|
82
|
+
## Processing Flow
|
|
83
|
+
|
|
84
|
+
### Request Translation
|
|
85
|
+
|
|
86
|
+
When a client sends a request to `/v1/responses`, the proxy:
|
|
87
|
+
|
|
88
|
+
1. Extracts the `input` array from the Responses API payload
|
|
89
|
+
2. For each message:
|
|
90
|
+
- Maps `role: "developer"` → `role: "system"` (DeepSeek doesn't support "developer" role)
|
|
91
|
+
- Flattens content arrays into a single string (concatenates `input_text` parts)
|
|
92
|
+
- Passes through `role: "user"` and `role: "assistant"` unchanged
|
|
93
|
+
3. Constructs a DeepSeek Chat Completions payload with `stream: true`
|
|
94
|
+
4. Streams the request to DeepSeek's API
|
|
95
|
+
|
|
96
|
+
### SSE Event Lifecycle
|
|
97
|
+
|
|
98
|
+
The proxy emits exactly these 8 events in order during a successful stream:
|
|
99
|
+
|
|
100
|
+
```
|
|
101
|
+
1. response.created → Stream begins, response metadata
|
|
102
|
+
2. response.in_progress → Response status confirmed
|
|
103
|
+
3. response.output_item.added → Output slot opened (type: "message")
|
|
104
|
+
4. response.content_part.added → Text part initialized
|
|
105
|
+
5. response.output_text.delta → Incremental content (one per token)
|
|
106
|
+
6. response.output_text.done → Full text with aggregated content
|
|
107
|
+
7. response.output_item.done → Output item completed
|
|
108
|
+
8. response.completed → Full response with usage info
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
On error, the proxy emits a single `response.error` event and stops.
|
|
112
|
+
|
|
113
|
+
### Field Mapping
|
|
114
|
+
|
|
115
|
+
| OpenAI Responses API | DeepSeek Chat API | Direction |
|
|
116
|
+
|---|---|---|
|
|
117
|
+
| `input[].role: "developer"` | `messages[].role: "system"` | → |
|
|
118
|
+
| `input[].content[].input_text` | `messages[].content` (string) | → |
|
|
119
|
+
| `choices[0].delta.content` | `response.output_text.delta.delta` | ← |
|
|
120
|
+
| `usage.prompt_tokens` | `usage.input_tokens` | ← |
|
|
121
|
+
| `usage.completion_tokens` | `usage.output_tokens` | ← |
|
|
122
|
+
| `prompt_tokens_details.cached_tokens` | `input_tokens_details.cached_tokens` | ← |
|
|
123
|
+
| `completion_tokens_details.reasoning_tokens` | `output_tokens_details.reasoning_tokens` | ← |
|
|
124
|
+
|
|
125
|
+
## Quick Start
|
|
126
|
+
|
|
127
|
+
### Prerequisites
|
|
128
|
+
|
|
129
|
+
- Python 3.8+
|
|
130
|
+
- A DeepSeek API key
|
|
131
|
+
|
|
132
|
+
### Installation
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
git clone <repo-url>
|
|
136
|
+
cd deepseek-proxy
|
|
137
|
+
pip install flask requests uvicorn asgiref
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### Run
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
export DEEPSEEK_API_KEY=sk-your-key-here
|
|
144
|
+
python ds_proxy.py
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
The proxy starts on `http://127.0.0.1:8787`.
|
|
148
|
+
|
|
149
|
+
### Verify
|
|
150
|
+
|
|
151
|
+
```bash
|
|
152
|
+
curl -X POST http://127.0.0.1:8787/v1/responses \
|
|
153
|
+
-H "Authorization: Bearer $DEEPSEEK_API_KEY" \
|
|
154
|
+
-H "Content-Type: application/json" \
|
|
155
|
+
-d '{"input":[{"role":"user","content":[{"type":"input_text","text":"hello"}]}],"model":"deepseek-v4-flash"}'
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
## Configure codex (Claude Code CLI)
|
|
159
|
+
|
|
160
|
+
codex can be configured to use the proxy in two ways.
|
|
161
|
+
|
|
162
|
+
### Option A: Proxy config (simpler)
|
|
163
|
+
|
|
164
|
+
Add to `~/.claude/settings.local.json`:
|
|
165
|
+
|
|
166
|
+
```json
|
|
167
|
+
{
|
|
168
|
+
"proxy": {
|
|
169
|
+
"url": "http://127.0.0.1:8787/v1/responses",
|
|
170
|
+
"model": "deepseek-v4-flash"
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
This tells Claude Code to route all requests through the proxy URL and use the specified model.
|
|
176
|
+
|
|
177
|
+
### Option B: Model provider config
|
|
178
|
+
|
|
179
|
+
Add to `~/.codex/config.toml`:
|
|
180
|
+
|
|
181
|
+
```toml
|
|
182
|
+
model = "deepseek-v4-flash"
|
|
183
|
+
model_provider = "deepseek"
|
|
184
|
+
|
|
185
|
+
[model_providers.deepseek]
|
|
186
|
+
name = "DeepSeek"
|
|
187
|
+
base_url = "http://127.0.0.1:8787/v1"
|
|
188
|
+
env_key = "DEEPSEEK_API_KEY"
|
|
189
|
+
wire_api = "responses"
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
This registers DeepSeek as a custom model provider, making it selectable alongside other providers.
|
|
193
|
+
|
|
194
|
+
### Environment Variable
|
|
195
|
+
|
|
196
|
+
Regardless of which option you choose, set the API key:
|
|
197
|
+
|
|
198
|
+
```bash
|
|
199
|
+
export DEEPSEEK_API_KEY=sk-your-actual-key-here
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
The proxy reads this from the environment and passes it as the `Authorization` header to DeepSeek's API.
|
|
203
|
+
|
|
204
|
+
### Verification
|
|
205
|
+
|
|
206
|
+
Run Claude Code and send a message:
|
|
207
|
+
|
|
208
|
+
```bash
|
|
209
|
+
codex "hello"
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
You should see a response from the DeepSeek model. Check the proxy logs for details:
|
|
213
|
+
|
|
214
|
+
```bash
|
|
215
|
+
tail -f /tmp/ds_proxy.log
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
---
|
|
219
|
+
|
|
220
|
+
<a name="chinese"></a>
|
|
221
|
+
|
|
222
|
+
# 中文
|
|
223
|
+
|
|
224
|
+
## 初衷
|
|
225
|
+
|
|
226
|
+
**codex**(Claude Code CLI)原生使用 OpenAI **Responses API**(`/v1/responses`),采用 SSE 流式传输和特定的事件生命周期。而 DeepSeek 只提供标准的 **Chat Completions API**(`/v1/chat/completions`)。这两种协议互不兼容——不能简单地把 codex 指向 DeepSeek 端点就指望它能工作。
|
|
227
|
+
|
|
228
|
+
这个代理通过实时转换两种协议解决了这个问题,让 codex 可以使用 DeepSeek 作为后端模型。
|
|
229
|
+
|
|
230
|
+
## 概述
|
|
231
|
+
|
|
232
|
+
DeepSeek Proxy 是一个单文件 Flask 应用,充当 codex 和 DeepSeek API 之间的桥梁。它将 Responses API 流式格式的请求转换为 DeepSeek 的对话补全格式,再将 DeepSeek 的流式输出转换回 Responses API 事件协议。
|
|
233
|
+
|
|
234
|
+
## 架构
|
|
235
|
+
|
|
236
|
+
```
|
|
237
|
+
┌─────────────┐ Responses API SSE ┌────────────────┐ DeepSeek Chat API ┌────────────┐
|
|
238
|
+
│ codex │ ───────────────────────→ │ ds_proxy.py │ ──────────────────────→ │ DeepSeek │
|
|
239
|
+
│ (CLI 客户端) │ ←─────────────────────── │ (Flask 代理) │ ←────────────────────── │ API │
|
|
240
|
+
└─────────────┘ SSE 事件 (7 种类型) └────────────────┘ SSE 流式数据块 └────────────┘
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
### 组件
|
|
244
|
+
|
|
245
|
+
| 层级 | 技术 | 职责 |
|
|
246
|
+
|---|---|---|
|
|
247
|
+
| **服务器** | Flask + uvicorn (ASGI) | HTTP 服务、SSE 流式传输 |
|
|
248
|
+
| **适配器** | `asgiref.wsgi.WsgiToAsgi` | WSGI → ASGI 包装,用于 uvicorn |
|
|
249
|
+
| **转换器** | `ds_proxy.py` 中的自定义逻辑 | 请求/响应格式转换 |
|
|
250
|
+
| **客户端** | `requests` (流式) | 向 DeepSeek API 发送 HTTP 请求 |
|
|
251
|
+
|
|
252
|
+
### 接口
|
|
253
|
+
|
|
254
|
+
| 路由 | 方法 | 用途 |
|
|
255
|
+
|---|---|---|
|
|
256
|
+
| `/v1/responses` | POST | 接收 Responses API 请求,返回 SSE 流 |
|
|
257
|
+
| `/v1/models` | GET | 列出可用模型 (`deepseek-v4-flash`) |
|
|
258
|
+
| `/v1/models/<id>` | GET | 获取模型能力信息 |
|
|
259
|
+
|
|
260
|
+
## 设计思路
|
|
261
|
+
|
|
262
|
+
代理采用**流式直通**架构:
|
|
263
|
+
|
|
264
|
+
1. **不缓冲** — DeepSeek 逐 token 返回时,代理立即转发为 SSE 事件
|
|
265
|
+
2. **最小转换** — 只应用必要的字段映射,保持低延迟
|
|
266
|
+
3. **快速失败** — DeepSeek 的错误通过 SSE 错误事件传播回客户端
|
|
267
|
+
4. **单文件** — 整个代理只有一个 Python 文件,便于部署和修改
|
|
268
|
+
|
|
269
|
+
## 处理流程
|
|
270
|
+
|
|
271
|
+
### 请求转换
|
|
272
|
+
|
|
273
|
+
客户端向 `/v1/responses` 发送请求时,代理执行以下操作:
|
|
274
|
+
|
|
275
|
+
1. 从 Responses API 请求体中提取 `input` 数组
|
|
276
|
+
2. 对每条消息:
|
|
277
|
+
- 将 `role: "developer"` 映射为 `role: "system"`(DeepSeek 不支持 "developer" 角色)
|
|
278
|
+
- 将 content 数组合并为一个字符串(拼接所有 `input_text` 片段)
|
|
279
|
+
- `role: "user"` 和 `role: "assistant"` 保持不变
|
|
280
|
+
3. 构造 DeepSeek Chat Completions 请求体,设置 `stream: true`
|
|
281
|
+
4. 以流式方式向 DeepSeek API 发送请求
|
|
282
|
+
|
|
283
|
+
### SSE 事件生命周期
|
|
284
|
+
|
|
285
|
+
一次成功的流式响应会按顺序发送以下 8 个事件:
|
|
286
|
+
|
|
287
|
+
```
|
|
288
|
+
1. response.created → 流开始,响应元数据
|
|
289
|
+
2. response.in_progress → 确认响应进行中
|
|
290
|
+
3. response.output_item.added → 开启输出槽 (类型: "message")
|
|
291
|
+
4. response.content_part.added → 初始化文本部分
|
|
292
|
+
5. response.output_text.delta → 增量内容(每个 token 一次)
|
|
293
|
+
6. response.output_text.done → 完整文本内容
|
|
294
|
+
7. response.output_item.done → 输出项完成
|
|
295
|
+
8. response.completed → 完整响应,含 usage 信息
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
发生错误时,代理发送一个 `response.error` 事件并停止。
|
|
299
|
+
|
|
300
|
+
### 字段映射
|
|
301
|
+
|
|
302
|
+
| OpenAI Responses API | DeepSeek Chat API | 方向 |
|
|
303
|
+
|---|---|---|
|
|
304
|
+
| `input[].role: "developer"` | `messages[].role: "system"` | → |
|
|
305
|
+
| `input[].content[].input_text` | `messages[].content` (字符串) | → |
|
|
306
|
+
| `choices[0].delta.content` | `response.output_text.delta.delta` | ← |
|
|
307
|
+
| `usage.prompt_tokens` | `usage.input_tokens` | ← |
|
|
308
|
+
| `usage.completion_tokens` | `usage.output_tokens` | ← |
|
|
309
|
+
| `prompt_tokens_details.cached_tokens` | `input_tokens_details.cached_tokens` | ← |
|
|
310
|
+
| `completion_tokens_details.reasoning_tokens` | `output_tokens_details.reasoning_tokens` | ← |
|
|
311
|
+
|
|
312
|
+
## 快速开始
|
|
313
|
+
|
|
314
|
+
### 前置条件
|
|
315
|
+
|
|
316
|
+
- Python 3.8+
|
|
317
|
+
- DeepSeek API 密钥
|
|
318
|
+
|
|
319
|
+
### 安装
|
|
320
|
+
|
|
321
|
+
```bash
|
|
322
|
+
git clone <repo-url>
|
|
323
|
+
cd deepseek-proxy
|
|
324
|
+
pip install flask requests uvicorn asgiref
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
### 运行
|
|
328
|
+
|
|
329
|
+
```bash
|
|
330
|
+
export DEEPSEEK_API_KEY=sk-your-key-here
|
|
331
|
+
python ds_proxy.py
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
代理启动在 `http://127.0.0.1:8787`。
|
|
335
|
+
|
|
336
|
+
### 验证
|
|
337
|
+
|
|
338
|
+
```bash
|
|
339
|
+
curl -X POST http://127.0.0.1:8787/v1/responses \
|
|
340
|
+
-H "Authorization: Bearer $DEEPSEEK_API_KEY" \
|
|
341
|
+
-H "Content-Type: application/json" \
|
|
342
|
+
-d '{"input":[{"role":"user","content":[{"type":"input_text","text":"你好"}]}],"model":"deepseek-v4-flash"}'
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
## 配置 codex (Claude Code CLI)
|
|
346
|
+
|
|
347
|
+
有两种方式让 codex 使用代理。
|
|
348
|
+
|
|
349
|
+
### 方式 A:代理配置(更简单)
|
|
350
|
+
|
|
351
|
+
添加到 `~/.claude/settings.local.json`:
|
|
352
|
+
|
|
353
|
+
```json
|
|
354
|
+
{
|
|
355
|
+
"proxy": {
|
|
356
|
+
"url": "http://127.0.0.1:8787/v1/responses",
|
|
357
|
+
"model": "deepseek-v4-flash"
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
这告诉 Claude Code 将所有请求通过代理 URL 路由,并使用指定模型。
|
|
363
|
+
|
|
364
|
+
### 方式 B:模型提供商配置
|
|
365
|
+
|
|
366
|
+
添加到 `~/.codex/config.toml`:
|
|
367
|
+
|
|
368
|
+
```toml
|
|
369
|
+
model = "deepseek-v4-flash"
|
|
370
|
+
model_provider = "deepseek"
|
|
371
|
+
|
|
372
|
+
[model_providers.deepseek]
|
|
373
|
+
name = "DeepSeek"
|
|
374
|
+
base_url = "http://127.0.0.1:8787/v1"
|
|
375
|
+
env_key = "DEEPSEEK_API_KEY"
|
|
376
|
+
wire_api = "responses"
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
这将 DeepSeek 注册为自定义模型提供商,可以在多个提供商之间切换选择。
|
|
380
|
+
|
|
381
|
+
### 环境变量
|
|
382
|
+
|
|
383
|
+
无论选择哪种方式,都需要设置 API 密钥:
|
|
384
|
+
|
|
385
|
+
```bash
|
|
386
|
+
export DEEPSEEK_API_KEY=sk-your-actual-key-here
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
代理从环境变量读取密钥,并将其作为 `Authorization` 头传递给 DeepSeek API。
|
|
390
|
+
|
|
391
|
+
### 验证
|
|
392
|
+
|
|
393
|
+
运行 Claude Code 发送消息:
|
|
394
|
+
|
|
395
|
+
```bash
|
|
396
|
+
codex "hello"
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
你应该能看到来自 DeepSeek 模型的响应。查看代理日志获取详情:
|
|
400
|
+
|
|
401
|
+
```bash
|
|
402
|
+
tail -f /tmp/ds_proxy.log
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
---
|
|
406
|
+
|
|
407
|
+
<p align="center">
|
|
408
|
+
<a href="#english">English</a> | <a href="#chinese">中文</a>
|
|
409
|
+
</p>
|