repair openai system format processing
This commit is contained in:
@@ -98,6 +98,9 @@ app.post("/v1/chat/completions", OpenAIApiKeyAuth, (req, res) => {
|
|||||||
res.setHeader("Access-Control-Allow-Origin", "*");
|
res.setHeader("Access-Control-Allow-Origin", "*");
|
||||||
let jsonBody = JSON.parse(req.rawBody);
|
let jsonBody = JSON.parse(req.rawBody);
|
||||||
|
|
||||||
|
// Normalize messages
|
||||||
|
jsonBody.messages = openaiNormalizeMessages(jsonBody.messages);
|
||||||
|
|
||||||
console.log("message length:" + jsonBody.messages.length);
|
console.log("message length:" + jsonBody.messages.length);
|
||||||
// decide which session to use randomly
|
// decide which session to use randomly
|
||||||
let randomSession = Object.keys(provider.sessions)[Math.floor(Math.random() * Object.keys(provider.sessions).length)];
|
let randomSession = Object.keys(provider.sessions)[Math.floor(Math.random() * Object.keys(provider.sessions).length)];
|
||||||
@@ -115,111 +118,40 @@ app.post("/v1/chat/completions", OpenAIApiKeyAuth, (req, res) => {
|
|||||||
console.log("Using model " + jsonBody.model);
|
console.log("Using model " + jsonBody.model);
|
||||||
|
|
||||||
// call provider to get completion
|
// call provider to get completion
|
||||||
await provider
|
try {
|
||||||
.getCompletion(
|
const {completion, cancel} = await provider.getCompletion({
|
||||||
{
|
username: randomSession,
|
||||||
username: randomSession,
|
messages: jsonBody.messages,
|
||||||
messages: jsonBody.messages,
|
stream: !!jsonBody.stream,
|
||||||
stream: !!jsonBody.stream,
|
proxyModel: jsonBody.model,
|
||||||
proxyModel: jsonBody.model,
|
useCustomMode: process.env.USE_CUSTOM_MODE === "true"
|
||||||
useCustomMode: process.env.USE_CUSTOM_MODE === "true"
|
});
|
||||||
}
|
|
||||||
)
|
|
||||||
.then(({completion, cancel}) => {
|
|
||||||
completion.on("start", (id) => {
|
|
||||||
if (jsonBody.stream) {
|
|
||||||
// send message start
|
|
||||||
res.write(createEvent(":", "queue heartbeat 114514"));
|
|
||||||
res.write(
|
|
||||||
createEvent("data", {
|
|
||||||
id: msgid,
|
|
||||||
object: "chat.completion.chunk",
|
|
||||||
created: Math.floor(new Date().getTime() / 1000),
|
|
||||||
model: jsonBody.model,
|
|
||||||
system_fingerprint: "114514",
|
|
||||||
choices: [{
|
|
||||||
index: 0,
|
|
||||||
delta: {role: "assistant", content: ""},
|
|
||||||
logprobs: null,
|
|
||||||
finish_reason: null
|
|
||||||
}],
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
completion.on("completion", (id, text) => {
|
completion.on("start", (id) => {
|
||||||
if (jsonBody.stream) {
|
|
||||||
// send message delta
|
|
||||||
res.write(
|
|
||||||
createEvent("data", {
|
|
||||||
choices: [
|
|
||||||
{
|
|
||||||
content_filter_results: {
|
|
||||||
hate: {filtered: false, severity: "safe"},
|
|
||||||
self_harm: {filtered: false, severity: "safe"},
|
|
||||||
sexual: {filtered: false, severity: "safe"},
|
|
||||||
violence: {filtered: false, severity: "safe"},
|
|
||||||
},
|
|
||||||
delta: {content: text},
|
|
||||||
finish_reason: null,
|
|
||||||
index: 0,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
created: Math.floor(new Date().getTime() / 1000),
|
|
||||||
id: id,
|
|
||||||
model: jsonBody.model,
|
|
||||||
object: "chat.completion.chunk",
|
|
||||||
system_fingerprint: "114514",
|
|
||||||
})
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
// 只会发一次,发送final response
|
|
||||||
res.write(
|
|
||||||
JSON.stringify({
|
|
||||||
id: id,
|
|
||||||
object: "chat.completion",
|
|
||||||
created: Math.floor(new Date().getTime() / 1000),
|
|
||||||
model: jsonBody.model,
|
|
||||||
system_fingerprint: "114514",
|
|
||||||
choices: [
|
|
||||||
{
|
|
||||||
index: 0,
|
|
||||||
message: {
|
|
||||||
role: "assistant",
|
|
||||||
content: text,
|
|
||||||
},
|
|
||||||
logprobs: null,
|
|
||||||
finish_reason: "stop",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
usage: {
|
|
||||||
prompt_tokens: 1,
|
|
||||||
completion_tokens: 1,
|
|
||||||
total_tokens: 1,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
);
|
|
||||||
res.end();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
completion.on("end", () => {
|
|
||||||
if (jsonBody.stream) {
|
|
||||||
res.write(createEvent("data", "[DONE]"));
|
|
||||||
res.end();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
res.on("close", () => {
|
|
||||||
console.log(" > [Client closed]");
|
|
||||||
completion.removeAllListeners();
|
|
||||||
cancel();
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
console.error(error);
|
|
||||||
if (jsonBody.stream) {
|
if (jsonBody.stream) {
|
||||||
|
// send message start
|
||||||
|
res.write(createEvent(":", "queue heartbeat 114514"));
|
||||||
|
res.write(
|
||||||
|
createEvent("data", {
|
||||||
|
id: id,
|
||||||
|
object: "chat.completion.chunk",
|
||||||
|
created: Math.floor(new Date().getTime() / 1000),
|
||||||
|
model: jsonBody.model,
|
||||||
|
system_fingerprint: "114514",
|
||||||
|
choices: [{
|
||||||
|
index: 0,
|
||||||
|
delta: {role: "assistant", content: ""},
|
||||||
|
logprobs: null,
|
||||||
|
finish_reason: null
|
||||||
|
}],
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
completion.on("completion", (id, text) => {
|
||||||
|
if (jsonBody.stream) {
|
||||||
|
// send message delta
|
||||||
res.write(
|
res.write(
|
||||||
createEvent("data", {
|
createEvent("data", {
|
||||||
choices: [
|
choices: [
|
||||||
@@ -230,25 +162,23 @@ app.post("/v1/chat/completions", OpenAIApiKeyAuth, (req, res) => {
|
|||||||
sexual: {filtered: false, severity: "safe"},
|
sexual: {filtered: false, severity: "safe"},
|
||||||
violence: {filtered: false, severity: "safe"},
|
violence: {filtered: false, severity: "safe"},
|
||||||
},
|
},
|
||||||
delta: {
|
delta: {content: text},
|
||||||
content: "Error occurred, please check the log.\n\n出现错误,请检查日志:<pre>" + error.stack || error + "</pre>",
|
|
||||||
},
|
|
||||||
finish_reason: null,
|
finish_reason: null,
|
||||||
index: 0,
|
index: 0,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
created: Math.floor(new Date().getTime() / 1000),
|
created: Math.floor(new Date().getTime() / 1000),
|
||||||
id: uuidv4(),
|
id: id,
|
||||||
model: jsonBody.model,
|
model: jsonBody.model,
|
||||||
object: "chat.completion.chunk",
|
object: "chat.completion.chunk",
|
||||||
system_fingerprint: "114514",
|
system_fingerprint: "114514",
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
res.end();
|
|
||||||
} else {
|
} else {
|
||||||
|
// 只会发一次,发送final response
|
||||||
res.write(
|
res.write(
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
id: uuidv4(),
|
id: id,
|
||||||
object: "chat.completion",
|
object: "chat.completion",
|
||||||
created: Math.floor(new Date().getTime() / 1000),
|
created: Math.floor(new Date().getTime() / 1000),
|
||||||
model: jsonBody.model,
|
model: jsonBody.model,
|
||||||
@@ -258,7 +188,7 @@ app.post("/v1/chat/completions", OpenAIApiKeyAuth, (req, res) => {
|
|||||||
index: 0,
|
index: 0,
|
||||||
message: {
|
message: {
|
||||||
role: "assistant",
|
role: "assistant",
|
||||||
content: "Error occurred, please check the log.\n\n出现错误,请检查日志:<pre>" + error.stack || error + "</pre>",
|
content: text,
|
||||||
},
|
},
|
||||||
logprobs: null,
|
logprobs: null,
|
||||||
finish_reason: "stop",
|
finish_reason: "stop",
|
||||||
@@ -274,8 +204,106 @@ app.post("/v1/chat/completions", OpenAIApiKeyAuth, (req, res) => {
|
|||||||
res.end();
|
res.end();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
completion.on("end", () => {
|
||||||
|
if (jsonBody.stream) {
|
||||||
|
res.write(createEvent("data", "[DONE]"));
|
||||||
|
res.end();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
res.on("close", () => {
|
||||||
|
console.log(" > [Client closed]");
|
||||||
|
completion.removeAllListeners();
|
||||||
|
cancel();
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
const errorMessage = "Error occurred, please check the log.\n\n出现错误,请检查日志:<pre>" + (error.stack || error) + "</pre>";
|
||||||
|
if (jsonBody.stream) {
|
||||||
|
res.write(
|
||||||
|
createEvent("data", {
|
||||||
|
choices: [
|
||||||
|
{
|
||||||
|
content_filter_results: {
|
||||||
|
hate: {filtered: false, severity: "safe"},
|
||||||
|
self_harm: {filtered: false, severity: "safe"},
|
||||||
|
sexual: {filtered: false, severity: "safe"},
|
||||||
|
violence: {filtered: false, severity: "safe"},
|
||||||
|
},
|
||||||
|
delta: {content: errorMessage},
|
||||||
|
finish_reason: null,
|
||||||
|
index: 0,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
created: Math.floor(new Date().getTime() / 1000),
|
||||||
|
id: uuidv4(),
|
||||||
|
model: jsonBody.model,
|
||||||
|
object: "chat.completion.chunk",
|
||||||
|
system_fingerprint: "114514",
|
||||||
|
})
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
res.write(
|
||||||
|
JSON.stringify({
|
||||||
|
id: uuidv4(),
|
||||||
|
object: "chat.completion",
|
||||||
|
created: Math.floor(new Date().getTime() / 1000),
|
||||||
|
model: jsonBody.model,
|
||||||
|
system_fingerprint: "114514",
|
||||||
|
choices: [
|
||||||
|
{
|
||||||
|
index: 0,
|
||||||
|
message: {
|
||||||
|
role: "assistant",
|
||||||
|
content: errorMessage,
|
||||||
|
},
|
||||||
|
logprobs: null,
|
||||||
|
finish_reason: "stop",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
usage: {
|
||||||
|
prompt_tokens: 1,
|
||||||
|
completion_tokens: 1,
|
||||||
|
total_tokens: 1,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
res.end();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Helper function: Normalize messages
|
||||||
|
function openaiNormalizeMessages(messages) {
|
||||||
|
let normalizedMessages = [];
|
||||||
|
let currentSystemMessage = "";
|
||||||
|
|
||||||
|
for (let message of messages) {
|
||||||
|
if (message.role === 'system') {
|
||||||
|
if (currentSystemMessage) {
|
||||||
|
currentSystemMessage += "\n" + message.content;
|
||||||
|
} else {
|
||||||
|
currentSystemMessage = message.content;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (currentSystemMessage) {
|
||||||
|
normalizedMessages.push({role: 'system', content: currentSystemMessage});
|
||||||
|
currentSystemMessage = "";
|
||||||
|
}
|
||||||
|
normalizedMessages.push(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentSystemMessage) {
|
||||||
|
normalizedMessages.push({role: 'system', content: currentSystemMessage});
|
||||||
|
}
|
||||||
|
|
||||||
|
return normalizedMessages;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// handle anthropic format model request
|
// handle anthropic format model request
|
||||||
app.post("/v1/messages", AnthropicApiKeyAuth, (req, res) => {
|
app.post("/v1/messages", AnthropicApiKeyAuth, (req, res) => {
|
||||||
req.rawBody = "";
|
req.rawBody = "";
|
||||||
@@ -292,7 +320,7 @@ app.post("/v1/messages", AnthropicApiKeyAuth, (req, res) => {
|
|||||||
let jsonBody = JSON.parse(req.rawBody);
|
let jsonBody = JSON.parse(req.rawBody);
|
||||||
|
|
||||||
// 处理消息格式
|
// 处理消息格式
|
||||||
jsonBody.messages = normalizeMessages(jsonBody.messages);
|
jsonBody.messages = anthropicNormalizeMessages(jsonBody.messages);
|
||||||
|
|
||||||
if (jsonBody.system) {
|
if (jsonBody.system) {
|
||||||
// 把系统消息加入messages的首条
|
// 把系统消息加入messages的首条
|
||||||
@@ -419,7 +447,7 @@ app.post("/v1/messages", AnthropicApiKeyAuth, (req, res) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// 辅助函数:规范化消息格式
|
// 辅助函数:规范化消息格式
|
||||||
function normalizeMessages(messages) {
|
function anthropicNormalizeMessages(messages) {
|
||||||
return messages.map(message => {
|
return messages.map(message => {
|
||||||
if (typeof message.content === 'string') {
|
if (typeof message.content === 'string') {
|
||||||
return message;
|
return message;
|
||||||
|
|||||||
Reference in New Issue
Block a user