koishi-plugin-davinci-003
Version:
997 lines (990 loc) • 39.1 kB
JavaScript
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
var __commonJS = (cb, mod) => function __require() {
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
};
var __export = (target, all) => {
for (var name2 in all)
__defProp(target, name2, { get: all[name2], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/locales/zh.yml
var require_zh = __commonJS({
"src/locales/zh.yml"(exports, module2) {
module2.exports = { commands: { dvc: { description: "AI聊天", usage: '<>\n <message forward>\n <message id=1>项目地址https://github.com/initialencounter/2022-12-24/blob/main/davinci-003#readme.md </message>\n <message id=2>对于部署者行为及所产生的任何纠纷, Koishi 及 koishi-plugin-davinci-003 概不负责</message>\n <message id=3>指令如下:</message>\n <message id=4>1.[重置会话] 请发送 "dvc.重置会话"</message>\n <message id=5>2.[添加人格] 请发送 "dvc.添加人格"</message>\n <message id=6>3.[清空所有回话] 请发送 "dvc.clear"</message>\n <message id=7>4.[切换人格] 请发送 "dvc.切换人格"</message>\n <message id=8>5.[查询余额] 请发送 "dvc.credit"</message>\n <message id=9>8.若出现400报错,请发送dvc.clear</message>\n </message>\n</>', messages: { censor: "不合规,请检查输入内容是否含有违禁词。", "no-prompt": "你好!很高兴认识你!", thinking: "思考中……", err: "寄!{0}", total_available: "滴!当前账户的余额为${0}。", tooLong: "滋滋..猪脑过载。", switch: "当前存在{0}{1}请输入编号。", "switch-output": "当前存在模式{0}请输入编号。", "switch-err": "不存在人格可切换。", get: "查询中...", clean: "舒服了", "set-personality": "设置失败,请重新触发指令,示例:dvc.添加人格", "set-personality-role": "role只能为system、assistant或user", painting: "GPT生成图片中...", "menu-err": "请输入正确的序号。", "switch-success": "切换{0}成功:{1}", block: "您已被block", louder: "听不清", "usage-exhausted": "调用次数已达上限。" } }, "dvc.count": { description: "减少dvc的使用次数" }, "dvc.clear": { description: "清空所有人的会话" }, "dvc.重置会话": { description: "清空个人的会话" }, "dvc.credit": { description: "查看余额" }, "dvc.output": { description: "切换输出模式" }, "dvc.设置人格": { description: "设置人格, AI的人格会发生改变" }, "dvc.添加人格": { description: "添加人格,会自动保存" }, "dvc.切换人格": { description: "切换现有的人格" }, "dvc.切换引擎": { description: "切换引擎" }, "dvc.生图": { description: "GPT生成图片" }, "dvc.翻译": { description: "AI翻译" } } };
}
});
// src/index.tsx
var src_exports = {};
__export(src_exports, {
default: () => src_default
});
module.exports = __toCommonJS(src_exports);
var import_koishi3 = require("koishi");
var import_fs = __toESM(require("fs"));
var import_koishi_plugin_rate_limit = require("koishi-plugin-rate-limit");
var import_path = require("path");
// src/utils.ts
var import_koishi = require("koishi");
async function recall(session, messageId, time) {
new Promise((resolve2) => setTimeout(() => {
session.bot.deleteMessage(session.channelId, messageId);
}, time));
}
__name(recall, "recall");
async function switch_menu(session, type_arr, name2) {
let type_str = "\n" + name2 + "\n";
let count = 0;
const result = (0, import_koishi.segment)("figure");
type_arr.forEach((i, id) => {
if (count > 50) {
count = 0;
result.children.push(
(0, import_koishi.segment)("message", {
userId: "1114039391",
nickname: "AI"
}, type_str)
);
type_str = "";
}
type_str += String(id + 1) + " " + i + "\n";
count++;
});
result.children.push(
(0, import_koishi.segment)("message", {
userId: "1114039391",
nickname: "AI"
}, type_str)
);
await session.send(result);
const input = await session.prompt();
if (!input || Number.isNaN(+input))
return "";
const index = parseInt(input) - 1;
if (index < 0 || index > type_arr.length - 1)
return "";
return type_arr[index];
}
__name(switch_menu, "switch_menu");
async function switch_menu_grid(session, type_arr, name2) {
let type_str = "\n" + name2 + "\n\n";
let count = 0;
function getActualLength(str) {
let actualLength = 0;
for (let i2 = 0; i2 < str.length; i2++) {
const charCode = str.charCodeAt(i2);
if (charCode >= 65281 && charCode <= 65374 || charCode >= 12288 && charCode <= 12351) {
actualLength += 2;
} else {
actualLength += 1;
}
}
return actualLength;
}
__name(getActualLength, "getActualLength");
function multiplyStrings(str, n) {
return Array.from({ length: n }, () => str).join("");
}
__name(multiplyStrings, "multiplyStrings");
const result = (0, import_koishi.segment)("figure");
for (let id = 0; id < type_arr.length; id += 2) {
if (count > 50) {
count = 0;
result.children.push(
(0, import_koishi.segment)("message", {
userId: "1114039391",
nickname: "AI"
}, type_str)
);
type_str = "";
}
const firstLen = getActualLength(String(id + 1) + " " + type_arr[id]);
const spaceString = multiplyStrings(" ", 20 - firstLen);
type_str += String(id + 1) + " " + type_arr[id] + spaceString + String(id + 2) + " " + type_arr[id + 1] + "\n";
count++;
}
result.children.push(
(0, import_koishi.segment)("message", {
userId: "1114039391",
nickname: "AI"
}, type_str)
);
await session.send(result);
let input = await session.prompt();
input = input.trim();
let res = [];
for (var i of input.split(" ")) {
if (!i || Number.isNaN(+i))
continue;
const index = parseInt(i) - 1;
if (index < 0 || index > type_arr.length - 1)
continue;
res.push(type_arr[index]);
}
return res;
}
__name(switch_menu_grid, "switch_menu_grid");
// src/type.ts
var import_koishi2 = require("koishi");
var Dvc = class extends import_koishi2.Service {
static {
__name(this, "Dvc");
}
static inject = {
required: ["console", "database"],
optional: ["puppeteer", "vits", "sst", "censor"]
};
output_type;
session_config;
sessions;
personality;
sessions_cmd;
aliasMap;
type;
l6k;
key_number;
maxRetryTimes;
constructor(ctx, config) {
super(ctx, "dvc", true);
}
};
((Dvc2) => {
Dvc2.Config = import_koishi2.Schema.intersect([
import_koishi2.Schema.union([
import_koishi2.Schema.object({
selectBaseURL: import_koishi2.Schema.const(true),
baseURL: import_koishi2.Schema.union([
import_koishi2.Schema.const("https://api.openai.com").description("https://api.openai.com"),
import_koishi2.Schema.const("https://api.deepseek.com").description("https://api.deepseek.com"),
import_koishi2.Schema.const("https://api.chatanywhere.com.cn").description("https://api.chatanywhere.com.cn"),
import_koishi2.Schema.const("https://maas-api.cn-huabei-1.xf-yun.com").description("(讯飞)https://maas-api.cn-huabei-1.xf-yun.com"),
import_koishi2.Schema.transform(String, (value) => value)
]).default("https://api.openai.com").description("选择平台")
}).description("选择平台"),
import_koishi2.Schema.object({
selectBaseURL: import_koishi2.Schema.const(false),
baseURL: import_koishi2.Schema.string().default("https://api.openai.com").description("自定义平台")
}).description("自定义平台")
]),
import_koishi2.Schema.union([
import_koishi2.Schema.object({
selectModel: import_koishi2.Schema.const(true),
appointModel: import_koishi2.Schema.union([
import_koishi2.Schema.const("gpt-4o").description("gpt-4o"),
import_koishi2.Schema.const("gpt-4o-mini").description("gpt-4o-mini"),
import_koishi2.Schema.const("o1").description("o1"),
import_koishi2.Schema.const("o3-mini").description("o3-mini"),
import_koishi2.Schema.const("deepseek-chat").description("deepseek-chat"),
import_koishi2.Schema.const("deepseek-reasoner").description("deepseek-reasoner"),
import_koishi2.Schema.const("xdeepseekr1").description("xdeepseekr1(讯飞 deepseekr1)"),
import_koishi2.Schema.transform(String, (value) => value)
]).default("gpt-4o-mini").description("[选择模型](https://openai.com/api/pricing/)")
}).description("选择模型"),
import_koishi2.Schema.object({
selectModel: import_koishi2.Schema.const(false),
appointModel: import_koishi2.Schema.string().default("gpt-4o-mini").description("自定义模型")
}).description("自定义模型")
]),
import_koishi2.Schema.object({
selectBaseURL: import_koishi2.Schema.boolean().default(true).description("选择平台"),
selectModel: import_koishi2.Schema.boolean().default(true).description("选择模型"),
key: import_koishi2.Schema.union([
import_koishi2.Schema.array(String).role("secret"),
import_koishi2.Schema.transform(String, (value) => [value])
]).default([]).role("secret").description("api_key"),
enableContext: import_koishi2.Schema.boolean().default(true).description("是否启用上下文, 关闭后将减少 token 消耗")
}).description("基础设置"),
import_koishi2.Schema.object({
onlyOnePersonality: import_koishi2.Schema.boolean().default(false).description("所有人共用一个人设,开启后将无法切换人格、删除人格、添加人格"),
onlyOneContext: import_koishi2.Schema.boolean().default(false).description("所有人共用一个上下文"),
whisper: import_koishi2.Schema.boolean().default(false).description("语音回复,开启后 AI 将回复你的语音消息"),
waiting: import_koishi2.Schema.boolean().default(true).description("消息反馈,开启后会发送 `思考中...`"),
nickwake: import_koishi2.Schema.boolean().default(false).description("当聊天中出现 AI 的人格名称,AI 将回复你的消息"),
recall: import_koishi2.Schema.boolean().default(true).description("一段时间后会撤回“思考中”"),
recall_time: import_koishi2.Schema.number().default(5e3).description("撤回的时间"),
lang: import_koishi2.Schema.string().description("要翻译的目标语言").default("英文"),
enableReasoningContent: import_koishi2.Schema.boolean().default(false).description("是否输出思维链内容"),
max_tokens: import_koishi2.Schema.number().description("请求长度,否则报错").default(3e3),
temperature: import_koishi2.Schema.number().role("slider").min(0.01).max(1).step(0.01).default(0.01).description("温度"),
authority: import_koishi2.Schema.number().role("slider").min(0).max(5).step(1).description("允许使用的最低权限").default(1),
superuser: import_koishi2.Schema.array(String).default(["3118087750"]).description("可以无限调用的用户"),
usage: import_koishi2.Schema.number().description("每人每日可用次数").default(100),
alias: import_koishi2.Schema.array(String).default(["ai"]).description("指令别名"),
resolution: import_koishi2.Schema.string().default("1024x1024").description("生成图像的默认比例"),
output: import_koishi2.Schema.union([
import_koishi2.Schema.const("minimal").description("只发送文字消息"),
import_koishi2.Schema.const("quote").description("引用消息"),
import_koishi2.Schema.const("figure").description("以聊天记录形式发送"),
import_koishi2.Schema.const("image").description("将对话转成图片"),
import_koishi2.Schema.const("voice").description("发送语音")
]).description("输出方式。").default("minimal"),
private: import_koishi2.Schema.boolean().default(true).description("开启后私聊AI可触发对话, 不需要使用指令"),
mention: import_koishi2.Schema.boolean().default(true).description("开启后机器人被提及(at/引用)可触发对话"),
randnum: import_koishi2.Schema.number().role("slider").min(0).max(1).step(0.01).default(0).description("随机触发对话的概率,如需关闭可设置为 0"),
maxRetryTimes: import_koishi2.Schema.number().default(30).description("报错后最大重试次数")
}).description("进阶设置"),
import_koishi2.Schema.object({
blockuser: import_koishi2.Schema.array(String).default([]).description("屏蔽的用户"),
blockchannel: import_koishi2.Schema.array(String).default([]).description("屏蔽的频道")
}).description("过滤器")
]);
})(Dvc || (Dvc = {}));
// src/index.tsx
var name = "davinci-003";
var logger = new import_koishi3.Logger(name);
var version = require("../package.json")["version"];
var localUsage = (0, import_fs.readFileSync)((0, import_path.resolve)(__dirname, "../readme.md")).toString("utf-8").split("更新日志")[0];
var DVc = class extends Dvc {
static {
__name(this, "DVc");
}
pluginConfig;
constructor(ctx, config) {
super(ctx, config);
this.output_type = config.output;
this.key_number = 0;
this.sessions = {};
this.maxRetryTimes = config.maxRetryTimes;
this.pluginConfig = config;
ctx.i18n.define("zh", require_zh());
ctx.on("ready", () => {
if (!ctx.puppeteer && config.output == "image")
logger.warn("未启用 pptr,将无法发送图片消息");
if (!ctx.vits && config.output == "voice")
logger.warn("未启用 vits,将无法输出语音");
});
ctx.inject(["console"], (ctx2) => {
ctx2.console.addEntry({
dev: (0, import_path.resolve)(__dirname, "../client/index.ts"),
prod: (0, import_path.resolve)(__dirname, "../dist")
});
});
try {
this.personality = JSON.parse(
import_fs.default.readFileSync("./personality.json", "utf-8")
);
} catch (e) {
this.personality = {
预设人格: [{ role: "system", content: "你是我的全能AI助理" }]
};
import_fs.default.writeFileSync(
"./personality.json",
JSON.stringify(this.personality, null, 2)
);
}
this.session_config = Object.values(this.personality)[0];
this.sessions_cmd = Object.keys(this.personality);
ctx.middleware(async (session, next) => {
return this.middleware(session, next);
});
ctx.command("dvc <text:text>", {
authority: config.authority,
usageName: "dvc",
maxUsage: config.usage
}).alias(...config.alias).userFields(["usage"]).action(async ({ session }, ...prompt) => {
return this.dvc(session, prompt.join(" "));
});
ctx.command("dvc.clear", "清空所有会话及人格", {
authority: 1
}).action(({ session }) => {
return this.clear(session);
});
if (!config.onlyOnePersonality) {
ctx.command("dvc.切换人格 <prompt:text>", "切换为现有的人格", {
authority: 1
}).alias("dvc.人格切换", "切换人格").action(async ({ session }, prompt) => {
return this.switch_personality(session, prompt);
});
ctx.command("dvc.添加人格 <prompt:text>", "更改AI的人格,并重置会话", {
authority: 1
}).action(({ session }, prompt) => {
session.send(
"添加人格失败?看这里!\n https://forum.koishi.xyz/t/topic/2349/4"
);
return this.add_personality(session, prompt);
});
ctx.command("dvc.删除人格 <prompt:text>", "删除AI的人格,并重置会话", {
authority: 1
}).action(({ session }, prompt) => {
return this.rm_personality(session, prompt);
});
}
ctx.command("dvc.重置会话", "重置会话", {
authority: 1
}).alias("重置会话").action(({ session }) => {
return this.reset(session);
});
ctx.command("dvc.output <type:string>", "切换dvc的输出方式").action(({ session }, type) => {
return this.switch_output(session, type);
});
ctx.command("dvc.生图 <prompt:text>", "生成图片", {
authority: 1,
usageName: "dvc"
}).option("resolution", "-r <resolution:string>").option("img_number", "-n <img_number:number>").action(async ({ session, options }, prompt) => {
return this.paint(
session,
prompt ? prompt : "landscape",
options.img_number ? options.img_number : 1,
options.resolution ? options.resolution : config.resolution
);
});
ctx.command("dvc.翻译 <prompt:text>", "AI翻译", { usageName: "dvc" }).option("lang", "-l <lang:t=string>", { fallback: config.lang }).action(async ({ session, options }, prompt) => {
return await this.translate(options.lang, prompt);
});
ctx.command("dvc.update", "一键加载 400 条极品预设", { authority: 4 }).alias("dvc.更新预设").option("displace", "-d").action(async ({ session, options }) => {
let prompts_latest = await ctx.http.get(
"https://gitee.com/initencunter/ChatPrompts/raw/master/safe",
{
responseType: "text"
}
);
const prompts_latest_ = JSON.parse(
Buffer.from(prompts_latest, "base64").toString("utf-8")
);
if (options.displace) {
await session.send("该选项将会导致人格丢失,其否继续[Y/n]?");
const confirm = await session.prompt(6e4);
if (!confirm)
return;
if (confirm.toLowerCase() !== "y")
return session.send("取消切换");
this.personality = prompts_latest_;
} else {
for (const i of Object.keys(prompts_latest_)) {
this.personality[i] = prompts_latest_[i];
}
}
import_fs.default.writeFileSync(
"./personality.json",
JSON.stringify(this.personality, null, 2)
);
logger.info("更新预设成功");
return session.execute("切换人格");
});
ctx.command("dvc.cat", "显示一个对话").alias("dvc.会话人格").option("all", "-a --all 显示所有字数").option("personality", "-p <personality:string> 指定人格昵称").option("id", "-i <id:number> 指定会话ID,默认为 0").action(async ({ session, options }) => {
if (options?.personality)
return JSON.stringify(
this.personality[options?.personality ?? "预设人格"]
);
const sid = options.id ?? 0;
let text = (this.sessions[session.userId]?.[sid] ?? this.session_config[0]).content;
if (!options.all && text.length > 200)
text = text.slice(0, 200) + "...";
return text;
});
ctx.console.addListener("davinci-003/chatTest", async (text) => {
const date = (/* @__PURE__ */ new Date()).toLocaleString();
let status = { date };
logger.info("user:" + text);
let sessionid = "e2b5e6a3b58f06b914e5ede4d5737afb93afd0cc03f25d66e778bb733e589228";
let session_of_id = this.get_chat_session(sessionid);
session_of_id.push({
role: "user",
content: `
${text},现在时间是:${JSON.stringify(status)}`
});
let message = await this.try_control(session_of_id);
session_of_id.push({ role: "assistant", content: message });
while (JSON.stringify(session_of_id).length > 1e4) {
session_of_id.splice(1, 1);
if (session_of_id.length <= 1)
break;
}
this.sessions[sessionid] = session_of_id;
logger.info(`${this.pluginConfig.appointModel}返回内容: `);
logger.info(message);
return message;
});
ctx.console.addListener("davinci-003/getusage", () => {
return localUsage;
});
ctx.console.addListener("davinci-003/addPersonality", async (personality) => {
try {
this.personality[personality.name] = personality.personality;
import_fs.default.writeFileSync("./personality.json", JSON.stringify(this.personality, null, 2));
return "success";
} catch (e) {
return "error" + e;
}
});
}
/**
*
* @param lang 目标语言
* @param prompt 要翻译的内容
* @returns 翻译后的内容
*/
async translate(lang, prompt) {
return this.try_control([
{
role: "system",
content: "你是一个翻译引擎,请将文本翻译为" + lang + ",只需要翻译不需要解释。"
},
{ role: "user", content: `请帮我我将如下文字翻译成${lang},“${prompt}”` }
]);
}
/**
*
* @param session 会话
* @param prompt 描述词
* @param n 生成数量
* @param size 图片大小
* @returns Promise<string|segment>
*/
async paint(session, prompt, n, size) {
session.send(
(0, import_koishi3.h)("quote", { id: session.messageId }) + session.text("commands.dvc.messages.painting")
);
try {
const response = await this.ctx.http.post(
(0, import_koishi3.trimSlash)(
`${this.pluginConfig.baseURL ?? "https://api.openai.com"}/v1/images/generations`
),
{
prompt,
n,
size
},
{
timeout: 0,
headers: {
Authorization: `Bearer ${this.pluginConfig.key[this.key_number]}`,
"Content-Type": "application/json"
}
}
);
const result = (0, import_koishi3.segment)("figure");
const attrs = {
userId: session.userId,
nickname: "GPT"
};
for (var msg of response.data) {
result.children.push((0, import_koishi3.segment)("message", attrs, import_koishi3.segment.image(msg.url)));
}
return result;
} catch (e) {
return session.text("commands.dvc.messages.err", [
`key${this.key_number + 1} 报错:${String(e)}`
]);
}
}
/**
*
* @param session 会话
* @param prompt 会话内容
* @returns Promise<string | Element>
*/
async dvc(session, prompt) {
if (this.pluginConfig.blockuser.includes(session.userId) || this.pluginConfig.blockchannel.includes(session.channelId))
return;
if (!this.pluginConfig.superuser.includes(session.userId)) {
let user = await this.ctx.database.getUser(
session.platform,
session.userId
);
let usage = (0, import_koishi_plugin_rate_limit.getUsage)("ai", user);
if (usage > this.pluginConfig.usage)
return session.text("commands.dvc.messages.usage-exhausted");
}
if (!prompt && !session.quote?.content)
return session.text("commands.dvc.messages.no-prompt");
if (prompt.length > this.pluginConfig.max_tokens)
return session.text("commands.dvc.messages.tooLong");
if (this.pluginConfig.waiting) {
const msgId = (await session.bot.sendMessage(
session.channelId,
(0, import_koishi3.h)("quote", { id: session.messageId }) + session.text("commands.dvc.messages.thinking"),
session.guildId
))[0];
if (this.pluginConfig.recall)
await recall(session, msgId, this.pluginConfig.recall_time);
}
if (this.ctx.censor)
prompt = await this.ctx.censor.transform(prompt, session);
if (!this.pluginConfig.enableContext) {
const text = await this.chat_with_gpt([
{ role: "user", content: prompt }
]);
const resp = [
{ role: "user", content: prompt },
{ role: "assistant", content: text }
];
return await this.getContent(
session.userId,
resp,
session.messageId,
session.bot.selfId
);
} else {
return await this.chat(prompt, session.userId, session);
}
}
/**
*
* @param session 当前会话
* @param next 通过函数
* @returns 消息
*/
async middleware(session, next) {
if (session.elements.filter((i2) => i2.type === "audio" || i2.type === "record").length > 0 && this.pluginConfig.whisper && this.ctx.sst) {
const text = await this.ctx.sst.audio2text(session);
if (!text)
return session.text("commands.dvc.messages.louder");
return this.dvc(session, text);
}
if (session.subtype === "private" && this.pluginConfig.private)
return this.dvc(session, session.content);
if (session.stripped.appel && this.pluginConfig.mention) {
let msg = "";
for (let i2 of session.elements.slice(1)) {
if (i2.type === "text")
msg += i2?.attrs?.content;
}
return this.dvc(session, msg);
}
if (this.pluginConfig.nickwake) {
for (var i of this.sessions_cmd) {
if (session.content.startsWith(i)) {
this.sessions[session.userId] = this.personality[i];
return await this.dvc(session, session.content);
}
}
}
if (this.pluginConfig.randnum == 0)
return next();
const randnum = Math.random();
if (randnum < this.pluginConfig.randnum)
return await this.dvc(session, session.content);
return next();
}
/**
*
* @param message 发送给chatgpt的json列表
* @returns 将返回文字处理成json
*/
async chat_with_gpt(message) {
let url = (0, import_koishi3.trimSlash)(
`${this.pluginConfig.baseURL ?? "https://api.openai.com"}/v1/chat/completions`
);
const payload = {
stream: true,
model: this.pluginConfig.appointModel,
temperature: this.pluginConfig.temperature,
top_p: 1,
frequency_penalty: 0,
presence_penalty: 0,
messages: message
};
const config = {
timeout: 0,
responseType: "stream",
keepAlive: true,
headers: {
Authorization: `Bearer ${this.pluginConfig.key[this.key_number]}`,
Accept: "application/json",
"Content-Type": "application/json"
},
data: payload
};
let data;
try {
data = (await this.ctx.http("POST", url, config)).data;
let { contents, reasoning_content } = await this.readableStreamDecoder(
data
);
reasoning_content = `<think>
${reasoning_content.trim()}
</think>
`;
if (!this.pluginConfig.enableReasoningContent) {
reasoning_content = "";
contents = contents.replace(/<think>[\s\S]*?<\/think>/g, "");
}
;
return `${reasoning_content}${contents.trim()}`;
} catch (e) {
if (String(e).includes("Bad Request")) {
console.dir(config.data.messages);
return "Bad Request";
}
this.switch_key(e);
return "";
}
}
async readableStreamDecoder(data) {
const reader = data.getReader();
const decoder = new TextDecoder("utf-8");
let sses = "", contents = "", reasoning_content = "";
while (true) {
const { done, value } = await reader.read();
if (done) {
break;
}
const newString = decoder.decode(value, { stream: true });
if (newString.startsWith("data:")) {
try {
for (let sse of sses.split("\n")) {
let jsonStr = sse.slice(5).trim();
if (!jsonStr)
continue;
const json = JSON.parse(jsonStr);
const content = json?.choices?.[0]?.delta?.content;
const reasoning = json?.choices?.[0]?.delta?.reasoning_content;
if (reasoning)
reasoning_content += reasoning;
if (content)
contents += content;
}
sses = newString;
} catch (e) {
sses += newString;
}
} else {
sses += newString;
}
}
return {
contents,
reasoning_content
};
}
/**
* 切换下一个 key
*/
key_number_pp() {
this.key_number++;
if (this.key_number === this.pluginConfig.key.length)
this.key_number = 0;
}
/**
* 先查询余额 ,如果余额为 0,切换key
* @param session 会话
* @param e Error
*/
async switch_key(e) {
logger.info(
`key${this.key_number + 1}. ${this.pluginConfig.key[this.key_number].slice(0, 10)}*** 报错:${String(e)}`
);
this.key_number_pp();
}
/**
*
* @param sessionid QQ号
* @returns 对应QQ的会话
*/
get_chat_session(sessionid) {
if (Object.keys(this.sessions).indexOf(sessionid) == -1)
this.sessions[sessionid] = [...this.session_config];
return this.sessions[sessionid];
}
/**
*
* @param msg prompt消息
* @param sessionid QQ号
* @returns json消息
*/
async chat(msg, sessionid, session) {
let name2 = session.author?.nick || session.username;
logger.info(name2 + ": " + msg);
if (this.pluginConfig.onlyOneContext)
sessionid = "e2b5e6a3b58f06b914e5ede4d5737afb93afd0cc03f25d66e778bb733e589228";
let session_of_id = this.get_chat_session(sessionid);
let message;
if (session_of_id[session_of_id.length - 1].role === "user" && this.pluginConfig?.baseURL.includes("api.deepseek.com")) {
message = "deepseek 不支持重复的 user, 请等待上一次对话结束";
} else {
let rawMsg = { role: "user", content: msg };
if (this.pluginConfig?.baseURL.includes("api.deepseek.com")) {
rawMsg["name"] = name2;
}
session_of_id.push(rawMsg);
message = await this.try_control(session_of_id);
}
if (session_of_id[session_of_id.length - 1].role !== "assistant" || !this.pluginConfig?.baseURL.includes("api.deepseek.com")) {
session_of_id.push({ role: "assistant", content: message });
}
while (JSON.stringify(session_of_id).length > 1e4) {
session_of_id.splice(1, 1);
if (session_of_id.length <= 1)
break;
}
this.sessions[sessionid] = session_of_id;
logger.info("ChatGPT返回内容: ");
logger.info(message);
return await this.getContent(
sessionid,
session_of_id,
session.messageId,
session.bot.selfId
);
}
/**
*
* @param cb chat 回调函数 chat_with_gpt
* @param session 会话
* @param session_of_id 会话 ID
* @returns
*/
async try_control(session_of_id) {
let try_times = 0;
while (try_times < this.pluginConfig.maxRetryTimes) {
const res = await this.chat_with_gpt(session_of_id);
if (res !== "")
return res;
try_times++;
await this.ctx.sleep(500);
}
return "请求错误,请查看日志";
}
/**
* 删除人格逻辑
* @param session
* @param nick_name
* @returns
*/
async rm_personality(session, nick_name) {
const nick_names = Object.keys(this.personality);
if (nick_names.length == 1)
return "再删下去就报错了";
if (nick_name && nick_names.indexOf(nick_name) > -1)
return this.personality_rm(session, [nick_name]);
const input = await switch_menu_grid(session, nick_names, "人格");
if (!input)
return session.text("commands.dvc.messages.menu-err");
return this.personality_rm(session, input);
}
/**
* 删除人格
* @param session 会话
* @param nick_name 人格名称
* @returns 字符串
*/
personality_rm(session, nick_name) {
for (var nick_name_0 of nick_name) {
const index = this.sessions_cmd.indexOf(nick_name_0);
this.sessions_cmd.splice(index, 1);
delete this.personality[nick_name_0];
}
this.sessions[session.userId] = [
{ role: "system", content: "你是我的全能AI助理" }
];
import_fs.default.writeFileSync(
"./personality.json",
JSON.stringify(this.personality, null, 2)
);
return "人格删除成功";
}
/**
*
* @param session 会话
* @param type 输出类型,字符串
* @returns Promise<string>
*/
// 切换输出模式
async switch_output(session, type) {
const type_arr = ["quote", "figure", "image", "minimal", "voice"];
if (type && type_arr.indexOf(type) > -1) {
this.output_type = type;
return session.text("commands.dvc.messages.switch-success", [type]);
}
const input = await switch_menu(session, type_arr, "输出模式");
if (!input)
return session.text("commands.dvc.messages.menu-err");
this.output_type = input;
return session.text("commands.dvc.messages.switch-success", [
"输出模式",
input
]);
}
/**
*
* @param userId 用户QQ号
* @param resp gpt返回的json
* @returns 文字,图片或聊天记录
*/
async getContent(userId, resp, messageId, botId) {
if (this.output_type == "voice" && this.ctx.vits)
return this.ctx.vits.say({ input: resp[resp.length - 1].content });
else if (this.output_type == "quote")
return (0, import_koishi3.h)("quote", { id: messageId }) + resp[resp.length - 1].content;
else if (this.output_type == "figure") {
const result = (0, import_koishi3.segment)("figure");
for (var msg of resp) {
if (msg.role == "user") {
result.children.push(
(0, import_koishi3.segment)(
"message",
{
userId,
nickname: msg.role
},
msg.content
)
);
continue;
}
if (msg.role == "assistant") {
result.children.push(
(0, import_koishi3.segment)(
"message",
{
userId: botId,
nickname: msg.role
},
msg.content
)
);
} else {
result.children.push(
(0, import_koishi3.segment)(
"message",
{
userId,
nickname: msg.role
},
msg.content
)
);
}
}
return result;
} else if (this.output_type == "image") {
const elements = [];
for (var msg of resp) {
if (msg.role == "user") {
elements.push(
`<div style='color:#ff9900;font-size: 25px;background:transparent;width=500px;height:50px'>用户:${msg.content}</div>`
);
continue;
}
if (msg.role == "assistant") {
elements.push(
`<div style='color:black;font-size: 25px;background:transparent;width:500px;height:50px'>AI:${msg.content}</div>`
);
} else {
elements.push(
`<div style='color:#723b8d;font-size: 25px;background:transparent;width:400px'>人格设定:${msg.content}</div>`
);
}
}
let html = `<html>
<div style='position: absolute;top:20px;left:20px;width:600px;'>
<p style='color:#723b8d'>ChatGPT3.5-Turbo</p>
${elements.join("")}
</div>
<div style='position: absolute;top:10px;'>create by koishi-plugin-davinci-003@${version}</div>
</html>`;
return this.ctx.puppeteer.render(html);
} else {
return import_koishi3.h.text(resp[resp.length - 1].content);
}
}
/**
*
* @param session 会话
* @returns 切换后的引擎
*/
/**
*
* @param session 会话
* @param prompt 人格昵称
* @returns 人格切换状态
*/
async switch_personality(session, prompt) {
const nick_names = Object.keys(this.personality);
if (prompt && nick_names.indexOf(prompt) > -1)
return this.set_personality(session, prompt);
const input = await switch_menu_grid(session, nick_names, "人格");
if (!input)
return session.text("commands.dvc.messages.menu-err");
return this.set_personality(session, input[0]);
}
/**
* 重置个人会话,保留人格
* @param session 会话
* @returns
*/
reset(session) {
let session_json = this.get_chat_session(session.userId);
this.sessions[session.userId] = [
{ role: "system", content: session_json[0].content }
];
return "重置成功";
}
async add_personality(session, nick_name) {
if (!nick_name) {
session.send("请输入人格昵称(输入q退出)");
nick_name = await session.prompt(6e4);
if (!nick_name || nick_name == "q")
session.text("commands.dvc.messages.set-personality");
}
let input_key;
let input_value;
const personality_session = [];
while (true) {
session.send("请输入role(system||assistant||user)(输入q退出,e结束)");
input_key = await session.prompt(6e4);
if (input_key == "q" || !input_key)
return session.text("commands.dvc.messages.set-personality");
if (input_key == "e")
break;
if (["system", "assistant", "user"].indexOf(input_key) == -1)
return session.text("commands.dvc.messages.set-personality-role");
session.send("请输入内容(输入q退出)");
input_value = await session.prompt(6e4);
if (input_value == "q" || !input_value)
return session.text("commands.dvc.messages.set-personality");
personality_session.push({ role: input_key, content: input_value });
}
this.sessions_cmd.push(nick_name);
this.personality[nick_name] = personality_session;
import_fs.default.writeFileSync(
"./personality.json",
JSON.stringify(this.personality, null, 2)
);
return this.set_personality(session, nick_name);
}
/**
* 设置人格
* @param session 会话
* @param nick_name 人格昵称
* @param description 对话
* @returns 字符
*/
set_personality(session, nick_name) {
this.sessions_cmd.push(nick_name);
this.sessions[session.userId] = this.personality[nick_name];
return "人格设置成功: " + nick_name;
}
/**
*
* @param session 当前会话
* @returns 返回清空的消息
*/
clear(session) {
this.sessions = {};
return session.text("commands.dvc.messages.clean");
}
};
var src_default = DVc;