再来个不限量 gpt-4.1 / gpt-4.5 / r1 / v3

04-20 已凉

worker.js 如下
然后直接按OpenAI 标准格式调用就行 :face_savoring_food:

/**
 * 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 });
}
5 个赞