升级到v1.3.1:为OpenAI端点的非流式 /v1/chat/completions 返回体转换为OpenAI兼容格式;保持Anthropic/Common非流式直传
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "droid2api",
|
"name": "droid2api",
|
||||||
"version": "1.3.0",
|
"version": "1.3.1",
|
||||||
"description": "OpenAI Compatible API Proxy",
|
"description": "OpenAI Compatible API Proxy",
|
||||||
"main": "server.js",
|
"main": "server.js",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|||||||
55
routes.js
55
routes.js
@@ -11,6 +11,44 @@ import { getApiKey } from './auth.js';
|
|||||||
|
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a /v1/responses API result to a /v1/chat/completions-compatible format.
|
||||||
|
* Works for non-streaming responses.
|
||||||
|
*/
|
||||||
|
function convertResponseToChatCompletion(resp) {
|
||||||
|
if (!resp || typeof resp !== 'object') {
|
||||||
|
throw new Error('Invalid response object');
|
||||||
|
}
|
||||||
|
|
||||||
|
const outputMsg = (resp.output || []).find(o => o.type === 'message');
|
||||||
|
const textBlocks = outputMsg?.content?.filter(c => c.type === 'output_text') || [];
|
||||||
|
const content = textBlocks.map(c => c.text).join('');
|
||||||
|
|
||||||
|
const chatCompletion = {
|
||||||
|
id: resp.id ? resp.id.replace(/^resp_/, 'chatcmpl-') : `chatcmpl-${Date.now()}`,
|
||||||
|
object: 'chat.completion',
|
||||||
|
created: resp.created_at || Math.floor(Date.now() / 1000),
|
||||||
|
model: resp.model || 'unknown-model',
|
||||||
|
choices: [
|
||||||
|
{
|
||||||
|
index: 0,
|
||||||
|
message: {
|
||||||
|
role: outputMsg?.role || 'assistant',
|
||||||
|
content: content || ''
|
||||||
|
},
|
||||||
|
finish_reason: resp.status === 'completed' ? 'stop' : 'unknown'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
usage: {
|
||||||
|
prompt_tokens: resp.usage?.input_tokens ?? 0,
|
||||||
|
completion_tokens: resp.usage?.output_tokens ?? 0,
|
||||||
|
total_tokens: resp.usage?.total_tokens ?? 0
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return chatCompletion;
|
||||||
|
}
|
||||||
|
|
||||||
router.get('/v1/models', (req, res) => {
|
router.get('/v1/models', (req, res) => {
|
||||||
logInfo('GET /v1/models');
|
logInfo('GET /v1/models');
|
||||||
|
|
||||||
@@ -161,8 +199,21 @@ async function handleChatCompletions(req, res) {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
logResponse(200, null, data);
|
if (model.type === 'openai') {
|
||||||
res.json(data);
|
try {
|
||||||
|
const converted = convertResponseToChatCompletion(data);
|
||||||
|
logResponse(200, null, converted);
|
||||||
|
res.json(converted);
|
||||||
|
} catch (e) {
|
||||||
|
// 如果转换失败,回退为原始数据
|
||||||
|
logResponse(200, null, data);
|
||||||
|
res.json(data);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// anthropic/common: 保持现有逻辑,直接转发
|
||||||
|
logResponse(200, null, data);
|
||||||
|
res.json(data);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
Reference in New Issue
Block a user