From 909796bd91d7ce22ef18a23ad00041a08ef83d81 Mon Sep 17 00:00:00 2001 From: Vinlic Date: Wed, 20 Mar 2024 01:37:25 +0800 Subject: [PATCH] =?UTF-8?q?=E6=94=AF=E6=8C=81=E6=A8=A1=E5=9E=8B=E5=90=8D?= =?UTF-8?q?=E7=A7=B0=E5=8C=85=E5=90=ABsilent=5Fsearch=E6=9D=A5=E9=9D=99?= =?UTF-8?q?=E9=BB=98=E6=90=9C=E7=B4=A2=E4=B8=8D=E8=BE=93=E5=87=BA=E6=90=9C?= =?UTF-8?q?=E7=B4=A2=E8=BF=87=E7=A8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 6 ++++++ package.json | 2 +- src/api/controllers/chat.ts | 36 +++++++++++++++++++++--------------- src/api/routes/chat.ts | 5 +++-- 4 files changed, 31 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 207ef5f..d4888d1 100644 --- a/README.md +++ b/README.md @@ -201,6 +201,8 @@ Authorization: Bearer [refresh_token] 请求数据: ```json { + // 模型名称随意填写,如果不希望输出检索过程模型名称请包含silent_search + "model": "kimi", "messages": [ { "role": "user", @@ -254,6 +256,8 @@ Authorization: Bearer [refresh_token] 请求数据: ```json { + // 模型名称随意填写,如果不希望输出检索过程模型名称请包含silent_search + "model": "kimi", "messages": [ { "role": "user", @@ -318,6 +322,8 @@ Authorization: Bearer [refresh_token] 请求数据: ```json { + // 模型名称随意填写,如果不希望输出检索过程模型名称请包含silent_search + "model": "kimi", "messages": [ { "role": "user", diff --git a/package.json b/package.json index 71f8ac2..767783e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "kimi-free-api", - "version": "0.0.15", + "version": "0.0.16", "description": "Kimi Free API Server", "type": "module", "main": "dist/index.js", diff --git a/src/api/controllers/chat.ts b/src/api/controllers/chat.ts index bb82a12..dee46b4 100644 --- a/src/api/controllers/chat.ts +++ b/src/api/controllers/chat.ts @@ -164,12 +164,13 @@ async function removeConversation(convId: string, refreshToken: string) { /** * 同步对话补全 * + * @param model 模型名称 * @param messages 参考gpt系列消息格式,多轮对话请完整提供上下文 * @param refreshToken 用于刷新access_token的refresh_token * @param useSearch 是否开启联网搜索 * @param retryCount 重试次数 */ -async function createCompletion(messages: any[], refreshToken: string, useSearch = true, retryCount = 0) { +async function createCompletion(model = MODEL_NAME, messages: any[], refreshToken: string, useSearch = true, retryCount = 0) { return (async () => { logger.info(messages); @@ -204,7 +205,7 @@ async function createCompletion(messages: any[], refreshToken: string, useSearch const streamStartTime = util.timestamp(); // 接收流为输出文本 - const answer = await receiveStream(convId, result.data); + const answer = await receiveStream(model, convId, result.data); logger.success(`Stream has completed transfer ${util.timestamp() - streamStartTime}ms`); // 异步移除会话,如果消息不合规,此操作可能会抛出数据库错误异常,请忽略 @@ -219,7 +220,7 @@ async function createCompletion(messages: any[], refreshToken: string, useSearch logger.warn(`Try again after ${RETRY_DELAY / 1000}s...`); return (async () => { await new Promise(resolve => setTimeout(resolve, RETRY_DELAY)); - return createCompletion(messages, refreshToken, useSearch, retryCount + 1); + return createCompletion(model, messages, refreshToken, useSearch, retryCount + 1); })(); } throw err; @@ -229,12 +230,13 @@ async function createCompletion(messages: any[], refreshToken: string, useSearch /** * 流式对话补全 * + * @param model 模型名称 * @param messages 参考gpt系列消息格式,多轮对话请完整提供上下文 * @param refreshToken 用于刷新access_token的refresh_token * @param useSearch 是否开启联网搜索 * @param retryCount 重试次数 */ -async function createCompletionStream(messages: any[], refreshToken: string, useSearch = true, retryCount = 0) { +async function createCompletionStream(model = MODEL_NAME, messages: any[], refreshToken: string, useSearch = true, retryCount = 0) { return (async () => { logger.info(messages); @@ -268,7 +270,7 @@ async function createCompletionStream(messages: any[], refreshToken: string, use }); const streamStartTime = util.timestamp(); // 创建转换流将消息格式转换为gpt兼容格式 - return createTransStream(convId, result.data, () => { + return createTransStream(model, convId, result.data, () => { logger.success(`Stream has completed transfer ${util.timestamp() - streamStartTime}ms`); // 流传输结束后异步移除会话,如果消息不合规,此操作可能会抛出数据库错误异常,请忽略 removeConversation(convId, refreshToken) @@ -281,7 +283,7 @@ async function createCompletionStream(messages: any[], refreshToken: string, use logger.warn(`Try again after ${RETRY_DELAY / 1000}s...`); return (async () => { await new Promise(resolve => setTimeout(resolve, RETRY_DELAY)); - return createCompletionStream(messages, refreshToken, useSearch, retryCount + 1); + return createCompletionStream(model, messages, refreshToken, useSearch, retryCount + 1); })(); } throw err; @@ -541,15 +543,16 @@ function checkResult(result: AxiosResponse, refreshToken: string) { /** * 从流接收完整的消息内容 * + * @param model 模型名称 * @param convId 会话ID * @param stream 消息流 */ -async function receiveStream(convId: string, stream: any) { +async function receiveStream(model: string, convId: string, stream: any) { return new Promise((resolve, reject) => { // 消息初始化 const data = { id: convId, - model: MODEL_NAME, + model, object: 'chat.completion', choices: [ { index: 0, message: { role: 'assistant', content: '' }, finish_reason: 'stop' } @@ -558,6 +561,7 @@ async function receiveStream(convId: string, stream: any) { created: util.unixTimestamp() }; let refContent = ''; + const silentSearch = model.indexOf('silent_search') != -1; const parser = createParser(event => { try { if (event.type !== "event") return; @@ -576,7 +580,7 @@ async function receiveStream(convId: string, stream: any) { resolve(data); } // 处理联网搜索 - else if (result.event == 'search_plus' && result.msg && result.msg.type == 'get_res') + else if (!silentSearch && result.event == 'search_plus' && result.msg && result.msg.type == 'get_res') refContent += `${result.msg.title}(${result.msg.url})\n`; // else // logger.warn(result.event, result); @@ -598,19 +602,21 @@ async function receiveStream(convId: string, stream: any) { * * 将流格式转换为gpt兼容流格式 * + * @param model 模型名称 * @param convId 会话ID * @param stream 消息流 * @param endCallback 传输结束回调 */ -function createTransStream(convId: string, stream: any, endCallback?: Function) { +function createTransStream(model: string, convId: string, stream: any, endCallback?: Function) { // 消息创建时间 const created = util.unixTimestamp(); // 创建转换流 const transStream = new PassThrough(); let searchFlag = false; + const silentSearch = model.indexOf('silent_search') != -1; !transStream.closed && transStream.write(`data: ${JSON.stringify({ id: convId, - model: MODEL_NAME, + model, object: 'chat.completion.chunk', choices: [ { index: 0, delta: { role: 'assistant', content: '' }, finish_reason: null } @@ -628,7 +634,7 @@ function createTransStream(convId: string, stream: any, endCallback?: Function) if (result.event == 'cmpl') { const data = `data: ${JSON.stringify({ id: convId, - model: MODEL_NAME, + model, object: 'chat.completion.chunk', choices: [ { index: 0, delta: { content: (searchFlag ? '\n' : '') + result.text }, finish_reason: null } @@ -643,7 +649,7 @@ function createTransStream(convId: string, stream: any, endCallback?: Function) else if (result.event == 'all_done' || result.event == 'error') { const data = `data: ${JSON.stringify({ id: convId, - model: MODEL_NAME, + model, object: 'chat.completion.chunk', choices: [ { @@ -660,12 +666,12 @@ function createTransStream(convId: string, stream: any, endCallback?: Function) endCallback && endCallback(); } // 处理联网搜索 - else if (result.event == 'search_plus' && result.msg && result.msg.type == 'get_res') { + else if (!silentSearch && result.event == 'search_plus' && result.msg && result.msg.type == 'get_res') { if (!searchFlag) searchFlag = true; const data = `data: ${JSON.stringify({ id: convId, - model: MODEL_NAME, + model, object: 'chat.completion.chunk', choices: [ { diff --git a/src/api/routes/chat.ts b/src/api/routes/chat.ts index 5f2346b..2810d37 100644 --- a/src/api/routes/chat.ts +++ b/src/api/routes/chat.ts @@ -19,15 +19,16 @@ export default { const tokens = chat.tokenSplit(request.headers.authorization); // 随机挑选一个refresh_token const token = _.sample(tokens); + const model = request.body.model; const messages = request.body.messages; if (request.body.stream) { - const stream = await chat.createCompletionStream(request.body.messages, token, request.body.use_search); + const stream = await chat.createCompletionStream(model, messages, token, request.body.use_search); return new Response(stream, { type: "text/event-stream" }); } else - return await chat.createCompletion(messages, token, request.body.use_search); + return await chat.createCompletion(model, messages, token, request.body.use_search); } }