Docker部署kimi-free-api
Contents
简介
🚀 KIMI AI 长文本大模型逆向API【特长:长文本解读整理】,支持高速流式输出、智能体对话、联网搜索、探索版、K1思考模型、长文档解读、图像解析、多轮对话,零配置部署,多路token支持,自动清理会话痕迹,仅供测试,如需商用请前往官方开放平台。 GitHub项目页面
Docker部署
docker run -it -d --init \
--name kimi \
-p 7086:8000 \
-e TZ=Asia/Shanghai \
--restart=unless-stopped \
vinlic/kimi-free-api:latest
之后可访问http://localhost:7086进行测试
获取KIMI refresh_token
从 kimi.moonshot.cn 获取refresh_token
进入kimi随便发起一个对话,然后F12打开开发者工具,从Application应用 > Local Storage本地存储空间
中找到refresh_token
的值,这将作为Authorization的Bearer Token值:Authorization: Bearer TOKEN
如果你看到的refresh_token
是一个数组,请使用.
拼接起来再使用。
目前kimi限制普通账号每3小时内只能进行30轮长文本的问答(短文本不限),你可以通过提供多个账号的refresh_token并使用,
拼接提供:
Authorization: Bearer TOKEN1,TOKEN2,TOKEN3
每次请求服务会从中挑选一个。
代码开发
代码用法示例,其他用法详见官方文档,很详细。
const axios = require('axios');
// 替换为你的refresh_token,获取方法见GitHub页面说明
const REFRESH_TOKEN = "eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJ1c2VyLWNlbnRlciIsImV4cCI6MTc1MDU2MTg4NywiaWF0IjoxNzQyNzg1ODg3LCJqdGkiOiJjdmdjcW5ydWEzZDVsb3RsM2U4ZyIsInR5cCI6InJlZnJlc2giLCJhcHBfaWQiOiJraW1pIiwic3ViIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANzAiLCJzcGFjZV9pZCI6ImNtcWkxdDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAl9pZCI6ImNtcWkxdDAzcjA3Y2pzbGs1djYwIiwicm9sZXMiOlsidmlkZW9fZ2VuX2FjY2VzcyJdfQ.Yw07vOZfAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA48w3llR4BAvtpGmqh-_WOJ6NPC70Gj76vc5A";
const API_URL = "https://kimi.xxxxxx.wang/v1/chat/completions"; // 如果是本地部署,使用localhost:8000;如果是远程部署,替换为实际的API地址
var CONVERSATION_ID = "none";//会话ID,开启新会话为none
/**
*
* @param {string} content 会话正文
* @param {string} conversation_id 会话ID,可实现多轮上下文会话
* @returns Object,id属性为会话id,msg属性为AI答复内容
*/
async function askAI(content, conversation_id = "none") {
try {
// 请求头
const headers = {
"Authorization": `Bearer ${REFRESH_TOKEN}`,
"Content-Type": "application/json"
};
// 请求体
const requestBody = {
model: "kimi", // 使用默认模型
conversation_id: conversation_id, // 如果是第一轮对话,不传conversation_id
messages: [
{
role: "user",
content: content
}
],
use_search: true, // 根据需求开启联网搜索
stream: false // 不使用流式输出
};
// 发送POST请求
const response = await axios.post(API_URL, requestBody, { headers });
// 提取响应中的输出文本
//console.log("API响应:");
//console.log(response.data);
//console.log(response.data.choices[0].message);
//AI回答正文
let outputText = response.data.choices[0].message.content;
//移除引用
if(outputText.split("\n搜索结果来自:\n")[0]){
outputText=outputText.split("\n搜索结果来自:\n")[0];
}
return {
id: response.data.id,
msg: outputText
};
} catch (error) {
console.error("POST到API时发生错误:", error.message);
throw error; // 抛出错误以便调用者处理
}
}
/**
* 发送推送消息到ntfy服务
* @param {string} topic - 消息的主题(必填)
* @param {string} message - 要发送的消息内容(必填)
* @param {string} title - 消息的大标题(默认不使用大标题)
* @param {int} [priority=3] - 消息的优先级(默认是3),可以是1-5的整数,分别是最小、小、默认、大、最大
* @param {array} [tags] - 消息的标签,字符串数组(默认无)
* @param {array} [attach] - 附件、图片URL(默认无)
* @param {array} [click] - 消息被点击时跳转的url(默认无)
* @param {string} [serverUrl='https://ntfy.sh'] - ntfy服务的URL,默认为官方服务器
*/
async function sendNtfyMessage(topic, message, title = null, priority = 3, tags = null, attach = null, click = null, serverUrl = 'https://ntfy.sh') {
try {
if (topic == null || message == null || priority > 5 || priority < 1) {
console.error("topic、message不能为空,priority的值只能取1、2、3、4、5!");
}
// 构建请求的headers
const headers = new Headers({
'Content-Type': 'application/json',
});
// 创建消息Object
const payload = { topic, message, priority };
if (title) payload.title = title;
if (tags) payload.tags = tags;
if (attach) payload.attach = attach;
if (click) payload.click = click;
// 构建请求的body
const body = JSON.stringify(payload);
//console.log('拟发出的消息body:', body);
// 发送POST请求到ntfy服务
const response = await fetch(serverUrl, { method: 'POST', headers: headers, body: body });
// 检查响应状态
if (!response.ok) {
throw new Error(`HTTP 错误! 状态: ${response.status}`);
}
// 获取响应数据
const data = await response.json();
//console.log('消息发送成功:\n', data);
} catch (error) {
console.error('消息发送失败:\n', error);
}
}
/**
* 把一个md格式的字符串转换成emoji的字符串
*/
function md_to_txt(string) {
// 删除引用(假设引用是用 `>` 开头的行)
string = string.replace(/^>.*\n?/gm, '');
// 将 ### 替换为 🔶
string = string.replace(/^####\s*/gm, '🔸 ');
string = string.replace(/^###\s*/gm, '🔶 ');
// 删除 Markdown 中的标题格式(如 #、## 等,但保留换行)
string = string.replace(/^#{1,2}\s*/gm, '');
// 删除 Markdown 中的加粗、斜体、下划线、删除线等格式
string = string.replace(/\*\*|\*|__|_|~~/g, '');
// 删除 Markdown 中的链接格式 [text](url)
string = string.replace(/\[.*?\]\(.*?\)/g, '');
// 保留无序列表符号,但将其替换为普通文本
string = string.replace(/^\s*[-*+]\s/gm, '- ');
// 保留有序列表符号
string = string.replace(/^\s*(\d+\.)\s/gm, '$1 ');
// 删除引用角标
string = string.replace(/\[\^[^\]]+\^]/g, '');
// 删除多余的空格(但保留换行和缩进)
//string = string.replace(/\s+/g, ' ').trim();
return string;
}
// 调用
(async () => {
try {
const result = await askAI("分析一下当前国内上海金价格,较上日变化,近期走势(包含影响金价走势的原因)。预测一下后续黄金价格是涨还是跌。给出投资建议。");
let msg = result.msg;
CONVERSATION_ID = result.id;
//console.log(`AI回答: ${msg}\nc_id:${CONVERSATION_ID}`);
sendNtfyMessage("hotine",md_to_txt(msg),"金价分析",3,["💰"]);
} catch (error) {
console.error("Error in askAI:", error);
}
})();