refactor: simplify ChatGPT component state management

This commit is contained in:
Jacky 2025-01-31 14:33:38 +08:00
parent 9e66c355bf
commit 4f674ec13e
No known key found for this signature in database
GPG key ID: 215C21B10DF38B4D

View file

@ -1,6 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import type { ChatComplicationMessage } from '@/api/openai' import type { ChatComplicationMessage } from '@/api/openai'
import type { Ref } from 'vue'
import openai from '@/api/openai' import openai from '@/api/openai'
import ChatGPT_logo from '@/assets/svg/ChatGPT_logo.svg?component' import ChatGPT_logo from '@/assets/svg/ChatGPT_logo.svg?component'
import { urlJoin } from '@/lib/helper' import { urlJoin } from '@/lib/helper'
@ -8,8 +7,8 @@ import { useSettingsStore, useUserStore } from '@/pinia'
import Icon, { SendOutlined } from '@ant-design/icons-vue' import Icon, { SendOutlined } from '@ant-design/icons-vue'
import hljs from 'highlight.js' import hljs from 'highlight.js'
import nginx from 'highlight.js/lib/languages/nginx' import nginx from 'highlight.js/lib/languages/nginx'
import { Marked } from 'marked'
import { Marked } from 'marked'
import { markedHighlight } from 'marked-highlight' import { markedHighlight } from 'marked-highlight'
import { storeToRefs } from 'pinia' import { storeToRefs } from 'pinia'
import 'highlight.js/styles/vs2015.css' import 'highlight.js/styles/vs2015.css'
@ -17,28 +16,19 @@ import 'highlight.js/styles/vs2015.css'
const props = defineProps<{ const props = defineProps<{
content: string content: string
path?: string path?: string
historyMessages?: ChatComplicationMessage[]
}>() }>()
const emit = defineEmits(['update:history_messages'])
hljs.registerLanguage('nginx', nginx) hljs.registerLanguage('nginx', nginx)
const { language: current } = storeToRefs(useSettingsStore()) const { language: current } = storeToRefs(useSettingsStore())
const history_messages = computed(() => props.historyMessages) const messages = defineModel<ChatComplicationMessage[]>('historyMessages', {
const messages = ref([]) as Ref<ChatComplicationMessage[] | undefined> type: Array,
default: reactive([]),
onMounted(() => {
messages.value = props.historyMessages
})
watch(history_messages, () => {
messages.value = props.historyMessages
}) })
const loading = ref(false) const loading = ref(false)
const ask_buffer = ref('') const askBuffer = ref('')
async function request() { async function request() {
loading.value = true loading.value = true
@ -52,9 +42,11 @@ async function request() {
const { token } = storeToRefs(user) const { token } = storeToRefs(user)
messages.value?.push(t.value) messages.value = [...messages.value!, t.value]
emit('update:history_messages', messages.value) await nextTick()
scrollToBottom()
const res = await fetch(urlJoin(window.location.pathname, '/api/chatgpt'), { const res = await fetch(urlJoin(window.location.pathname, '/api/chatgpt'), {
method: 'POST', method: 'POST',
@ -76,7 +68,7 @@ async function request() {
scrollToBottom() scrollToBottom()
}, 500) }, 500)
loading.value = false loading.value = false
store_record() storeRecord()
break break
} }
apply(value!) apply(value!)
@ -146,18 +138,21 @@ async function send() {
messages.value = [] messages.value = []
if (messages.value.length === 0) { if (messages.value.length === 0) {
messages.value.push({ messages.value = [{
role: 'user', role: 'user',
content: `${props.content}\n\nCurrent Language Code: ${current.value}`, content: `${props.content}\n\nCurrent Language Code: ${current.value}`,
}) }]
} }
else { else {
messages.value.push({ messages.value = [...messages.value, {
role: 'user', role: 'user',
content: ask_buffer.value, content: askBuffer.value,
}) }]
ask_buffer.value = '' askBuffer.value = ''
} }
await nextTick()
await request() await request()
} }
@ -167,9 +162,7 @@ const marked = new Marked(
highlight(code, lang) { highlight(code, lang) {
const language = hljs.getLanguage(lang) ? lang : 'nginx' const language = hljs.getLanguage(lang) ? lang : 'nginx'
const highlightedCode = hljs.highlight(code, { language }).value return hljs.highlight(code, { language }).value
return `<pre><code class="hljs ${language}">${highlightedCode}</code></pre>`
}, },
}), }),
) )
@ -180,27 +173,27 @@ marked.setOptions({
breaks: false, breaks: false,
}) })
function store_record() { function storeRecord() {
openai.store_record({ openai.store_record({
file_name: props.path, file_name: props.path,
messages: messages.value, messages: messages.value,
}) })
} }
function clear_record() { function clearRecord() {
openai.store_record({ openai.store_record({
file_name: props.path, file_name: props.path,
messages: [], messages: [],
}) })
messages.value = [] messages.value = []
emit('update:history_messages', [])
} }
const editing_idx = ref(-1) const editingIdx = ref(-1)
async function regenerate(index: number) { async function regenerate(index: number) {
editing_idx.value = -1 editingIdx.value = -1
messages.value = messages.value?.slice(0, index) messages.value = messages.value?.slice(0, index)
await nextTick()
await request() await request()
} }
@ -237,27 +230,27 @@ const show = computed(() => !messages.value || messages.value?.length === 0)
<AComment :author="item.role === 'assistant' ? $gettext('Assistant') : $gettext('User')"> <AComment :author="item.role === 'assistant' ? $gettext('Assistant') : $gettext('User')">
<template #content> <template #content>
<div <div
v-if="item.role === 'assistant' || editing_idx !== index" v-if="item.role === 'assistant' || editingIdx !== index"
v-dompurify-html="marked.parse(item.content)" v-dompurify-html="marked.parse(item.content)"
class="content" class="content"
/> />
<AInput <AInput
v-else v-else
v-model:value="item.content" v-model:value="item.content"
style="padding: 0" class="pa-0"
:bordered="false" :bordered="false"
/> />
</template> </template>
<template #actions> <template #actions>
<span <span
v-if="item.role === 'user' && editing_idx !== index" v-if="item.role === 'user' && editingIdx !== index"
@click="editing_idx = index" @click="editingIdx = index"
> >
{{ $gettext('Modify') }} {{ $gettext('Modify') }}
</span> </span>
<template v-else-if="editing_idx === index"> <template v-else-if="editingIdx === index">
<span @click="regenerate(index + 1)">{{ $gettext('Save') }}</span> <span @click="regenerate(index + 1)">{{ $gettext('Save') }}</span>
<span @click="editing_idx = -1">{{ $gettext('Cancel') }}</span> <span @click="editingIdx = -1">{{ $gettext('Cancel') }}</span>
</template> </template>
<span <span
v-else-if="!loading" v-else-if="!loading"
@ -277,7 +270,7 @@ const show = computed(() => !messages.value || messages.value?.length === 0)
:cancel-text="$gettext('No')" :cancel-text="$gettext('No')"
:ok-text="$gettext('OK')" :ok-text="$gettext('OK')"
:title="$gettext('Are you sure you want to clear the record of chat?')" :title="$gettext('Are you sure you want to clear the record of chat?')"
@confirm="clear_record" @confirm="clearRecord"
> >
<AButton type="text"> <AButton type="text">
{{ $gettext('Clear') }} {{ $gettext('Clear') }}
@ -292,7 +285,7 @@ const show = computed(() => !messages.value || messages.value?.length === 0)
</ASpace> </ASpace>
</div> </div>
<ATextarea <ATextarea
v-model:value="ask_buffer" v-model:value="askBuffer"
auto-size auto-size
/> />
<div class="send-btn"> <div class="send-btn">