Skip to content

Commit 40f4ad6

Browse files
author
lrhh123
committed
add:
- 新增企业微信支持(预览版) - 新增展示版本号 - 修复微信无法回复图片的问题 - 修复抖店无法登录的 BUG - 修复平台配置的空格剔除 - 修复千牛无法定位的问题
1 parent 745b611 commit 40f4ad6

File tree

10 files changed

+235
-35
lines changed

10 files changed

+235
-35
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "chatgpt-on-cs",
33
"description": "多平台智能客服,允许使用 ChatGPT 作为客服机器人",
4-
"version": "1.0.3",
4+
"version": "1.0.5-beta",
55
"keywords": [
66
"electron",
77
"boilerplate",

release/app/package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

release/app/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "chatgpt-on-cs",
3-
"version": "1.0.4",
3+
"version": "1.0.5-beta",
44
"description": "多平台智能客服,允许使用 ChatGPT 作为客服机器人",
55
"license": "AGPL-3.0",
66
"author": {

src/__tests__/App.test.tsx

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,52 @@
11
import '@testing-library/jest-dom';
22
import { render } from '@testing-library/react';
33
import App from '../renderer/App';
4+
import { isVersionGreater } from '../renderer/services/system/controller';
45

56
describe('App', () => {
67
it('should render', () => {
78
expect(render(<App />)).toBeTruthy();
89
});
910
});
11+
12+
describe('Version Comparison Tests', () => {
13+
test('Standard version comparison where online version is greater', () => {
14+
expect(isVersionGreater('1.0.1', '1.0.0')).toBe(true);
15+
});
16+
17+
test('Standard version comparison where current version is greater', () => {
18+
expect(isVersionGreater('1.0.0', '1.0.1')).toBe(false);
19+
});
20+
21+
test('Beta version comparison with higher beta number', () => {
22+
expect(isVersionGreater('1.0.0-beta.2', '1.0.0-beta.1')).toBe(true);
23+
});
24+
25+
test('Beta version comparison with lower beta number', () => {
26+
expect(isVersionGreater('1.0.0-beta.1', '1.0.0-beta.2')).toBe(false);
27+
});
28+
29+
test('Beta versus stable where stable should be greater', () => {
30+
expect(isVersionGreater('1.0.0', '1.0.0-beta.1')).toBe(true);
31+
});
32+
33+
test('Stable versus beta where beta should be lesser', () => {
34+
expect(isVersionGreater('1.0.0-beta.1', '1.0.0')).toBe(false);
35+
});
36+
37+
test('Identical versions should not be greater', () => {
38+
expect(isVersionGreater('1.0.0', '1.0.0')).toBe(false);
39+
});
40+
41+
test('Beta suffix without number compared to numeric beta suffix', () => {
42+
expect(isVersionGreater('1.0.0-beta', '1.0.0-beta.1')).toBe(false);
43+
});
44+
45+
test('Numeric beta suffix compared to beta suffix without number', () => {
46+
expect(isVersionGreater('1.0.0-beta.1', '1.0.0-beta')).toBe(true);
47+
});
48+
49+
test('Beta version comparison with identical suffix and number', () => {
50+
expect(isVersionGreater('1.0.0-beta.1', '1.0.0-beta.1')).toBe(false);
51+
});
52+
});

src/main/backend/backend.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ class BKServer {
166166
'/api/v1/base/platform/all',
167167
asyncHandler(async (req, res) => {
168168
if (this.ptfs.length === 0) {
169-
this.ptfs = this.strategyService.getAllPlatforms();
169+
this.ptfs = await this.strategyService.getAllPlatforms();
170170
}
171171

172172
res.json({ success: true, data: this.ptfs });
@@ -300,7 +300,7 @@ class BKServer {
300300

301301
const data = autoReplies;
302302
if (this.ptfs.length === 0) {
303-
this.ptfs = this.strategyService.getAllPlatforms();
303+
this.ptfs = await this.strategyService.getAllPlatforms();
304304
}
305305

306306
const ptfMap = new Map(this.ptfs.map((ptf) => [ptf.id, ptf]));

src/main/backend/services/sessionService.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ export class SessionService {
2020
socket.on('sessionService-getSession', async (data: any, callback) => {
2121
const { platformId, username, goodsName, goodsAvatar } = data;
2222

23-
const ptf = this.strategyService.getPlatformInfoById(platformId);
23+
const ptf = await this.strategyService.getPlatformInfoById(platformId);
2424
const startTime = new Date().getTime();
2525
try {
2626
if (!username) {
@@ -86,7 +86,7 @@ export class SessionService {
8686
return this.sessionController.update(session.id, session);
8787
}
8888

89-
const ptf = this.strategyService.getPlatformInfoById(platformId);
89+
const ptf = await this.strategyService.getPlatformInfoById(platformId);
9090

9191
return this.sessionController.create({
9292
platform_id: platformId,

src/main/backend/services/strategyService.ts

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,11 @@ import { ALL_PLATFORMS } from '../constants';
55
export class StrategyService {
66
private io: socketIo.Server;
77

8+
private platformInfo: Platform[];
9+
810
constructor(io: socketIo.Server) {
911
this.io = io;
12+
this.platformInfo = [];
1013
}
1114

1215
async emitAndWait<T>(
@@ -31,6 +34,11 @@ export class StrategyService {
3134
return {} as T;
3235
}
3336

37+
// 如果 response[0] 也是数组,那么直接返回
38+
if (Array.isArray(response[0])) {
39+
return response[0] as T;
40+
}
41+
3442
return JSON.parse(response[0]);
3543
}
3644

@@ -62,12 +70,24 @@ export class StrategyService {
6270
}
6371
}
6472

65-
public getPlatformInfoById(id: string): Platform | null {
66-
const platforms = this.getAllPlatforms();
73+
public async getPlatformInfoById(id: string): Promise<Platform | null> {
74+
const platforms = await this.getAllPlatforms();
6775
return platforms.find((platform) => platform.id === id) || null;
6876
}
6977

70-
public getAllPlatforms(): Platform[] {
71-
return ALL_PLATFORMS;
78+
public async getAllPlatforms(): Promise<Platform[]> {
79+
if (this.platformInfo.length > 0) {
80+
return this.platformInfo;
81+
}
82+
83+
try {
84+
const data = await this.emitAndWait<Platform[]>(
85+
'strategyService-getAllPlatforms',
86+
);
87+
return data;
88+
} catch (error) {
89+
console.error('Failed to update strategies', error);
90+
return ALL_PLATFORMS;
91+
}
7292
}
7393
}

src/renderer/pages/About/index.tsx

Lines changed: 102 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,65 @@
1-
import React from 'react';
1+
import React, { useState } from 'react';
2+
import {
3+
Box,
4+
Button,
5+
Text,
6+
Modal,
7+
ModalOverlay,
8+
ModalContent,
9+
ModalHeader,
10+
ModalFooter,
11+
ModalBody,
12+
ModalCloseButton,
13+
VStack,
14+
Stack,
15+
useToast,
16+
} from '@chakra-ui/react';
217
import PageContainer from '../../components/PageContainer';
318
import Markdown from '../../components/Markdown';
19+
import { getVersionInfo } from '../../services/system/controller';
420

521
const AboutPage: React.FC = () => {
22+
const toast = useToast();
23+
const currentVersion = window.electron.ipcRenderer.get('get-version');
24+
const [isUpdateModalOpen, setIsUpdateModalOpen] = useState(false);
25+
const [updates, setUpdates] = useState<
26+
{
27+
version: string;
28+
url: string;
29+
description: string;
30+
}[]
31+
>([]);
32+
33+
const checkUpdate = async () => {
34+
const cv = window.electron.ipcRenderer.get('get-version');
35+
const versionUpdates = await getVersionInfo(cv);
36+
if (versionUpdates.length > 0) {
37+
setUpdates(versionUpdates);
38+
setIsUpdateModalOpen(true);
39+
} else {
40+
toast({
41+
title: '已经是最新版本',
42+
position: 'top',
43+
status: 'success',
44+
duration: 1000,
45+
isClosable: true,
46+
});
47+
}
48+
};
49+
50+
// 确认更新则跳转到最新版本的下载链接
51+
const confirmUpdate = () => {
52+
const latestVersion = updates[0]; // 假设第一个总是最新版本
53+
if (latestVersion) {
54+
window.electron.ipcRenderer.sendMessage('open-url', latestVersion.url);
55+
}
56+
};
57+
658
return (
759
<PageContainer>
8-
<Markdown
9-
content={`
60+
<VStack>
61+
<Markdown
62+
content={`
1063
本项目是基于大模型的智能对话客服工具,支持哔哩哔哩、抖音企业号、抖音、抖店、微博聊天、小红书专业号运营、小红书、知乎等平台接入,可选择 GPT3.5/GPT4.0,能处理文本、语音和图片,通过插件访问操作系统和互联网等外部资源,支持基于自有知识库定制企业 AI 应用。
1164
1265
## 使用说明
@@ -20,7 +73,52 @@ const AboutPage: React.FC = () => {
2073
* [GitHub](https://github.com/lrhh123/ChatGPT-On-CS)
2174
* [Gitee](https://gitee.com/alsritter/ChatGPT-On-CS) (国内用户推荐)
2275
`}
23-
/>
76+
/>
77+
</VStack>
78+
79+
<br />
80+
<br />
81+
82+
<Box p={5}>
83+
<Stack spacing={3}>
84+
<Text fontWeight="bold">版本信息</Text>
85+
<Text>懒人客服 {currentVersion}</Text>
86+
87+
{/* 检查更新 */}
88+
<Button size="sm" onClick={checkUpdate}>
89+
检查更新
90+
</Button>
91+
</Stack>
92+
</Box>
93+
94+
<Modal
95+
isOpen={isUpdateModalOpen}
96+
onClose={() => setIsUpdateModalOpen(false)}
97+
>
98+
<ModalOverlay />
99+
<ModalContent>
100+
<ModalHeader>版本更新</ModalHeader>
101+
<ModalCloseButton />
102+
<ModalBody>
103+
<Text>当前版本是 {currentVersion}. 检查到以下更新:</Text>
104+
<VStack spacing={4} mt="20px">
105+
{updates.map((update, index) => (
106+
<Box key={index}>
107+
<Markdown content={update.description} />
108+
</Box>
109+
))}
110+
</VStack>
111+
</ModalBody>
112+
<ModalFooter>
113+
<Button colorScheme="blue" mr={3} onClick={confirmUpdate}>
114+
立即更新到最新版本
115+
</Button>
116+
<Button variant="ghost" onClick={() => setIsUpdateModalOpen(false)}>
117+
关闭
118+
</Button>
119+
</ModalFooter>
120+
</ModalContent>
121+
</Modal>
24122
</PageContainer>
25123
);
26124
};

src/renderer/services/system/controller.ts

Lines changed: 27 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,20 @@
11
import axios from 'axios';
22

3-
// 一个辅助函数,用于比较两个版本号,考虑非数字部分
4-
function isVersionGreater(onlineVersion: string, currentVersion: string) {
5-
// 正则表达式用于分离数字部分和后缀
6-
const versionRegex = /(\d+\.\d+\.\d+)(.*)/;
7-
const [, onlineMain, onlineSuffix] = onlineVersion.match(versionRegex) || [];
8-
const [, currentMain, currentSuffix] =
3+
export const isVersionGreater = (
4+
onlineVersion: string,
5+
currentVersion: string,
6+
) => {
7+
// 更新正则表达式,更好地分离数字和后缀部分
8+
const versionRegex = /(\d+\.\d+\.\d+)(-?[^.]*)(\.\d+)?/;
9+
const [, onlineMain, onlinePre, onlinePreNum] =
10+
onlineVersion.match(versionRegex) || [];
11+
const [, currentMain, currentPre, currentPreNum] =
912
currentVersion.match(versionRegex) || [];
1013

11-
// 先比较主版本号
14+
// 比较主版本号
1215
const onlineParts = onlineMain.split('.').map(Number);
1316
const currentParts = currentMain.split('.').map(Number);
1417

15-
// eslint-disable-next-line no-plusplus
1618
for (let i = 0; i < Math.max(onlineParts.length, currentParts.length); i++) {
1719
const onlinePart = onlineParts[i] || 0;
1820
const currentPart = currentParts[i] || 0;
@@ -24,19 +26,25 @@ function isVersionGreater(onlineVersion: string, currentVersion: string) {
2426
}
2527
}
2628

27-
// 如果主版本号相同,比较后缀,视 "beta" 等作为较小
28-
if (onlineSuffix && currentSuffix) {
29-
return onlineSuffix > currentSuffix;
30-
}
31-
if (onlineSuffix) {
32-
return false; // online 有后缀但 current 无后缀,online 为较小版本
33-
}
34-
if (currentSuffix) {
35-
return true; // current 有后缀但 online 无后缀,online 为较大版本
29+
// 如果主版本号相同,先比较后缀是否存在(如果存在数字后缀的话)
30+
if (onlinePre || currentPre) {
31+
if (!onlinePre && currentPre) return true; // online 没有后缀,current 有后缀,online 更大
32+
if (onlinePre && !currentPre) return false; // online 有后缀,current 没有后缀,online 更小
33+
if (onlinePre !== currentPre) {
34+
return onlinePre > currentPre; // 直接字符串比较后缀
35+
}
36+
// 如果后缀相同,比较数字后缀
37+
const onlinePreNumValue = onlinePreNum
38+
? parseInt(onlinePreNum.substring(1), 10)
39+
: 0;
40+
const currentPreNumValue = currentPreNum
41+
? parseInt(currentPreNum.substring(1), 10)
42+
: 0;
43+
return onlinePreNumValue > currentPreNumValue;
3644
}
3745

38-
return false;
39-
}
46+
return false; // 如果主版本号和后缀完全相同,返回 false
47+
};
4048

4149
export const getVersionInfo = async (currentVersion: string) => {
4250
let updates: { version: string; url: string; description: string }[] = [];

0 commit comments

Comments
 (0)