mirror of
https://github.com/cs-lazy-tools/ChatGPT-On-CS.git
synced 2026-08-28 18:17:40 +08:00
fix: 修复插件对接的 BUG
This commit is contained in:
@@ -1,12 +1,12 @@
|
||||
// 固定会传递的上下文参数
|
||||
export const CTX_APP_NAME = 'app_name';
|
||||
export const CTX_APP_ID = 'app_id';
|
||||
export const CTX_INSTANCE_ID = 'instance_id';
|
||||
export const CTX_APP_NAME = 'CTX_APP_NAME';
|
||||
export const CTX_APP_ID = 'CTX_APP_ID';
|
||||
export const CTX_INSTANCE_ID = 'CTX_INSTANCE_ID';
|
||||
|
||||
export const CTX_USERNAME = 'username'; // 当前操作的用户名
|
||||
export const CTX_PLATFORM = 'platform'; // 当前所在平台
|
||||
export const CTX_HAS_NEW_MESSAGE = 'has_new_message'; // 是否有新消息
|
||||
export const CTX_HAS_GROUP_MESSAGE = 'has_group_message'; // 是否有群消息
|
||||
export const CTX_USERNAME = 'CTX_USERNAME'; // 当前操作的用户名
|
||||
export const CTX_PLATFORM = 'CTX_PLATFORM'; // 当前所在平台
|
||||
export const CTX_HAS_NEW_MESSAGE = 'CTX_HAS_NEW_MESSAGE'; // 是否有新消息
|
||||
export const CTX_HAS_GROUP_MESSAGE = 'CTX_HAS_GROUP_MESSAGE'; // 是否有群消息
|
||||
|
||||
// 电商平台
|
||||
export const CTX_CURRENT_GOODS = 'CTX_CURRENT_GOODS'; // 当前商品
|
||||
@@ -15,6 +15,12 @@ export const CTX_MEMBER_TAG = 'CTX_MEMBER_TAG'; // 会员标签
|
||||
export const CTX_FAN_TAG = 'CTX_FAN_TAG'; // 粉丝标签
|
||||
export const CTX_NEW_CUSTOMER_TAG = 'CTX_NEW_CUSTOMER_TAG'; // 新客标签
|
||||
|
||||
export const CTX_ORDER_STATUS = 'CTX_ORDER_STATUS'; // 订单状态
|
||||
export const CTX_ORDER_ID = 'CTX_ORDER_ID'; // 订单 ID
|
||||
export const CTX_ORDER_AMOUNT = 'CTX_ORDER_AMOUNT'; // PDD 平台特有 [订单金额]
|
||||
export const CTX_GOODS_SPEC = 'CTX_GOODS_SPEC'; // PDD 平台特有 [商品规格]
|
||||
export const CTX_LOGISTICS_STATUS = 'CTX_LOGISTICS_STATUS'; // 物流状态
|
||||
|
||||
export const PluginDefaultRunCode = `
|
||||
const cc = require('config_srv');
|
||||
const rp = require('reply_srv');
|
||||
@@ -27,5 +33,5 @@ const rp = require('reply_srv');
|
||||
*/
|
||||
async function main(ctx, messages) {
|
||||
const cfg = await cc.get(ctx);
|
||||
return await rp.getDefaultReply(cfg, ctx, messages);
|
||||
return await rp.getReply(cfg, ctx, messages);
|
||||
}`;
|
||||
|
||||
@@ -86,7 +86,7 @@ export async function checkAndAddFields(sequelize: Sequelize) {
|
||||
.addColumn('n_config', 'truncate_word_count', {
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: true,
|
||||
defaultValue: 210,
|
||||
defaultValue: 4000,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -260,7 +260,7 @@ export function initConfig(sequelize: Sequelize) {
|
||||
truncate_word_count: {
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: true,
|
||||
defaultValue: 210,
|
||||
defaultValue: 4000,
|
||||
},
|
||||
truncate_word_key: {
|
||||
type: DataTypes.STRING,
|
||||
|
||||
@@ -97,16 +97,15 @@ export class DispatchService {
|
||||
},使用默认回复`,
|
||||
);
|
||||
|
||||
reply = {
|
||||
content: cfg.default_reply || 'Failed to execute plugin',
|
||||
type: 'TEXT',
|
||||
};
|
||||
reply = await this.messageService.getDefaultReply(cfg);
|
||||
}
|
||||
|
||||
callback(reply);
|
||||
|
||||
// 回复后保存消息
|
||||
await this.messageController.saveMessages(ctxMap, reply, msgs);
|
||||
if (reply.type !== 'NO_REPLY') {
|
||||
// 回复后保存消息
|
||||
await this.messageController.saveMessages(ctxMap, reply, msgs);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -66,11 +66,33 @@ export class MessageService {
|
||||
* @param messages
|
||||
* @returns
|
||||
*/
|
||||
public async getDefaultReply(
|
||||
public async getDefaultReply(cfg: Config): Promise<ReplyDTO> {
|
||||
let reply = {
|
||||
type: 'TEXT' as MessageType,
|
||||
content: cfg.default_reply || '当前消息有点多,我稍后再回复你',
|
||||
};
|
||||
|
||||
const replyContent = await this.choseRandomReply(reply.content);
|
||||
reply = {
|
||||
type: reply.type as MessageType,
|
||||
content: replyContent,
|
||||
};
|
||||
|
||||
return reply;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取回复
|
||||
* @param cfg
|
||||
* @param ctx
|
||||
* @param messages
|
||||
* @returns
|
||||
*/
|
||||
public async getReply(
|
||||
cfg: Config,
|
||||
ctx: Context,
|
||||
messages: MessageDTO[],
|
||||
): Promise<{ type: string; content: string }> {
|
||||
): Promise<ReplyDTO> {
|
||||
// 先检查是否存在用户的消息
|
||||
const lastUserMsg = messages
|
||||
.slice()
|
||||
@@ -78,15 +100,9 @@ export class MessageService {
|
||||
.find((msg) => msg.role === 'OTHER');
|
||||
|
||||
let hasDefaultReply = true;
|
||||
let reply = null;
|
||||
|
||||
let reply = {
|
||||
type: 'TEXT',
|
||||
content: cfg.default_reply || '当前消息有点多,我稍后再回复你',
|
||||
};
|
||||
|
||||
if (!lastUserMsg) {
|
||||
this.log.warn(`未匹配到用户消息,所以使用默认回复: ${reply.content}`);
|
||||
} else {
|
||||
if (lastUserMsg) {
|
||||
if (cfg.has_transfer) {
|
||||
// 检查是否需要转接
|
||||
const isTransfer = await this.matchTransferKeyword(ctx, lastUserMsg);
|
||||
@@ -94,8 +110,8 @@ export class MessageService {
|
||||
this.log.info('需要转接');
|
||||
hasDefaultReply = false;
|
||||
return {
|
||||
type: 'TRANSFER',
|
||||
content: '',
|
||||
type: 'TRANSFER' as MessageType,
|
||||
content: '无',
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -143,20 +159,17 @@ export class MessageService {
|
||||
}
|
||||
|
||||
if (hasDefaultReply) {
|
||||
const replyContent = await this.choseRandomReply(reply.content);
|
||||
reply = {
|
||||
type: reply.type as MessageType,
|
||||
content: replyContent,
|
||||
};
|
||||
reply = await this.getDefaultReply(cfg);
|
||||
this.log.warn(`未匹配到用户消息,所以使用默认回复: ${reply.content}`);
|
||||
}
|
||||
|
||||
if (cfg.has_replace) {
|
||||
if (reply.type === 'TEXT') {
|
||||
if (reply && reply.type === 'TEXT') {
|
||||
reply.content = await this.matchReplaceKeyword(ctx, reply.content);
|
||||
}
|
||||
}
|
||||
|
||||
return reply;
|
||||
return reply as ReplyDTO;
|
||||
}
|
||||
|
||||
public async createTextReply(content: string) {
|
||||
|
||||
@@ -95,18 +95,12 @@ export class PluginService {
|
||||
throw new Error('Plugin not found');
|
||||
}
|
||||
|
||||
const cfg = await this.configController.get(ctx);
|
||||
|
||||
try {
|
||||
const { data } = await this.executePluginCode(plugin.code, ctx, messages);
|
||||
return { ...data };
|
||||
} catch (error) {
|
||||
console.error('Plugin execution error:', error);
|
||||
return {
|
||||
type: 'TEXT',
|
||||
content:
|
||||
cfg.default_reply || 'An error occurred while executing the plugin',
|
||||
};
|
||||
this.log.error(`插件执行失败: ${error}`);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -211,15 +205,15 @@ export class PluginService {
|
||||
return { data: data as ReplyDTO, consoleOutput };
|
||||
}
|
||||
|
||||
this.log.error('未返回有效响应');
|
||||
|
||||
throw new Error('Plugin function did not return a valid response');
|
||||
this.log.error(`未返回有效响应,插件返回数据: ${JSON.stringify(data)}`);
|
||||
throw new Error('Plugin function did not return a valid response', data);
|
||||
} catch (error: any) {
|
||||
console.error('Plugin execution error:', error);
|
||||
|
||||
this.log.error(`运行插件的日志信息: ${JSON.stringify(consoleOutput)}`);
|
||||
this.log.error(
|
||||
`回复失败: ${error instanceof Error ? error.message : String(error)}`,
|
||||
);
|
||||
|
||||
error.consoleOutput = consoleOutput;
|
||||
throw error;
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ export enum PlatformTypeEnum {
|
||||
}
|
||||
|
||||
export type RoleType = 'SELF' | 'OTHER' | 'SYSTEM';
|
||||
export type MessageType = 'TEXT' | 'IMAGE' | 'VIDEO' | 'FILE';
|
||||
export type MessageType = 'TEXT' | 'IMAGE' | 'VIDEO' | 'FILE' | 'NO_REPLY';
|
||||
|
||||
export type Context = Map<string, string>;
|
||||
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@ export interface PlatformSettings {
|
||||
}
|
||||
|
||||
export type RoleType = 'SELF' | 'OTHER' | 'SYSTEM';
|
||||
export type MessageType = 'TEXT' | 'IMAGE' | 'VIDEO' | 'FILE';
|
||||
export type MessageType = 'TEXT' | 'IMAGE' | 'VIDEO' | 'FILE' | 'NO_REPLY';
|
||||
|
||||
export interface Reply {
|
||||
content: string;
|
||||
|
||||
@@ -16,7 +16,7 @@ export const PluginExtraLib = `
|
||||
|
||||
type RoleType = 'SELF' | 'OTHER' | 'SYSTEM';
|
||||
|
||||
type MessageType = 'TEXT' | 'IMAGE' | 'VIDEO' | 'FILE';
|
||||
type MessageType = 'TEXT' | 'IMAGE' | 'VIDEO' | 'FILE' | 'NO_REPLY';
|
||||
|
||||
type Message = {
|
||||
sender: string; // 发送者
|
||||
@@ -42,7 +42,7 @@ const rp = require('reply_srv');
|
||||
*/
|
||||
async function main(ctx, messages) {
|
||||
const cfg = await cc.get(ctx);
|
||||
return await rp.getDefaultReply(cfg, ctx, messages);
|
||||
return await rp.getReply(cfg, ctx, messages);
|
||||
}`;
|
||||
|
||||
export const LLMTypeList = [
|
||||
@@ -168,14 +168,14 @@ export const ModelList = [
|
||||
];
|
||||
|
||||
// 固定会传递的上下文参数
|
||||
export const CTX_APP_NAME = 'app_name';
|
||||
export const CTX_APP_ID = 'app_id';
|
||||
export const CTX_INSTANCE_ID = 'instance_id';
|
||||
export const CTX_APP_NAME = 'CTX_APP_NAME';
|
||||
export const CTX_APP_ID = 'CTX_APP_ID';
|
||||
export const CTX_INSTANCE_ID = 'CTX_INSTANCE_ID';
|
||||
|
||||
export const CTX_USERNAME = 'username'; // 当前操作的用户名
|
||||
export const CTX_PLATFORM = 'platform'; // 当前所在平台
|
||||
export const CTX_HAS_NEW_MESSAGE = 'has_new_message'; // 是否有新消息
|
||||
export const CTX_HAS_GROUP_MESSAGE = 'has_group_message'; // 是否有群消息
|
||||
export const CTX_USERNAME = 'CTX_USERNAME'; // 当前操作的用户名
|
||||
export const CTX_PLATFORM = 'CTX_PLATFORM'; // 当前所在平台
|
||||
export const CTX_HAS_NEW_MESSAGE = 'CTX_HAS_NEW_MESSAGE'; // 是否有新消息
|
||||
export const CTX_HAS_GROUP_MESSAGE = 'CTX_HAS_GROUP_MESSAGE'; // 是否有群消息
|
||||
|
||||
// 电商平台
|
||||
export const CTX_CURRENT_GOODS = 'CTX_CURRENT_GOODS'; // 当前商品
|
||||
@@ -184,6 +184,12 @@ export const CTX_MEMBER_TAG = 'CTX_MEMBER_TAG'; // 会员标签
|
||||
export const CTX_FAN_TAG = 'CTX_FAN_TAG'; // 粉丝标签
|
||||
export const CTX_NEW_CUSTOMER_TAG = 'CTX_NEW_CUSTOMER_TAG'; // 新客标签
|
||||
|
||||
export const CTX_ORDER_STATUS = 'CTX_ORDER_STATUS'; // 订单状态
|
||||
export const CTX_ORDER_ID = 'CTX_ORDER_ID'; // 订单 ID
|
||||
export const CTX_ORDER_AMOUNT = 'CTX_ORDER_AMOUNT'; // PDD 平台特有 [订单金额]
|
||||
export const CTX_GOODS_SPEC = 'CTX_GOODS_SPEC'; // PDD 平台特有 [商品规格]
|
||||
export const CTX_LOGISTICS_STATUS = 'CTX_LOGISTICS_STATUS'; // 物流状态
|
||||
|
||||
export const ContextKeys = [
|
||||
CTX_APP_NAME,
|
||||
CTX_APP_ID,
|
||||
@@ -197,6 +203,11 @@ export const ContextKeys = [
|
||||
CTX_MEMBER_TAG,
|
||||
CTX_FAN_TAG,
|
||||
CTX_NEW_CUSTOMER_TAG,
|
||||
CTX_ORDER_STATUS,
|
||||
CTX_ORDER_ID,
|
||||
CTX_ORDER_AMOUNT,
|
||||
CTX_GOODS_SPEC,
|
||||
CTX_LOGISTICS_STATUS,
|
||||
];
|
||||
|
||||
export const MockCtx = new Map<string, string>([
|
||||
|
||||
@@ -9,5 +9,5 @@ const rp = require('reply_srv');
|
||||
*/
|
||||
async function main(ctx, messages) {
|
||||
const cfg = await cc.get(ctx);
|
||||
return await rp.getDefaultReply(cfg, ctx, messages);
|
||||
return await rp.getReply(cfg, ctx, messages);
|
||||
}`;
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
export const QIANNIU_GOODS_PLUGIN = `const cc = require('config_srv');
|
||||
const rp = require('reply_srv');
|
||||
|
||||
/**
|
||||
* 插件主函数
|
||||
* @param {AppContext} ctx - 上下文信息
|
||||
* @param {Message[]} messages - 消息数组
|
||||
* @returns {Reply} 插件执行结果
|
||||
*/
|
||||
async function main(ctx, messages) {
|
||||
const appId = ctx.get('app_id');
|
||||
const cfg = cc.get(ctx);
|
||||
|
||||
if (appId === 'win_qianniu') {
|
||||
// 取得用户最后一条消息
|
||||
const lastMessage = messages[messages.length - 1];
|
||||
|
||||
// 可以取得它的消息内容
|
||||
const goodsId = ctx.get('CTX_CURRENT_GOODS_ID');
|
||||
const goodsName = ctx.get('CTX_CURRENT_GOODS');
|
||||
|
||||
// 构建一个消息
|
||||
const msg = {
|
||||
sender: 'SYSTEM',
|
||||
role: 'OTHER',
|
||||
content: \`1. 当前客户询问的商品 ID 是:
|
||||
"""
|
||||
\${goodsId}
|
||||
"""
|
||||
|
||||
2. 咨询的商品名称是:
|
||||
"""
|
||||
\${goodsName}
|
||||
"""
|
||||
|
||||
3. 当前客户的问题是:
|
||||
"""
|
||||
\${lastMessage.content}
|
||||
"""
|
||||
\`,
|
||||
type: 'TEXT',
|
||||
};
|
||||
|
||||
// 替换用户的这条消息
|
||||
messages = [msg];
|
||||
const reply = await rp.getDefaultReply(cfg, ctx, messages);
|
||||
return reply;
|
||||
}
|
||||
const reply = await rp.getDefaultReply(cfg, ctx, messages);
|
||||
return reply;
|
||||
}
|
||||
`;
|
||||
@@ -1,63 +0,0 @@
|
||||
export const WECHAT_NEWS_PLUGIN = `const cc = require('config_srv');
|
||||
const rp = require('reply_srv');
|
||||
const axios = require('axios');
|
||||
|
||||
/**
|
||||
* 插件主函数
|
||||
* @param {AppContext} ctx - 上下文信息
|
||||
* @param {Message[]} messages - 消息数组
|
||||
* @returns {Reply} 插件执行结果
|
||||
*/
|
||||
async function main(ctx, messages) {
|
||||
const appId = ctx.get('app_id');
|
||||
const cfg = cc.get(ctx);
|
||||
|
||||
if (appId === 'win_wechat') {
|
||||
// 取得用户最后一条消息
|
||||
const lastMessage = messages[messages.length - 1];
|
||||
|
||||
// 可以取得它的消息内容
|
||||
const hasGroup = ctx.get('CTX_HAS_GROUP_MESSAGE');
|
||||
|
||||
// 检查当前消息是否携带 @BOT 指令
|
||||
const hasBotCommand = lastMessage.content.includes('@BOT');
|
||||
|
||||
// 如果还携带了 [热榜] 关键词
|
||||
const hasNewsKeyword = lastMessage.content.includes('[热榜]');
|
||||
|
||||
if (hasGroup && hasBotCommand && hasNewsKeyword) {
|
||||
try {
|
||||
// 使用 axios 请求新闻数据
|
||||
const response = await axios.get('https://api.vvhan.com/api/hotlist/all');
|
||||
const newsData = response.data;
|
||||
|
||||
if (newsData.success) {
|
||||
const newsList = newsData.data;
|
||||
let replyContent = \`\${new Date().toLocaleDateString('zh-CN', { year: 'numeric', month: 'long', day: 'numeric', weekday: 'long' })}\\n\\n\`;
|
||||
|
||||
// 遍历每个平台的新闻
|
||||
newsList.forEach(platform => {
|
||||
replyContent += \`\${platform.name} \${platform.subtitle} 更新于 \${platform.update_time}\\n\`;
|
||||
platform.data.slice(0, 3).forEach((news, index) => {
|
||||
replyContent += \`\${index + 1}. \${news.title} 热度: \${news.hot}\\n\`;
|
||||
});
|
||||
replyContent += '\\n';
|
||||
});
|
||||
|
||||
// 发送回复
|
||||
return rp.createTextReply(replyContent);
|
||||
} else {
|
||||
return rp.createTextReply('无法获取新闻数据,请稍后再试。');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取新闻数据出错:', error);
|
||||
return rp.createTextReply('获取新闻数据时出错,请稍后再试。');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 默认回复
|
||||
const reply = await rp.getDefaultReply(cfg, ctx, messages);
|
||||
return reply;
|
||||
}
|
||||
`;
|
||||
@@ -308,7 +308,7 @@ const GeneralSettings = ({
|
||||
</Flex>
|
||||
<Slider
|
||||
min={50}
|
||||
max={210}
|
||||
max={4000}
|
||||
step={5}
|
||||
value={config.truncateWordCount}
|
||||
onChange={(truncateWordCount) =>
|
||||
|
||||
Reference in New Issue
Block a user