mirror of
https://github.com/Jerryplusy/rc-plugin.git
synced 2025-10-14 16:19:18 +00:00
✨ feat: 删除冷门识图 & 增加微信文章分享总结
1. 识图用户较少直接删除 2. 增加可能热门的微信文章分享总结
This commit is contained in:
parent
6753bba89c
commit
786e2476b6
23
README.md
23
README.md
@ -198,23 +198,27 @@ git clone -b 1.6.7-lts https://gitee.com/kyrzy0416/rconsole-plugin.git
|
||||
|
||||
<img src="./img/lagrange.webp" width="30%" height="30%">
|
||||
|
||||
### 🤖 关于识图 [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),这是我开源这个插件的最大动力!
|
||||
|
@ -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<boolean>}
|
||||
*/
|
||||
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
|
||||
|
@ -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
|
||||
|
@ -90,3 +90,5 @@ export const OCR_PROMPT = `
|
||||
▲ 图片中提取的文本,在适当的地方使用换行符。如果文本被某物遮挡,请使其不受阻隔,以便阅读。如果图像中没有文本,只需回复描述。不要包含任何其他信息。
|
||||
示例:▲ 文本编辑器中的代码行。▲ const x = 5; const y = 10; const z = x + y; console.log(z);
|
||||
`
|
||||
|
||||
export const SUMMARY_PROMPT = `请返回您仔细阅读正文后精心写成的详尽笔记`
|
@ -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({
|
||||
|
Loading…
x
Reference in New Issue
Block a user