Browse Source

refactor: simplify ChatGPT component state management

Jacky 3 months ago
parent
commit
4f674ec13e
1 changed files with 33 additions and 40 deletions
  1. 33 40
      app/src/components/ChatGPT/ChatGPT.vue

+ 33 - 40
app/src/components/ChatGPT/ChatGPT.vue

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