fix: 修复日志同步,add: 添加自动暂停功能

This commit is contained in:
lrhh123
2024-06-15 00:46:28 +08:00
parent 1c5c955f1a
commit 2a4927d8ee
25 changed files with 405 additions and 197 deletions
+1 -2
View File
@@ -2,5 +2,4 @@ PY_HOSTNAME=localhost
PY_PORT=9999
VAR=1234
BKEXE_PATH=./backend/__main__.exe
PKG_VERSION=0.0.1
DEBUG=true
PKG_VERSION=0.0.1
-1
View File
@@ -126,7 +126,6 @@
"ms": "^2.1.3",
"net": "^1.0.2",
"node-cron": "^3.0.3",
"node-fetch": "2.6.7",
"openai": "^4.38.3",
"pg-connection-string": "^2.6.4",
"pg-hstore": "^2.3.4",
-3
View File
@@ -104,9 +104,6 @@ dependencies:
node-cron:
specifier: ^3.0.3
version: 3.0.3
node-fetch:
specifier: 2.6.7
version: 2.6.7
openai:
specifier: ^4.38.3
version: 4.38.5
+5 -21
View File
@@ -6,7 +6,6 @@ import http from 'http';
import { Server } from 'socket.io';
import { BrowserWindow, shell } from 'electron';
import { sequelize } from './ormconfig';
import { StrategyServiceStatusEnum } from './types';
import { ConfigController } from './controllers/configController';
import { MessageController } from './controllers/messageController';
import { KeywordReplyController } from './controllers/keywordReplyController';
@@ -196,7 +195,7 @@ class BKServer {
const data = {
appId: appId ? String(appId) : undefined,
instanceId: instanceId ? String(instanceId) : undefined,
type: type ? String(type) : 'generic',
type: type ? String(type) : ('generic' as any),
};
const obj = await configController.getConfigByType(data);
@@ -225,30 +224,15 @@ class BKServer {
};
await configController.updateConfigByType(data);
await this.dispatchService.syncConfig();
res.json({ success: true });
}),
);
// Endpoint to update runner status based on incoming configuration
this.app.post('/api/v1/base/runner', async (req, res) => {
const {
is_paused: isPaused,
is_keyword_match: isKeywordMatch,
is_use_gpt: isUseGptReply,
} = req.body;
this.app.post('/api/v1/base/sync', async (req, res) => {
try {
if (isPaused) {
await this.dispatchService.updateStatus(
StrategyServiceStatusEnum.STOPPED,
);
} else {
await this.dispatchService.updateStatus(
StrategyServiceStatusEnum.RUNNING,
);
}
this.messageService.updateKeywordMatch(isKeywordMatch, isUseGptReply);
await this.dispatchService.syncConfig();
res.json({ success: true });
} catch (error) {
if (error instanceof Error) {
@@ -432,9 +416,9 @@ class BKServer {
data: task,
});
} catch (error) {
console.error(error);
res.json({
success: false,
error: error instanceof Error ? error.message : String(error),
data: null,
});
}
+2 -2
View File
@@ -109,13 +109,13 @@ async function main(ctx, messages) {
});
// 再检查是否使用关键词匹配
if (rp.isKeywordMatch) {
if (cfg.has_keyword_match) {
const data = await rp.matchKeyword(ctx, lastUserMsg);
if (data) return data;
}
// 最后检查是否使用 GPT 生成回复
if (rp.isUseGptReply) {
if (cfg.has_use_gpt) {
const data = await rp.getLLMResponse(cfg, ctx, messages);
if (data) return data;
}
@@ -6,6 +6,7 @@ import {
LLMConfig,
AccountConfig,
PluginConfig,
DriverConfig,
} from '../types';
import { CTX_APP_ID, CTX_INSTANCE_ID } from '../constants';
@@ -41,6 +42,18 @@ export class ConfigController {
config = await Config.create({
global: true,
});
} else {
const globalConfig = await Config.findOne({
where: { global: true },
});
// 这三个配置项是全局配置,需要合并到实例配置中
if (globalConfig) {
config.has_keyword_match = globalConfig.has_keyword_match;
config.has_paused = globalConfig.has_paused;
config.has_use_gpt = globalConfig.has_use_gpt;
config.has_mouse_close = globalConfig.has_mouse_close;
}
}
return config;
@@ -156,9 +169,14 @@ export class ConfigController {
}: {
appId: string | undefined;
instanceId: string | undefined;
type: string;
type: 'generic' | 'llm' | 'plugin' | 'driver' | 'account';
}): Promise<
GenericConfig | LLMConfig | AccountConfig | PluginConfig | undefined
| GenericConfig
| LLMConfig
| AccountConfig
| PluginConfig
| DriverConfig
| undefined
> {
let config = null;
if (instanceId) {
@@ -206,6 +224,7 @@ export class ConfigController {
defaultReply: config?.default_reply || '',
};
}
if (type === 'llm') {
return {
appId: config?.platform_id || '',
@@ -216,6 +235,7 @@ export class ConfigController {
model: config?.model || 'gpt-3.5-turbo',
};
}
if (type === 'plugin') {
let pluginCode = '';
@@ -232,6 +252,15 @@ export class ConfigController {
};
}
if (type === 'driver') {
return {
hasPaused: config?.has_paused || false,
hasKeywordMatch: config?.has_keyword_match || false,
hasUseGpt: config?.has_use_gpt || false,
hasMouseClose: config?.has_mouse_close || false,
};
}
return {
activationCode: config?.activation_code || '',
};
@@ -250,7 +279,12 @@ export class ConfigController {
appId: string | undefined;
instanceId: string | undefined;
type: string;
cfg: GenericConfig | LLMConfig | AccountConfig | PluginConfig;
cfg:
| GenericConfig
| LLMConfig
| AccountConfig
| PluginConfig
| DriverConfig;
}) {
let dbConfig = null;
if (instanceId) {
@@ -328,6 +362,21 @@ export class ConfigController {
use_plugin: config.usePlugin,
plugin_id: pluginId,
});
} else if (type === 'driver') {
// TODO: 目前只有全局配置,后续再实现实例配置
const config = cfg as DriverConfig;
dbConfig = await Config.findOne({
where: { global: true },
});
if (!dbConfig) {
throw new Error('Driver config not found');
}
await dbConfig.update({
has_paused: config.hasPaused,
has_keyword_match: config.hasKeywordMatch,
has_use_gpt: config.hasUseGpt,
has_mouse_close: config.hasMouseClose,
});
} else {
const config = cfg as AccountConfig;
await dbConfig.update({
@@ -335,4 +384,31 @@ export class ConfigController {
});
}
}
/**
* 更新配置
* @param
*/
public async moveMouseHandler(): Promise<boolean> {
const dbConfig = await Config.findOne({
where: { global: true },
});
if (!dbConfig) {
return false;
}
// 检查是否开启了鼠标移动自动暂停功能
if (dbConfig.has_mouse_close) {
if (!dbConfig.has_paused) {
await dbConfig.update({
has_paused: true,
});
return true;
}
}
return false;
}
}
+29
View File
@@ -45,6 +45,14 @@ export class Config extends Model {
declare activation_code: string;
declare version: string;
declare has_paused: boolean;
declare has_keyword_match: boolean;
declare has_use_gpt: boolean;
declare has_mouse_close: boolean; // 鼠标移动时是否自动关闭
}
export function initConfig(sequelize: Sequelize) {
@@ -111,6 +119,7 @@ export function initConfig(sequelize: Sequelize) {
default_reply: {
type: DataTypes.STRING,
allowNull: true,
defaultValue: '当前消息有点多,我稍后再回复你',
},
context_count: {
type: DataTypes.FLOAT,
@@ -147,6 +156,26 @@ export function initConfig(sequelize: Sequelize) {
defaultValue: '1.0.0',
allowNull: true,
},
has_paused: {
type: DataTypes.BOOLEAN,
defaultValue: true,
allowNull: true,
},
has_keyword_match: {
type: DataTypes.BOOLEAN,
defaultValue: true,
allowNull: true,
},
has_use_gpt: {
type: DataTypes.BOOLEAN,
defaultValue: true,
allowNull: true,
},
has_mouse_close: {
type: DataTypes.BOOLEAN,
defaultValue: true,
allowNull: true,
},
},
{
sequelize,
+6
View File
@@ -60,6 +60,12 @@ export class AppService {
throw new Error('Failed to update tasks');
}
// 遍历 result 检查,判断是否存在 error 属性
const err_target = result.find((task) => task.error);
if (err_target) {
throw new Error(err_target.error);
}
const target = result.find(
(task) => task.task_id === String(instance.id),
);
+72 -19
View File
@@ -25,7 +25,7 @@ export class DispatchService {
constructor(
mainWindow: BrowserWindow,
io: socketIo.Server,
configService: ConfigController,
configController: ConfigController,
messageService: MessageService,
messageController: MessageController,
pluginService: PluginService,
@@ -34,17 +34,28 @@ export class DispatchService {
this.mainWindow = mainWindow;
this.messageService = messageService;
this.messageController = messageController;
this.configController = configService;
this.configController = configController;
this.pluginService = pluginService;
}
public registerHandlers(socket: socketIo.Socket): void {
socket.on('messageService-broadcast', (msg: any, callback) => {
const { event_id: eventId, message } = msg;
this.receiveBroadcast(msg);
socket.on('messageService-broadcast', async (msg: any, callback) => {
const { event, data } = msg;
if (event === 'mouse_move') {
const change = await this.configController.moveMouseHandler();
if (change) {
this.receiveBroadcast({
event: 'has_paused',
data: {},
});
}
} else {
this.receiveBroadcast(msg);
}
callback({
event_id: eventId,
event_type: message,
event,
data,
});
});
@@ -60,18 +71,27 @@ export class DispatchService {
// 检查是否使用插件
const cfg = await this.configController.get(ctxMap);
await this.messageService.extractMsgInfo(cfg, ctxMap, messages);
if (cfg.use_plugin && cfg.plugin_id) {
reply = await this.pluginService.executePlugin(
cfg.plugin_id,
ctx,
messages,
);
} else {
reply = await this.pluginService.executePluginCode(
PluginDefaultRunCode,
ctxMap,
messages,
);
try {
if (cfg.use_plugin && cfg.plugin_id) {
reply = await this.pluginService.executePlugin(
cfg.plugin_id,
ctx,
messages,
);
} else {
reply = await this.pluginService.executePluginCode(
PluginDefaultRunCode,
ctxMap,
messages,
);
}
} catch (error) {
console.error('Failed to execute plugin', error);
reply = {
content: cfg.default_reply || 'Failed to execute plugin',
type: 'TEXT',
};
}
callback(reply);
@@ -94,10 +114,43 @@ export class DispatchService {
}
}
public async syncConfig(): Promise<boolean> {
try {
const cfg = await this.configController.getConfigByType({
appId: undefined,
instanceId: undefined,
type: 'driver',
});
if (!cfg) {
return false;
}
let hasPaused = false;
if ('hasPaused' in cfg) {
hasPaused = cfg.hasPaused || false;
}
await emitAndWait(this.io, 'strategyService-updateStatus', {
status: hasPaused
? StrategyServiceStatusEnum.STOPPED
: StrategyServiceStatusEnum.RUNNING,
});
const instances = await Instance.findAll();
await this.updateTasks(instances);
return true;
} catch (error) {
console.error('Failed to sync config', error);
return false;
}
}
public async updateTasks(tasks: Instance[]): Promise<
| {
task_id: string;
env_id: string;
error?: string;
}[]
| null
> {
@@ -185,6 +185,10 @@ export class PluginService {
throw new Error('Plugin does not export a function');
}
if (!messages || messages.length === 0) {
throw new Error('No messages provided to the plugin');
}
let data;
if (sandbox.module.exports[Symbol.toStringTag] === 'AsyncFunction') {
data = await sandbox.module.exports(ctx, messages);
+7
View File
@@ -70,3 +70,10 @@ export interface PluginConfig {
usePlugin: boolean;
pluginCode: string;
}
export interface DriverConfig {
hasPaused: boolean;
hasKeywordMatch: boolean;
hasUseGpt: boolean;
hasMouseClose: boolean;
}
+45
View File
@@ -0,0 +1,45 @@
import axios from 'axios';
import { BrowserWindow } from 'electron';
import { setCron } from './system/cron';
import type BackendServiceManager from './system/backend';
const setupCron = (mainWindow: BrowserWindow, bsm: BackendServiceManager) => {
const baseURL = (url: string) => {
return `http://127.0.0.1:${bsm.getPort()}/${url}`;
};
// 每隔 5 秒执行一次,通知和渲染进程刷新配置
setCron('*/5 * * * * *', () => {
mainWindow.webContents.send('refresh-config');
});
// 每隔 5 秒执行一次检查后端服务是否健康
setCron('*/5 * * * * *', async () => {
if (!bsm) {
console.error('BackendServiceManager not found');
return;
}
const {
data: { data },
} = await axios.get(baseURL(`api/v1/base/health`));
mainWindow.webContents.send('check-health', data);
});
// 每隔 5 秒同步一次 Backend 服务的状态
setCron('*/20 * * * * *', async () => {
if (!bsm) {
console.error('BackendServiceManager not found');
return;
}
// 为了避免依赖麻烦,这里直接通过 axios 发送请求
try {
await axios.post(baseURL('api/v1/base/sync'), {});
} catch (error) {
console.error('Error syncing backend service status:', error);
}
});
};
export default setupCron;
@@ -41,6 +41,7 @@ export class Completions extends APIResource {
// return this.afterSSEResponse(response, controller);
return Completions.fromOpenAIStream(
'your-model-id',
// @ts-ignore
Stream.fromSSEResponse(response, controller),
controller,
);
@@ -49,6 +50,7 @@ export class Completions extends APIResource {
return this.afterResponse(
Completions.fromOpenAIStream(
'your-model-id',
// @ts-ignore
Stream.fromSSEResponse(response, controller),
controller,
),
-17
View File
@@ -9,7 +9,6 @@ import {
import Store from 'electron-store';
import os from 'os';
import path from 'path';
import { setCron } from './system/cron';
import type BackendServiceManager from './system/backend';
import { getBrowserVersionFromOS } from './system/chrome';
@@ -92,22 +91,6 @@ const setupIpcHandlers = (
};
new Notification(notification).show();
});
// 每隔 5 秒执行一次
setCron('*/5 * * * * *', () => {
mainWindow.webContents.send('refresh-config');
});
// 每隔 5 秒执行一次检查后端服务是否健康
setCron('*/5 * * * * *', async () => {
if (!bsm) {
console.error('BackendServiceManager not found');
return;
}
const isHealthy = await bsm.check_health();
mainWindow.webContents.send('check-health', isHealthy);
});
};
export default setupIpcHandlers;
+2
View File
@@ -15,6 +15,7 @@ import { app, BrowserWindow, shell } from 'electron';
import MenuBuilder from './menu';
import { resolveHtmlPath } from './util';
import setupIpcHandlers from './ipcHandlers';
import setupCron from './cron';
import BackendServiceManager from './system/backend';
import Server from './backend/backend';
@@ -114,6 +115,7 @@ const createWindow = async () => {
}
setupIpcHandlers(mainWindow, backendServiceManager);
setupCron(mainWindow, backendServiceManager);
const server = new Server(backendServiceManager.getPort(), mainWindow);
// 启动服务器
-13
View File
@@ -1,6 +1,5 @@
import { spawn, exec } from 'child_process';
import { createServer } from 'net';
import axios from 'axios';
import fs from 'fs';
import path from 'path';
import { getTempPath } from '../utils';
@@ -126,18 +125,6 @@ class BackendServiceManager {
});
}
async check_health() {
// 发送 HTTP 请求检查服务是否健康
try {
const {
data: { data },
} = await axios.get(`http://127.0.0.1:${this.port}/api/v1/base/health`);
return data;
} catch (error) {
return false;
}
}
stop() {
// 修改停止方法以标记不自动重启
return new Promise((resolve, reject) => {
@@ -19,7 +19,6 @@ import {
useDisclosure,
} from '@chakra-ui/react';
import { useWebSocketContext } from '../../hooks/useBroadcastContext';
import { useSystemStore } from '../../stores/useSystemStore';
const SystemCheck = () => {
const [humanTaskMsg, setHumanTaskMsg] = useState<string>('');
@@ -27,13 +26,12 @@ const SystemCheck = () => {
const [isModalOpen, setIsModalOpen] = useState(false);
const cancelRef = React.useRef<any>();
const { registerEventHandler } = useWebSocketContext();
const { setDriverSettings, driverSettings } = useSystemStore();
useEffect(() => {
const unregister = registerEventHandler((message) => {
if (message.message === 'chrome_download') {
if (message.event === 'chrome_download') {
setIsModalOpen(true);
} else if (message.message === 'human_task') {
} else if (message.event === 'human_task') {
if (!message.data) {
return;
}
@@ -44,11 +42,6 @@ const SystemCheck = () => {
'有需要人工处理的消息,请手动处理,注意处理完成后请取消暂停勾选。',
);
setDriverSettings({
...driverSettings,
isPaused: true,
});
const data = message.data as {
message: string;
value: string;
+2 -2
View File
@@ -9,9 +9,8 @@ import React, {
// 定义 Broadcast 消息类型
interface BroadcastMessage {
message: string;
data: any;
event_id: string;
event: string;
}
// 定义上下文类型
@@ -44,6 +43,7 @@ export const BroadcastProvider = ({ children }: { children: ReactNode }) => {
window.electron.ipcRenderer.on('broadcast', (msg) => {
const message = msg as BroadcastMessage;
console.log('Received broadcast', message);
eventHandlers.forEach((handler) => handler(message));
});
@@ -181,7 +181,11 @@ export const AppManagerProvider = ({ children }: AppManagerProviderProps) => {
if (selectedAppId) {
setIsTasksLoading(true);
try {
await addTask(selectedAppId);
const { error } = await addTask(selectedAppId);
if (error) {
throw new Error(error);
}
await refetchTasks();
} finally {
setIsTasksLoading(false);
@@ -7,6 +7,7 @@ import {
IconButton,
Tooltip,
Spinner,
useToast,
} from '@chakra-ui/react';
import { AddIcon } from '@chakra-ui/icons';
import InstanceCardComponent from './InstanceCardComponent';
@@ -26,6 +27,7 @@ const InstanceListComponent = () => {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const [currentAppId, setCurrentAppId] = useState(selectedAppId);
const toast = useToast();
useEffect(() => {
console.log('selectedAppId', selectedAppId, filteredInstances);
@@ -33,6 +35,21 @@ const InstanceListComponent = () => {
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [selectedAppId]);
const handleAddTaskWrapper = async () => {
try {
await handleAddTask();
} catch (error) {
toast({
title: '添加失败',
description: (error as Error).message || '未知错误',
position: 'top',
status: 'error',
duration: 5000,
isClosable: true,
});
}
};
let content;
if (!selectedAppId) {
@@ -83,7 +100,7 @@ const InstanceListComponent = () => {
p={3}
justify="center"
cursor="pointer"
onClick={handleAddTask}
onClick={handleAddTaskWrapper}
_hover={{ bg: 'gray.200' }}
>
<IconButton
+1 -1
View File
@@ -21,7 +21,7 @@ const LogBox = () => {
useEffect(() => {
const unregister = registerEventHandler((message) => {
if (message.message === 'log_show') {
if (message.event === 'log_show') {
if (message.data) {
const log = message.data as {
time: string;
+104 -66
View File
@@ -1,77 +1,97 @@
import React, { useEffect } from 'react';
import React, { useEffect, useState } from 'react';
import { Checkbox, Stack, HStack, Tooltip } from '@chakra-ui/react';
import { updateRunner } from '../../../services/platform/controller';
import { useSystemStore } from '../../../stores/useSystemStore';
import { useQuery } from '@tanstack/react-query';
import { useToast } from '../../../hooks/useToast';
import { getConfig, updateConfig } from '../../../services/platform/controller';
import { DriverConfig } from '../../../services/platform/platform.d';
import { useWebSocketContext } from '../../../hooks/useBroadcastContext';
const Panels = () => {
const { toast } = useToast();
const { driverSettings, setDriverSettings } = useSystemStore();
const { registerEventHandler } = useWebSocketContext();
const [driverSettings, setDriverSettings] = useState<DriverConfig>({
hasPaused: true,
hasKeywordMatch: false,
hasUseGpt: false,
hasMouseClose: true,
});
const { data } = useQuery(['config', 'driver'], async () => {
try {
const resp = await getConfig({
type: 'driver',
});
return resp;
} catch (error) {
toast({
title: '获取配置失败',
description: error instanceof Error ? error.message : String(error),
status: 'error',
});
return null;
}
});
useEffect(() => {
window.electron.ipcRenderer.on('refresh-config', () => {
const { isPaused, isKeywordMatch, isUseGpt } = driverSettings;
(async () => {
try {
await updateRunner({
is_paused: isPaused,
is_keyword_match: isKeywordMatch,
is_use_gpt: isUseGpt,
});
} catch (error: any) {
console.error(error);
}
})();
});
return () => {
window.electron.ipcRenderer.remove('refresh-config');
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
const handleFormChange = (field: string) => (event: any) => {
const { value, checked, type } = event.target;
const newDriverSettings = {
...driverSettings,
[field]: type === 'checkbox' ? checked : value,
};
setDriverSettings(newDriverSettings);
if (field === 'isPaused') {
if (checked) {
toast({
position: 'top',
title: '已经暂停自动回复功能',
status: 'warning',
const unregister = registerEventHandler((message) => {
if (message.event === 'has_paused') {
setDriverSettings({
...driverSettings,
hasPaused: true,
});
} else {
toast({
title: '自动回复已暂停',
status: 'info',
position: 'top',
title: '已经开启自动回复功能',
status: 'success',
duration: 5000,
isClosable: true,
});
}
});
updateRunner({
is_paused: checked,
is_keyword_match: driverSettings.isKeywordMatch,
is_use_gpt: driverSettings.isUseGpt,
// 组件卸载时注销事件处理器
return () => unregister();
}, [registerEventHandler]); // eslint-disable-line
useEffect(() => {
if (data) {
const obj = data.data as DriverConfig;
setDriverSettings(obj);
}
}, [data]);
const handleUpdateConfig = async (newConfig: Partial<DriverConfig>) => {
const updatedConfig = { ...driverSettings, ...newConfig };
setDriverSettings(updatedConfig);
try {
await updateConfig({
type: 'driver',
cfg: updatedConfig,
});
} else if (field === 'isKeywordMatch') {
updateRunner({
is_paused: driverSettings.isPaused,
is_keyword_match: checked,
is_use_gpt: driverSettings.isUseGpt,
});
} else if (field === 'isUseGpt') {
updateRunner({
is_paused: driverSettings.isPaused,
is_keyword_match: driverSettings.isKeywordMatch,
is_use_gpt: checked,
// 检查是否是 hasPaused 变更
if ('hasPaused' in newConfig) {
toast({
title: '更新配置成功',
description: newConfig.hasPaused
? '已经暂停自动回复功能'
: '已经开启自动回复功能',
status: 'success',
duration: 5000,
isClosable: true,
});
}
} catch (error) {
const errormsg =
error instanceof Error ? error.message : JSON.stringify(error);
toast({
title: '更新配置失败',
description: errormsg,
status: 'error',
duration: 5000,
isClosable: true,
});
}
};
@@ -82,28 +102,46 @@ const Panels = () => {
<HStack width="full" alignItems="center">
<Checkbox
mr={4}
isChecked={driverSettings.isPaused}
onChange={handleFormChange('isPaused')}
isChecked={driverSettings.hasPaused}
onChange={(e) =>
handleUpdateConfig({ hasPaused: e.target.checked })
}
>
<Tooltip label="暂停软件后,将不再自动回复消息"></Tooltip>
</Checkbox>
<Checkbox
isChecked={driverSettings.isKeywordMatch}
onChange={handleFormChange('isKeywordMatch')}
isChecked={driverSettings.hasKeywordMatch}
onChange={(e) =>
handleUpdateConfig({ hasKeywordMatch: e.target.checked })
}
>
<Tooltip label="将优先匹配关键词,未匹配的才去调用 GPT 接口">
</Tooltip>
</Checkbox>
<Checkbox
isChecked={driverSettings.isUseGpt}
onChange={handleFormChange('isUseGpt')}
isChecked={driverSettings.hasUseGpt}
onChange={(e) =>
handleUpdateConfig({ hasUseGpt: e.target.checked })
}
>
<Tooltip label="是否开启 GPT 回复,关闭后只会使用关键词回复">
GPT
</Tooltip>
</Checkbox>
</HStack>
<HStack width="full" alignItems="center">
<Checkbox
isChecked={driverSettings.hasMouseClose}
onChange={(e) =>
handleUpdateConfig({ hasMouseClose: e.target.checked })
}
>
<Tooltip label="是否开启鼠标移动时,自动暂停自动客服">
</Tooltip>
</Checkbox>
</HStack>
</Stack>
</>
);
+11 -11
View File
@@ -6,6 +6,7 @@ import {
LLMConfig,
AccountConfig,
PluginConfig,
DriverConfig,
Message,
} from './platform';
import { GET, POST } from '../common/api/request';
@@ -22,14 +23,6 @@ export async function updatePlatform(ids: string[]) {
await POST('/api/v1/base/platform', ids);
}
export async function updateRunner(data: {
is_paused: boolean;
is_keyword_match: boolean;
is_use_gpt: boolean;
}) {
await POST('/api/v1/base/runner', data);
}
export async function getReplyList({
page,
pageSize,
@@ -113,7 +106,12 @@ export async function getConfig({
instanceId?: string;
}) {
const data = await GET<{
data: GenericConfig | LLMConfig | AccountConfig | PluginConfig;
data:
| GenericConfig
| LLMConfig
| AccountConfig
| PluginConfig
| DriverConfig;
}>('/api/v1/base/setting', {
appId,
instanceId,
@@ -131,7 +129,7 @@ export async function updateConfig({
type: string;
appId?: string;
instanceId?: string;
cfg: GenericConfig | LLMConfig | AccountConfig | PluginConfig;
cfg: GenericConfig | LLMConfig | AccountConfig | PluginConfig | DriverConfig;
}) {
await POST('/api/v1/base/setting', {
appId,
@@ -217,7 +215,9 @@ export async function getTasks() {
}
export async function addTask(appId: string) {
const data = await POST(`/api/v1/strategy/tasks`, {
const data = await POST<{
error?: string;
}>(`/api/v1/strategy/tasks`, {
appId,
});
return data;
+7
View File
@@ -70,3 +70,10 @@ export interface PluginConfig {
usePlugin: boolean;
pluginCode: string;
}
export interface DriverConfig {
hasPaused: boolean;
hasKeywordMatch: boolean;
hasUseGpt: boolean;
hasMouseClose: boolean;
}
+1 -25
View File
@@ -29,36 +29,13 @@ type MessageState = {
removeMessage: (index: number) => void;
};
type DriverState = {
driverSettings: {
isPaused: boolean;
isKeywordMatch: boolean;
isUseGpt: boolean;
};
setDriverSettings: (settings: {
isPaused: boolean;
isKeywordMatch: boolean;
isUseGpt: boolean;
}) => void;
};
type State = MessageState & DriverState;
type State = MessageState;
// Create Zustand store
export const useSystemStore = create<State>()(
devtools(
persist(
immer((set) => ({
driverSettings: {
isPaused: true,
isUseGpt: true,
isKeywordMatch: true,
},
setDriverSettings: (settings) => {
set((state) => {
state.driverSettings = settings;
});
},
context: {},
setContext: (key, value) =>
set((state) => {
@@ -79,7 +56,6 @@ export const useSystemStore = create<State>()(
storage: createJSONStorage(() => electronStore),
partialize: (state) => ({
context: state.context,
driverSettings: state.driverSettings,
messages: state.messages,
}),
},