2024-06-25 13:19 广东
原贴 :https://linux.do/t/topic/118702
GCP 部分
点这里打开Google Cloud Shell
执行以下命令
Google cloud shell执行
gcloud auth application-default login
点击链接并完成授权
这里出现一段链接,鼠标点击一下这个链接,打开之后一路允许,随后出现下面这个界面,点一下Copy复制下面的验证码
返回Cloud Shell,粘贴验证码并确认
回去刚刚的界面鼠标右键粘贴,然后回车确认
[验证文件(密钥)] 的保存位置
接着提示验证文件保存在了这个位置
查看验证文件内容
使用cat空格加这个路径进行查看,比如我这里是
cat /tmp/tmp.ABCD/application_default_credentials.json
从里面复制出三个值保留备用,project_id就是项目ID这个也要用到
Cloudflare 部分
创建Cloudflare Workers
随后直接进入cloudflare 创建 Workers (是Worker不是Page请注意)
随后一路继续,随后点击这里的编辑按钮
进去之后根据上一节中的信息替换下面脚本中的内容,直接全部覆盖worker.js里面的内容
编辑Worker脚本
脚本内容
const MODEL = 'claude-3-5-sonnet@20240620'; const PROJECT_ID = '项目ID'; const CLIENT_ID = '填写'; const CLIENT_SECRET = '填写'; const REFRESH_TOKEN = '填写'; // 相当于密码的功能,接口密钥 const API_KEY = 'sk-pass' const TOKEN_URL = 'https://www.googleapis.com/oauth2/v4/token'; let accessToken = ''; let tokenExpiry = 0; // 获取 access_token async function getAccessToken() { if (Date.now() / 1000 < tokenExpiry - 60) { return accessToken; } const response = await fetch(TOKEN_URL, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ client_id: CLIENT_ID, client_secret: CLIENT_SECRET, refresh_token: REFRESH_TOKEN, grant_type: 'refresh_token' }) }); const data = await response.json(); accessToken = data.access_token; tokenExpiry = Date.now() / 1000 + data.expires_in; return accessToken; } // 选择区域 function getLocation() { const currentSeconds = new Date().getSeconds(); return currentSeconds < 30 ? 'europe-west1' : 'us-east5'; } // 构建 API URL function constructApiUrl(location) { return `https://${location}-aiplatform.googleapis.com/v1/projects/${PROJECT_ID}/locations/${location}/publishers/anthropic/models/${MODEL}:streamRawPredict`; } // 处理请求 async function handleRequest(request) { if (request.method === 'OPTIONS') { return handleOptions(); } // 检查x-api-key const apiKey = request.headers.get('x-api-key'); if (apiKey !== API_KEY) { const errorResponse = new Response(JSON.stringify({ type: "error", error: { type: "permission_error", message: "Your API key does not have permission to use the specified resource." } }), { status: 403, headers: { 'Content-Type': 'application/json' } }); errorResponse.headers.set('Access-Control-Allow-Origin', '*'); errorResponse.headers.set('Access-Control-Allow-Methods', 'POST, GET, OPTIONS, DELETE, HEAD'); errorResponse.headers.set('Access-Control-Allow-Headers', 'Content-Type, Authorization, x-api-key, anthropic-version, model'); return errorResponse; } const accessToken = await getAccessToken(); const location = getLocation(); const apiUrl = constructApiUrl(location); let requestBody = await request.json(); // 删除原始请求中的"anthropic_version"字段(如果存在) if (requestBody.anthropic_version) { delete requestBody.anthropic_version; } // 删除原始请求中的"model"字段(如果存在) if (requestBody.model) { delete requestBody.model; } // 添加新的"anthropic_version"字段 requestBody.anthropic_version = "vertex-2023-10-16"; const modifiedHeaders = new Headers(request.headers); modifiedHeaders.set('Authorization', `Bearer ${accessToken}`); modifiedHeaders.set('Content-Type', 'application/json; charset=utf-8'); modifiedHeaders.delete('anthropic-version'); const modifiedRequest = new Request(apiUrl, { headers: modifiedHeaders, method: request.method, body: JSON.stringify(requestBody), redirect: 'follow' }); const response = await fetch(modifiedRequest); const modifiedResponse = new Response(response.body, { status: response.status, statusText: response.statusText, headers: response.headers }); modifiedResponse.headers.set('Access-Control-Allow-Origin', '*'); modifiedResponse.headers.set('Access-Control-Allow-Methods', 'POST, GET, OPTIONS'); modifiedResponse.headers.set('Access-Control-Allow-Headers', 'Content-Type, Authorization, x-api-key, anthropic-version, model'); return modifiedResponse; } function handleOptions() { const headers = new Headers(); headers.set('Access-Control-Allow-Origin', '*'); headers.set('Access-Control-Allow-Methods', 'POST, GET, OPTIONS'); headers.set('Access-Control-Allow-Headers', 'Content-Type, Authorization, x-api-key, anthropic-version, model'); return new Response(null, { status: 204, headers: headers }); } export default { async fetch(request) { return handleRequest(request); } }
部署Worker
随后重击 Deploy 部署到 部署之后可以测试一下结果,注意最后的API格式遵循原版Anthropic格式
文档:Create a Message - Anthropic 21
备注:
有效性测试方法:
{"messages":[{"role":"user","content":"hello world!"}],"stream":false,"model":"claude-3-opus-20240229","max_tokens":4000,"temperature":0.5,"top_p":1,"top_k":5}
workers的地址
域名绑定:
NextChat 15配置,注意密码和worker.js中一致,图片中因为我改了密码所以和脚本里面的不一样,然后模型选择claude系列中任意模型即可(有3.5就选3.5,没有选3 Sonnet):
效果:
API测试地址,可直接填入NextChat中使用
(建议使用网页版 41):https://claude.jgk-blog.tech 47 (终端地址) 密码:sk-key
感谢 @eggacheb 大佬的反馈,可无需修改oneapi/newapi程序,直接加入现有oneapi/newapi渠道中