diff --git a/API.en.md b/API.en.md index a0b2f78..d363d3e 100644 --- a/API.en.md +++ b/API.en.md @@ -173,7 +173,7 @@ Gemini-compatible clients can also send `x-goog-api-key`, `?key=`, or `?api_key= ### `GET /v1/models` -No auth required. Returns supported models. +No auth required. Returns the currently supported DeepSeek native model list. **Response**: @@ -184,11 +184,21 @@ No auth required. Returns supported models. {"id": "deepseek-chat", "object": "model", "created": 1677610602, "owned_by": "deepseek", "permission": []}, {"id": "deepseek-reasoner", "object": "model", "created": 1677610602, "owned_by": "deepseek", "permission": []}, {"id": "deepseek-chat-search", "object": "model", "created": 1677610602, "owned_by": "deepseek", "permission": []}, - {"id": "deepseek-reasoner-search", "object": "model", "created": 1677610602, "owned_by": "deepseek", "permission": []} + {"id": "deepseek-reasoner-search", "object": "model", "created": 1677610602, "owned_by": "deepseek", "permission": []}, + {"id": "deepseek-expert-chat", "object": "model", "created": 1677610602, "owned_by": "deepseek", "permission": []}, + {"id": "deepseek-expert-reasoner", "object": "model", "created": 1677610602, "owned_by": "deepseek", "permission": []}, + {"id": "deepseek-expert-chat-search", "object": "model", "created": 1677610602, "owned_by": "deepseek", "permission": []}, + {"id": "deepseek-expert-reasoner-search", "object": "model", "created": 1677610602, "owned_by": "deepseek", "permission": []}, + {"id": "deepseek-vision-chat", "object": "model", "created": 1677610602, "owned_by": "deepseek", "permission": []}, + {"id": "deepseek-vision-reasoner", "object": "model", "created": 1677610602, "owned_by": "deepseek", "permission": []}, + {"id": "deepseek-vision-chat-search", "object": "model", "created": 1677610602, "owned_by": "deepseek", "permission": []}, + {"id": "deepseek-vision-reasoner-search", "object": "model", "created": 1677610602, "owned_by": "deepseek", "permission": []} ] } ``` +> Note: `/v1/models` returns normalized DeepSeek native model IDs. Common aliases are accepted only as request input and are not expanded as separate items in this endpoint. + ### Model Alias Resolution For `chat` / `responses` / `embeddings`, DS2API follows a wide-input/strict-output policy: @@ -211,7 +221,7 @@ Content-Type: application/json | Field | Type | Required | Notes | | --- | --- | --- | --- | -| `model` | string | ✅ | DeepSeek native models + common aliases (`gpt-4o`, `gpt-5-codex`, `o3`, `claude-sonnet-4-5`, etc.) | +| `model` | string | ✅ | DeepSeek native models + common aliases (`gpt-4o`, `gpt-5-codex`, `o3`, `claude-sonnet-4-5`, `gemini-2.5-pro`, etc.) | | `messages` | array | ✅ | OpenAI-style messages | | `stream` | boolean | ❌ | Default `false` | | `tools` | array | ❌ | Function calling schema | @@ -408,7 +418,7 @@ No auth required. } ``` -> Note: the example is partial; the real response includes historical Claude 1.x/2.x/3.x/4.x IDs and common aliases. +> Note: the example is partial; besides the current primary aliases, the real response also includes Claude 4.x snapshots plus historical 3.x / 2.x / 1.x IDs and common aliases. ### `POST /anthropic/v1/messages` diff --git a/API.md b/API.md index e0f4a6e..6c73b05 100644 --- a/API.md +++ b/API.md @@ -173,7 +173,7 @@ Gemini 兼容客户端还可以使用 `x-goog-api-key`、`?key=` 或 `?api_key=` ### `GET /v1/models` -无需鉴权。返回当前支持的模型列表。 +无需鉴权。返回当前支持的 DeepSeek 原生模型列表。 **响应示例**: @@ -184,11 +184,21 @@ Gemini 兼容客户端还可以使用 `x-goog-api-key`、`?key=` 或 `?api_key=` {"id": "deepseek-chat", "object": "model", "created": 1677610602, "owned_by": "deepseek", "permission": []}, {"id": "deepseek-reasoner", "object": "model", "created": 1677610602, "owned_by": "deepseek", "permission": []}, {"id": "deepseek-chat-search", "object": "model", "created": 1677610602, "owned_by": "deepseek", "permission": []}, - {"id": "deepseek-reasoner-search", "object": "model", "created": 1677610602, "owned_by": "deepseek", "permission": []} + {"id": "deepseek-reasoner-search", "object": "model", "created": 1677610602, "owned_by": "deepseek", "permission": []}, + {"id": "deepseek-expert-chat", "object": "model", "created": 1677610602, "owned_by": "deepseek", "permission": []}, + {"id": "deepseek-expert-reasoner", "object": "model", "created": 1677610602, "owned_by": "deepseek", "permission": []}, + {"id": "deepseek-expert-chat-search", "object": "model", "created": 1677610602, "owned_by": "deepseek", "permission": []}, + {"id": "deepseek-expert-reasoner-search", "object": "model", "created": 1677610602, "owned_by": "deepseek", "permission": []}, + {"id": "deepseek-vision-chat", "object": "model", "created": 1677610602, "owned_by": "deepseek", "permission": []}, + {"id": "deepseek-vision-reasoner", "object": "model", "created": 1677610602, "owned_by": "deepseek", "permission": []}, + {"id": "deepseek-vision-chat-search", "object": "model", "created": 1677610602, "owned_by": "deepseek", "permission": []}, + {"id": "deepseek-vision-reasoner-search", "object": "model", "created": 1677610602, "owned_by": "deepseek", "permission": []} ] } ``` +> 说明:`/v1/models` 返回的是规范化后的 DeepSeek 原生模型 ID;常见 alias 仅用于请求入参解析,不会在该接口中单独展开返回。 + ### 模型 alias 解析策略 对 `chat` / `responses` / `embeddings` 的 `model` 字段采用“宽进严出”: @@ -211,7 +221,7 @@ Content-Type: application/json | 字段 | 类型 | 必填 | 说明 | | --- | --- | --- | --- | -| `model` | string | ✅ | 支持 DeepSeek 原生模型 + 常见 alias(如 `gpt-4o`、`gpt-5-codex`、`o3`、`claude-sonnet-4-5`) | +| `model` | string | ✅ | 支持 DeepSeek 原生模型 + 常见 alias(如 `gpt-4o`、`gpt-5-codex`、`o3`、`claude-sonnet-4-5`、`gemini-2.5-pro` 等) | | `messages` | array | ✅ | OpenAI 风格消息数组 | | `stream` | boolean | ❌ | 默认 `false` | | `tools` | array | ❌ | Function Calling 定义 | @@ -414,7 +424,7 @@ data: [DONE] } ``` -> 说明:示例仅展示部分模型;实际返回包含 Claude 1.x/2.x/3.x/4.x 历史模型 ID 与常见别名。 +> 说明:示例仅展示部分模型;实际返回除当前主别名外,还包含 Claude 4.x snapshots,以及 3.x / 2.x / 1.x 历史模型 ID 与常见别名。 ### `POST /anthropic/v1/messages` diff --git a/internal/adapter/openai/file_inline_upload.go b/internal/adapter/openai/file_inline_upload.go index 589caeb..c199498 100644 --- a/internal/adapter/openai/file_inline_upload.go +++ b/internal/adapter/openai/file_inline_upload.go @@ -147,7 +147,7 @@ func (s *inlineUploadState) tryUploadBlock(block map[string]any) (map[string]any } func (s *inlineUploadState) uploadInlineFile(file inlineDecodedFile) (string, error) { - sum := sha256.Sum256(append(append([]byte(file.ContentType+"\x00"+file.Filename+"\x00"), file.Data...))) + sum := sha256.Sum256(append([]byte(file.ContentType+"\x00"+file.Filename+"\x00"), file.Data...)) cacheKey := fmt.Sprintf("%x", sum[:]) if fileID, ok := s.uploadedByID[cacheKey]; ok && strings.TrimSpace(fileID) != "" { return fileID, nil diff --git a/internal/adapter/openai/handler_files.go b/internal/adapter/openai/handler_files.go index 23f981f..5a86d24 100644 --- a/internal/adapter/openai/handler_files.go +++ b/internal/adapter/openai/handler_files.go @@ -33,7 +33,7 @@ func (h *Handler) UploadFile(w http.ResponseWriter, r *http.Request) { return } if r.MultipartForm != nil { - defer r.MultipartForm.RemoveAll() + defer func() { _ = r.MultipartForm.RemoveAll() }() } r = r.WithContext(auth.WithAuth(r.Context(), a)) file, header, err := r.FormFile("file") @@ -41,7 +41,7 @@ func (h *Handler) UploadFile(w http.ResponseWriter, r *http.Request) { writeOpenAIError(w, http.StatusBadRequest, "file is required") return } - defer file.Close() + defer func() { _ = file.Close() }() data, err := io.ReadAll(file) if err != nil { writeOpenAIError(w, http.StatusBadRequest, "failed to read uploaded file")