mirror of
https://github.com/LLM-Red-Team/qwen-free-api.git
synced 2024-12-23 07:29:21 +08:00
支持AI绘图
This commit is contained in:
parent
d6a799bc87
commit
92712eeba3
@ -5,7 +5,7 @@
|
|||||||
![](https://img.shields.io/github/forks/llm-red-team/qwen-free-api.svg)
|
![](https://img.shields.io/github/forks/llm-red-team/qwen-free-api.svg)
|
||||||
![](https://img.shields.io/docker/pulls/vinlic/qwen-free-api.svg)
|
![](https://img.shields.io/docker/pulls/vinlic/qwen-free-api.svg)
|
||||||
|
|
||||||
支持高速流式输出、支持多轮对话、支持长文档解读、支持图像解析,零配置部署,多路token支持,自动清理会话痕迹。
|
支持高速流式输出、支持多轮对话、支持AI绘图、支持长文档解读(正在开发)、图像解析(正在开发),零配置部署,多路token支持,自动清理会话痕迹。
|
||||||
|
|
||||||
与ChatGPT接口完全兼容。
|
与ChatGPT接口完全兼容。
|
||||||
|
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import { URL } from "url";
|
||||||
import { PassThrough } from "stream";
|
import { PassThrough } from "stream";
|
||||||
import path from "path";
|
import path from "path";
|
||||||
import _ from "lodash";
|
import _ from "lodash";
|
||||||
@ -56,7 +57,7 @@ async function removeConversation(convId: string, ticket: string) {
|
|||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
Cookie: generateCookie(ticket),
|
Cookie: generateCookie(ticket),
|
||||||
...FAKE_HEADERS
|
...FAKE_HEADERS,
|
||||||
},
|
},
|
||||||
timeout: 15000,
|
timeout: 15000,
|
||||||
validateStatus: () => true,
|
validateStatus: () => true,
|
||||||
@ -122,9 +123,7 @@ async function createCompletion(
|
|||||||
);
|
);
|
||||||
|
|
||||||
// 异步移除会话,如果消息不合规,此操作可能会抛出数据库错误异常,请忽略
|
// 异步移除会话,如果消息不合规,此操作可能会抛出数据库错误异常,请忽略
|
||||||
removeConversation(answer.id, ticket).catch((err) =>
|
removeConversation(answer.id, ticket).catch((err) => console.error(err));
|
||||||
console.error(err)
|
|
||||||
);
|
|
||||||
|
|
||||||
return answer;
|
return answer;
|
||||||
})().catch((err) => {
|
})().catch((err) => {
|
||||||
@ -197,9 +196,7 @@ async function createCompletionStream(
|
|||||||
`Stream has completed transfer ${util.timestamp() - streamStartTime}ms`
|
`Stream has completed transfer ${util.timestamp() - streamStartTime}ms`
|
||||||
);
|
);
|
||||||
// 流传输结束后异步移除会话,如果消息不合规,此操作可能会抛出数据库错误异常,请忽略
|
// 流传输结束后异步移除会话,如果消息不合规,此操作可能会抛出数据库错误异常,请忽略
|
||||||
removeConversation(convId, ticket).catch((err) =>
|
removeConversation(convId, ticket).catch((err) => console.error(err));
|
||||||
console.error(err)
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
})().catch((err) => {
|
})().catch((err) => {
|
||||||
if (retryCount < MAX_RETRY_COUNT) {
|
if (retryCount < MAX_RETRY_COUNT) {
|
||||||
@ -207,12 +204,7 @@ async function createCompletionStream(
|
|||||||
logger.warn(`Try again after ${RETRY_DELAY / 1000}s...`);
|
logger.warn(`Try again after ${RETRY_DELAY / 1000}s...`);
|
||||||
return (async () => {
|
return (async () => {
|
||||||
await new Promise((resolve) => setTimeout(resolve, RETRY_DELAY));
|
await new Promise((resolve) => setTimeout(resolve, RETRY_DELAY));
|
||||||
return createCompletionStream(
|
return createCompletionStream(model, messages, ticket, retryCount + 1);
|
||||||
model,
|
|
||||||
messages,
|
|
||||||
ticket,
|
|
||||||
retryCount + 1
|
|
||||||
);
|
|
||||||
})();
|
})();
|
||||||
}
|
}
|
||||||
throw err;
|
throw err;
|
||||||
@ -268,13 +260,17 @@ function messagesPrepare(messages: any[]) {
|
|||||||
return _content + (v["text"] || "");
|
return _content + (v["text"] || "");
|
||||||
}, content);
|
}, content);
|
||||||
}
|
}
|
||||||
return (content += `<|im_start|>${message.role || "user"}\n${message.content}<|im_end|>\n`);
|
return (content += `<|im_start|>${message.role || "user"}\n${
|
||||||
|
message.content
|
||||||
|
}<|im_end|>\n`);
|
||||||
}, "");
|
}, "");
|
||||||
return [{
|
return [
|
||||||
|
{
|
||||||
role: "user",
|
role: "user",
|
||||||
contentType: "text",
|
contentType: "text",
|
||||||
content
|
content,
|
||||||
}];
|
},
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -324,20 +320,33 @@ async function receiveStream(stream: any): Promise<any> {
|
|||||||
if (_.isError(result))
|
if (_.isError(result))
|
||||||
throw new Error(`Stream response invalid: ${event.data}`);
|
throw new Error(`Stream response invalid: ${event.data}`);
|
||||||
if (!data.id && result.sessionId) data.id = result.sessionId;
|
if (!data.id && result.sessionId) data.id = result.sessionId;
|
||||||
if (result.msgStatus != "finished") {
|
|
||||||
const text = (result.contents || []).reduce((str, part) => {
|
const text = (result.contents || []).reduce((str, part) => {
|
||||||
const { role, content } = part;
|
const { role, content } = part;
|
||||||
if (role != "assistant" && !_.isString(content)) return str;
|
if (role != "assistant" && !_.isString(content)) return str;
|
||||||
return str + content;
|
return str + content;
|
||||||
}, "");
|
}, "");
|
||||||
const chunk = text.substring(
|
let chunk = text.substring(
|
||||||
data.choices[0].message.content.length - textOffset,
|
data.choices[0].message.content.length - textOffset,
|
||||||
text.length
|
text.length
|
||||||
);
|
);
|
||||||
|
if (chunk && result.contentType == "text2image") {
|
||||||
|
chunk = chunk.replace(
|
||||||
|
/https?:\/\/[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_\+.~#?&//=\,]*)/gi,
|
||||||
|
(url) => {
|
||||||
|
const urlObj = new URL(url);
|
||||||
|
urlObj.search = "";
|
||||||
|
return urlObj.toString();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (result.msgStatus != "finished") {
|
||||||
|
if (result.contentType == "text")
|
||||||
data.choices[0].message.content += chunk;
|
data.choices[0].message.content += chunk;
|
||||||
} else {
|
} else {
|
||||||
|
data.choices[0].message.content += chunk;
|
||||||
if (!result.canShare)
|
if (!result.canShare)
|
||||||
data.choices[0].message.content += '\n[内容由于不合规被停止生成,我们换个话题吧]';
|
data.choices[0].message.content +=
|
||||||
|
"\n[内容由于不合规被停止生成,我们换个话题吧]";
|
||||||
if (result.errorCode)
|
if (result.errorCode)
|
||||||
data.choices[0].message.content += `服务暂时不可用,第三方响应错误:${result.errorCode}`;
|
data.choices[0].message.content += `服务暂时不可用,第三方响应错误:${result.errorCode}`;
|
||||||
resolve(data);
|
resolve(data);
|
||||||
@ -367,7 +376,7 @@ function createTransStream(stream: any, endCallback?: Function) {
|
|||||||
const created = util.unixTimestamp();
|
const created = util.unixTimestamp();
|
||||||
// 创建转换流
|
// 创建转换流
|
||||||
const transStream = new PassThrough();
|
const transStream = new PassThrough();
|
||||||
let content = '';
|
let content = "";
|
||||||
!transStream.closed &&
|
!transStream.closed &&
|
||||||
transStream.write(
|
transStream.write(
|
||||||
`data: ${JSON.stringify({
|
`data: ${JSON.stringify({
|
||||||
@ -392,49 +401,59 @@ function createTransStream(stream: any, endCallback?: Function) {
|
|||||||
const result = _.attempt(() => JSON.parse(event.data));
|
const result = _.attempt(() => JSON.parse(event.data));
|
||||||
if (_.isError(result))
|
if (_.isError(result))
|
||||||
throw new Error(`Stream response invalid: ${event.data}`);
|
throw new Error(`Stream response invalid: ${event.data}`);
|
||||||
if (result.msgStatus != "finished") {
|
|
||||||
const text = (result.contents || []).reduce((str, part) => {
|
const text = (result.contents || []).reduce((str, part) => {
|
||||||
const { role, content } = part;
|
const { role, content } = part;
|
||||||
if (role != "assistant" && !_.isString(content)) return str;
|
if (role != "assistant" && !_.isString(content)) return str;
|
||||||
return str + content;
|
return str + content;
|
||||||
}, "");
|
}, "");
|
||||||
const chunk = text.substring(content.length, text.length);
|
let chunk = text.substring(content.length, text.length);
|
||||||
if(chunk) {
|
if (chunk && result.contentType == "text2image") {
|
||||||
|
chunk = chunk.replace(
|
||||||
|
/https?:\/\/[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_\+.~#?&//=\,]*)/gi,
|
||||||
|
(url) => {
|
||||||
|
const urlObj = new URL(url);
|
||||||
|
urlObj.search = "";
|
||||||
|
return urlObj.toString();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (result.msgStatus != "finished") {
|
||||||
|
if (chunk && result.contentType == "text") {
|
||||||
content += chunk;
|
content += chunk;
|
||||||
const data = `data: ${JSON.stringify({
|
const data = `data: ${JSON.stringify({
|
||||||
id: result.conversation_id,
|
id: result.sessionId,
|
||||||
model: MODEL_NAME,
|
model: MODEL_NAME,
|
||||||
object: 'chat.completion.chunk',
|
object: "chat.completion.chunk",
|
||||||
choices: [
|
choices: [
|
||||||
{ index: 0, delta: { content: chunk }, finish_reason: null }
|
{ index: 0, delta: { content: chunk }, finish_reason: null },
|
||||||
],
|
],
|
||||||
created
|
created,
|
||||||
})}\n\n`;
|
})}\n\n`;
|
||||||
!transStream.closed && transStream.write(data);
|
!transStream.closed && transStream.write(data);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let delta = {};
|
const delta = { content: chunk || "" };
|
||||||
if (!result.canShare)
|
if (!result.canShare)
|
||||||
delta = { content: '\n[内容由于不合规被停止生成,我们换个话题吧]' }
|
delta.content += "\n[内容由于不合规被停止生成,我们换个话题吧]";
|
||||||
if (result.errorCode)
|
if (result.errorCode)
|
||||||
delta = { content: `服务暂时不可用,第三方响应错误:${result.errorCode}` };
|
delta.content += `服务暂时不可用,第三方响应错误:${result.errorCode}`;
|
||||||
const data = `data: ${JSON.stringify({
|
const data = `data: ${JSON.stringify({
|
||||||
id: result.conversation_id,
|
id: result.sessionId,
|
||||||
model: MODEL_NAME,
|
model: MODEL_NAME,
|
||||||
object: 'chat.completion.chunk',
|
object: "chat.completion.chunk",
|
||||||
choices: [
|
choices: [
|
||||||
{
|
{
|
||||||
index: 0,
|
index: 0,
|
||||||
delta,
|
delta,
|
||||||
finish_reason: 'stop'
|
finish_reason: "stop",
|
||||||
}
|
},
|
||||||
],
|
],
|
||||||
usage: { prompt_tokens: 1, completion_tokens: 1, total_tokens: 2 },
|
usage: { prompt_tokens: 1, completion_tokens: 1, total_tokens: 2 },
|
||||||
created
|
created,
|
||||||
})}\n\n`;
|
})}\n\n`;
|
||||||
!transStream.closed && transStream.write(data);
|
!transStream.closed && transStream.write(data);
|
||||||
!transStream.closed && transStream.end('data: [DONE]\n\n');
|
!transStream.closed && transStream.end("data: [DONE]\n\n");
|
||||||
content = '';
|
content = "";
|
||||||
endCallback && endCallback(result.sessionId);
|
endCallback && endCallback(result.sessionId);
|
||||||
}
|
}
|
||||||
// else
|
// else
|
||||||
@ -473,22 +492,22 @@ function tokenSplit(authorization: string) {
|
|||||||
*/
|
*/
|
||||||
function generateCookie(ticket: string) {
|
function generateCookie(ticket: string) {
|
||||||
return [
|
return [
|
||||||
// `login_aliyunid_csrf=_csrf_tk_1338411200877960`,
|
|
||||||
// '_samesite_flag_=true',
|
|
||||||
// 'cookie2=17f5d8b4b310ced751b4884bf6f90a59',
|
|
||||||
// `munb=2205561979317`,
|
|
||||||
// `csg=d2a7667c`,
|
|
||||||
// `t=b147e56818bb17773dbbac0b0f5124d4`,
|
|
||||||
// `_tb_token_=e0e1e0eaf6397`,
|
|
||||||
`login_tongyi_ticket=${ticket}`,
|
`login_tongyi_ticket=${ticket}`,
|
||||||
// `cna=2BIPGQLBaUoCAXF0dTVJX4J7`,
|
'_samesite_flag_=true',
|
||||||
// `cnaui=1717007863755884`,
|
`t=${util.uuid(false)}`,
|
||||||
// `atpsida=96034589ac4b10f25d62eeb3_1711200918_2`,
|
// `login_aliyunid_csrf=_csrf_tk_${util.generateRandomString({ charset: 'numeric', length: 15 })}`,
|
||||||
// `isg=BJeXsmIBvhDupD4W9uGbnvw8Jg3h3Gs-fDl6NunHdWZIGLxa9a2mj8r6e7gGxkO2`,
|
// `cookie2=${util.uuid(false)}`,
|
||||||
// `tfstk=crDFBRcFK801Valh3RezgJtCWRxdaCMmeNr7teNJ-WUBJiF8usY1ylAoB5PfbaVh.`,
|
// `munb=22${util.generateRandomString({ charset: 'numeric', length: 11 })}`,
|
||||||
// `aui=1717007863755884`,
|
// `csg=`,
|
||||||
// `sca=48fca504`
|
// `_tb_token_=${util.generateRandomString({ length: 10, capitalization: 'lowercase' })}`,
|
||||||
].join('; ');
|
// `cna=`,
|
||||||
|
// `cnaui=`,
|
||||||
|
// `atpsida=`,
|
||||||
|
// `isg=`,
|
||||||
|
// `tfstk=`,
|
||||||
|
// `aui=`,
|
||||||
|
// `sca=`
|
||||||
|
].join("; ");
|
||||||
}
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
Loading…
Reference in New Issue
Block a user