mirror of
https://github.com/cs-lazy-tools/ChatGPT-On-CS.git
synced 2026-09-01 15:00:59 +08:00
add: 添加配置项
This commit is contained in:
+87
-65
@@ -145,6 +145,40 @@ class BKServer {
|
||||
}),
|
||||
);
|
||||
|
||||
// 取得平台是否激活
|
||||
this.app.get(
|
||||
'/api/v1/base/platform/active',
|
||||
asyncHandler(async (req, res) => {
|
||||
const { appId, instanceId } = req.query;
|
||||
const active = await configController.checkConfigActive({
|
||||
appId: appId ? String(appId) : undefined,
|
||||
instanceId: instanceId ? String(instanceId) : undefined,
|
||||
});
|
||||
res.json({
|
||||
success: true,
|
||||
data: {
|
||||
active,
|
||||
},
|
||||
});
|
||||
}),
|
||||
);
|
||||
|
||||
// 更新平台激活状态
|
||||
this.app.post(
|
||||
'/api/v1/base/platform/active',
|
||||
asyncHandler(async (req, res) => {
|
||||
const { appId, instanceId, active } = req.body;
|
||||
await configController.activeConfig({
|
||||
appId: appId ? String(appId) : undefined,
|
||||
instanceId: instanceId ? String(instanceId) : undefined,
|
||||
active,
|
||||
});
|
||||
res.json({
|
||||
success: true,
|
||||
});
|
||||
}),
|
||||
);
|
||||
|
||||
// 获取配置
|
||||
this.app.get(
|
||||
'/api/v1/base/setting',
|
||||
@@ -214,69 +248,6 @@ class BKServer {
|
||||
}
|
||||
});
|
||||
|
||||
// // Endpoint to retrieve configuration settings
|
||||
// this.app.get('/api/v1/base/settings', async (req, res) => {
|
||||
// try {
|
||||
// const config = await configController.getConfig();
|
||||
// // @ts-ignore 兼容性处理
|
||||
// config.reply_speed = [config.reply_speed, config.reply_random_speed];
|
||||
// res.json({ success: true, data: config });
|
||||
// } catch (error) {
|
||||
// if (error instanceof Error) {
|
||||
// res.status(500).json({ success: false, message: error.message });
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
|
||||
// // Endpoint to update configuration settings
|
||||
// this.app.post('/api/v1/base/settings', async (req, res) => {
|
||||
// try {
|
||||
// const cfg = req.body as {
|
||||
// extract_phone: boolean; // 提取手机号
|
||||
// extract_product: boolean; // 提取商品
|
||||
// save_path?: string; // 保存路径
|
||||
// default_reply?: string; // 默认回复
|
||||
// reply_speed: number[]; // 回复速度
|
||||
// context_count: number; // 合并消息数量
|
||||
// wait_humans_time: number; // 等待人工时间
|
||||
// gpt_base_url?: string; // GPT服务地址
|
||||
// gpt_key?: string; // GPT服务key
|
||||
// gpt_model?: string; // GPT服务模型
|
||||
// gpt_temperature?: number; // GPT服务温度
|
||||
// gpt_top_p?: number; // GPT服务top_p
|
||||
// stream?: boolean; // 是否开启stream
|
||||
// use_dify?: boolean; // 是否使用 Dify 百宝箱
|
||||
// };
|
||||
|
||||
// if (!cfg.reply_speed || cfg.reply_speed.length !== 2) {
|
||||
// cfg.reply_speed = [0, 0];
|
||||
// }
|
||||
|
||||
// await configController.updateConfig(1, {
|
||||
// extract_phone: cfg.extract_phone,
|
||||
// extract_product: cfg.extract_product,
|
||||
// default_reply: cfg.default_reply,
|
||||
// save_path: cfg.save_path,
|
||||
// reply_speed: cfg.reply_speed[0],
|
||||
// reply_random_speed: cfg.reply_speed[1],
|
||||
// context_count: cfg.context_count,
|
||||
// wait_humans_time: cfg.wait_humans_time,
|
||||
// gpt_base_url: cfg.gpt_base_url,
|
||||
// gpt_key: cfg.gpt_key,
|
||||
// gpt_model: cfg.gpt_model,
|
||||
// gpt_temperature: cfg.gpt_temperature,
|
||||
// gpt_top_p: cfg.gpt_top_p,
|
||||
// stream: cfg.stream,
|
||||
// use_dify: cfg.use_dify,
|
||||
// });
|
||||
// res.json({ success: true });
|
||||
// } catch (error) {
|
||||
// if (error instanceof Error) {
|
||||
// res.status(500).json({ success: false, message: error.message });
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
|
||||
this.app.get('/api/v1/reply/list', async (req, res) => {
|
||||
const { page = 1, page_size: pageSize, ptf_id: platformId } = req.query;
|
||||
|
||||
@@ -391,8 +362,7 @@ class BKServer {
|
||||
|
||||
// 检查 GPT 链接是否正常
|
||||
this.app.get('/api/v1/base/gpt/health', async (req, res) => {
|
||||
const { base_url: gptBaseUrl, key, use_dify: useDify, model } = req.query;
|
||||
|
||||
// const { base_url: gptBaseUrl, key, use_dify: useDify, model } = req.query;
|
||||
// try {
|
||||
// const { status, message } = await this.messageService.checkApiHealth({
|
||||
// baseUrl: String(gptBaseUrl),
|
||||
@@ -412,6 +382,58 @@ class BKServer {
|
||||
// });
|
||||
// }
|
||||
});
|
||||
|
||||
// 获取任务列表
|
||||
this.app.get('/api/v1/strategy/tasks', async (req, res) => {
|
||||
const { appId } = req.query;
|
||||
try {
|
||||
const tasks = await this.dispatchService.getTasks(String(appId));
|
||||
res.json({
|
||||
success: true,
|
||||
data: tasks,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
res.json({
|
||||
success: false,
|
||||
data: null,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 添加任务
|
||||
this.app.post('/api/v1/strategy/tasks', async (req, res) => {
|
||||
const { appId } = req.body;
|
||||
try {
|
||||
const task = await this.dispatchService.addTask(String(appId));
|
||||
res.json({
|
||||
success: true,
|
||||
data: task,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
res.json({
|
||||
success: false,
|
||||
data: null,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 删除任务
|
||||
this.app.post('/api/v1/strategy/task/remove', async (req, res) => {
|
||||
const { taskId } = req.body;
|
||||
try {
|
||||
await this.dispatchService.removeTask(String(taskId));
|
||||
res.json({
|
||||
success: true,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
res.json({
|
||||
success: false,
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 启动服务器的方法
|
||||
|
||||
@@ -75,12 +75,23 @@ export class ConfigController {
|
||||
config = await Config.findOne({
|
||||
where: { instance_id: instanceId },
|
||||
});
|
||||
if (!config) {
|
||||
config = await Config.create({
|
||||
platform_id: appId,
|
||||
instance_id: instanceId,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (!config && appId) {
|
||||
config = await Config.findOne({
|
||||
where: { platform_id: appId },
|
||||
});
|
||||
if (!config) {
|
||||
config = await Config.create({
|
||||
platform_id: appId,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (!config) {
|
||||
@@ -112,19 +123,21 @@ export class ConfigController {
|
||||
config = await Config.findOne({
|
||||
where: { instance_id: instanceId },
|
||||
});
|
||||
|
||||
return config?.active || false;
|
||||
}
|
||||
|
||||
if (!config && appId) {
|
||||
if (appId) {
|
||||
config = await Config.findOne({
|
||||
where: { platform_id: appId },
|
||||
});
|
||||
|
||||
return config?.active || false;
|
||||
}
|
||||
|
||||
if (!config) {
|
||||
config = await Config.findOne({
|
||||
where: { global: true },
|
||||
});
|
||||
}
|
||||
config = await Config.findOne({
|
||||
where: { global: true },
|
||||
});
|
||||
|
||||
return config?.active || false;
|
||||
}
|
||||
@@ -152,12 +165,25 @@ export class ConfigController {
|
||||
config = await Config.findOne({
|
||||
where: { instance_id: instanceId },
|
||||
});
|
||||
|
||||
if (!config) {
|
||||
config = await Config.create({
|
||||
platform_id: appId,
|
||||
instance_id: instanceId,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (!config && appId) {
|
||||
config = await Config.findOne({
|
||||
where: { platform_id: appId },
|
||||
});
|
||||
|
||||
if (!config) {
|
||||
config = await Config.create({
|
||||
platform_id: appId,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (!config) {
|
||||
@@ -284,10 +310,7 @@ export class ConfigController {
|
||||
let pluginId = null;
|
||||
const config = cfg as PluginConfig;
|
||||
if (dbConfig.use_plugin) {
|
||||
let plugin = await Plugin.findOne({
|
||||
where: { code: config.pluginCode },
|
||||
});
|
||||
|
||||
let plugin = await Plugin.findByPk(dbConfig.plugin_id);
|
||||
if (!plugin) {
|
||||
plugin = await Plugin.create({
|
||||
code: config.pluginCode,
|
||||
|
||||
@@ -83,6 +83,39 @@ export class DispatchService {
|
||||
}
|
||||
}
|
||||
|
||||
public async getTasks(appId: string): Promise<any> {
|
||||
try {
|
||||
return await emitAndWait(this.io, 'strategyService-getTasks', {
|
||||
app_id: appId,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Failed to get tasks', error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public async addTask(appId: string): Promise<any> {
|
||||
try {
|
||||
return await emitAndWait(this.io, 'strategyService-addTask', {
|
||||
app_id: appId,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Failed to add task', error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public async removeTask(taskId: string): Promise<any> {
|
||||
try {
|
||||
return await emitAndWait(this.io, 'strategyService-removeTask', {
|
||||
task_id: taskId,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Failed to remove task', error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public async updateStatus(status: StrategyServiceStatusEnum): Promise<any> {
|
||||
try {
|
||||
return await emitAndWait(this.io, 'strategyService-updateStatus', {
|
||||
|
||||
@@ -11,7 +11,6 @@ import SettingsPage from './pages/Settings';
|
||||
import AboutPage from './pages/About';
|
||||
import MsgList from './pages/MsgList';
|
||||
import FullScreenLoader from './pages/FullScreenLoader';
|
||||
import { SettingsProvider } from './components/Settings/SettingsContext';
|
||||
import Updater from './components/Updater';
|
||||
import SystemCheck from './components/SystemCheck';
|
||||
import { BroadcastProvider } from './hooks/useBroadcastContext';
|
||||
@@ -61,14 +60,7 @@ function App() {
|
||||
<Routes>
|
||||
<Route path="/" element={<HomePage />} />
|
||||
<Route path="/msg" element={<MsgList />} />
|
||||
<Route
|
||||
path="/settings"
|
||||
element={
|
||||
<SettingsProvider>
|
||||
<SettingsPage />
|
||||
</SettingsProvider>
|
||||
}
|
||||
/>
|
||||
<Route path="/settings" element={<SettingsPage />} />
|
||||
<Route path="/about" element={<AboutPage />} />
|
||||
</Routes>
|
||||
</Box>
|
||||
|
||||
@@ -63,7 +63,7 @@ const AboutPage: React.FC = () => {
|
||||
本项目是基于大模型的智能对话客服工具,支持哔哩哔哩、抖音企业号、抖音、抖店、微博聊天、小红书专业号运营、小红书、知乎等平台接入,可选择 GPT3.5/GPT4.0,能处理文本、语音和图片,通过插件访问操作系统和互联网等外部资源,支持基于自有知识库定制企业 AI 应用。
|
||||
|
||||
## 使用说明
|
||||
项目文档: [懒人百宝箱使用说明](https://gitee.com/alsritter/ChatGPT-On-CS)
|
||||
项目文档: [懒人百宝箱使用说明](https://doc.lazaytools.top/)
|
||||
|
||||
## 演示视频
|
||||
[哔哩哔哩](https://www.bilibili.com/video/BV1qz421Q73S)
|
||||
|
||||
@@ -1,165 +0,0 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import {
|
||||
Tabs,
|
||||
TabList,
|
||||
Tab,
|
||||
TabPanels,
|
||||
TabPanel,
|
||||
Tooltip,
|
||||
Checkbox,
|
||||
Stack,
|
||||
Image,
|
||||
Box,
|
||||
Skeleton,
|
||||
CheckboxGroup,
|
||||
IconButton,
|
||||
VStack,
|
||||
Grid,
|
||||
} from '@chakra-ui/react';
|
||||
import { SettingsIcon } from '@chakra-ui/icons';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import {
|
||||
getPlatformList,
|
||||
updatePlatform,
|
||||
} from '../../../services/platform/controller';
|
||||
import { Platform } from '../../../services/platform/platform';
|
||||
import PlatformSettings from '../../../components/PlatformConfigs';
|
||||
import {
|
||||
PlatformTypeMap,
|
||||
PlatformTypeEnum,
|
||||
} from '../../../services/platform/constant';
|
||||
import { useSystemStore } from '../../../stores/useSystemStore';
|
||||
import defaultPlatformIcon from '../../../../assets/base/default-platform-icon.png';
|
||||
import windowsIcon from '../../../../assets/base/windows.png';
|
||||
import { trackCheckboxChange } from '../../../services/analytics';
|
||||
|
||||
const PlatformTabs = () => {
|
||||
const { data, isLoading } = useQuery(['platformList'], getPlatformList);
|
||||
const [firstLoad, setFirstLoad] = useState<boolean>(true);
|
||||
const [isSettingsOpen, setIsSettingsOpen] = useState(false);
|
||||
const [selectedPlatformId, setSelectedPlatformId] = useState<string | null>(
|
||||
null,
|
||||
);
|
||||
|
||||
const { selectedPlatforms, setSelectedPlatforms } = useSystemStore();
|
||||
|
||||
// 处理数据加载完毕后的平台分组
|
||||
const groupedPlatforms = data?.data.reduce(
|
||||
(acc, platform) => {
|
||||
const type = String(platform.type) || 'other';
|
||||
if (!acc[type]) acc[type] = [];
|
||||
acc[type].push(platform);
|
||||
return acc;
|
||||
},
|
||||
{} as Record<string, Platform[]>,
|
||||
);
|
||||
|
||||
// 第一次加载时需要更新一次后端
|
||||
useEffect(() => {
|
||||
if (selectedPlatforms && firstLoad) {
|
||||
updatePlatform(selectedPlatforms);
|
||||
setFirstLoad(false);
|
||||
}
|
||||
}, [firstLoad, setFirstLoad, selectedPlatforms]);
|
||||
|
||||
const handleCheckboxChange = async (selectedIds: string[]) => {
|
||||
setSelectedPlatforms(selectedIds);
|
||||
await updatePlatform(selectedIds);
|
||||
trackCheckboxChange('platforms', selectedIds);
|
||||
};
|
||||
|
||||
if (isLoading) {
|
||||
return (
|
||||
<Stack>
|
||||
<Skeleton height="20px" />
|
||||
<Skeleton height="20px" />
|
||||
<Skeleton height="20px" />
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
|
||||
const renderTabPanels = () => {
|
||||
const types = Object.keys(groupedPlatforms || {});
|
||||
return types.map((type) => (
|
||||
<TabPanel key={type}>
|
||||
<CheckboxGroup
|
||||
colorScheme="green"
|
||||
value={selectedPlatforms}
|
||||
onChange={handleCheckboxChange}
|
||||
>
|
||||
<Grid templateColumns="repeat(2, 1fr)" gap={4}>
|
||||
{groupedPlatforms?.[type]?.map((platform) => (
|
||||
<Box key={platform.id} display="flex" alignItems="center">
|
||||
{/* 显示平台图标,如果没有则显示默认图标 */}
|
||||
<Image
|
||||
src={platform.avatar || defaultPlatformIcon}
|
||||
fallbackSrc={defaultPlatformIcon}
|
||||
boxSize="25px"
|
||||
marginRight="12px"
|
||||
/>
|
||||
<Checkbox value={platform.id} isDisabled={!platform.impl}>
|
||||
{platform.name}
|
||||
</Checkbox>
|
||||
<VStack>
|
||||
{platform.impl && (
|
||||
<Tooltip label={`设置 ${platform.name} 平台`}>
|
||||
<IconButton
|
||||
variant="borderless"
|
||||
aria-label={`设置 ${platform.name} 平台`}
|
||||
fontSize="12px"
|
||||
w={2}
|
||||
h={2}
|
||||
icon={<SettingsIcon />}
|
||||
onClick={() => {
|
||||
setSelectedPlatformId(platform.id);
|
||||
setIsSettingsOpen(true);
|
||||
}}
|
||||
/>
|
||||
</Tooltip>
|
||||
)}
|
||||
{
|
||||
// 如果 id 前缀有 win_ 则显示一个小图标标识
|
||||
platform.id.startsWith('win_') && (
|
||||
<Tooltip label="客户端应用,需要先手动打开该应用">
|
||||
<Image
|
||||
src={windowsIcon}
|
||||
boxSize="10px"
|
||||
marginLeft="4px"
|
||||
alt="windows"
|
||||
/>
|
||||
</Tooltip>
|
||||
)
|
||||
}
|
||||
</VStack>
|
||||
</Box>
|
||||
))}
|
||||
</Grid>
|
||||
</CheckboxGroup>
|
||||
</TabPanel>
|
||||
));
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Tabs>
|
||||
<TabList>
|
||||
{Object.keys(groupedPlatforms || {}).map((type) => (
|
||||
<Tab key={type}>{PlatformTypeMap[type as PlatformTypeEnum]}</Tab>
|
||||
))}
|
||||
</TabList>
|
||||
|
||||
<TabPanels>{renderTabPanels()}</TabPanels>
|
||||
</Tabs>
|
||||
|
||||
{selectedPlatformId && (
|
||||
<PlatformSettings
|
||||
platformId={selectedPlatformId}
|
||||
isOpen={isSettingsOpen}
|
||||
onClose={() => setIsSettingsOpen(false)}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default PlatformTabs;
|
||||
@@ -0,0 +1,179 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import {
|
||||
ChakraProvider,
|
||||
Tabs,
|
||||
TabList,
|
||||
TabPanels,
|
||||
Tab,
|
||||
TabPanel,
|
||||
Modal,
|
||||
ModalOverlay,
|
||||
ModalContent,
|
||||
ModalHeader,
|
||||
ModalCloseButton,
|
||||
ModalBody,
|
||||
Checkbox,
|
||||
Box,
|
||||
Flex,
|
||||
Text,
|
||||
useToast,
|
||||
} from '@chakra-ui/react';
|
||||
import GeneralSettings from '../../../components/Settings/GeneralSettings';
|
||||
import LLMSettings from '../../../components/Settings/LLMSettings';
|
||||
import PluginSettings from '../../../components/Settings/PluginSettings';
|
||||
import {
|
||||
activeConfig,
|
||||
checkConfigActive,
|
||||
} from '../../../services/platform/controller';
|
||||
|
||||
const SettingsModal = ({
|
||||
isOpen,
|
||||
onClose,
|
||||
appId,
|
||||
instanceId,
|
||||
}: {
|
||||
isOpen: boolean;
|
||||
onClose: () => void;
|
||||
appId?: string;
|
||||
instanceId?: string;
|
||||
}) => {
|
||||
const toast = useToast();
|
||||
const [isActive, setIsActive] = useState(false);
|
||||
const [data, setData] = useState<{
|
||||
active: boolean;
|
||||
} | null>(null);
|
||||
|
||||
const fetchConfigActive = async () => {
|
||||
try {
|
||||
const resp = await checkConfigActive({ appId, instanceId });
|
||||
// @ts-ignore
|
||||
setData(resp.data);
|
||||
} catch (error) {
|
||||
const errormsg =
|
||||
error instanceof Error ? error.message : JSON.stringify(error);
|
||||
toast({
|
||||
title: '获取配置失败',
|
||||
description: errormsg,
|
||||
status: 'error',
|
||||
duration: 5000,
|
||||
isClosable: true,
|
||||
});
|
||||
setData(null);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
fetchConfigActive();
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [appId, instanceId]);
|
||||
|
||||
useEffect(() => {
|
||||
if (data) {
|
||||
setIsActive(data.active);
|
||||
}
|
||||
}, [data]);
|
||||
|
||||
const handleCheckboxChange = async (
|
||||
event: React.ChangeEvent<HTMLInputElement>,
|
||||
) => {
|
||||
if (!data) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
setIsActive(event.target.checked);
|
||||
await activeConfig({
|
||||
active: event.target.checked,
|
||||
appId,
|
||||
instanceId,
|
||||
});
|
||||
toast({
|
||||
title: '更新配置成功',
|
||||
position: 'top',
|
||||
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,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<ChakraProvider>
|
||||
<Modal isOpen={isOpen} onClose={onClose} size="xl">
|
||||
<ModalOverlay />
|
||||
<ModalContent>
|
||||
<ModalHeader>
|
||||
设置
|
||||
<Checkbox
|
||||
ml={4}
|
||||
isChecked={isActive}
|
||||
onChange={handleCheckboxChange}
|
||||
>
|
||||
激活{' '}
|
||||
{instanceId ? `客服 ${instanceId} 设置` : `应用 ${appId} 设置`}
|
||||
</Checkbox>
|
||||
<Text color="gray.500" fontSize="sm">
|
||||
请注意:激活设置后,设置才会生效
|
||||
</Text>
|
||||
</ModalHeader>
|
||||
<ModalCloseButton />
|
||||
<ModalBody position="relative" overflowY="auto" maxHeight="60vh">
|
||||
{!isActive && (
|
||||
<Flex
|
||||
position="absolute"
|
||||
top="0"
|
||||
left="0"
|
||||
right="0"
|
||||
bottom="0"
|
||||
backgroundColor="rgba(0, 0, 0, 0.5)"
|
||||
justifyContent="center"
|
||||
alignItems="center"
|
||||
zIndex="1"
|
||||
>
|
||||
<Text color="white" fontSize="lg">
|
||||
请先激活设置
|
||||
</Text>
|
||||
</Flex>
|
||||
)}
|
||||
<Box
|
||||
opacity={isActive ? 1 : 0.4}
|
||||
pointerEvents={isActive ? 'auto' : 'none'}
|
||||
>
|
||||
<Tabs variant="enclosed" isFitted>
|
||||
<TabList>
|
||||
<Tab>通用设置</Tab>
|
||||
<Tab>AI 配置</Tab>
|
||||
<Tab>插件设置</Tab>
|
||||
</TabList>
|
||||
|
||||
<TabPanels>
|
||||
<TabPanel>
|
||||
<GeneralSettings appId={appId} instanceId={instanceId} />
|
||||
</TabPanel>
|
||||
<TabPanel>
|
||||
<LLMSettings appId={appId} instanceId={instanceId} />
|
||||
</TabPanel>
|
||||
<TabPanel>
|
||||
<PluginSettings appId={appId} instanceId={instanceId} />
|
||||
</TabPanel>
|
||||
</TabPanels>
|
||||
</Tabs>
|
||||
</Box>
|
||||
</ModalBody>
|
||||
</ModalContent>
|
||||
</Modal>
|
||||
</ChakraProvider>
|
||||
);
|
||||
};
|
||||
|
||||
export default React.memo(SettingsModal);
|
||||
@@ -14,6 +14,7 @@ import {
|
||||
IconButton,
|
||||
Stack,
|
||||
Skeleton,
|
||||
useToast,
|
||||
} from '@chakra-ui/react';
|
||||
import {
|
||||
SearchIcon,
|
||||
@@ -24,12 +25,24 @@ import {
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import defaultPlatformIcon from '../../../../../assets/base/default-platform-icon.png';
|
||||
import windowsIcon from '../../../../../assets/base/windows.png';
|
||||
import { getPlatformList } from '../../../services/platform/controller';
|
||||
import {
|
||||
getPlatformList,
|
||||
getTasks,
|
||||
removeTask,
|
||||
addTask,
|
||||
} from '../../../services/platform/controller';
|
||||
import SettingsModal from './SettingsModal';
|
||||
|
||||
const AppManagerComponent = () => {
|
||||
const toast = useToast();
|
||||
const { data, isLoading } = useQuery(['platformList'], getPlatformList);
|
||||
const [selectedApp, setSelectedApp] = useState<number | null>(null);
|
||||
const [selectedInstance, setSelectedInstance] = useState<number | null>(null);
|
||||
const [selectedAppId, setSelectedAppId] = useState<string | null>(null);
|
||||
const [selectedInstanceId, setSelectedInstanceId] = useState<string | null>(
|
||||
null,
|
||||
);
|
||||
|
||||
const [filteredInstances, setFilteredInstances] = useState<
|
||||
{
|
||||
task_id: string;
|
||||
@@ -38,6 +51,10 @@ const AppManagerComponent = () => {
|
||||
avatar: string;
|
||||
}[]
|
||||
>([]);
|
||||
const [isSettingsOpen, setIsSettingsOpen] = useState(false);
|
||||
const openSettings = () => setIsSettingsOpen(true);
|
||||
const closeSettings = () => setIsSettingsOpen(false);
|
||||
|
||||
const high = '42vh'; // 调整为合适的全局高度
|
||||
|
||||
const instances = [
|
||||
@@ -59,11 +76,19 @@ const AppManagerComponent = () => {
|
||||
{ task_id: '3136613131', app_id: 'zhihu', env_id: '2' },
|
||||
];
|
||||
|
||||
const getTasksQuery = useQuery(
|
||||
['tasks', selectedAppId],
|
||||
() => getTasks(selectedAppId || ''),
|
||||
{
|
||||
enabled: selectedAppId !== null,
|
||||
},
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedApp !== null && data && data.data) {
|
||||
const selectedAppId = data.data[selectedApp]?.id;
|
||||
const said = data.data[selectedApp]?.id;
|
||||
const matchedInstances = instances.filter(
|
||||
(instance) => instance.app_id === selectedAppId,
|
||||
(instance) => instance.app_id === said,
|
||||
);
|
||||
setFilteredInstances(
|
||||
matchedInstances.map((x) => {
|
||||
@@ -73,12 +98,36 @@ const AppManagerComponent = () => {
|
||||
};
|
||||
}),
|
||||
);
|
||||
|
||||
const appId = data.data[selectedApp]?.id;
|
||||
setSelectedAppId(appId || null);
|
||||
if (appId) {
|
||||
getTasksQuery.refetch();
|
||||
}
|
||||
} else {
|
||||
setFilteredInstances([]);
|
||||
setSelectedAppId(null);
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [selectedApp, data]);
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedInstance !== null) {
|
||||
setSelectedInstanceId(
|
||||
filteredInstances[selectedInstance]?.task_id || null,
|
||||
);
|
||||
} else {
|
||||
setSelectedInstanceId(null);
|
||||
}
|
||||
}, [selectedInstance, filteredInstances]);
|
||||
|
||||
useEffect(() => {
|
||||
if (getTasksQuery.data) {
|
||||
console.log('getTasksQuery.data', getTasksQuery.data);
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [getTasksQuery.data]);
|
||||
|
||||
if (isLoading || !data || !data.data) {
|
||||
return (
|
||||
<Stack>
|
||||
@@ -89,10 +138,32 @@ const AppManagerComponent = () => {
|
||||
);
|
||||
}
|
||||
|
||||
const handleDelete = (taskId: string) => {
|
||||
setFilteredInstances(
|
||||
filteredInstances.filter((instance) => instance.task_id !== taskId),
|
||||
);
|
||||
const handleDelete = async (taskId: string) => {
|
||||
try {
|
||||
await removeTask(taskId);
|
||||
setFilteredInstances(
|
||||
filteredInstances.filter((instance) => instance.task_id !== taskId),
|
||||
);
|
||||
} catch (error) {
|
||||
const errormsg = error instanceof Error ? error.message : '未知错误';
|
||||
toast({
|
||||
title: '删除失败',
|
||||
position: 'top',
|
||||
description: errormsg,
|
||||
status: 'error',
|
||||
duration: 5000,
|
||||
isClosable: true,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const handleAddTask = async () => {
|
||||
if (!selectedAppId) {
|
||||
return;
|
||||
}
|
||||
|
||||
await addTask(selectedAppId);
|
||||
getTasksQuery.refetch();
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -194,7 +265,7 @@ const AppManagerComponent = () => {
|
||||
w={4}
|
||||
h={4}
|
||||
icon={<SettingsIcon />}
|
||||
onClick={() => {}}
|
||||
onClick={openSettings}
|
||||
/>
|
||||
</Tooltip>
|
||||
</Box>
|
||||
@@ -238,7 +309,7 @@ const AppManagerComponent = () => {
|
||||
fontSize="15px"
|
||||
aria-label="Settings"
|
||||
icon={<SettingsIcon />}
|
||||
onClick={() => {}}
|
||||
onClick={openSettings}
|
||||
/>
|
||||
<IconButton
|
||||
color="red.500"
|
||||
@@ -274,11 +345,19 @@ const AppManagerComponent = () => {
|
||||
aria-label="Add instance"
|
||||
variant="unstyled"
|
||||
icon={<AddIcon />}
|
||||
onClick={handleAddTask}
|
||||
/>
|
||||
</Flex>
|
||||
</Tooltip>
|
||||
</VStack>
|
||||
</Box>
|
||||
|
||||
<SettingsModal
|
||||
isOpen={isSettingsOpen}
|
||||
onClose={closeSettings}
|
||||
appId={selectedAppId || undefined}
|
||||
instanceId={selectedInstanceId || undefined}
|
||||
/>
|
||||
</Flex>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -71,6 +71,38 @@ export async function exportReplyExcel() {
|
||||
return data;
|
||||
}
|
||||
|
||||
export async function activeConfig({
|
||||
active,
|
||||
appId,
|
||||
instanceId,
|
||||
}: {
|
||||
active: boolean;
|
||||
appId?: string;
|
||||
instanceId?: string;
|
||||
}) {
|
||||
await POST('/api/v1/base/platform/active', {
|
||||
active,
|
||||
appId,
|
||||
instanceId,
|
||||
});
|
||||
}
|
||||
|
||||
export async function checkConfigActive({
|
||||
appId,
|
||||
instanceId,
|
||||
}: {
|
||||
appId?: string;
|
||||
instanceId?: string;
|
||||
}) {
|
||||
const data = await GET<{
|
||||
active: boolean;
|
||||
}>('/api/v1/base/platform/active', {
|
||||
appId,
|
||||
instanceId,
|
||||
});
|
||||
return data;
|
||||
}
|
||||
|
||||
export async function getConfig({
|
||||
type,
|
||||
appId,
|
||||
@@ -83,8 +115,8 @@ export async function getConfig({
|
||||
const data = await GET<{
|
||||
data: GenericConfig | LLMConfig | AccountConfig | PluginConfig;
|
||||
}>('/api/v1/base/setting', {
|
||||
app_id: appId,
|
||||
instance_id: instanceId,
|
||||
appId,
|
||||
instanceId,
|
||||
type,
|
||||
});
|
||||
return data;
|
||||
@@ -154,3 +186,28 @@ export async function checkGptHealth(data: {
|
||||
});
|
||||
return resp;
|
||||
}
|
||||
|
||||
export async function getTasks(appId: string) {
|
||||
const data = await GET<{
|
||||
data: {
|
||||
[key: string]: any;
|
||||
};
|
||||
}>(`/api/v1/strategy/tasks`, {
|
||||
appId,
|
||||
});
|
||||
return data;
|
||||
}
|
||||
|
||||
export async function addTask(appId: string) {
|
||||
const data = await POST(`/api/v1/strategy/tasks`, {
|
||||
appId,
|
||||
});
|
||||
return data;
|
||||
}
|
||||
|
||||
export async function removeTask(taskId: string) {
|
||||
const data = await POST(`/api/v1/strategy/task/remove`, {
|
||||
taskId,
|
||||
});
|
||||
return data;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user