Multiple improvements for conversation

This commit is contained in:
Rafi
2023-03-30 21:45:23 +08:00
parent 97649e4bee
commit f67ed7621c
7 changed files with 95 additions and 61 deletions

View File

@@ -1,5 +1,6 @@
<script setup>
import {EventStreamContentType, fetchEventSource} from '@microsoft/fetch-event-source'
import {addConversation} from "../utils/helper";
const { $i18n, $auth } = useNuxtApp()
const runtimeConfig = useRuntimeConfig()
@@ -137,9 +138,17 @@ const scrollChatWindow = () => {
grab.value.scrollIntoView({behavior: 'smooth'})
}
const checkOrAddConversation = () => {
if (props.conversation.messages.length === 0) {
props.conversation.messages.push({id: null, is_bot: true, message: ''})
}
}
const send = (message) => {
fetchingResponse.value = true
if (props.conversation.messages.length === 0) {
addConversation(props.conversation)
}
props.conversation.messages.push({message: message})
fetchReply(message)
scrollChatWindow()
@@ -182,42 +191,55 @@ watchEffect(() => {
<template>
<div
v-if="conversation.messages"
ref="chatWindow"
v-if="conversation.loadingMessages"
class="text-center"
>
<v-container>
<v-row>
<v-col
v-for="(message, index) in conversation.messages" :key="index"
cols="12"
>
<div
class="d-flex align-center"
:class="message.is_bot ? 'justify-start' : 'justify-end'"
>
<MessageActions
v-if="!message.is_bot"
:message="message"
:message-index="index"
:use-prompt="usePrompt"
:delete-message="deleteMessage"
/>
<MsgContent :message="message" />
<MessageActions
v-if="message.is_bot"
:message="message"
:message-index="index"
:use-prompt="usePrompt"
:delete-message="deleteMessage"
/>
</div>
</v-col>
</v-row>
</v-container>
<div ref="grab" class="w-100" style="height: 200px;"></div>
<v-progress-circular
indeterminate
color="primary"
></v-progress-circular>
</div>
<Welcome v-else />
<div v-else>
<div
v-if="conversation.messages.length > 0"
ref="chatWindow"
>
<v-container>
<v-row>
<v-col
v-for="(message, index) in conversation.messages" :key="index"
cols="12"
>
<div
class="d-flex align-center"
:class="message.is_bot ? 'justify-start' : 'justify-end'"
>
<MessageActions
v-if="!message.is_bot"
:message="message"
:message-index="index"
:use-prompt="usePrompt"
:delete-message="deleteMessage"
/>
<MsgContent :message="message" />
<MessageActions
v-if="message.is_bot"
:message="message"
:message-index="index"
:use-prompt="usePrompt"
:delete-message="deleteMessage"
/>
</div>
</v-col>
</v-row>
</v-container>
<div ref="grab" class="w-100" style="height: 200px;"></div>
</div>
<Welcome v-if="conversation.id === null && conversation.messages.length === 0" />
</div>
<v-footer app>
<div class="px-md-16 w-100 d-flex flex-column">
<div class="d-flex align-center">

View File

@@ -21,6 +21,7 @@
"themeMode": "Theme Mode",
"feedback": "Feedback",
"newConversation": "New conversation",
"defaultConversationTitle": "Unnamed",
"clearConversations": "Clear conversations",
"modelParameters": "Model Parameters",
"model": "Model",
@@ -40,6 +41,7 @@
"signOut": "Sign out",
"webSearch": "Web Search",
"webSearchDefaultPrompt": "Web search results:\n\n[web_results]\nCurrent date: [current_date]\n\nInstructions: Using the provided web search results, write a comprehensive reply to the given query. Make sure to cite results using [[number](URL)] notation after the reference. If the provided search results refer to multiple subjects with the same name, write separate answers for each subject.\nQuery: [query]",
"genTitlePrompt": "Generate a short title for the following content, no more than 10 words. \n\nContent: ",
"welcomeScreen": {
"introduction1": "is an unofficial client for ChatGPT, but uses the official OpenAI API.",
"introduction2": "You will need an OpenAI API Key before you can use this client.",

View File

@@ -21,6 +21,7 @@
"themeMode": "Тема",
"feedback": "Обратная связь",
"newConversation": "Новый чат",
"defaultConversationTitle": "Безымянный",
"clearConversations": "Очистить чаты",
"modelParameters": "Параметры модели",
"model": "Модель",
@@ -40,6 +41,7 @@
"signOut": "Выход",
"webSearch": "Поиск в интернете",
"webSearchDefaultPrompt": "Результаты веб-поиска:\n\n[web_results]\nТекущая дата: [current_date]\n\nИнструкции: Используя предоставленные результаты веб-поиска, напишите развернутый ответ на заданный запрос. Обязательно цитируйте результаты, используя обозначение [[number](URL)] после ссылки. Если предоставленные результаты поиска относятся к нескольким темам с одинаковым названием, напишите отдельные ответы для каждой темы.\nЗапрос: [query]",
"genTitlePrompt": "Придумайте короткий заголовок для следующего содержания, не более 10 слов. \n\nСодержание: ",
"welcomeScreen": {
"introduction1": "является неофициальным клиентом для ChatGPT, но использует официальный API OpenAI.",
"introduction2": "Вам понадобится ключ API OpenAI, прежде чем вы сможете использовать этот клиент.",

View File

@@ -21,6 +21,7 @@
"themeMode": "主题模式",
"feedback": "反馈",
"newConversation": "新的对话",
"defaultConversationTitle": "未命名",
"clearConversations": "清除对话",
"modelParameters": "模型参数",
"model": "模型",
@@ -40,6 +41,7 @@
"signOut": "退出登录",
"webSearch": "网页搜索",
"webSearchDefaultPrompt": "网络搜索结果:\n\n[web_results]\n当前日期[current_date]\n\n说明使用提供的网络搜索结果对给定的查询写出全面的回复。确保在引用参考文献后使用 [[number](URL)] 符号进行引用结果. 如果提供的搜索结果涉及到多个具有相同名称的主题,请针对每个主题编写单独的答案。\n查询[query]",
"genTitlePrompt": "为以下内容生成一个不超过10个字的简短标题。 \n\n内容: ",
"welcomeScreen": {
"introduction1": "是一个非官方的ChatGPT客户端但使用OpenAI的官方API",
"introduction2": "在使用本客户端之前您需要一个OpenAI API密钥。",

View File

@@ -54,6 +54,7 @@ const deleteConversation = async (index) => {
deletingConversationIndex.value = null
if (!error.value) {
if (conversations.value[index].id === currentConversation.value.id) {
console.log('delete current conversation')
createNewConversation()
}
conversations.value.splice(index, 1)
@@ -130,8 +131,8 @@ onMounted(async () => {
block
variant="outlined"
prepend-icon="add"
@click="createNewConversation()"
class="text-none"
@click="createNewConversation"
>
{{ $t('newConversation') }}
</v-btn>
@@ -172,19 +173,19 @@ onMounted(async () => {
<v-list-item
rounded="xl"
active-color="primary"
:to="`/${conversation.id}`"
:to="conversation.id ? `/${conversation.id}` : undefined"
v-bind="props"
>
<v-list-item-title>{{ conversation.topic }}</v-list-item-title>
<template v-slot:append>
<div
v-show="isHovering"
v-show="isHovering && conversation.id"
>
<v-btn
icon="edit"
size="small"
variant="text"
@click.stop="editConversation(cIdx)"
@click.prevent="editConversation(cIdx)"
>
</v-btn>
<v-btn
@@ -192,7 +193,7 @@ onMounted(async () => {
size="small"
variant="text"
:loading="deletingConversationIndex === cIdx"
@click.stop="deleteConversation(cIdx)"
@click.prevent="deleteConversation(cIdx)"
>
</v-btn>
</div>

View File

@@ -1,26 +1,32 @@
<script setup>
import {getDefaultConversationData} from "~/utils/helper";
definePageMeta({
middleware: ["auth"],
path: '/:id?',
keepalive: true
})
const route = useRoute()
const conversation = ref({})
const currentConversation = useConversation()
const conversation = ref(getDefaultConversationData())
watchEffect(() => {
if (!route.params.id) {
conversation.value = getDefaultConversationData()
}
})
const loadMessage = async () => {
conversation.value = Object.assign(conversation.value, conversation)
conversation.value.loadingMessages = true
const { data, error } = await useAuthFetch('/api/chat/messages/?conversationId=' + route.params.id)
if (!error.value) {
conversation.value.messages = data.value
}
conversation.value.loadingMessages = true
conversation.value.loadingMessages = false
}
onMounted(async () => {
if (route.params.id) {
conversation.value.id = parseInt(route.params.id)
await loadMessage()
}
currentConversation.value = Object.assign({}, conversation.value)
})
</script>

View File

@@ -1,8 +1,9 @@
export const getDefaultConversationData = () => {
const { $i18n } = useNuxtApp()
return {
id: null,
topic: null,
topic: $i18n.t('defaultConversationTitle'),
messages: [],
loadingMessages: false,
}
@@ -19,34 +20,32 @@ export const getConversations = async () => {
export const createNewConversation = () => {
const conversation = useConversation()
conversation.value = getDefaultConversationData()
navigateTo('/')
}
export const openConversationMessages = async (currentConversation) => {
const conversation = useConversation()
conversation.value = Object.assign(conversation.value, currentConversation)
conversation.value.loadingMessages = true
const { data, error } = await useAuthFetch('/api/chat/messages/?conversationId=' + currentConversation.id)
if (!error.value) {
conversation.value.messages = data.value
}
conversation.value.loadingMessages = true
export const addConversation = (conversation) => {
const conversations = useConversations()
conversations.value = [conversation, ...conversations.value]
}
export const genTitle = async (conversationId) => {
const { $i18n } = useNuxtApp()
const { data, error } = await useAuthFetch('/api/gen_title/', {
method: 'POST',
body: {
conversationId: conversationId
conversationId: conversationId,
prompt: $i18n.t('genTitlePrompt')
}
})
if (!error.value) {
const conversation = {
id: conversationId,
topic: data.value.title,
}
const conversations = useConversations()
// prepend to conversations
conversations.value = [conversation, ...conversations.value]
let index = conversations.value.findIndex(item => item.id === conversationId)
if (index === -1) {
index = 0
}
conversations.value[index].topic = data.value.title
return data.value.title
}
return null