【New-API最新版本已支持:tieba_087:】CF Worker:合并调用火山 R1 模型 及 R1 BOT 时的请求路径

注意:最新版本的 New-API Docker 镜像已支持该渠道,会根据实际请求的模型 id 选择转发路径。更新后,直接编辑渠道,选择 火山方舟(豆包) 渠道 → 填入 API Key → 填写模型id与应用 id (或填写模型 id 并设置重定向)即可正常使用。

工作流程

流程图

备注:固定的模型列表包含 Volces/DeepSeek-R1Volces/DeepSeek-R1-Online,添加 “Volces/” 前缀的目的是为了方便与其他渠道的 R1 相区别。如果需要更改,可以直接修改 worker.js。

建立新的 KV 命名空间

CF Dashboard → 储存空间和资料库 → KV → 建立


依次添加 api_key, auth_key, r1-model-id, r1-online-bot-id。
其含义请参见下图。

相关链接

  1. 火山方舟
  2. 获取配置信息的参考教程贴:

注意事项

在获取配置的过程中,可以关注一下 API调用指南 → 通过 API Key 授权 → 2. 选择示例代码 → 第三方 API-SDK 调用示例 中的 base_url。

如果与下方代码块显示的内容不一致,则需要更改 workers.js 代码中的 API_ENDPOINTS。

模型配置时: "https://ark.cn-beijing.volces.com/api/v3",
BOT配置时: "https://ark.cn-beijing.volces.com/api/v3/bots"

修改 workers 设定

CF Dashboard → Workers → Workers 和 Pages → 建立 Worker → 快速启动 → 设定 worker 名称/域名前缀 → 部署 → 继续 → 设定 → 绑定/联结

配置KV:[变量]名称为KV,在值选择为你建立的KV命名空间,此处以VolcEngine_RP_KV为例

worker.js

var __defProp = Object.defineProperty;
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });

var KV_CONFIG = {
  AUTH_KEY: "auth_key",
  API_KEY: "api_key", 
  R1_MODEL_ID: "r1-model-id",
  R1_ONLINE_BOT_ID: "r1-online-bot-id"
};

var CORS_CONFIG = {
  allowOrigin: "*",
  allowMethods: "GET, POST, PUT, DELETE, OPTIONS",
  allowHeaders: "Content-Type, Authorization"
};

const API_ENDPOINTS = {
  CHAT: "https://ark.cn-beijing.volces.com/api/v3/chat/completions",
  BOT_CHAT: "https://ark.cn-beijing.volces.com/api/v3/bots/chat/completions"
};

var src_default = {
  async fetch(request, env) {
    console.log("[请求] 原始URL:", request.url);
    
    if (request.method === "OPTIONS") {
      return handleCorsPreflight();
    }

    const authError = await checkAuth(request, env);
    if (authError) return authError;

    const url = new URL(request.url);
    
    if (url.pathname === "/v1/models" && request.method === "GET") {
      return handleModelList();
    }

    if (url.pathname === "/v1/chat/completions" && request.method === "POST") {
      try {
        const body = await request.json();
        return await handleChatRequest(body, env);
      } catch (error) {
        console.error("[错误]", error);
        return new Response(JSON.stringify({
          error: {
            message: error.message,
            type: "internal_error"
          }
        }), {
          status: 500,
          headers: {
            "Content-Type": "application/json",
            ...corsHeaders()
          }
        });
      }
    }

    return new Response(JSON.stringify({
      error: {
        message: "Not found",
        type: "invalid_request_error" 
      }
    }), {
      status: 404,
      headers: {
        "Content-Type": "application/json",
        ...corsHeaders()
      }
    });
  }
};

async function handleChatRequest(requestBody, env) {
  try {
    const apiKey = await env.KV.get(KV_CONFIG.API_KEY);
    console.log("[系统] API Key 获取状态:", !!apiKey ? "已获取" : "未获取");
    
    if (!apiKey) {
      throw new Error("KV存储中未配置API Key");
    }
    
    const authorization = `Bearer ${apiKey}`;
    console.log("[系统] 认证头信息:", authorization.substring(0, 15) + "...");
    
    const model = requestBody.model;
    console.log("[系统] 请求的模型:", model);
    
    let endpoint, modelId;
    if (model === "Volces/DeepSeek-R1") {
      endpoint = API_ENDPOINTS.CHAT;
      modelId = await env.KV.get(KV_CONFIG.R1_MODEL_ID);
    } else if (model === "Volces/DeepSeek-R1-Online") {
      endpoint = API_ENDPOINTS.BOT_CHAT;
      modelId = await env.KV.get(KV_CONFIG.R1_ONLINE_BOT_ID);
    } else {
      throw new Error(`不支持的模型类型: ${model}`);
    }
    
    console.log("[系统] 选择的接口端点:", endpoint);
    console.log("[系统] 模型/机器人ID:", modelId);
    
    const modifiedBody = {
      ...requestBody,
      model: modelId
    };
    console.log("[系统] 请求负载:", JSON.stringify(modifiedBody, null, 2));
    
    const headers = {
      "Content-Type": "application/json",
      "Authorization": authorization
    };
    console.log("[系统] 请求头信息:", JSON.stringify(headers, null, 2));
    
    const newRequest = new Request(endpoint, {
      method: "POST",
      headers,
      body: JSON.stringify(modifiedBody)
    });
    
    console.log("[系统] 最终请求URL:", newRequest.url);
    
    const response = await fetch(newRequest);
    console.log("[系统] 响应状态码:", response.status);
    
    if (!response.ok) {
      const errorData = await response.json();
      console.error("[错误] API响应:", JSON.stringify(errorData, null, 2));
      return new Response(JSON.stringify({
        error: {
          message: errorData.error?.message || "API请求失败",
          type: errorData.error?.type || "api_error",
          status: response.status,
          requestId: errorData.error?.requestId,
          chinese_message: "API调用过程中发生错误,请检查认证信息和请求参数"
        }
      }), {
        status: response.status,
        headers: {
          "Content-Type": "application/json",
          ...corsHeaders()
        }
      });
    }
    
    return addCorsHeaders(response);
    
  } catch (error) {
    console.error("[错误] 堆栈信息:", error.stack);
    console.error("[错误] 详细信息:", {
      消息: error.message,
      类型: error.name,
      原因: error.cause
    });
    
    return new Response(JSON.stringify({
      error: {
        message: error.message,
        type: "internal_error",
        chinese_message: "服务器内部错误,请联系管理员",
        details: process.env.NODE_ENV === 'development' ? error.stack : undefined
      }
    }), {
      status: 500,
      headers: {
        "Content-Type": "application/json",
        ...corsHeaders()
      }
    });
  }
}

async function checkAuth(request, env) {
  const authHeader = request.headers.get("Authorization");
  const storedKey = await env.KV.get(KV_CONFIG.AUTH_KEY);
  if (!authHeader || !authHeader.startsWith("Bearer ") || authHeader.substring(7) !== storedKey) {
    return new Response("Unauthorized", {
      status: 401,
      headers: corsHeaders()
    });
  }
}

function handleCorsPreflight() {
  return new Response(null, {
    status: 204,
    headers: {
      ...corsHeaders(),
      "Access-Control-Max-Age": "86400"
    }
  });
}

function corsHeaders() {
  return {
    "Access-Control-Allow-Origin": CORS_CONFIG.allowOrigin,
    "Access-Control-Allow-Methods": CORS_CONFIG.allowMethods,
    "Access-Control-Allow-Headers": CORS_CONFIG.allowHeaders
  };
}

function addCorsHeaders(response) {
  const newResponse = new Response(response.body, response);
  Object.entries(corsHeaders()).forEach(([k, v]) => {
    newResponse.headers.set(k, v);
  });
  return newResponse;
}

function handleModelList() {
  const currentTime = Math.floor(Date.now() / 1000);
  const modelList = {
    "object": "list",
    "data": [
      {
        "id": "Volces/DeepSeek-R1",
        "object": "model",
        "created": currentTime - 86400,
        "owned_by": "system"
      },
      {
        "id": "",
        "object": "model",
        "created": currentTime - 43200,
        "owned_by": "system"
      }
    ]
  };

  return new Response(JSON.stringify(modelList), {
    headers: {
      "Content-Type": "application/json",
      ...corsHeaders()
    }
  });
}

__name(checkAuth, "checkAuth");
__name(handleCorsPreflight, "handleCorsPreflight");
__name(handleChatRequest, "handleChatRequest");
__name(corsHeaders, "corsHeaders");
__name(addCorsHeaders, "addCorsHeaders");
__name(handleModelList, "handleModelList");

export {
  src_default as default
};

New-API 配置

13 个赞

感谢分享

1 个赞

感谢大佬!

1 个赞

神一样的大佬啊,刚想找怎么接入newapi你就来了

1 个赞

部署成功,并接入了owu,可以直接联网使用,爽

1 个赞

最新的newapi不是支持了吗? 渠道选豆包就行

1 个赞

还真是 :tieba_087: 更新了一下镜像发现根本不需要再转一道了

可以手动拉一下最新的 New-API 镜像,最新版本选择 火山方舟(豆包) 渠道可以直接支持了, 模型重定向那边改一下就行,不用转发了 :tieba_087:

佬能再出个教程么?或者贴个图

1 个赞

请问是对哪一部分有问题呢 :eyes:

选择的类型是火山方舟(豆包)
url 我填入:https://ark.cn-beijing.volces.com/api/v3/bots
api 填入。
模型我填入的是 bot 开头的。
测试的时候一直报404 错误,地址后面加/也试过了,还需要做什么呢?

模型重定向加了也试过了

渠道选了 火山方舟(豆包),就不需要添加 BASE_URL(反向代理)了呀

多谢佬,搞定了

我是直接重定向到ep-那个接入点的:rofl:

我拉取了最新镜像但是为什么没有火山的渠道 :thinking:

要求是 New-API 的最新版本噢

我使用的是

docker run --name new-api -d --restart always -p 3000:3000 -e TZ=Asia/Shanghai -v /home/ubuntu/data/new-api:/data calciumion/new-api:latest

重新拉下镜像 / 往上划拉划拉 试试呢

镜像删了之后,从宝塔拉或者命令行拉,还是没有,怪了,只好用佬友的办法了