Skip to content

Commit 7ef9764

Browse files
committed
Merge branch 'v3-dev' into v3
2 parents a04c98a + 637a1b8 commit 7ef9764

28 files changed

+564
-675
lines changed

packages/backend/src/libs/jwt/jwt.service.ts

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,16 @@ export type JWTPayload = JWTPayloadDefault & {
1919
export class JwtService {
2020
constructor(private configService: ConfigService) {}
2121

22-
async getKey(type: 'public' | 'private') {
22+
async getKey(type: 'public' | 'private', refresh = false) {
2323
switch (this.configService.get('jwt').algorithm) {
24+
case 'HS256':
25+
if (refresh) {
26+
const refreshSecret = this.configService.get('jwt')?.refreshSecret;
27+
if (refreshSecret) {
28+
return new TextEncoder().encode(refreshSecret);
29+
}
30+
}
31+
return new TextEncoder().encode(this.configService.get('jwt').secret);
2432
case 'ES256':
2533
if (type === 'private') {
2634
return await importJWK(
@@ -32,23 +40,28 @@ export class JwtService {
3240
JSON.parse(this.configService.get('jwt').publicKey),
3341
'ES256',
3442
);
35-
case 'HS256':
36-
return new TextEncoder().encode(this.configService.get('jwt').secret);
3743
}
3844
}
3945

40-
async sign(payload: JWTPayload): Promise<string> {
46+
async sign(
47+
payload: JWTPayload,
48+
duration = 7 * 24 * 60 * 60,
49+
refresh = false,
50+
): Promise<string> {
4151
const iat = Math.floor(Date.now() / 1000); // Not before: Now
42-
const exp = iat + 7 * 24 * 60 * 60; // One week
43-
return await new SignJWT({ ...payload })
52+
const exp = iat + duration; // One week
53+
return await new SignJWT({
54+
...payload,
55+
...(refresh ? { sub: 'refresh' } : {}),
56+
})
4457
.setProtectedHeader({
4558
alg: this.configService.get('jwt').algorithm,
4659
typ: 'JWT',
4760
})
4861
.setExpirationTime(exp)
4962
.setIssuedAt(iat)
5063
.setNotBefore(iat)
51-
.sign(await this.getKey('private'));
64+
.sign(await this.getKey('private', refresh));
5265
}
5366

5467
async verify(token: string): Promise<JWTPayload> {

packages/backend/src/modules/auth/auth.controller.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { ConfigService } from '@/common/config';
55
import { BizException } from '@/common/exceptions/biz.exception';
66
import { Payload, Public } from '@/common/guards/auth.guard';
77
import { ZodValidationPipe } from '@/common/pipes/zod';
8+
import { JWTPayload } from '@/libs/jwt/jwt.service';
89
import { WechatService } from '@/modules/auth/wechat.service';
910

1011
import { AuthDTO, ErrorCodeEnum } from 'shared';
@@ -185,4 +186,12 @@ export class AuthController {
185186
data: roles,
186187
};
187188
}
189+
190+
@Get('refresh')
191+
async refresh(@Payload() payload: JWTPayload) {
192+
return {
193+
success: true,
194+
...(await this.authService.refresh(payload.id, payload.role)),
195+
};
196+
}
188197
}

packages/backend/src/modules/auth/auth.service.ts

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -62,18 +62,19 @@ export class AuthService {
6262
* 1. 检查是否绑定账户
6363
* 2. 检查是否设置密码
6464
*/
65-
async #signWithCheck(user: any): Promise<{
66-
token: string;
67-
status: IAccountStatus;
68-
}> {
65+
async #signWithCheck(user: any) {
6966
let status: IAccountStatus = 'ok';
7067
if (!user.email && !user.phone) {
7168
status = 'bind';
7269
} else if (!user.newPassword) {
7370
status = 'password';
7471
}
7572
return {
76-
token: await this.jwt.sign({ id: user.id, role: user.role }),
73+
sessionToken: await this.jwt.sign({ id: user.id, role: user.role }),
74+
refreshToken: await this.jwt.sign(
75+
{ id: user.id, role: user.role },
76+
30 * 24 * 60 * 60,
77+
),
7778
status,
7879
};
7980
}
@@ -342,4 +343,8 @@ export class AuthService {
342343
},
343344
});
344345
}
346+
347+
async refresh(userId: number, userRole: string) {
348+
return this.#signWithCheck({ id: userId, role: userRole });
349+
}
345350
}

packages/backend/src/modules/chat/chat.controller.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ export class ChatController {
164164
modelId: data.modelId,
165165
input: data.content,
166166
messages: chatSession.messages,
167-
// key,
167+
topic: chatSession.topic,
168168
});
169169
}
170170
}

packages/backend/src/modules/chat/chat.service.ts

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -234,16 +234,15 @@ export class ChatService {
234234

235235
async summarizeTopic(message: string, sessionId: string) {
236236
const result = (await this.#chat({
237-
input: `Give me the topic title about the following text by use as few words as possible.
237+
input: `summarize the text in 4 words.
238238
Text: """
239239
${message}
240240
"""`,
241241
model: 'gpt-3.5-turbo',
242242
histories: [
243243
{
244244
role: 'system',
245-
content:
246-
'You are an assistant who uses a few words to summarize conversations',
245+
content: 'You are an assistant who uses 4 words to summarize text',
247246
},
248247
],
249248
stream: false,
@@ -263,6 +262,7 @@ ${message}
263262
input,
264263
modelId,
265264
messages, // key,
265+
topic,
266266
}: {
267267
userId: number;
268268
sessionId: string;
@@ -273,6 +273,7 @@ ${message}
273273
messages: ChatMessage[];
274274
/* Request API Key */
275275
// key: string;
276+
topic?: string;
276277
}) {
277278
const { name: model } = await this.prisma.client.model.findUniqueOrThrow({
278279
where: { id: modelId },
@@ -338,6 +339,24 @@ ${message}
338339
}),
339340
]);
340341
subscriber.complete();
342+
/* 首次对话自动总结对话,
343+
* First conversation automatically summarizes the conversation
344+
*/
345+
if (!topic) {
346+
await this.summarizeTopic(
347+
[
348+
...histories,
349+
{ role: 'user', content: input },
350+
{
351+
role: 'assistant',
352+
content: generated,
353+
},
354+
]
355+
.map((m) => `${m.role}: ${m.content}`)
356+
.join('\n'),
357+
sessionId,
358+
);
359+
}
341360
}
342361
})();
343362
});

packages/frontend/.eslintrc.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,7 @@
77
},
88
"rules": {
99
"@next/next/no-html-link-for-pages": [
10-
"error",
11-
"packages/frontend/src/app"
10+
"off"
1211
]
1312
}
1413
}

packages/frontend/package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
"@radix-ui/react-icons": "^1.3.0",
1919
"@radix-ui/themes": "^2.0.0",
2020
"@svgr/webpack": "^8.1.0",
21-
"@tremor/react": "^3.11.1",
2221
"@types/ramda": "^0.29.7",
2322
"clsx": "^2.0.0",
2423
"emoji-picker-react": "^4.4.7",

packages/frontend/src/app/(admin-end)/dashboard/page.tsx

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
import useSWR from 'swr';
44

55
import { Box, Grid, Text } from '@radix-ui/themes';
6-
import { Card, LineChart, Title } from '@tremor/react';
76

87
import { Loading } from '@/components/loading';
98
import { useStore } from '@/store';
@@ -32,14 +31,14 @@ export default function DashboardIndex() {
3231
return (
3332
<Grid columns="6" gap="3" width="auto">
3433
{analytics.map((item) => (
35-
<Card key={item.key}>
34+
<Box key={item.key}>
3635
<Text as="p" size="2" weight="medium">
3736
{item.label}
3837
</Text>
3938
<Text as="p" size="6" weight="bold">
4039
{data[item.key]}
4140
</Text>
42-
</Card>
41+
</Box>
4342
))}
4443
</Grid>
4544
);

packages/frontend/src/app/(admin-end)/layout.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ import '@radix-ui/themes/styles.css';
44
import '@/styles/dashboard.css';
55

66
export const metadata = {
7-
title: 'Dashboard | ChatGPT Admin ',
7+
title: 'Dashboard | ChatGPT Admin Web',
8+
description: 'Manage Dashboard for ChatGPT Admin Web',
89
};
910

1011
export default function AdminEndLayout({

packages/frontend/src/app/auth/page.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ const weChatOauthRedirectUrl =
2929
/* 验证码登录/注册 */
3030
function ValidateCodeLogin() {
3131
const router = useRouter();
32-
const { fetcher, setSessionToken } = useStore();
32+
const { fetcher, setAuthToken } = useStore();
3333
const [identity, setIdentity] = useState('');
3434
const [ifCodeSent, setIfCodeSent] = useState(false);
3535
const [validateCode, setValidateCode] = useState('');
@@ -65,7 +65,7 @@ function ValidateCodeLogin() {
6565
.then((res) => res.json())
6666
.then((res) => {
6767
if (res.success) {
68-
setSessionToken(res.token);
68+
setAuthToken(res.sessionToken, res.refreshToken);
6969
return router.push('/');
7070
} else {
7171
showToast(res.message);
@@ -151,7 +151,7 @@ function ValidateCodeLogin() {
151151
/* 密码登录 */
152152
const PasswordLogin: React.FC = () => {
153153
const router = useRouter();
154-
const { fetcher, setSessionToken } = useStore();
154+
const { fetcher, setAuthToken } = useStore();
155155
const [identity, setIdentity] = useState('');
156156
const [password, setPassword] = useState('');
157157
const [isSubmitting, handleSubmit] = usePreventFormSubmit();
@@ -165,7 +165,7 @@ const PasswordLogin: React.FC = () => {
165165
.then((res) => res.json())
166166
.then((res) => {
167167
if (res.success) {
168-
setSessionToken(res.token);
168+
setAuthToken(res.sessionToken, res.refreshToken);
169169
router.push('/');
170170
} else {
171171
router.refresh();

0 commit comments

Comments
 (0)