Skip to content

Commit

Permalink
feat: support room specific prompt
Browse files Browse the repository at this point in the history
fix: mobile login modal (Closes #41)
  • Loading branch information
Kerwin committed Apr 18, 2023
1 parent 807d400 commit 14c323c
Show file tree
Hide file tree
Showing 16 changed files with 197 additions and 19 deletions.
14 changes: 13 additions & 1 deletion README.en.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,18 @@
</br>

## Introduction
> **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.**
> **This project is forked from [Chanzhaoyu/chatgpt-web](https://github.com/Chanzhaoyu/chatgpt-web), some unique features have been added:**
[] Register & Login & Reset Password

[] Sync chat history

[] Front-end page setting apikey

[] Custom Sensitive Words

[] Set unique prompts for each chat room

</br>

## Screenshots
Expand All @@ -17,6 +28,7 @@
![cover](./docs/c1.png)
![cover2](./docs/c2.png)
![cover3](./docs/basesettings.jpg)
![cover3](./docs/prompt_en.jpg)

- [ChatGPT Web](#chatgpt-web)
- [Introduction](#introduction)
Expand Down
13 changes: 12 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,17 @@
</br>

## 说明
> **此项目 Fork 自 [Chanzhaoyu/chatgpt-web](https://github.com/Chanzhaoyu/chatgpt-web), 除了定时合并该分支, 新增了部分特色功能, 注册&登录, 前端页面设置apikey 等**
> **此项目 Fork 自 [Chanzhaoyu/chatgpt-web](https://github.com/Chanzhaoyu/chatgpt-web), 新增了部分特色功能:**
[] 注册&登录&重置密码

[] 同步历史会话

[] 前端页面设置apikey

[] 自定义敏感词

[] 每个会话设置独有 Prompt
</br>

## 截图
Expand All @@ -17,6 +27,7 @@
![cover](./docs/c1.png)
![cover2](./docs/c2.png)
![cover3](./docs/basesettings.jpg)
![cover3](./docs/prompt.jpg)

- [ChatGPT Web](#chatgpt-web)
- [介绍](#介绍)
Expand Down
Binary file added docs/prompt.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/prompt_en.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "chatgpt-web",
"version": "2.12.0",
"version": "2.12.3",
"private": false,
"description": "ChatGPT Web",
"author": "ChenZhaoYu <chenzhaoyu1994@gmail.com>",
Expand Down
25 changes: 24 additions & 1 deletion service/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
deleteChatRoom,
existsChatRoom,
getChat,
getChatRoom,
getChatRooms,
getChats,
getUser,
Expand All @@ -26,6 +27,7 @@ import {
renameChatRoom,
updateChat,
updateConfig,
updateRoomPrompt,
updateUserInfo,
updateUserPassword,
verifyUser,
Expand Down Expand Up @@ -61,6 +63,7 @@ router.get('/chatrooms', auth, async (req, res) => {
uuid: r.roomId,
title: r.title,
isEdit: false,
prompt: r.prompt,
})
})
res.send({ status: 'Success', message: null, data: result })
Expand Down Expand Up @@ -97,6 +100,22 @@ router.post('/room-rename', auth, async (req, res) => {
}
})

router.post('/room-prompt', auth, async (req, res) => {
try {
const userId = req.headers.userId as string
const { prompt, roomId } = req.body as { prompt: string; roomId: number }
const success = await updateRoomPrompt(userId, roomId, prompt)
if (success)
res.send({ status: 'Success', message: 'Saved successfully', data: null })
else
res.send({ status: 'Fail', message: 'Saved Failed', data: null })
}
catch (error) {
console.error(error)
res.send({ status: 'Fail', message: 'Rename error', data: null })
}
})

router.post('/room-delete', auth, async (req, res) => {
try {
const userId = req.headers.userId as string
Expand Down Expand Up @@ -272,7 +291,11 @@ router.post('/chat', auth, async (req, res) => {
router.post('/chat-process', [auth, limiter], async (req, res) => {
res.setHeader('Content-type', 'application/octet-stream')

const { roomId, uuid, regenerate, prompt, options = {}, systemMessage, temperature, top_p } = req.body as RequestProps
let { roomId, uuid, regenerate, prompt, options = {}, systemMessage, temperature, top_p } = req.body as RequestProps
const userId = req.headers.userId as string
const room = await getChatRoom(userId, roomId)
if (room != null && isNotEmptyString(room.prompt))
systemMessage = room.prompt

let lastResponse
let result
Expand Down
2 changes: 2 additions & 0 deletions service/src/storage/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,12 @@ export class ChatRoom {
roomId: number
userId: string
title: string
prompt: string
status: Status = Status.Normal
constructor(userId: string, title: string, roomId: number) {
this.userId = userId
this.title = title
this.prompt = undefined
this.roomId = roomId
}
}
Expand Down
15 changes: 15 additions & 0 deletions service/src/storage/mongo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,13 +77,28 @@ export async function deleteChatRoom(userId: string, roomId: number) {
return result
}

export async function updateRoomPrompt(userId: string, roomId: number, prompt: string) {
const query = { userId, roomId }
const update = {
$set: {
prompt,
},
}
const result = await roomCol.updateOne(query, update)
return result.modifiedCount > 0
}

export async function getChatRooms(userId: string) {
const cursor = await roomCol.find({ userId, status: { $ne: Status.Deleted } })
const rooms = []
await cursor.forEach(doc => rooms.push(doc))
return rooms
}

export async function getChatRoom(userId: string, roomId: number) {
return await roomCol.findOne({ userId, roomId, status: { $ne: Status.Deleted } }) as ChatRoom
}

export async function existsChatRoom(userId: string, roomId: number) {
const room = await roomCol.findOne({ roomId, userId })
return !!room
Expand Down
7 changes: 7 additions & 0 deletions src/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,13 @@ export function fetchRenameChatRoom<T = any>(title: string, roomId: number) {
})
}

export function fetchUpdateChatRoomPrompt<T = any>(prompt: string, roomId: number) {
return post<T>({
url: '/room-prompt',
data: { prompt, roomId },
})
}

export function fetchDeleteChatRoom<T = any>(roomId: number) {
return post<T>({
url: '/room-delete',
Expand Down
73 changes: 73 additions & 0 deletions src/components/common/Setting/Prompt.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
<script lang="ts" setup>
import { computed, ref } from 'vue'
import { NButton, NInput, NModal, NSpace, useMessage } from 'naive-ui'
import { t } from '@/locales'
import { fetchUpdateChatRoomPrompt } from '@/api'
import { useChatStore } from '@/store'
const props = defineProps<Props>()
const emit = defineEmits<Emit>()
const chatStore = useChatStore()
const currentChatHistory = computed(() => chatStore.getChatHistoryByCurrentActive)
const ms = useMessage()
const testing = ref(false)
const title = `Prompt For [${currentChatHistory.value?.title}]`
interface Props {
visible: boolean
roomId: string
}
interface Emit {
(e: 'update:visible', visible: boolean): void
}
const show = computed({
get() {
return props.visible
},
set(visible: boolean) {
emit('update:visible', visible)
},
})
async function handleSaveChatRoomPrompt() {
if (!currentChatHistory.value || !currentChatHistory.value)
return
testing.value = true
try {
const { message } = await fetchUpdateChatRoomPrompt(currentChatHistory.value.prompt ?? '', +props.roomId) as { status: string; message: string }
ms.success(message)
show.value = false
}
catch (error: any) {
ms.error(error.message)
}
testing.value = false
}
</script>

<template>
<NModal
v-model:show="show" :auto-focus="false" class="custom-card" preset="card" :style="{ width: '600px' }" :title="title" size="huge"
:bordered="false"
>
<!-- <template #header-extra>
噢!
</template> -->
<NInput
:value="currentChatHistory && currentChatHistory.prompt"
type="textarea"
:autosize="{ minRows: 4, maxRows: 10 }" placeholder="Prompt for this room, If empty will use Settings -> Advanced -> Role" @input="(val) => { if (currentChatHistory) currentChatHistory.prompt = val }"
/>
<template #footer>
<NSpace justify="end">
<NButton :loading="testing" type="success" @click="handleSaveChatRoomPrompt">
{{ t('common.save') }}
</NButton>
</NSpace>
</template>
</NModal>
</template>
17 changes: 12 additions & 5 deletions src/components/common/UserAvatar/index.vue
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
<script setup lang='ts'>
import { computed, ref } from 'vue'
import { NAvatar, NButton } from 'naive-ui'
import { useUserStore } from '@/store'
import { useAuthStore, useUserStore } from '@/store'
import defaultAvatar from '@/assets/avatar.jpg'
import { isString } from '@/utils/is'
import Permission from '@/views/chat/layout/Permission.vue'
import { useBasicLayout } from '@/hooks/useBasicLayout'
const userStore = useUserStore()
// const authStore = useAuthStore()
// const needPermission = computed(() => !!authStore.session?.auth && !authStore.token)
const authStore = useAuthStore()
const needPermission = ref(false)
const { isMobile } = useBasicLayout()
if (!!authStore.session?.auth && !authStore.token)
needPermission.value = isMobile.value
const userInfo = computed(() => userStore.userInfo)
</script>

Expand All @@ -33,8 +37,11 @@ const userInfo = computed(() => userStore.userInfo)
<h2 v-if="userInfo.name" class="overflow-hidden font-bold text-md text-ellipsis whitespace-nowrap">
{{ userInfo.name }}
</h2>
<NButton v-else tag="a" type="info" ghost @click="needPermission = true">
<span class="text-xl text-[#4f555e] dark:text-white">
<NButton
v-else tag="a" text
@click="needPermission = true"
>
<span class="text-xl text-[#ff69b4] dark:text-white">
{{ $t('common.notLoggedIn') }}
</span>
</NButton>
Expand Down
10 changes: 10 additions & 0 deletions src/icons/Prompt.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<template>
<div class="text-[#142D6E] dark:text-[#3a71ff]">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24">
<g fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M5 7l5 5l-5 5" />
<path d="M13 17h6" />
</g>
</svg>
</div>
</template>
1 change: 1 addition & 0 deletions src/typings/chat.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ declare namespace Chat {
uuid: number
loading?: boolean
all?: boolean
prompt?: string
}

interface ChatState {
Expand Down
12 changes: 12 additions & 0 deletions src/views/chat/components/Header/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,17 @@
import { computed, nextTick } from 'vue'
import { HoverButton, SvgIcon } from '@/components/common'
import { useAppStore, useChatStore } from '@/store'
import IconPrompt from '@/icons/Prompt.vue'
interface Props {
usingContext: boolean
showPrompt: boolean
}
interface Emit {
(ev: 'export'): void
(ev: 'toggleUsingContext'): void
(ev: 'toggleShowPrompt'): void
}
defineProps<Props>()
Expand Down Expand Up @@ -39,6 +42,10 @@ function handleExport() {
function toggleUsingContext() {
emit('toggleUsingContext')
}
function handleShowPrompt() {
emit('toggleShowPrompt')
}
</script>

<template>
Expand All @@ -62,6 +69,11 @@ function toggleUsingContext() {
{{ currentChatHistory?.title ?? '' }}
</h1>
<div class="flex items-center space-x-2">
<HoverButton @click="handleShowPrompt">
<span class="text-xl" :class="{ 'text-[#4b9e5f]': usingContext, 'text-[#a8071a]': !usingContext }">
<IconPrompt class="w-[20px] m-auto" />
</span>
</HoverButton>
<HoverButton @click="toggleUsingContext">
<span class="text-xl" :class="{ 'text-[#4b9e5f]': usingContext, 'text-[#a8071a]': !usingContext }">
<SvgIcon icon="ri:chat-history-line" />
Expand Down
Loading

0 comments on commit 14c323c

Please sign in to comment.