13 Commits

Author SHA1 Message Date
Vinlic科技
38d59e20fc Merge pull request #141 from Yanyutin753/优化web搜索输出
🦄 优化web搜索输出
2024-10-27 21:12:00 +08:00
Clivia
bc37f56d1f 🦄 优化web搜索输出
🦄 优化web搜索输出
2024-10-27 20:13:20 +08:00
Vinlic
b2ae0554ee Release 0.0.34 2024-07-12 11:02:43 +08:00
Vinlic
399de41b61 补充请求新增项 2024-07-12 11:02:36 +08:00
Vinlic科技
44316372a5 Update README.md 2024-05-15 13:35:10 +08:00
Vinlic科技
fcc2c9f795 Update README.md 2024-05-10 15:52:03 +08:00
Vinlic科技
a626a78553 Update README.md 2024-05-10 15:51:38 +08:00
Vinlic科技
5f2eb803aa Update README.md 2024-05-04 17:06:02 +08:00
Vinlic科技
684aedae1c Update README.md 2024-05-04 17:05:50 +08:00
Vinlic
984d724367 Release 0.0.33 2024-04-30 11:54:17 +08:00
Vinlic
889c874264 支持kimi+智能体调用 2024-04-30 11:53:51 +08:00
Vinlic
6105410dd2 Release 0.0.32 2024-04-28 17:54:44 +08:00
Vinlic
01ff5c250a 处理首轮传送文件时导致对话合并问题 2024-04-28 17:54:31 +08:00
4 changed files with 63 additions and 39 deletions

View File

@@ -11,11 +11,11 @@
![](https://img.shields.io/github/forks/llm-red-team/kimi-free-api.svg)
![](https://img.shields.io/docker/pulls/vinlic/kimi-free-api.svg)
支持高速流式输出、支持多轮对话、支持联网搜索、支持长文档解读、支持图像解析零配置部署多路token支持自动清理会话痕迹。
支持高速流式输出、支持多轮对话、支持联网搜索、支持智能体对话、支持长文档解读、支持图像OCR零配置部署多路token支持自动清理会话痕迹。
与ChatGPT接口完全兼容。
还有以下个free-api欢迎关注
还有以下个free-api欢迎关注
阶跃星辰 (跃问StepChat) 接口转API [step-free-api](https://github.com/LLM-Red-Team/step-free-api)
@@ -27,6 +27,10 @@
讯飞星火Spark接口转API [spark-free-api](https://github.com/LLM-Red-Team/spark-free-api)
MiniMax海螺AI接口转API [hailuo-free-api](https://github.com/LLM-Red-Team/hailuo-free-api)
深度求索DeepSeek接口转API [deepseek-free-api](https://github.com/LLM-Red-Team/deepseek-free-api)
聆心智能 (Emohaa) 接口转API [emohaa-free-api](https://github.com/LLM-Red-Team/emohaa-free-api)
## 目录
@@ -85,11 +89,17 @@ https://udify.app/chat/Po0F6BMJ15q5vu2P
![联网搜索](./doc/example-2.png)
### 智能体对话Demo
此处使用 [翻译通](https://kimi.moonshot.cn/chat/coo6l3pkqq4ri39f36bg) 智能体。
![智能体对话](./doc/example-7.png)
### 长文档解读Demo
![长文档解读](./doc/example-5.png)
### 图像解析Demo
### 图像OCR Demo
![图像解析](./doc/example-3.png)
@@ -269,7 +279,8 @@ Authorization: Bearer [refresh_token]
请求数据:
```json
{
// 模型名称随意填写如果不希望输出检索过程模型名称请包含silent_search
// model随意填写如果不希望输出检索过程模型名称请包含silent_search
// 如果使用kimi+智能体model请填写智能体ID就是浏览器地址栏上尾部的一串英文+数字20个字符的ID
"model": "kimi",
// 目前多轮对话基于消息合并实现某些场景可能导致能力下降且受单轮最大Token数限制
// 如果您想获得原生的多轮对话体验可以传入首轮消息获得的id来接续上下文注意如果使用这个首轮必须传none否则第二轮会空响应
@@ -377,7 +388,7 @@ Authorization: Bearer [refresh_token]
}
```
### 图像解析
### 图像OCR
提供一个可访问的图像URL或者BASE64_URL进行解析。

BIN
doc/example-7.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

View File

@@ -1,6 +1,6 @@
{
"name": "kimi-free-api",
"version": "0.0.31",
"version": "0.0.34",
"description": "Kimi Free API Server",
"type": "module",
"main": "dist/index.js",

View File

@@ -137,6 +137,7 @@ async function getUserInfo(accessToken: string, refreshToken: string) {
headers: {
Authorization: `Bearer ${accessToken}`,
Referer: 'https://kimi.moonshot.cn/',
'X-Msh-Platform': 'web',
'X-Traffic-Id': `7${util.generateRandomString({ length: 18, charset: 'numeric' })}`,
...FAKE_HEADERS
},
@@ -153,18 +154,21 @@ async function getUserInfo(accessToken: string, refreshToken: string) {
*
* @param refreshToken 用于刷新access_token的refresh_token
*/
async function createConversation(name: string, refreshToken: string) {
async function createConversation(model: string, name: string, refreshToken: string) {
const {
accessToken,
userId
} = await acquireToken(refreshToken);
const result = await axios.post('https://kimi.moonshot.cn/api/chat', {
born_from: '',
is_example: false,
kimiplus_id: /^[0-9a-z]{20}$/.test(model) ? model : 'kimi',
name
}, {
headers: {
Authorization: `Bearer ${accessToken}`,
Referer: 'https://kimi.moonshot.cn/',
'X-Msh-Platform': 'web',
'X-Traffic-Id': userId,
...FAKE_HEADERS
},
@@ -193,6 +197,7 @@ async function removeConversation(convId: string, refreshToken: string) {
headers: {
Authorization: `Bearer ${accessToken}`,
Referer: `https://kimi.moonshot.cn/chat/${convId}`,
'X-Msh-Platform': 'web',
'X-Traffic-Id': userId,
...FAKE_HEADERS
},
@@ -221,6 +226,7 @@ async function promptSnippetSubmit(query: string, refreshToken: string) {
headers: {
Authorization: `Bearer ${accessToken}`,
Referer: 'https://kimi.moonshot.cn/',
'X-Msh-Platform': 'web',
'X-Traffic-Id': userId,
...FAKE_HEADERS
},
@@ -253,7 +259,7 @@ async function createCompletion(model = MODEL_NAME, messages: any[], refreshToke
.catch(err => logger.error(err));
// 创建会话
const convId = /[0-9a-zA-Z]{20}/.test(refConvId) ? refConvId : await createConversation("未命名会话", refreshToken);
const convId = /[0-9a-zA-Z]{20}/.test(refConvId) ? refConvId : await createConversation(model, "未命名会话", refreshToken);
// 请求流
const {
@@ -261,20 +267,18 @@ async function createCompletion(model = MODEL_NAME, messages: any[], refreshToke
userId
} = await acquireToken(refreshToken);
const sendMessages = messagesPrepare(messages, !!refConvId);
console.log(convId, {
messages: sendMessages,
refs,
use_search: useSearch
});
const result = await axios.post(`https://kimi.moonshot.cn/api/chat/${convId}/completion/stream`, {
kimiplus_id: /^[0-9a-z]{20}$/.test(model) ? model : 'kimi',
messages: sendMessages,
refs,
is_pro_search: false,
use_search: useSearch
}, {
headers: {
Authorization: `Bearer ${accessToken}`,
Referer: `https://kimi.moonshot.cn/chat/${convId}`,
'Priority': 'u=1, i',
'X-Msh-Platform': 'web',
'X-Traffic-Id': userId,
...FAKE_HEADERS
},
@@ -334,7 +338,7 @@ async function createCompletionStream(model = MODEL_NAME, messages: any[], refre
.catch(err => logger.error(err));
// 创建会话
const convId = /[0-9a-zA-Z]{20}/.test(refConvId) ? refConvId : await createConversation("未命名会话", refreshToken);
const convId = /[0-9a-zA-Z]{20}/.test(refConvId) ? refConvId : await createConversation(model, "未命名会话", refreshToken);
// 请求流
const {
@@ -343,6 +347,7 @@ async function createCompletionStream(model = MODEL_NAME, messages: any[], refre
} = await acquireToken(refreshToken);
const sendMessages = messagesPrepare(messages, !!refConvId);
const result = await axios.post(`https://kimi.moonshot.cn/api/chat/${convId}/completion/stream`, {
kimiplus_id: /^[0-9a-z]{20}$/.test(model) ? model : undefined,
messages: sendMessages,
refs,
use_search: useSearch
@@ -353,6 +358,7 @@ async function createCompletionStream(model = MODEL_NAME, messages: any[], refre
Authorization: `Bearer ${accessToken}`,
Referer: `https://kimi.moonshot.cn/chat/${convId}`,
'Priority': 'u=1, i',
'X-Msh-Platform': 'web',
'X-Traffic-Id': userId,
...FAKE_HEADERS
},
@@ -400,6 +406,7 @@ async function fakeRequest(refreshToken: string) {
headers: {
Authorization: `Bearer ${accessToken}`,
Referer: `https://kimi.moonshot.cn/`,
'X-Msh-Platform': 'web',
'X-Traffic-Id': userId,
...FAKE_HEADERS
}
@@ -461,12 +468,25 @@ function extractRefFileUrls(messages: any[]) {
* @param isRefConv 是否为引用会话
*/
function messagesPrepare(messages: any[], isRefConv = false) {
// 注入消息提升注意力
let latestMessage = messages[messages.length - 1];
let hasFileOrImage = Array.isArray(latestMessage.content)
&& latestMessage.content.some(v => (typeof v === 'object' && ['file', 'image_url'].includes(v['type'])));
// 第二轮开始注入system prompt
if (messages.length > 2) {
let content;
if (isRefConv || messages.length < 2) {
content = messages.reduce((content, message) => {
if (_.isArray(message.content)) {
return message.content.reduce((_content, v) => {
if (!_.isObject(v) || v['type'] != 'text') return _content;
return _content + `${v["text"] || ""}\n`;
}, content);
}
return content += `${message.role == 'user' ? wrapUrlsToTags(message.content) : message.content}\n`;
}, '')
logger.info("\n透传内容\n" + content);
}
else {
// 注入消息提升注意力
let latestMessage = messages[messages.length - 1];
let hasFileOrImage = Array.isArray(latestMessage.content)
&& latestMessage.content.some(v => (typeof v === 'object' && ['file', 'image_url'].includes(v['type'])));
// 第二轮开始注入system prompt
if (hasFileOrImage) {
let newFileMessage = {
"content": "关注用户最新发送文件和消息",
@@ -482,22 +502,6 @@ function messagesPrepare(messages: any[], isRefConv = false) {
messages.splice(messages.length - 1, 0, newTextMessage);
logger.info("注入提升尾部消息注意力system prompt");
}
}
let content;
if (isRefConv || messages.length < 2) {
content = messages.reduce((content, message) => {
if (_.isArray(message.content)) {
return message.content.reduce((_content, v) => {
if (!_.isObject(v) || v['type'] != 'text') return _content;
return _content + `${v["text"] || ""}\n`;
}, content);
}
return content += `${message.role == 'user' ? wrapUrlsToTags(message.content) : message.content}\n`;
}, '')
logger.info("\n透传内容\n" + content);
}
else {
content = messages.reduce((content, message) => {
if (_.isArray(message.content)) {
return message.content.reduce((_content, v) => {
@@ -545,6 +549,7 @@ async function preSignUrl(filename: string, refreshToken: string) {
headers: {
Authorization: `Bearer ${accessToken}`,
Referer: `https://kimi.moonshot.cn/`,
'X-Msh-Platform': 'web',
'X-Traffic-Id': userId,
...FAKE_HEADERS
},
@@ -630,6 +635,7 @@ async function uploadFile(fileUrl: string, refreshToken: string) {
'Content-Type': mimeType,
Authorization: `Bearer ${accessToken}`,
Referer: `https://kimi.moonshot.cn/`,
'X-Msh-Platform': 'web',
'X-Traffic-Id': userId,
...FAKE_HEADERS
},
@@ -651,6 +657,7 @@ async function uploadFile(fileUrl: string, refreshToken: string) {
headers: {
Authorization: `Bearer ${accessToken}`,
Referer: `https://kimi.moonshot.cn/`,
'X-Msh-Platform': 'web',
'X-Traffic-Id': userId,
...FAKE_HEADERS
}
@@ -672,6 +679,7 @@ async function uploadFile(fileUrl: string, refreshToken: string) {
headers: {
Authorization: `Bearer ${accessToken}`,
Referer: `https://kimi.moonshot.cn/`,
'X-Msh-Platform': 'web',
'X-Traffic-Id': userId,
...FAKE_HEADERS
}
@@ -715,6 +723,7 @@ function checkResult(result: AxiosResponse, refreshToken: string) {
* @param stream 消息流
*/
async function receiveStream(model: string, convId: string, stream: any) {
let webSearchCount = 0;
return new Promise((resolve, reject) => {
// 消息初始化
const data = {
@@ -748,8 +757,10 @@ async function receiveStream(model: string, convId: string, stream: any) {
resolve(data);
}
// 处理联网搜索
else if (!silentSearch && result.event == 'search_plus' && result.msg && result.msg.type == 'get_res')
refContent += `${result.msg.title} - ${result.msg.url}\n`;
else if (!silentSearch && result.event == 'search_plus' && result.msg && result.msg.type == 'get_res'){
webSearchCount += 1;
refContent += `【检索 ${webSearchCount}】 [${result.msg.title}](${result.msg.url})\n\n`;
}
// else
// logger.warn(result.event, result);
}
@@ -780,6 +791,7 @@ function createTransStream(model: string, convId: string, stream: any, endCallba
const created = util.unixTimestamp();
// 创建转换流
const transStream = new PassThrough();
let webSearchCount = 0;
let searchFlag = false;
const silentSearch = model.indexOf('silent_search') != -1;
!transStream.closed && transStream.write(`data: ${JSON.stringify({
@@ -839,6 +851,7 @@ function createTransStream(model: string, convId: string, stream: any, endCallba
else if (!silentSearch && result.event == 'search_plus' && result.msg && result.msg.type == 'get_res') {
if (!searchFlag)
searchFlag = true;
webSearchCount += 1;
const data = `data: ${JSON.stringify({
id: convId,
model,
@@ -846,7 +859,7 @@ function createTransStream(model: string, convId: string, stream: any, endCallba
choices: [
{
index: 0, delta: {
content: `检索 ${result.msg.title} - ${result.msg.url} ...\n`
content: `检索 ${webSearchCount}】 [${result.msg.title}](${result.msg.url})\n`
}, finish_reason: null
}
],