Skip to content

Commit 14c323c

Browse files
author
Kerwin
committed
feat: support room specific prompt
fix: mobile login modal (Closes #41)
1 parent 807d400 commit 14c323c

File tree

16 files changed

+197
-19
lines changed

16 files changed

+197
-19
lines changed

README.en.md

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,18 @@
77
</br>
88

99
## Introduction
10-
> **This project is forked from [Chanzhaoyu/chatgpt-web](https://github.com/Chanzhaoyu/chatgpt-web). In addition to regularly merging this branch, some unique features have been added such as registration and login, setting API key on the front-end page.**
10+
> **This project is forked from [Chanzhaoyu/chatgpt-web](https://github.com/Chanzhaoyu/chatgpt-web), some unique features have been added:**
11+
12+
[] Register & Login & Reset Password
13+
14+
[] Sync chat history
15+
16+
[] Front-end page setting apikey
17+
18+
[] Custom Sensitive Words
19+
20+
[] Set unique prompts for each chat room
21+
1122
</br>
1223

1324
## Screenshots
@@ -17,6 +28,7 @@
1728
![cover](./docs/c1.png)
1829
![cover2](./docs/c2.png)
1930
![cover3](./docs/basesettings.jpg)
31+
![cover3](./docs/prompt_en.jpg)
2032

2133
- [ChatGPT Web](#chatgpt-web)
2234
- [Introduction](#introduction)

README.md

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,17 @@
77
</br>
88

99
## 说明
10-
> **此项目 Fork 自 [Chanzhaoyu/chatgpt-web](https://github.com/Chanzhaoyu/chatgpt-web), 除了定时合并该分支, 新增了部分特色功能, 注册&登录, 前端页面设置apikey 等**
10+
> **此项目 Fork 自 [Chanzhaoyu/chatgpt-web](https://github.com/Chanzhaoyu/chatgpt-web), 新增了部分特色功能:**
11+
12+
[] 注册&登录&重置密码
13+
14+
[] 同步历史会话
15+
16+
[] 前端页面设置apikey
17+
18+
[] 自定义敏感词
19+
20+
[] 每个会话设置独有 Prompt
1121
</br>
1222

1323
## 截图
@@ -17,6 +27,7 @@
1727
![cover](./docs/c1.png)
1828
![cover2](./docs/c2.png)
1929
![cover3](./docs/basesettings.jpg)
30+
![cover3](./docs/prompt.jpg)
2031

2132
- [ChatGPT Web](#chatgpt-web)
2233
- [介绍](#介绍)

docs/prompt.jpg

154 KB
Loading

docs/prompt_en.jpg

170 KB
Loading

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "chatgpt-web",
3-
"version": "2.12.0",
3+
"version": "2.12.3",
44
"private": false,
55
"description": "ChatGPT Web",
66
"author": "ChenZhaoYu <chenzhaoyu1994@gmail.com>",

service/src/index.ts

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import {
1717
deleteChatRoom,
1818
existsChatRoom,
1919
getChat,
20+
getChatRoom,
2021
getChatRooms,
2122
getChats,
2223
getUser,
@@ -26,6 +27,7 @@ import {
2627
renameChatRoom,
2728
updateChat,
2829
updateConfig,
30+
updateRoomPrompt,
2931
updateUserInfo,
3032
updateUserPassword,
3133
verifyUser,
@@ -61,6 +63,7 @@ router.get('/chatrooms', auth, async (req, res) => {
6163
uuid: r.roomId,
6264
title: r.title,
6365
isEdit: false,
66+
prompt: r.prompt,
6467
})
6568
})
6669
res.send({ status: 'Success', message: null, data: result })
@@ -97,6 +100,22 @@ router.post('/room-rename', auth, async (req, res) => {
97100
}
98101
})
99102

103+
router.post('/room-prompt', auth, async (req, res) => {
104+
try {
105+
const userId = req.headers.userId as string
106+
const { prompt, roomId } = req.body as { prompt: string; roomId: number }
107+
const success = await updateRoomPrompt(userId, roomId, prompt)
108+
if (success)
109+
res.send({ status: 'Success', message: 'Saved successfully', data: null })
110+
else
111+
res.send({ status: 'Fail', message: 'Saved Failed', data: null })
112+
}
113+
catch (error) {
114+
console.error(error)
115+
res.send({ status: 'Fail', message: 'Rename error', data: null })
116+
}
117+
})
118+
100119
router.post('/room-delete', auth, async (req, res) => {
101120
try {
102121
const userId = req.headers.userId as string
@@ -272,7 +291,11 @@ router.post('/chat', auth, async (req, res) => {
272291
router.post('/chat-process', [auth, limiter], async (req, res) => {
273292
res.setHeader('Content-type', 'application/octet-stream')
274293

275-
const { roomId, uuid, regenerate, prompt, options = {}, systemMessage, temperature, top_p } = req.body as RequestProps
294+
let { roomId, uuid, regenerate, prompt, options = {}, systemMessage, temperature, top_p } = req.body as RequestProps
295+
const userId = req.headers.userId as string
296+
const room = await getChatRoom(userId, roomId)
297+
if (room != null && isNotEmptyString(room.prompt))
298+
systemMessage = room.prompt
276299

277300
let lastResponse
278301
let result

service/src/storage/model.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,12 @@ export class ChatRoom {
3737
roomId: number
3838
userId: string
3939
title: string
40+
prompt: string
4041
status: Status = Status.Normal
4142
constructor(userId: string, title: string, roomId: number) {
4243
this.userId = userId
4344
this.title = title
45+
this.prompt = undefined
4446
this.roomId = roomId
4547
}
4648
}

service/src/storage/mongo.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,13 +77,28 @@ export async function deleteChatRoom(userId: string, roomId: number) {
7777
return result
7878
}
7979

80+
export async function updateRoomPrompt(userId: string, roomId: number, prompt: string) {
81+
const query = { userId, roomId }
82+
const update = {
83+
$set: {
84+
prompt,
85+
},
86+
}
87+
const result = await roomCol.updateOne(query, update)
88+
return result.modifiedCount > 0
89+
}
90+
8091
export async function getChatRooms(userId: string) {
8192
const cursor = await roomCol.find({ userId, status: { $ne: Status.Deleted } })
8293
const rooms = []
8394
await cursor.forEach(doc => rooms.push(doc))
8495
return rooms
8596
}
8697

98+
export async function getChatRoom(userId: string, roomId: number) {
99+
return await roomCol.findOne({ userId, roomId, status: { $ne: Status.Deleted } }) as ChatRoom
100+
}
101+
87102
export async function existsChatRoom(userId: string, roomId: number) {
88103
const room = await roomCol.findOne({ roomId, userId })
89104
return !!room

src/api/index.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,13 @@ export function fetchRenameChatRoom<T = any>(title: string, roomId: number) {
134134
})
135135
}
136136

137+
export function fetchUpdateChatRoomPrompt<T = any>(prompt: string, roomId: number) {
138+
return post<T>({
139+
url: '/room-prompt',
140+
data: { prompt, roomId },
141+
})
142+
}
143+
137144
export function fetchDeleteChatRoom<T = any>(roomId: number) {
138145
return post<T>({
139146
url: '/room-delete',
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
<script lang="ts" setup>
2+
import { computed, ref } from 'vue'
3+
import { NButton, NInput, NModal, NSpace, useMessage } from 'naive-ui'
4+
import { t } from '@/locales'
5+
import { fetchUpdateChatRoomPrompt } from '@/api'
6+
import { useChatStore } from '@/store'
7+
8+
const props = defineProps<Props>()
9+
const emit = defineEmits<Emit>()
10+
11+
const chatStore = useChatStore()
12+
const currentChatHistory = computed(() => chatStore.getChatHistoryByCurrentActive)
13+
const ms = useMessage()
14+
const testing = ref(false)
15+
const title = `Prompt For [${currentChatHistory.value?.title}]`
16+
17+
interface Props {
18+
visible: boolean
19+
roomId: string
20+
}
21+
22+
interface Emit {
23+
(e: 'update:visible', visible: boolean): void
24+
}
25+
26+
const show = computed({
27+
get() {
28+
return props.visible
29+
},
30+
set(visible: boolean) {
31+
emit('update:visible', visible)
32+
},
33+
})
34+
35+
async function handleSaveChatRoomPrompt() {
36+
if (!currentChatHistory.value || !currentChatHistory.value)
37+
return
38+
39+
testing.value = true
40+
try {
41+
const { message } = await fetchUpdateChatRoomPrompt(currentChatHistory.value.prompt ?? '', +props.roomId) as { status: string; message: string }
42+
ms.success(message)
43+
show.value = false
44+
}
45+
catch (error: any) {
46+
ms.error(error.message)
47+
}
48+
testing.value = false
49+
}
50+
</script>
51+
52+
<template>
53+
<NModal
54+
v-model:show="show" :auto-focus="false" class="custom-card" preset="card" :style="{ width: '600px' }" :title="title" size="huge"
55+
:bordered="false"
56+
>
57+
<!-- <template #header-extra>
58+
噢!
59+
</template> -->
60+
<NInput
61+
:value="currentChatHistory && currentChatHistory.prompt"
62+
type="textarea"
63+
:autosize="{ minRows: 4, maxRows: 10 }" placeholder="Prompt for this room, If empty will use Settings -> Advanced -> Role" @input="(val) => { if (currentChatHistory) currentChatHistory.prompt = val }"
64+
/>
65+
<template #footer>
66+
<NSpace justify="end">
67+
<NButton :loading="testing" type="success" @click="handleSaveChatRoomPrompt">
68+
{{ t('common.save') }}
69+
</NButton>
70+
</NSpace>
71+
</template>
72+
</NModal>
73+
</template>

src/components/common/UserAvatar/index.vue

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,20 @@
11
<script setup lang='ts'>
22
import { computed, ref } from 'vue'
33
import { NAvatar, NButton } from 'naive-ui'
4-
import { useUserStore } from '@/store'
4+
import { useAuthStore, useUserStore } from '@/store'
55
import defaultAvatar from '@/assets/avatar.jpg'
66
import { isString } from '@/utils/is'
77
import Permission from '@/views/chat/layout/Permission.vue'
8+
import { useBasicLayout } from '@/hooks/useBasicLayout'
89
910
const userStore = useUserStore()
10-
// const authStore = useAuthStore()
11-
// const needPermission = computed(() => !!authStore.session?.auth && !authStore.token)
11+
const authStore = useAuthStore()
1212
const needPermission = ref(false)
1313
14+
const { isMobile } = useBasicLayout()
15+
if (!!authStore.session?.auth && !authStore.token)
16+
needPermission.value = isMobile.value
17+
1418
const userInfo = computed(() => userStore.userInfo)
1519
</script>
1620

@@ -33,8 +37,11 @@ const userInfo = computed(() => userStore.userInfo)
3337
<h2 v-if="userInfo.name" class="overflow-hidden font-bold text-md text-ellipsis whitespace-nowrap">
3438
{{ userInfo.name }}
3539
</h2>
36-
<NButton v-else tag="a" type="info" ghost @click="needPermission = true">
37-
<span class="text-xl text-[#4f555e] dark:text-white">
40+
<NButton
41+
v-else tag="a" text
42+
@click="needPermission = true"
43+
>
44+
<span class="text-xl text-[#ff69b4] dark:text-white">
3845
{{ $t('common.notLoggedIn') }}
3946
</span>
4047
</NButton>

src/icons/Prompt.vue

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<template>
2+
<div class="text-[#142D6E] dark:text-[#3a71ff]">
3+
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24">
4+
<g fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
5+
<path d="M5 7l5 5l-5 5" />
6+
<path d="M13 17h6" />
7+
</g>
8+
</svg>
9+
</div>
10+
</template>

src/typings/chat.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ declare namespace Chat {
2323
uuid: number
2424
loading?: boolean
2525
all?: boolean
26+
prompt?: string
2627
}
2728

2829
interface ChatState {

src/views/chat/components/Header/index.vue

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,17 @@
22
import { computed, nextTick } from 'vue'
33
import { HoverButton, SvgIcon } from '@/components/common'
44
import { useAppStore, useChatStore } from '@/store'
5+
import IconPrompt from '@/icons/Prompt.vue'
56
67
interface Props {
78
usingContext: boolean
9+
showPrompt: boolean
810
}
911
1012
interface Emit {
1113
(ev: 'export'): void
1214
(ev: 'toggleUsingContext'): void
15+
(ev: 'toggleShowPrompt'): void
1316
}
1417
1518
defineProps<Props>()
@@ -39,6 +42,10 @@ function handleExport() {
3942
function toggleUsingContext() {
4043
emit('toggleUsingContext')
4144
}
45+
46+
function handleShowPrompt() {
47+
emit('toggleShowPrompt')
48+
}
4249
</script>
4350

4451
<template>
@@ -62,6 +69,11 @@ function toggleUsingContext() {
6269
{{ currentChatHistory?.title ?? '' }}
6370
</h1>
6471
<div class="flex items-center space-x-2">
72+
<HoverButton @click="handleShowPrompt">
73+
<span class="text-xl" :class="{ 'text-[#4b9e5f]': usingContext, 'text-[#a8071a]': !usingContext }">
74+
<IconPrompt class="w-[20px] m-auto" />
75+
</span>
76+
</HoverButton>
6577
<HoverButton @click="toggleUsingContext">
6678
<span class="text-xl" :class="{ 'text-[#4b9e5f]': usingContext, 'text-[#a8071a]': !usingContext }">
6779
<SvgIcon icon="ri:chat-history-line" />

0 commit comments

Comments
 (0)