Upload 5 files
Browse files
README.md
CHANGED
|
@@ -1,84 +1,71 @@
|
|
| 1 |
-
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
-
|
| 29 |
-
|
| 30 |
-
|
| 31 |
-
-
|
| 32 |
-
-
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
-
|
| 36 |
-
|
| 37 |
-
|
| 38 |
-
|
| 39 |
-
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
-
|
| 44 |
-
|
| 45 |
-
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
|
| 49 |
-
|
| 50 |
-
|
| 51 |
-
|
| 52 |
-
|
| 53 |
-
|
| 54 |
-
|
| 55 |
-
|
| 56 |
-
|
| 57 |
-
|
| 58 |
-
|
| 59 |
-
|
| 60 |
-
|
| 61 |
-
|
| 62 |
-
|
| 63 |
-
-
|
| 64 |
-
|
| 65 |
-
|
| 66 |
-
|
| 67 |
-
|
| 68 |
-
|
| 69 |
-
|
| 70 |
-
|
| 71 |
-
|
| 72 |
-
"model": "deepseek-ai/DeepSeek-R1-0528-Turbo",
|
| 73 |
-
"messages": [
|
| 74 |
-
{
|
| 75 |
-
"role": "user",
|
| 76 |
-
"content": "Hello, how are you?"
|
| 77 |
-
}
|
| 78 |
-
],
|
| 79 |
-
"stream": false
|
| 80 |
-
}'
|
| 81 |
-
```
|
| 82 |
-
> 将 `<你的用户名>-<你的Space名>` 和 `<你的TOKEN>` 替换为你自己的信息。
|
| 83 |
-
|
| 84 |
-
现在你可以随时随地使用 DeepInfra 上的优秀模型了!
|
|
|
|
| 1 |
+
---
|
| 2 |
+
title: DeepInfra to OpenAI Adapter
|
| 3 |
+
emoji: 🚀
|
| 4 |
+
colorFrom: blue
|
| 5 |
+
colorTo: green
|
| 6 |
+
sdk: docker
|
| 7 |
+
pinned: false
|
| 8 |
+
---
|
| 9 |
+
|
| 10 |
+
# DeepInfra to OpenAI API Adapter
|
| 11 |
+
|
| 12 |
+
[](https://huggingface.co/new/space?template=deepinfra-openai-adapter)
|
| 13 |
+
|
| 14 |
+
这是一个代理服务,可以将 [DeepInfra](https://deepinfra.com/) 的模型 API 转换为与 OpenAI API 兼容的格式。这使得在各种为 OpenAI API 设计的客户端和工具中使用 DeepInfra 的模型成为可能。
|
| 15 |
+
|
| 16 |
+
## ✨ 功能
|
| 17 |
+
|
| 18 |
+
- **OpenAI 格式兼容**:将 DeepInfra API 无缝转换为 OpenAI Chat Completions API 格式。
|
| 19 |
+
- **模型列表接口**:支持 `/v1/models` 接口,可以获取预设的模型列表。
|
| 20 |
+
- **自定义鉴权**:通过环境变量设置 `TOKEN`,保护你的 API 不被滥用。
|
| 21 |
+
- **轻松部署**:可以一键部署到 Hugging Face Spaces。
|
| 22 |
+
|
| 23 |
+
## 🚀 部署到 Hugging Face Spaces
|
| 24 |
+
|
| 25 |
+
按照以下步骤,你可以轻松地将此服务部署到你自己的 Hugging Face Space。
|
| 26 |
+
|
| 27 |
+
1. **创建 Space**
|
| 28 |
+
- 点击上方的 "Deploy to Hugging Face Spaces" 徽章,或访问 [Hugging Face 新建 Space 页面](https://huggingface.co/new/space)。
|
| 29 |
+
- 给你的 Space 起一个名字(`Space name`)。
|
| 30 |
+
- 在 `Select the Space SDK` 选项中,选择 **Docker**。
|
| 31 |
+
- 在 `Docker template` 中,选择 **Blank**。
|
| 32 |
+
- 点击 `Create Space`。
|
| 33 |
+
|
| 34 |
+
2. **上传文件**
|
| 35 |
+
- 在你的 Space 页面,进入 `Files` 标签页。
|
| 36 |
+
- 点击 `Add file` -> `Upload file`。
|
| 37 |
+
- 将项目中的 `app.js` 和 `Dockerfile` 这两个文件上传。
|
| 38 |
+
|
| 39 |
+
3. **设置 API 密钥**
|
| 40 |
+
- 在你的 Space 页面,进入 `Settings` 标签页。
|
| 41 |
+
- 找到 `Secrets management` 部分,点击 `New secret`。
|
| 42 |
+
- 在 `Name` 字段中输入 `TOKEN`。
|
| 43 |
+
- 在 `Value` 字段中输入一个你自己的密码,例如 `sk-my-secret-key-12345`。这个密码将作为访问你服务的 API Key。
|
| 44 |
+
- 点击 `Save secret`。Hugging Face 会自动重新构建你的 Space 以应用这个密钥。
|
| 45 |
+
|
| 46 |
+
部署完成后,你的 Space 页面应该会显示 `Running` 状态。
|
| 47 |
+
|
| 48 |
+
## 🛠️ 如何使用
|
| 49 |
+
|
| 50 |
+
部署成功后,你就可以在任何支持 OpenAI API 的客户端或代码中配置并使用你的代理了。
|
| 51 |
+
|
| 52 |
+
- **API 地址 (Endpoint / Base URL)**:
|
| 53 |
+
你的 Hugging Face Space 的公开 URL,格式为 `https://<你的用户名>-<你的Space名>.hf.space`。
|
| 54 |
+
**重要**: 请在 URL 后面加上 `/v1`,完整的地址应该是 `https://<你的用户名>-<你的Space名>.hf.space/v1`。
|
| 55 |
+
|
| 56 |
+
- **API 密钥 (API Key)**:
|
| 57 |
+
你在 Hugging Face `TOKEN` 密钥中设置的值。
|
| 58 |
+
|
| 59 |
+
- **模型名称**:
|
| 60 |
+
任何 DeepInfra 支持的模型,或者使用 `/v1/models` 接口中提供的模型,例如:
|
| 61 |
+
- `deepseek-ai/DeepSeek-R1-0528-Turbo`
|
| 62 |
+
- `deepseek-ai/DeepSeek-V3-0324-Turbo`
|
| 63 |
+
- `deepseek-ai/DeepSeek-R1-Distill-Llama-70B`
|
| 64 |
+
- `zai-org/GLM-4.6`
|
| 65 |
+
- `moonshotai/Kimi-K2-Instruct`
|
| 66 |
+
- `deepseek-ai/DeepSeek-V3.2-Exp`
|
| 67 |
+
- `deepseek-ai/DeepSeek-V3.1-Terminus`
|
| 68 |
+
|
| 69 |
+
### 使用 cURL 测试
|
| 70 |
+
|
| 71 |
+
你可以使用 `
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
app.js
CHANGED
|
@@ -1,123 +1,147 @@
|
|
| 1 |
-
import { serve } from "https://deno.land/std/http/server.ts";
|
| 2 |
-
|
| 3 |
-
const handler = async (request) => {
|
| 4 |
-
const url = new URL(request.url);
|
| 5 |
-
|
| 6 |
-
// Handle CORS preflight requests
|
| 7 |
-
if (request.method === "OPTIONS") {
|
| 8 |
-
return new Response(null, {
|
| 9 |
-
headers: {
|
| 10 |
-
"Access-Control-Allow-Origin": "*",
|
| 11 |
-
"Access-Control-Allow-Methods": "POST, GET, OPTIONS",
|
| 12 |
-
"Access-Control-Allow-Headers": "Content-Type, Authorization",
|
| 13 |
-
"Access-Control-Max-Age": "86400",
|
| 14 |
-
},
|
| 15 |
-
});
|
| 16 |
-
}
|
| 17 |
-
|
| 18 |
-
const TOKEN = Deno.env.get("TOKEN");
|
| 19 |
-
|
| 20 |
-
// Authentication check
|
| 21 |
-
if (TOKEN) {
|
| 22 |
-
const authHeader = request.headers.get("Authorization");
|
| 23 |
-
if (!authHeader || authHeader !== `Bearer ${TOKEN}`) {
|
| 24 |
-
return new Response("Unauthorized", {
|
| 25 |
-
status: 401,
|
| 26 |
-
headers: {
|
| 27 |
-
"Content-Type": "application/json",
|
| 28 |
-
"Access-Control-Allow-Origin": "*",
|
| 29 |
-
},
|
| 30 |
-
});
|
| 31 |
-
}
|
| 32 |
-
}
|
| 33 |
-
|
| 34 |
-
// Handle /v1/models endpoint
|
| 35 |
-
if (url.pathname === "/v1/models" && request.method === "GET") {
|
| 36 |
-
const models = {
|
| 37 |
-
object: "list",
|
| 38 |
-
data: [
|
| 39 |
-
{
|
| 40 |
-
id: "deepseek-ai/DeepSeek-R1-0528-Turbo",
|
| 41 |
-
object: "model",
|
| 42 |
-
created: 1624980000,
|
| 43 |
-
owned_by: "deepseek-ai",
|
| 44 |
-
},
|
| 45 |
-
{
|
| 46 |
-
id: "deepseek-ai/DeepSeek-V3-0324-Turbo",
|
| 47 |
-
object: "model",
|
| 48 |
-
created: 1632000000,
|
| 49 |
-
owned_by: "deepseek-ai",
|
| 50 |
-
},
|
| 51 |
-
{
|
| 52 |
-
id: "deepseek-ai/DeepSeek-R1-Distill-Llama-70B",
|
| 53 |
-
object: "model",
|
| 54 |
-
created: 1640000000,
|
| 55 |
-
owned_by: "deepseek-ai",
|
| 56 |
-
},
|
| 57 |
-
|
| 58 |
-
|
| 59 |
-
|
| 60 |
-
|
| 61 |
-
|
| 62 |
-
|
| 63 |
-
|
| 64 |
-
|
| 65 |
-
|
| 66 |
-
|
| 67 |
-
|
| 68 |
-
|
| 69 |
-
|
| 70 |
-
|
| 71 |
-
|
| 72 |
-
|
| 73 |
-
|
| 74 |
-
|
| 75 |
-
|
| 76 |
-
|
| 77 |
-
|
| 78 |
-
|
| 79 |
-
|
| 80 |
-
|
| 81 |
-
|
| 82 |
-
|
| 83 |
-
|
| 84 |
-
|
| 85 |
-
|
| 86 |
-
|
| 87 |
-
|
| 88 |
-
|
| 89 |
-
|
| 90 |
-
|
| 91 |
-
|
| 92 |
-
|
| 93 |
-
|
| 94 |
-
|
| 95 |
-
|
| 96 |
-
|
| 97 |
-
|
| 98 |
-
|
| 99 |
-
|
| 100 |
-
|
| 101 |
-
|
| 102 |
-
|
| 103 |
-
|
| 104 |
-
|
| 105 |
-
|
| 106 |
-
|
| 107 |
-
|
| 108 |
-
|
| 109 |
-
|
| 110 |
-
|
| 111 |
-
|
| 112 |
-
|
| 113 |
-
|
| 114 |
-
|
| 115 |
-
|
| 116 |
-
|
| 117 |
-
|
| 118 |
-
|
| 119 |
-
|
| 120 |
-
|
| 121 |
-
|
| 122 |
-
|
| 123 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import { serve } from "https://deno.land/std/http/server.ts";
|
| 2 |
+
|
| 3 |
+
const handler = async (request) => {
|
| 4 |
+
const url = new URL(request.url);
|
| 5 |
+
|
| 6 |
+
// Handle CORS preflight requests
|
| 7 |
+
if (request.method === "OPTIONS") {
|
| 8 |
+
return new Response(null, {
|
| 9 |
+
headers: {
|
| 10 |
+
"Access-Control-Allow-Origin": "*",
|
| 11 |
+
"Access-Control-Allow-Methods": "POST, GET, OPTIONS",
|
| 12 |
+
"Access-Control-Allow-Headers": "Content-Type, Authorization",
|
| 13 |
+
"Access-Control-Max-Age": "86400",
|
| 14 |
+
},
|
| 15 |
+
});
|
| 16 |
+
}
|
| 17 |
+
|
| 18 |
+
const TOKEN = Deno.env.get("TOKEN");
|
| 19 |
+
|
| 20 |
+
// Authentication check
|
| 21 |
+
if (TOKEN) {
|
| 22 |
+
const authHeader = request.headers.get("Authorization");
|
| 23 |
+
if (!authHeader || authHeader !== `Bearer ${TOKEN}`) {
|
| 24 |
+
return new Response("Unauthorized", {
|
| 25 |
+
status: 401,
|
| 26 |
+
headers: {
|
| 27 |
+
"Content-Type": "application/json",
|
| 28 |
+
"Access-Control-Allow-Origin": "*",
|
| 29 |
+
},
|
| 30 |
+
});
|
| 31 |
+
}
|
| 32 |
+
}
|
| 33 |
+
|
| 34 |
+
// Handle /v1/models endpoint
|
| 35 |
+
if (url.pathname === "/v1/models" && request.method === "GET") {
|
| 36 |
+
const models = {
|
| 37 |
+
object: "list",
|
| 38 |
+
data: [
|
| 39 |
+
{
|
| 40 |
+
id: "deepseek-ai/DeepSeek-R1-0528-Turbo",
|
| 41 |
+
object: "model",
|
| 42 |
+
created: 1624980000,
|
| 43 |
+
owned_by: "deepseek-ai",
|
| 44 |
+
},
|
| 45 |
+
{
|
| 46 |
+
id: "deepseek-ai/DeepSeek-V3-0324-Turbo",
|
| 47 |
+
object: "model",
|
| 48 |
+
created: 1632000000,
|
| 49 |
+
owned_by: "deepseek-ai",
|
| 50 |
+
},
|
| 51 |
+
{
|
| 52 |
+
id: "deepseek-ai/DeepSeek-R1-Distill-Llama-70B",
|
| 53 |
+
object: "model",
|
| 54 |
+
created: 1640000000,
|
| 55 |
+
owned_by: "deepseek-ai",
|
| 56 |
+
},
|
| 57 |
+
{
|
| 58 |
+
id: "zai-org/GLM-4.6",
|
| 59 |
+
object: "model",
|
| 60 |
+
created: 1720000000,
|
| 61 |
+
owned_by: "zai-org",
|
| 62 |
+
},
|
| 63 |
+
{
|
| 64 |
+
id: "moonshotai/Kimi-K2-Instruct",
|
| 65 |
+
object: "model",
|
| 66 |
+
created: 1721000000,
|
| 67 |
+
owned_by: "moonshotai",
|
| 68 |
+
},
|
| 69 |
+
{
|
| 70 |
+
id: "deepseek-ai/DeepSeek-V3.2-Exp",
|
| 71 |
+
object: "model",
|
| 72 |
+
created: 1722000000,
|
| 73 |
+
owned_by: "deepseek-ai",
|
| 74 |
+
},
|
| 75 |
+
{
|
| 76 |
+
id: "deepseek-ai/DeepSeek-V3.1-Terminus",
|
| 77 |
+
object: "model",
|
| 78 |
+
created: 1723000000,
|
| 79 |
+
owned_by: "deepseek-ai",
|
| 80 |
+
},
|
| 81 |
+
],
|
| 82 |
+
};
|
| 83 |
+
|
| 84 |
+
return new Response(JSON.stringify(models), {
|
| 85 |
+
headers: {
|
| 86 |
+
"Content-Type": "application/json",
|
| 87 |
+
"Access-Control-Allow-Origin": "*",
|
| 88 |
+
},
|
| 89 |
+
});
|
| 90 |
+
}
|
| 91 |
+
|
| 92 |
+
// Handle chat completions
|
| 93 |
+
if (url.pathname === "/v1/chat/completions" && request.method === "POST") {
|
| 94 |
+
try {
|
| 95 |
+
const body = await request.json();
|
| 96 |
+
const headers = new Headers({
|
| 97 |
+
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36 Edg/133.0.0.0",
|
| 98 |
+
"Accept": "text/event-stream",
|
| 99 |
+
"Accept-Encoding": "gzip, deflate, br, zstd",
|
| 100 |
+
"Content-Type": "application/json",
|
| 101 |
+
"sec-ch-ua-platform": "Windows",
|
| 102 |
+
"X-Deepinfra-Source": "web-page",
|
| 103 |
+
"sec-ch-ua": '"Not(A:Brand";v="99", "Microsoft Edge";v="133", "Chromium";v="133"',
|
| 104 |
+
"sec-ch-ua-mobile": "?0",
|
| 105 |
+
"Origin": "https://deepinfra.com",
|
| 106 |
+
"Sec-Fetch-Site": "same-site",
|
| 107 |
+
"Sec-Fetch-Mode": "cors",
|
| 108 |
+
"Sec-Fetch-Dest": "empty",
|
| 109 |
+
"Referer": "https://deepinfra.com/",
|
| 110 |
+
});
|
| 111 |
+
|
| 112 |
+
const response = await fetch("https://api.deepinfra.com/v1/openai/chat/completions", {
|
| 113 |
+
method: "POST",
|
| 114 |
+
headers: headers,
|
| 115 |
+
body: JSON.stringify(body),
|
| 116 |
+
});
|
| 117 |
+
|
| 118 |
+
return new Response(response.body, {
|
| 119 |
+
status: response.status,
|
| 120 |
+
statusText: response.statusText,
|
| 121 |
+
headers: {
|
| 122 |
+
"Access-Control-Allow-Origin": "*",
|
| 123 |
+
"Content-Type": response.headers.get("Content-Type") || "application/json",
|
| 124 |
+
},
|
| 125 |
+
});
|
| 126 |
+
} catch (error) {
|
| 127 |
+
return new Response(JSON.stringify({ error: error.message }), {
|
| 128 |
+
status: 500,
|
| 129 |
+
headers: {
|
| 130 |
+
"Content-Type": "application/json",
|
| 131 |
+
"Access-Control-Allow-Origin": "*",
|
| 132 |
+
},
|
| 133 |
+
});
|
| 134 |
+
}
|
| 135 |
+
}
|
| 136 |
+
|
| 137 |
+
return new Response("Not Found", {
|
| 138 |
+
status: 404,
|
| 139 |
+
headers: {
|
| 140 |
+
"Access-Control-Allow-Origin": "*",
|
| 141 |
+
}
|
| 142 |
+
});
|
| 143 |
+
};
|
| 144 |
+
|
| 145 |
+
const port = Deno.env.get("PORT") ? parseInt(Deno.env.get("PORT")) : 7860;
|
| 146 |
+
console.log(`HTTP server running. Access it at: http://localhost:${port}/`);
|
| 147 |
+
serve(handler, { port });
|