想试试cline这个插件,但是没有卡可以充值。想问下那个佬的公益支持Anthropic格式,用的好了再想办法搞个卡
4 个赞
可以自己转一下?不懂帮顶。
原生格式大部分都得花钱了,1:3或者1:4,而且claude dev消耗贼快,并发要求也高,便宜的一问到上限了…想玩这个稳定点的还得付费,或者用gpt,效果不那么好就是了
自己转一下
这种能转吗,真不知道
当然可以
aws这些羊毛可以还是说逆向啥的都行
你只管提需求,Claude 会帮你写完整代码。
付费也可以,反正就测试一下,主要官网的太麻烦了,又要美国电话,又要卡的
放到cloudflare worker里面,改一下全局变量BASE_URL 就行了
// 设置全局变量
const BASE_URL = 'https:123.com';
addEventListener('fetch', event => {
event.respondWith(handleRequest(event.request));
});
async function handleRequest(request) {
const url = new URL(request.url);
if (url.pathname === '/v1/messages') {
return handleMessagesRequest(request);
} else if (url.pathname === '/v1/models') {
return handleModelsRequest(request);
} else {
return new Response('Not Found', { status: 404 });
}
}
// 处理 /models 请求
async function handleModelsRequest(request) {
const apiKey = request.headers.get('x-api-key');
const response = await fetch(`${BASE_URL}/v1/models`, {
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${apiKey}`
}
});
const models = await response.json();
// 转换 OpenAI 模型列表为 Claude 模型列表格式
const claudeModels = {
models: models.data.map(model => {
const claudeModel = {
name: model.id
};
// 只添加存在的属性
if (model.max_tokens !== undefined) {
claudeModel.max_tokens = model.max_tokens;
}
if (model.description !== undefined) {
claudeModel.description = model.description;
}
return claudeModel;
})
};
return new Response(JSON.stringify(claudeModels), {
headers: {
'Content-Type': 'application/json'
}
});
}
// 处理 /messages 请求
async function handleMessagesRequest(request) {
try {
const inputBody = await request.json();
// 构造 OpenAI 请求体,仅包含存在的属性
const openaiRequestBody = {
model: inputBody.model,
messages: inputBody.messages.map(message => ({
role: message.role,
content: message.content
}))
};
// 添加可选参数
if (inputBody.max_tokens !== undefined) {
openaiRequestBody.max_tokens = inputBody.max_tokens;
}
if (inputBody.temperature !== undefined) {
openaiRequestBody.temperature = inputBody.temperature;
}
if (inputBody.stream !== undefined) {
openaiRequestBody.stream = inputBody.stream;
}
const apiKey = request.headers.get('x-api-key');
const response = await fetch(`${BASE_URL}/v1/chat/completions`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${apiKey}`
},
body: JSON.stringify(openaiRequestBody)
});
if (inputBody.stream) {
// 处理流式响应
return new Response(await streamOpenAIToClaude(response.body), {
headers: {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive'
}
});
} else {
// 处理非流式响应
const responseBody = await response.json();
// 转换 OpenAI 响应为 Claude 格式
const claudeResponseBody = {
content: [
{
text: responseBody.choices[0].message.content,
type: 'text'
}
],
id: responseBody.id,
model: inputBody.model,
role: 'assistant',
stop_reason: responseBody.choices[0].finish_reason,
stop_sequence: null,
type: 'message',
usage: responseBody.usage
};
return new Response(JSON.stringify(claudeResponseBody), {
headers: {
'Content-Type': 'application/json'
}
});
}
} catch (error) {
console.error('Request error:', error);
return new Response(JSON.stringify({
error: 'Internal Server Error',
message: error.message
}), {
status: 500,
headers: {
'Content-Type': 'application/json'
}
});
}
}
// 流式响应转换函数
async function streamOpenAIToClaude(readableStream) {
const encoder = new TextEncoder();
const decoder = new TextDecoder();
const transformStream = new TransformStream();
const writer = transformStream.writable.getWriter();
const reader = readableStream.getReader();
// 发送初始事件:message_start
writer.write(encoder.encode(`event: message_start\ndata: {"type":"message_start","message":{"id":"","type":"message","role":"assistant","content":[],"stop_reason":null,"stop_sequence":null,"usage":null}}\n\n`));
// 发送 content_block_start 事件
writer.write(encoder.encode(`event: content_block_start\ndata: {"type":"content_block_start","index":0,"content_block":{"type":"text","text":""}}\n\n`));
let buffer = '';
async function processStream() {
while (true) {
const { done, value } = await reader.read();
if (done) {
break;
}
buffer += decoder.decode(value, { stream: true });
let lines = buffer.split('\n');
buffer = lines.pop();
for (const line of lines) {
if (line.startsWith('data: ')) {
const dataStr = line.slice(6).trim();
if (dataStr === '[DONE]') {
// 发送 content_block_stop 事件
writer.write(encoder.encode(`event: content_block_stop\ndata: {"type":"content_block_stop","index":0}\n\n`));
// 发送 message_stop 事件
writer.write(encoder.encode(`event: message_stop\ndata: {"type":"message_stop"}\n\n`));
await writer.close();
return;
}
try {
const data = JSON.parse(dataStr);
if (data.choices && data.choices.length > 0) {
const delta = data.choices[0].delta;
if (delta && delta.content) {
// 转换为 Claude 的 content_block_delta 事件
const contentDelta = {
type: 'content_block_delta',
index: 0,
delta: {
type: 'text_delta',
text: delta.content
}
};
writer.write(encoder.encode(`event: content_block_delta\ndata: ${JSON.stringify(contentDelta)}\n\n`));
}
}
} catch (e) {
console.error('Error parsing JSON:', e);
}
}
}
}
// 流结束时,发送 content_block_stop 和 message_stop 事件
writer.write(encoder.encode(`event: content_block_stop\ndata: {"type":"content_block_stop","index":0}\n\n`));
writer.write(encoder.encode(`event: message_stop\ndata: {"type":"message_stop"}\n\n`));
await writer.close();
}
processStream();
return transformStream.readable;
}
6 个赞
感谢大佬,我试试