feat: 更新版本

This commit is contained in:
lrhh123
2024-06-30 16:49:12 +08:00
parent 60af2783d4
commit 95465ae679
24 changed files with 524 additions and 113 deletions
+1 -1
View File
@@ -65,7 +65,7 @@
- Add experimental support for vscode debugging
- Revert https://github.com/electron-react-boilerplate/electron-react-boilerplate/pull/2365 as default for users, provide as opt in option
# 1.1.0
# 1.2.0-beta.1
- Fix #2402
- Simplify configs (https://github.com/electron-react-boilerplate/electron-react-boilerplate/pull/2406)
+1 -1
View File
@@ -60,7 +60,7 @@
## 下载地址
<a href="https://github.com/cs-lazy-tools/ChatGPT-On-CS/releases/download/v1.1.0/1.1.0.exe" style="display: inline-block; background-color: #008CBA; color: white; padding: 10px 20px; text-align: center; text-decoration: none; font-weight: bold; border-radius: 5px; margin: 4px 2px; cursor: pointer;">点击下载</a>
<a href="https://github.com/cs-lazy-tools/ChatGPT-On-CS/releases/download/v1.2.0-beta.1/1.2.0-beta.1.exe" style="display: inline-block; background-color: #008CBA; color: white; padding: 10px 20px; text-align: center; text-decoration: none; font-weight: bold; border-radius: 5px; margin: 4px 2px; cursor: pointer;">点击下载</a>
如果网络环境导致下载不了,可以使用百度云盘下载:
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "chatgpt-on-cs",
"description": "多平台智能客服,允许使用 ChatGPT 作为客服机器人",
"version": "1.1.0",
"version": "1.2.0-beta.1",
"keywords": [
"electron",
"boilerplate",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "chatgpt-on-cs",
"version": "1.1.0",
"version": "1.2.0-beta.1",
"lockfileVersion": 3,
"requires": true,
"packages": {
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "chatgpt-on-cs",
"version": "1.1.0",
"version": "1.2.0-beta.1",
"description": "多平台智能客服,允许使用 ChatGPT 作为客服机器人",
"license": "AGPL-3.0",
"author": {
+25 -2
View File
@@ -284,6 +284,8 @@ class BKServer {
keyword: item.keyword,
reply: item.reply,
mode: item.mode,
fuzzy: item.fuzzy,
has_regular: item.has_regular,
app_name: ptf ? ptf.name : '全局',
};
@@ -300,23 +302,42 @@ class BKServer {
});
this.app.post('/api/v1/reply/create', async (req, res) => {
const { platform_id: platformId, keyword, reply, mode } = req.body;
const {
platform_id: platformId,
keyword,
reply,
mode,
fuzzy,
has_regular,
} = req.body;
await this.keywordReplyController.create({
mode,
platform_id: platformId,
keyword,
reply,
fuzzy,
has_regular,
});
res.json({ success: true });
});
this.app.post('/api/v1/reply/update', async (req, res) => {
const { id, platform_id: platformId, keyword, reply, mode } = req.body;
const {
id,
platform_id: platformId,
keyword,
reply,
mode,
fuzzy,
has_regular,
} = req.body;
await this.keywordReplyController.update(id, {
mode,
platform_id: platformId,
keyword,
reply,
fuzzy,
has_regular,
});
res.json({ success: true });
});
@@ -474,6 +495,8 @@ class BKServer {
replace: item.replace,
app_id: item.app_id,
app_name: ptf ? ptf.name : '全局',
has_regular: item.has_regular,
fuzzy: item.fuzzy,
};
results.push(result);
@@ -68,6 +68,8 @@ export class KeywordReplyController {
const keyword = row.getCell(1).text.trim();
const reply = row.getCell(2).text.trim();
const platform = row.getCell(3).text.trim();
const fuzzy = row.getCell(4).text.trim() === '是';
const has_regular = row.getCell(5).text.trim() === '是';
let platformId = '';
if (platform && platformMap.has(platform)) {
@@ -78,7 +80,8 @@ export class KeywordReplyController {
keyword: String(keyword),
reply: String(reply),
platform_id: String(platformId),
mode: 'fuzzy',
fuzzy,
has_regular,
});
}
});
@@ -122,6 +125,8 @@ export class KeywordReplyController {
{ key: 'keyword', width: 32 },
{ key: 'reply', width: 100 },
{ key: 'platform', width: 32 },
{ key: 'fuzzy', width: 10 },
{ key: 'has_regular', width: 10 },
];
// 添加复杂的标题描述并设置换行和加粗
@@ -149,12 +154,24 @@ export class KeywordReplyController {
};
worksheet.getRow(1).height = 150;
worksheet.addRow(['匹配关键词', '回复内容', '平台']);
worksheet.addRow([
'匹配关键词',
'回复内容',
'平台',
'模糊匹配',
'支持正则',
]);
// 添加数据行
autoReplies.forEach((autoReply) => {
const name = platformMap.get(autoReply.platform_id) || '';
worksheet.addRow([autoReply.keyword, autoReply.reply, name]);
worksheet.addRow([
autoReply.keyword,
autoReply.reply,
name,
autoReply.fuzzy ? '是' : '否',
autoReply.has_regular ? '是' : '否',
]);
});
// 检查是否存在 excels 文件夹,不存在则创建
@@ -186,6 +203,42 @@ export class KeywordReplyController {
return [...globalKeywords, ...autoReplies];
}
async getReplaceKeywords(platformId: string) {
const replaceKeywords = await ReplaceKeyword.findAll({
where: {
app_id: platformId,
},
});
const globalKeywords = await ReplaceKeyword.findAll({
where: {
app_id: {
[Op.or]: [null, ''],
},
},
});
return [...globalKeywords, ...replaceKeywords];
}
async getTransferKeywords(platformId: string) {
const transferKeywords = await TransferKeyword.findAll({
where: {
app_id: platformId,
},
});
const globalKeywords = await TransferKeyword.findAll({
where: {
app_id: {
[Op.or]: [null, ''],
},
},
});
return [...globalKeywords, ...transferKeywords];
}
async list({
page,
pageSize,
@@ -409,8 +462,8 @@ export class KeywordReplyController {
const name = platformMap.get(autoReply.app_id) || '';
worksheet.addRow([
autoReply.keyword,
autoReply.fuzzy,
autoReply.has_regular,
autoReply.fuzzy ? '是' : '否',
autoReply.has_regular ? '是' : '否',
name,
]);
});
+38
View File
@@ -11,6 +11,32 @@ export class Keyword extends Model {
declare mode: string;
declare platform_id: string;
declare fuzzy: boolean;
declare has_regular: boolean;
}
export async function checkAndAddFields(sequelize: Sequelize) {
const tableDescription = await Keyword.describe();
// @ts-ignore
if (!tableDescription.fuzzy) {
await sequelize.getQueryInterface().addColumn('keyword', 'fuzzy', {
type: DataTypes.BOOLEAN,
allowNull: true,
defaultValue: true,
});
}
// @ts-ignore
if (!tableDescription.has_regular) {
await sequelize.getQueryInterface().addColumn('keyword', 'has_regular', {
type: DataTypes.BOOLEAN,
allowNull: true,
defaultValue: false,
});
}
}
export function initKeyword(sequelize: Sequelize) {
@@ -37,6 +63,16 @@ export function initKeyword(sequelize: Sequelize) {
type: DataTypes.STRING(255),
allowNull: true,
},
fuzzy: {
type: DataTypes.BOOLEAN,
allowNull: true,
defaultValue: true,
},
has_regular: {
type: DataTypes.BOOLEAN,
allowNull: true,
defaultValue: false,
},
},
{
sequelize,
@@ -45,4 +81,6 @@ export function initKeyword(sequelize: Sequelize) {
timestamps: false,
},
);
checkAndAddFields(sequelize);
}
+1 -1
View File
@@ -128,7 +128,7 @@ export function initPlugin(sequelize: Sequelize) {
},
version: {
type: DataTypes.STRING(255),
defaultValue: '1.1.0',
defaultValue: '1.2.0-beta.1',
allowNull: true,
},
source: {
+2 -1
View File
@@ -33,7 +33,8 @@ export function initReplace(sequelize: Sequelize) {
},
has_regular: {
type: DataTypes.BOOLEAN,
allowNull: false,
allowNull: true,
defaultValue: false,
},
app_id: {
type: DataTypes.STRING(255),
+2 -1
View File
@@ -27,7 +27,8 @@ export function initTransfer(sequelize: Sequelize) {
},
has_regular: {
type: DataTypes.BOOLEAN,
allowNull: false,
allowNull: true,
defaultValue: false,
},
app_id: {
type: DataTypes.STRING(255),
+154 -41
View File
@@ -17,7 +17,11 @@ import {
CTX_FAN_TAG,
CTX_NEW_CUSTOMER_TAG,
} from '../constants';
import { rangeMatch, specialTokenReplace } from '../../utils/strings';
import {
rangeMatch,
specialTokenReplace,
replaceKeyword,
} from '../../utils/strings';
import {
ErnieAI,
GeminiAI,
@@ -55,66 +59,91 @@ export class MessageService {
this.llmClientMap = new Map();
}
/**
* 获取默认回复
* @param cfg
* @param ctx
* @param messages
* @returns
*/
public async getDefaultReply(
cfg: Config,
ctx: Context,
messages: MessageDTO[],
) {
): Promise<{ type: string; content: string }> {
// 先检查是否存在用户的消息
const lastUserMsg = messages
.slice()
.reverse()
.find((msg) => msg.role === 'OTHER');
const reply = {
let reply = {
type: 'TEXT',
content: cfg.default_reply || '当前消息有点多,我稍后再回复你',
};
if (!lastUserMsg) {
this.log.warn(`未匹配到用户消息,所以使用默认回复: ${reply.content}`);
return reply;
}
// 再根据 context_count 去保留最后几条消息
if (cfg.context_count > 0) {
// eslint-disable-next-line no-param-reassign
messages = messages.slice(-cfg.context_count);
}
// 等待随机时间
await new Promise((resolve) => {
const min = cfg.reply_speed;
const max = cfg.reply_random_speed + cfg.reply_speed;
const randomTime = min + Math.random() * (max - min);
setTimeout(resolve, randomTime * 1000);
});
// 再检查是否使用关键词匹配
if (cfg.has_keyword_match) {
const data = await this.matchKeyword(ctx, lastUserMsg);
if (data && data.content) {
this.log.success(`匹配关键词: ${data.content}`);
return data;
}
this.log.warn(`未匹配到关键词`);
}
// 最后检查是否使用 GPT 生成回复
if (cfg.has_use_gpt) {
this.log.info(`开始使用 GPT 生成回复`);
const data = await this.getLLMResponse(cfg, ctx, messages);
if (data && data.content) {
this.log.success(`GPT 生成回复: ${data.content}`);
return data;
} else {
// 检查是否需要转接
const isTransfer = await this.matchTransferKeyword(ctx, lastUserMsg);
if (isTransfer) {
this.log.info('需要转接');
return {
type: 'TRANSFER',
content: '',
};
}
this.log.warn(`AI 回复生成失败`);
// 再根据 context_count 去保留最后几条消息
if (cfg.context_count > 0) {
// eslint-disable-next-line no-param-reassign
messages = messages.slice(-cfg.context_count);
}
// 等待随机时间
await new Promise((resolve) => {
const min = cfg.reply_speed;
const max = cfg.reply_random_speed + cfg.reply_speed;
const randomTime = min + Math.random() * (max - min);
setTimeout(resolve, randomTime * 1000);
});
// 再检查是否使用关键词匹配
if (cfg.has_keyword_match) {
const data = await this.matchKeyword(ctx, lastUserMsg);
if (data && data.content) {
this.log.success(`匹配关键词: ${data.content}`);
reply = data;
} else {
this.log.warn(`未匹配到关键词`);
}
}
// 最后检查是否使用 GPT 生成回复
if (
cfg.has_use_gpt &&
reply.content ===
(cfg.default_reply || '当前消息有点多,我稍后再回复你')
) {
this.log.info(`开始使用 GPT 生成回复`);
const data = await this.getLLMResponse(cfg, ctx, messages);
if (data && data.content) {
this.log.success(`GPT 生成回复: ${data.content}`);
reply = data;
} else {
this.log.warn(`AI 回复生成失败`);
}
}
}
this.log.info('使用默认回复');
if (reply.type === 'TEXT') {
reply.content = await this.matchReplaceKeyword(ctx, reply.content);
}
return reply;
}
@@ -125,6 +154,85 @@ export class MessageService {
};
}
/**
* 匹配需要替换的关键词
* @param ctx
* @param message
* @returns
*/
public async matchReplaceKeyword(
ctx: Context,
reply: string,
): Promise<string> {
const appId = ctx.get(CTX_APP_ID);
if (!appId) return reply;
const replaceKeywords =
await this.autoReplyController.getReplaceKeywords(appId);
// 先找到匹配的关键词
const foundKeywordObj = replaceKeywords.find((keywordObj) => {
return keywordObj.keyword.split('|').some((pattern) => {
return rangeMatch(
pattern,
reply,
keywordObj.fuzzy,
keywordObj.has_regular,
);
});
});
// 如果找到匹配的关键词对象,进行替换
if (foundKeywordObj) {
foundKeywordObj.keyword.split('|').forEach((pattern) => {
// eslint-disable-next-line no-param-reassign
reply = replaceKeyword(
pattern,
reply,
foundKeywordObj.replace,
foundKeywordObj.fuzzy,
foundKeywordObj.has_regular,
);
});
}
return reply;
}
/**
* 匹配关键词
* @param ctx
* @param message
* @returns
*/
public async matchTransferKeyword(
ctx: Context,
message: MessageDTO,
): Promise<boolean> {
const appId = ctx.get(CTX_APP_ID);
if (!appId) return false;
const keywords = await this.autoReplyController.getTransferKeywords(appId);
// 先找到匹配的关键词
const foundKeywordObj = keywords.find((keywordObj) => {
return keywordObj.keyword.split('|').some((pattern) => {
return rangeMatch(
pattern,
message.content,
keywordObj.fuzzy,
keywordObj.has_regular,
);
});
});
if (foundKeywordObj) {
return true;
}
return false;
}
/**
* 匹配关键词
* @param ctx
@@ -143,7 +251,12 @@ export class MessageService {
// 先找到匹配的关键词
const foundKeywordObj = keywords.find((keywordObj) => {
return keywordObj.keyword.split('|').some((pattern) => {
return rangeMatch(pattern, message.content);
return rangeMatch(
pattern,
message.content,
keywordObj.fuzzy,
keywordObj.has_regular,
);
});
});
+165 -26
View File
@@ -2,56 +2,195 @@
* 范围匹配
* @param ptt 范围查询关键词 e.g. 'hello [and] world'
* @param msg 消息
* @param fuzzy 是否模糊匹配
* @param has_regular 是否使用正则表达式
* @returns
*/
export function rangeMatch(ptt: string, msg: string): boolean {
export function rangeMatch(
ptt: string,
msg: string,
fuzzy: boolean,
has_regular: boolean,
): boolean {
if (ptt.includes('[and]')) {
const keywords = ptt.split('[and]');
return keywords.every((keyword) => matchKeyword(keyword.trim(), msg));
return keywords.every((keyword, index) => {
if (index === 0) {
return matchKeyword(keyword.trim(), msg, fuzzy, has_regular);
}
const prevKeyword = keywords[index - 1].trim();
const prevIndex = msg.indexOf(prevKeyword);
if (prevIndex === -1) {
return false;
}
return matchKeyword(
keyword.trim(),
msg.slice(prevIndex + prevKeyword.length),
fuzzy,
has_regular,
);
});
}
return matchKeyword(ptt, msg);
return matchKeyword(ptt, msg, fuzzy, has_regular);
}
/**
* 匹配关键词
* @param ptt 匹配模式
* @param msg 消息
* @param fuzzy 是否模糊匹配
* @param has_regular 是否使用正则表达式
* @returns
*/
export function matchKeyword(ptt: string, msg: string): boolean {
let pattern = ptt.trim();
export function matchKeyword(
ptt: string,
msg: string,
fuzzy: boolean,
has_regular: boolean,
): boolean {
try {
const pattern = ptt.trim();
if (has_regular) {
const regex = new RegExp(pattern);
return regex.test(msg);
}
// 如果模式只是一个星号,它应该匹配任何消息。
if (pattern === '*') {
return true;
if (fuzzy) {
return msg.includes(pattern);
}
return msg.trim() === pattern;
} catch (e) {
console.error(e);
return false;
}
}
/**
* 范围匹配
* @param ptt 范围查询关键词 e.g. 'hello [and] world'
* @param msg 消息
* @param fuzzy 是否模糊匹配
* @param has_regular 是否使用正则表达式
* @returns 匹配到的开始和结束位置数组
*/
export function rangeMatchPosition(
ptt: string,
msg: string,
fuzzy: boolean,
has_regular: boolean,
): Array<[number, number]> {
const matchPositions: Array<[number, number]> = [];
if (ptt.includes('[and]')) {
const keywords = ptt.split('[and]');
let searchStart = 0;
// eslint-disable-next-line no-restricted-syntax
for (const keyword of keywords) {
const trimmedKeyword = keyword.trim();
const matchPosition = matchKeywordPosition(
trimmedKeyword,
msg,
fuzzy,
has_regular,
searchStart,
);
if (matchPosition) {
matchPositions.push(matchPosition);
// eslint-disable-next-line prefer-destructuring
searchStart = matchPosition[1];
} else {
return [];
}
}
} else {
const matchPosition = matchKeywordPosition(ptt, msg, fuzzy, has_regular, 0);
if (matchPosition) {
matchPositions.push(matchPosition);
}
}
// 合并连续的 '*' 字符为一个 '*'
pattern = pattern.replace(/\*+/g, '*');
return matchPositions;
}
// 如果模式不包含 '*',则检查是否包含关键词
if (!pattern.includes('*')) {
return msg.includes(pattern);
/**
* 匹配关键词并返回位置
* @param ptt 匹配模式
* @param msg 消息
* @param fuzzy 是否模糊匹配
* @param has_regular 是否使用正则表达式
* @param searchStart 搜索的起始位置
* @returns 匹配到的开始和结束位置
*/
function matchKeywordPosition(
ptt: string,
msg: string,
fuzzy: boolean,
has_regular: boolean,
searchStart: number,
): [number, number] | null {
const pattern = ptt.trim();
if (has_regular) {
const regex = new RegExp(pattern);
const match = regex.exec(msg.slice(searchStart));
if (match) {
return [
searchStart + match.index,
searchStart + match.index + match[0].length,
];
}
return null;
}
const parts = pattern.split('*');
if (fuzzy) {
const index = msg.indexOf(pattern, searchStart);
if (index !== -1) {
return [index, index + pattern.length];
}
return null;
}
const index = msg.indexOf(pattern, searchStart);
if (index !== -1 && index + pattern.length === msg.length) {
return [index, index + pattern.length];
}
return null;
}
/**
* 替换匹配的关键词
* @param ptt 匹配模式
* @param msg 消息
* @param replace 替换字符串
* @param fuzzy 是否模糊匹配
* @param has_regular 是否使用正则表达式
* @returns
*/
export function replaceKeyword(
ptt: string,
msg: string,
replace: string,
fuzzy: boolean,
has_regular: boolean,
): string {
const matchPositions = rangeMatchPosition(ptt, msg, fuzzy, has_regular);
if (matchPositions.length === 0) {
return msg;
}
let result = '';
let lastIndex = 0;
// eslint-disable-next-line no-restricted-syntax
for (const part of parts) {
// 跳过空字符串(它们来自模式开始、结束或连续 '*'
if (part === '') continue;
const index = msg.indexOf(part, lastIndex);
// 如果找不到部分或部分不是按顺序出现,则匹配失败
if (index === -1 || index < lastIndex) {
return false;
}
lastIndex = index + part.length;
for (const [start, end] of matchPositions) {
result += msg.slice(lastIndex, start) + replace;
lastIndex = end;
}
// 确保消息的剩余部分可以被模式尾部的 '*' 匹配
return parts[parts.length - 1] === '' || lastIndex <= msg.length;
result += msg.slice(lastIndex);
return result;
}
/**
+2
View File
@@ -130,6 +130,8 @@ export interface Keyword {
platform_id?: string;
keyword: string;
reply: string;
fuzzy?: boolean;
has_regular?: boolean;
}
export interface TransferKeyword {
@@ -1,5 +1,4 @@
import { WECHAT_NEWS_PLUGIN } from './wechat';
import { QIANNIU_GOODS_PLUGIN } from './qianniu';
import { NORMAL_PLUGIN } from './normal';
// 转换为 JSON 格式
// https://www.lambdatest.com/free-online-tools/json-escape
@@ -13,21 +12,12 @@ export const SystemPluginList = [
},
{
type: 'plugin',
title: '微信热榜播报插件',
author: '系统插件',
description: '当用户使用 @BOT 并且携带 [热榜] 关键字时,将会触发此插件。',
tags: ['微信', '热榜', '机器人'],
code: WECHAT_NEWS_PLUGIN,
icon: '📰',
},
{
type: 'plugin',
title: '千牛商品查询插件',
title: '基础对话插件',
author: '系统插件',
description:
'会携带商品名称,商品 ID 等信息去询问 GPT 知识库(需要自己配置知识库)',
tags: ['千牛', '商品', '机器人'],
code: QIANNIU_GOODS_PLUGIN,
icon: '🎁',
'默认的回复流程,会根据设置去选择使用关键词回复或者使用 GPT 回复。',
tags: ['系统'],
code: NORMAL_PLUGIN,
icon: '⚙️',
},
];
@@ -0,0 +1,13 @@
export const NORMAL_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 cfg = await cc.get(ctx);
return await rp.getDefaultReply(cfg, ctx, messages);
}`;
@@ -9,6 +9,11 @@ import {
ModalBody,
ModalFooter,
useToast,
Flex,
Box,
Switch,
FormControl,
FormLabel,
} from '@chakra-ui/react';
import { useQuery } from '@tanstack/react-query';
import {
@@ -54,6 +59,8 @@ const EditKeyword = ({
const [currentPlatform, setCurrentPlatform] = useState<App | undefined>(
undefined,
);
const [fuzzy, setFuzzy] = useState<boolean>(true);
const [regular, setRegular] = useState<boolean>(false);
useEffect(() => {
if (!editKeyword?.keyword) {
@@ -204,6 +211,34 @@ const EditKeyword = ({
isLoading={isPlatformsLoading}
/>
)}
<Flex direction="column">
<Box m={2}>
<FormControl display="flex" alignItems="center">
<FormLabel htmlFor="fuzzy" mb="0">
</FormLabel>
<Switch
id="fuzzy"
isChecked={fuzzy}
onChange={() => setFuzzy(!fuzzy)}
/>
</FormControl>
</Box>
<Box m={2}>
<FormControl display="flex" alignItems="center">
<FormLabel htmlFor="regular" mb="0">
</FormLabel>
<Switch
id="regular"
isChecked={regular}
onChange={() => setRegular(!regular)}
/>
</FormControl>
</Box>
</Flex>
<KeywordInput
newKeyword={newKeyword}
setNewKeyword={setNewKeyword}
@@ -177,8 +177,8 @@ const ReplaceKeyword = () => {
<Box>
<Box display="flex" justifyContent="space-between" mb={2}>
<Alert status="info" mr={'20px'}>
ChatGPT
ChatGPT
ChatGPT
</Alert>
<Flex alignItems="center">
<HStack>
@@ -229,6 +229,8 @@ const ReplyKeyword = () => {
<Th></Th>
<Th></Th>
<Th></Th>
<Th></Th>
<Th></Th>
<Th></Th>
</Tr>
</Thead>
@@ -256,6 +258,8 @@ const ReplyKeyword = () => {
>
{keyword.reply}
</Td>
<Td>{keyword.fuzzy ? '是' : '否'}</Td>
<Td>{keyword.has_regular ? '是' : '否'}</Td>
<Td>
<Grid templateColumns="repeat(2, 1fr)" gap={2}>
<Tooltip label="删除">
@@ -232,8 +232,8 @@ const TransferKeyword = () => {
<Tr>
<Th></Th>
<Th></Th>
<Th></Th>
<Th></Th>
<Th></Th>
<Th></Th>
<Th></Th>
</Tr>
</Thead>
@@ -31,7 +31,6 @@ const InstanceListComponent = () => {
const toast = useToast();
useEffect(() => {
console.log('selectedAppId', selectedAppId, filteredInstances);
setCurrentAppId(selectedAppId);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [selectedAppId]);
+6 -6
View File
@@ -19,7 +19,7 @@ import {
Button,
} from '@chakra-ui/react';
import { loader } from '@monaco-editor/react';
import { BrowserRouter as Router, Route, Routes } from 'react-router-dom';
import { HashRouter as Router, Route, Routes } from 'react-router-dom';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import GeneralSettings from './components/Settings/GeneralSettings';
import LLMSettings from './components/Settings/LLMSettings';
@@ -64,6 +64,9 @@ const App = () => {
trackPageView('Settings');
}, []);
// 打印当前的 url
// console.log('current url:', window.location.href);
const fetchConfigActive = useCallback(
async (appId: string, instanceId?: string) => {
try {
@@ -236,7 +239,7 @@ const App = () => {
<Router>
<Routes>
<Route
path="/settings.html"
path="/"
element={
<PluginPage
appId={settings.appId}
@@ -244,10 +247,7 @@ const App = () => {
/>
}
/>
<Route
path="/settings.html/editor"
element={<PluginEditPage />}
/>
<Route path="/editor" element={<PluginEditPage />} />
</Routes>
</Router>
</TabPanel>
@@ -198,12 +198,12 @@ const PluginPage = ({ appId, instanceId }: PluginPageProps) => {
const handleEdit = (plugin: Plugin) => {
if (plugin.type === 'plugin') {
setCurrentPlugin(plugin);
navigate('/settings.html/editor');
navigate('/editor');
}
if (plugin.type === 'custom') {
setCurrentPlugin(null);
navigate('/settings.html/editor');
navigate('/editor');
}
};
@@ -165,7 +165,7 @@ const PluginEdit = () => {
<Button
leftIcon={<FiChevronLeft />}
colorScheme="teal"
onClick={() => navigate('/settings.html')}
onClick={() => navigate('/')}
>
</Button>
@@ -258,7 +258,7 @@ const PluginEdit = () => {
onClick={async () => {
await handleDeletePlugin();
onClose();
navigate('/settings.html');
navigate('/');
}}
ml={3}
>