From 786e2476b682a8702b0d0a96ee71afd0998dba85 Mon Sep 17 00:00:00 2001
From: zhiyu <542716863@qq.com>
Date: Thu, 23 May 2024 12:13:47 +0800
Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20feat:=20=E5=88=A0=E9=99=A4=E5=86=B7?=
=?UTF-8?q?=E9=97=A8=E8=AF=86=E5=9B=BE=20&=20=E5=A2=9E=E5=8A=A0=E5=BE=AE?=
=?UTF-8?q?=E4=BF=A1=E6=96=87=E7=AB=A0=E5=88=86=E4=BA=AB=E6=80=BB=E7=BB=93?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
1. 识图用户较少直接删除
2. 增加可能热门的微信文章分享总结
---
README.md | 23 +++++++-----
apps/query.js | 80 +----------------------------------------
apps/tools.js | 35 +++++++++++++++---
constants/constant.js | 4 ++-
utils/openai-builder.js | 36 ++++++++++++-------
5 files changed, 73 insertions(+), 105 deletions(-)
diff --git a/README.md b/README.md
index 2836224..4a2aece 100644
--- a/README.md
+++ b/README.md
@@ -198,23 +198,27 @@ git clone -b 1.6.7-lts https://gitee.com/kyrzy0416/rconsole-plugin.git
-### 🤖 关于识图 [beta功能]
+### 微信文章总结 (完全免费总结)
-R 插件集成了我的新作品`gpt2txt`:https://github.com/zhiyu1998/gpt2txt
+官方Kimi API 暂时没有看到可以联网搜索的选项,所以选用开源的[kimi-free-api](https://github.com/LLM-Red-Team/kimi-free-api)
+
+1. 部署 kimi-free-api
+
+```shell
+docker run -it -d --init --name kimi-free-api -p 8000:8000 -e TZ=Asia/Shanghai vinlic/kimi-free-api:latest
+```
+
+2. 更改下面两个选项,自行修改 `tools.yaml` 或者锅巴:
-使用需要在锅巴 or tools.yaml修改以下内容:
```yaml
aiBaseURL: '' # 用于识图的接口,kimi默认接口为:https://api.moonshot.cn,其他服务商自己填写
aiApiKey: '' # 用于识图的api key,kimi接口申请:https://platform.moonshot.cn/console/api-keys
-aiModel: 'claude-3-haiku-20240307' # 模型,使用kimi不用填写,其他要填写
```
-`Kimi`用户只需填写`aiBaseURL` 和 `aiApiKey`,其他用户都需要填写!效果展示如下:
+- aiBaseURL:你服务器的地址
+- aiApiKey:kimi 的 `refresh_token` (F12 -> 应用(Application) -> Local Storage -> `https://kimi.moonshot.cn` -> 找到)
-
-
-- [Kimi开放平台](https://platform.moonshot.cn/console/info)
-- [OpenAI](https://platform.openai.com/api-keys)
+3. 开始游玩
## 🤺 R插件交流群
扫码不行就:575663150
@@ -272,6 +276,7 @@ aiModel: 'claude-3-haiku-20240307' # 模型,使用kimi不用填写,其他要
🌸 感谢以下框架的开源:
- [yt-dlp:A youtube-dl fork with additional features and fixes](https://github.com/yt-dlp/yt-dlp)
- [freyr-js](https://github.com/miraclx/freyr-js)
+- [kimi-free-api](https://github.com/LLM-Red-Team/kimi-free-api)
## ☕ 请我喝一杯瑞幸咖啡
如果你觉得插件能帮助到你增进好友关系,那么你可以在有条件的情况下[请我喝一杯瑞幸咖啡](https://afdian.net/a/zhiyu1998),这是我开源这个插件的最大动力!
diff --git a/apps/query.js b/apps/query.js
index 59c43f9..ac01ff7 100644
--- a/apps/query.js
+++ b/apps/query.js
@@ -4,19 +4,14 @@ import fetch from "node-fetch";
import puppeteer from "../../../lib/puppeteer/puppeteer.js";
// http库
import axios from "axios";
-// url库
-import url from 'url';
// 常量
-import { CAT_LIMIT, OCR_PROMPT } from "../constants/constant.js";
+import { CAT_LIMIT } from "../constants/constant.js";
// 配置文件
import config from "../model/index.js";
// 书库
import { getYiBook, getZBook, getZHelper } from "../utils/books.js";
// 工具类
import TokenBucket from '../utils/token-bucket.js'
-import { downloadImg } from "../utils/common.js";
-import { checkAndRemoveFile, toBase64 } from "../utils/file.js";
-import { OpenaiBuilder } from "../utils/openai-builder.js";
export class query extends plugin {
/**
@@ -63,10 +58,6 @@ export class query extends plugin {
{
reg: "^#(wiki|百科)(.*)$",
fnc: "wiki",
- },
- {
- reg: "^识图",
- fnc: "openAiOCR"
}
],
});
@@ -74,12 +65,6 @@ export class query extends plugin {
this.toolsConfig = config.getConfig("tools");
// 视频保存路径
this.defaultPath = this.toolsConfig.defaultPath;
- // ai接口
- this.aiBaseURL = this.toolsConfig.aiBaseURL;
- // ai api key
- this.aiApiKey = this.toolsConfig.aiApiKey;
- // ai模型
- this.aiModel = this.toolsConfig.aiModel;
}
async doctor(e) {
@@ -338,69 +323,6 @@ export class query extends plugin {
return true;
}
- // 识图
- async openAiOCR(e) {
- if (e.source) {
- let reply;
- if (e.isGroup) {
- reply = (await e.group.getChatHistory(this.e.source.seq, 1)).pop()?.message;
- } else {
- reply = (await e.friend.getChatHistory(this.e.source.time, 1)).pop()?.message;
- }
- if (reply) {
- for (let val of reply) {
- if (val.type == "image") {
- e.img = [val.url];
- break;
- }
- }
- }
- }
-
- if (!e.img) {
- this.setContext('openAiProcess');
- await e.reply("「R插件 x 月之暗面 Kimi」联合识别提醒你:请发送图片!", false, { at: true });
- } else {
- this.openAiProcess();
- }
- }
-
- /**
- * AI引擎提供图像识别能力
- * @return {Promise}
- */
- async openAiProcess() {
- if (!this.e.img) {
- e.reply("「R插件 x 月之暗面 Kimi」联合识别提醒你:无法找到图片!")
- return true;
- }
- const img = this.e.img.find(item => item.startsWith("http"));
- const parsedUrl = url.parse(img);
- const pathArray = parsedUrl.pathname.split('/');
- const filenameWithExtension = pathArray[pathArray.length - 1];
- const path = `${ this.defaultPath }${ this.e.group_id || this.e.user_id }`
- // 下载图片
- const imgPath = await downloadImg(img, path, filenameWithExtension);
- // 构造OpenAI引擎
- try {
- const { model, ans } = await new OpenaiBuilder()
- .setBaseURL(this.aiBaseURL)
- .setApiKey(this.aiApiKey)
- .setModel(this.aiModel)
- .setPrompt(OCR_PROMPT)
- .setPath(imgPath)
- .build();
- const ocrAns = ans.split("▲");
- logger.info(ocrAns)
- this.e.reply(`「R插件 x ${ model }」联合识别:\n描述:${ ocrAns[1] } \nOCR识别结果:${ ocrAns[2] }`);
- await checkAndRemoveFile(filenameWithExtension);
- } catch (err) {
- this.e.reply("「R插件 x 月之暗面 Kimi」联合识别提醒你:无法找到图片路径!")
- logger.error(err);
- }
- return true;
- }
-
/**
* 限制用户调用(默认1分钟1次)
* @param e
diff --git a/apps/tools.js b/apps/tools.js
index 2ca1402..ea6a88f 100644
--- a/apps/tools.js
+++ b/apps/tools.js
@@ -27,6 +27,7 @@ import {
douyinTypeMap,
REDIS_YUNZAI_ISOVERSEA,
REDIS_YUNZAI_LAGRANGE,
+ SUMMARY_PROMPT,
transMap,
TWITTER_BEARER_TOKEN,
XHS_NO_WATERMARK_HEADER,
@@ -68,6 +69,7 @@ import GeneralLinkAdapter from "../utils/general-link-adapter.js";
import { mid2id } from "../utils/weibo.js";
import { LagrangeAdapter } from "../utils/lagrange-adapter.js";
import path from "path";
+import { OpenaiBuilder } from "../utils/openai-builder.js";
export class tools extends plugin {
/**
@@ -171,6 +173,10 @@ export class tools extends plugin {
{
reg: "(music.apple.com|open.spotify.com)",
fnc: "freyr"
+ },
+ {
+ reg: "mp.weixin",
+ fnc: "weixin"
}
],
});
@@ -198,6 +204,12 @@ export class tools extends plugin {
this.queue = new PQueue({ concurrency: Number(this.toolsConfig.queueConcurrency) });
// 视频下载的并发数量
this.videoDownloadConcurrency = this.toolsConfig.videoDownloadConcurrency;
+ // ai接口
+ this.aiBaseURL = this.toolsConfig.aiBaseURL;
+ // ai api key
+ this.aiApiKey = this.toolsConfig.aiApiKey;
+ // ai模型
+ this.aiModel = this.toolsConfig.aiModel;
}
// 翻译插件
@@ -1446,7 +1458,7 @@ export class tools extends plugin {
logger.info(result.toString());
// 获取信息
const { title, album, artist } = await this.parseFreyrLog(result.toString());
- e.reply(`识别:${freyrName},${ title }--${ artist }\n${ album }`);
+ e.reply(`识别:${ freyrName },${ title }--${ artist }\n${ album }`);
// 判断是否是海外服务器
const isOversea = await this.isOverseasServer();
// 国内服务器解决方案
@@ -1481,7 +1493,7 @@ export class tools extends plugin {
// 读取目录中的所有文件和文件夹
fs.readdir(musicPath, (err, files) => {
if (err) {
- e.reply(`${freyrName}解析出错,请查看日志!`)
+ e.reply(`${ freyrName }解析出错,请查看日志!`)
logger.error('读取目录时出错:', err);
return;
}
@@ -1496,11 +1508,11 @@ export class tools extends plugin {
});
});
} else {
- e.reply(`下载失败!没有找到${freyrName}下载下来文件!`);
+ e.reply(`下载失败!没有找到${ freyrName }下载下来文件!`);
}
// 计数
tools.#amCount += 1;
- logger.info(`当前${freyrName}已经下载了:${ tools.#amCount }次`);
+ logger.info(`当前${ freyrName }已经下载了:${ tools.#amCount }次`);
// 定时清理
if (tools.#amCount >= 5) {
await deleteFolderRecursive(currentWorkingDirectory + "/am");
@@ -1528,6 +1540,21 @@ export class tools extends plugin {
return { title, album, artist };
}
+ async weixin(e) {
+ const urlReg = /(?:https?:\/\/)?mp\.weixin\.qq\.com\/[A-Za-z\d._?%&+\-=\/#]*/g;
+ const wxUrl = urlReg.exec(e.msg)?.[0];
+ const builder = await new OpenaiBuilder()
+ .setBaseURL(this.aiBaseURL)
+ .setApiKey(this.aiApiKey)
+ .setModel(this.aiModel)
+ .setPrompt(SUMMARY_PROMPT)
+ .build();
+ e.reply(`识别:微信文章,正在为您总结,请稍等...`);
+ const { ans: kimiAns, model } = await builder.kimi(wxUrl);
+ e.reply(`「R插件 x ${ model }」联合为您总结内容:\n${ kimiAns }`)
+ return true;
+ }
+
/**
* 哔哩哔哩下载
* @param title
diff --git a/constants/constant.js b/constants/constant.js
index b519c1f..af0b886 100644
--- a/constants/constant.js
+++ b/constants/constant.js
@@ -89,4 +89,6 @@ export const OCR_PROMPT = `
▲ 首先,对将要用作替代文本的图像进行简短描述。不要在描述中描述或提取文本。
▲ 图片中提取的文本,在适当的地方使用换行符。如果文本被某物遮挡,请使其不受阻隔,以便阅读。如果图像中没有文本,只需回复描述。不要包含任何其他信息。
示例:▲ 文本编辑器中的代码行。▲ const x = 5; const y = 10; const z = x + y; console.log(z);
-`
\ No newline at end of file
+`
+
+export const SUMMARY_PROMPT = `请返回您仔细阅读正文后精心写成的详尽笔记`
\ No newline at end of file
diff --git a/utils/openai-builder.js b/utils/openai-builder.js
index 65e3d7f..dc6283f 100644
--- a/utils/openai-builder.js
+++ b/utils/openai-builder.js
@@ -39,31 +39,43 @@ export class OpenaiBuilder {
}
async build() {
- if (this.path === '') {
- throw Error("无法获取到文件路径");
- return null;
- }
// logger.info(this.baseURL, this.apiKey)
// 创建客户端
this.client = new OpenAI({
baseURL: this.baseURL,
apiKey: this.apiKey
});
- // 构建
- if (this.baseURL.includes("api.moonshot.cn")) {
- return await this.kimi(this.path);
- } else {
- return await this.openai(this.path);
+ return this;
+ }
+
+ async kimi(query) {
+ // 请求Kimi
+ const completion = await this.client.chat.completions.create({
+ model: "moonshot-v1-8k",
+ messages: [
+ {
+ "role": "system",
+ "content": this.prompt,
+ },
+ {
+ role: "user",
+ content: query
+ },
+ ],
+ });
+ return {
+ "model": "月之暗面 Kimi",
+ "ans": completion.choices[0].message.content
}
}
- async kimi(path) {
+ async kimi_pic(path) {
let file_object = await this.client.files.create({
file: fs.createReadStream(path),
purpose: "file-extract"
})
let file_content = await (await this.client.files.content(file_object.id)).text()
- // 请求OpenAI
+ // 请求Kimi
const completion = await this.client.chat.completions.create({
model: "moonshot-v1-8k",
messages: [
@@ -84,7 +96,7 @@ export class OpenaiBuilder {
}
}
- async openai(path) {
+ async openai_pic(path) {
// 转换base64
const pic = await toBase64(path);
const completion = await this.client.chat.completions.create({