04-20 已凉
worker.js 如下
然后直接按OpenAI 标准格式调用就行 ![]()
/**
* Helix ↔︎ OpenAI 代理(全路径 + 流式过滤)
* 2025‑04‑19
*/
addEventListener('fetch', e => e.respondWith(router(e.request)));
async function router(req) {
const url = new URL(req.url);
const p = url.pathname.replace(/\/+$/, '');
const m = req.method;
if (m === 'OPTIONS') return cors(new Response(null, { status: 204 }));
if ((p === '/models' || p === '/v1/models') && m === 'GET')
return cors(modelsList());
if (
(p === '/chat/completions' || p === '/v1/chat/completions') &&
m === 'POST'
)
return cors(await chatProxy(req));
return cors(json({ error: 'Not Found', path: p }, 404));
}
/* ---------- 模型列表 ---------- */
function modelsList() {
return json({
object: 'list',
data: [
{ id: 'gpt-4o', object: 'model', created: 0, owned_by: 'helix' },
{ id: 'gpt-3.5-turbo', object: 'model', created: 0, owned_by: 'helix' }
]
});
}
/* ---------- 聊天 ---------- */
async function chatProxy(req) {
let body;
try {
body = await req.json();
} catch {
return json({ error: 'Bad JSON' }, 400);
}
const {
model,
messages = [],
stream = false,
temperature,
top_p,
presence_penalty,
frequency_penalty,
...rest
} = body;
const historyText = messages
.map(m => (m.role === 'user' ? '用户:' : 'AI:') + m.content)
.join('\n');
const helixPayload = {
type: 'text',
stream,
provider: getProvider(model),
model,
messages: [
{ role: 'user', content: { content_type: 'text', parts: [historyText] } }
],
temperature,
top_p,
presence_penalty,
frequency_penalty,
...rest
};
const helixRes = await fetch(
'https://app.tryhelix.ai/api/v1/sessions/chat',
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: req.headers.get('Authorization') || ''
},
body: JSON.stringify(helixPayload)
}
);
if (!stream) {
const data = await helixRes.json();
const reply = data?.choices?.[0]?.message?.content ?? '';
const openai = {
id: `chatcmpl-proxy-${data.id ?? Date.now()}`,
object: 'chat.completion',
created: Math.floor(Date.now() / 1000),
model,
choices: [
{
index: 0,
message: { role: 'assistant', content: reply },
finish_reason: 'stop'
}
]
};
return json(openai, helixRes.status);
}
/* ---- 流式过滤 ---- */
const filteredStream = helixRes.body
.pipeThrough(new TextDecoderStream()) // bytes -> string
.pipeThrough(sseLineSplitter()) // 按行切
.pipeThrough(new TransformStream({
transform(line, controller) {
if (!line.startsWith('data:')) { controller.enqueue(line); return; }
const payload = line.slice(5).trim();
if (payload === '[DONE]') { controller.enqueue(line); return; }
try {
const obj = JSON.parse(payload);
if (obj.choices === null || (Array.isArray(obj.choices) && obj.choices.length === 0))
return; // 过滤哑包
} catch { /* ignore */ }
controller.enqueue(line); // 合法块透传
}
}))
.pipeThrough(new TextEncoderStream()); // string -> bytes
return new Response(filteredStream, {
status: helixRes.status,
headers: { 'Content-Type': 'text/event-stream' }
});
}
/* ---------- 工具 ---------- */
function getProvider(m) {
if (/^gpt-[34]|^gpt-3\.5/.test(m)) return 'openai';
if (/^(llama|phi|aya|gemma|deepseek|qwen)/.test(m)) return 'helix';
return 'togetherai';
}
const json = (o, s = 200) =>
new Response(JSON.stringify(o), {
status: s,
headers: { 'Content-Type': 'application/json' }
});
function cors(res) {
const h = new Headers(res.headers);
h.set('Access-Control-Allow-Origin', '*');
h.set('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
h.set('Access-Control-Allow-Headers', 'Content-Type, Authorization');
return new Response(res.body, { ...res, headers: h });
}
/* 把字符串流按行切割(保留分隔符 \n) */
function sseLineSplitter() {
let buf = '';
return new TransformStream({
transform(chunk, controller) {
buf += chunk;
const lines = buf.split('\n');
buf = lines.pop();
for (const l of lines) controller.enqueue(l + '\n');
},
flush(controller) {
if (buf) controller.enqueue(buf);
}
});
}
----------------------------- 历史代码
/**
* Helix ↔︎ OpenAI 代理
* 支持:
* • 非流式转包为 OpenAI 格式
* • 流式 passthrough
* • 完整 CORS (POST / OPTIONS)
* 2025‑04‑19
*/
addEventListener('fetch', event =>
event.respondWith(handle(event.request))
);
async function handle(req) {
const { pathname } = new URL(req.url);
/* ---------- 1. CORS 预检 ---------- */
if (req.method === 'OPTIONS') {
return cors(new Response(null, { status: 204 }));
}
/* 只代理 POST /v1/chat/completions */
if (pathname !== '/v1/chat/completions' || req.method !== 'POST') {
return new Response('Not Found', { status: 404 });
}
/* ---------- 2. 解析 OpenAI JSON ---------- */
let openai;
try {
openai = await req.json();
} catch {
return cors(json({ error: 'Bad JSON' }, 400));
}
const {
model,
messages = [],
stream = false,
temperature,
top_p,
presence_penalty,
frequency_penalty,
...rest
} = openai;
/* ---------- 3. 把历史合并给 Helix ---------- */
const historyText = messages
.map(m => (m.role === 'user' ? '用户:' : 'AI:') + m.content)
.join('\n');
const helixBody = {
type: 'text',
stream,
provider: getProvider(model),
model,
messages: [
{
role: 'user',
content: { content_type: 'text', parts: [historyText] }
}
],
temperature,
top_p,
presence_penalty,
frequency_penalty,
...rest
};
/* ---------- 4. 向 Helix 发送 ---------- */
const helixRes = await fetch(
'https://app.tryhelix.ai/api/v1/sessions/chat',
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: req.headers.get('Authorization') || ''
},
body: JSON.stringify(helixBody)
}
);
/* ---------- 5‑A 非流式 → OpenAI ---------- */
if (!stream) {
const data = await helixRes.json();
const reply = data?.choices?.[0]?.message?.content ?? '';
const openaiRes = {
id: `chatcmpl-proxy-${data.id ?? Date.now()}`,
object: 'chat.completion',
created: Math.floor(Date.now() / 1000),
model,
choices: [
{
index: 0,
message: { role: 'assistant', content: reply },
finish_reason: 'stop'
}
]
};
return cors(json(openaiRes, helixRes.status));
}
/* ---------- 5‑B 流式 passthrough ---------- */
const streamHeaders = {
'Content-Type': helixRes.headers.get('Content-Type') || 'text/event-stream'
};
return cors(new Response(helixRes.body, {
status: helixRes.status,
headers: streamHeaders
}));
}
/* ---------- 辅助 ---------- */
function getProvider(model) {
if (/^gpt-[34]|^gpt-3\.5/.test(model)) return 'openai';
if (/^(llama|phi|aya|gemma|deepseek|qwen)/.test(model)) return 'helix';
return 'togetherai';
}
function json(obj, status = 200) {
return new Response(JSON.stringify(obj), {
status,
headers: { 'Content-Type': 'application/json' }
});
}
/* 给所有响应打上 CORS 头 */
function cors(res) {
const newHeaders = new Headers(res.headers);
newHeaders.set('Access-Control-Allow-Origin', '*');
newHeaders.set('Access-Control-Allow-Methods', 'POST, OPTIONS');
newHeaders.set(
'Access-Control-Allow-Headers',
'Content-Type, Authorization'
);
return new Response(res.body, { ...res, headers: newHeaders });
}