From ff2d01588d4e69d3bf1ad856e8e225b7f6a3c0f2 Mon Sep 17 00:00:00 2001
From: zhaowei <zhaowei>
Date: 星期一, 26 八月 2024 11:01:48 +0800
Subject: [PATCH] 1、基本实现电子说明书页面布局及功能 2、基本实现语言大模型页面与后端数据联动

---
 src/views/ai/LanguageModel.vue |  517 +++++++++++++++++++++++++++++++++++++++-----------------
 1 files changed, 356 insertions(+), 161 deletions(-)

diff --git a/src/views/ai/LanguageModel.vue b/src/views/ai/LanguageModel.vue
index e2d3666..36c4eb6 100644
--- a/src/views/ai/LanguageModel.vue
+++ b/src/views/ai/LanguageModel.vue
@@ -1,11 +1,15 @@
 <template>
   <div class="page-container">
     <div class="outer-container">
+      <!--宸︿晶鍘嗗彶浼氳瘽鍖哄煙-->
       <div class="left-container">
+        <!--logo鍖哄煙-->
         <div class="logo-container"><img src="@/assets/page/languageModel/logo.png"></div>
+
+        <!--鍔熻兘鎸夐敭鍖哄煙-->
         <div class="manage-history-container">
           <div @click="createNewConversation"
-               :class="[isAtNewConversation?'create-history-container-active':'',isDeletingBatch?'fold-create-history-container':'expand-create-history-container']"
+               :class="[isAtNewConversation?'create-history-container-active':'',isDeletingBatch?'fold-create-history-container':'expand-create-history-container',isModelResponding?'disable-expand':'']"
                class="create-new-conversation">
             <a-icon type="plus"></a-icon>
             <span v-if="!isDeletingBatch">鏂板浼氳瘽</span>
@@ -38,7 +42,7 @@
                     </div>
                   </template>
                   <div @click="deleteBatchConversation" id="delete-batch-button"
-                       :class="[checkedConversationIdList.length?'able-delete-button':'disable-delete-button']">
+                       :class="[checkedConversationIdList.length&&!isModelResponding?'able-delete-button':'disable-delete-button']">
                     <a-icon type="delete"/>
                     <div>鍒犻櫎</div>
                   </div>
@@ -52,9 +56,18 @@
             </template>
           </div>
         </div>
+
+        <!--鍘嗗彶浼氳瘽鍒楄〃鍖哄煙-->
         <div class="chat-history-container">
+          <template v-if="!chatHistoryList.length">
+            <a-empty>
+              <span slot="description">鏃犲巻鍙蹭細璇�</span>
+            </a-empty
+            >
+          </template>
+
           <div v-for="(item,index) in chatHistoryList" :key="item.id"
-               :class="[item.id===activeHistoryIndex?'single-history-active':'',item.inputVisible?'input-visible-class':'']"
+               :class="[item.id===activeHistoryIndex?'single-history-active':'',item.inputVisible?'input-visible-class':'',isModelResponding?'disable-switch':'']"
                @click="switchToCurrentConversation(item,$event)"
                @mouseenter="item.iconVisible=true"
                @mouseleave="item.iconVisible=false">
@@ -65,7 +78,6 @@
               <span class="check-mark"></span>
             </label>
 
-
             <a-popover placement="top" :visible="item.deletePopVisible" trigger="click"
                        :getPopupContainer="node=>node.parentNode">
               <template slot="content">
@@ -73,13 +85,14 @@
                   <div>鍒犻櫎鍚庢棤娉曟仮澶嶏紝鏄惁缁х画鍒犻櫎锛�</div>
                   <div>
                     <button class="cancel-delete-button" @click="cancelDeleteConversation(item,$event)">鍙栨秷</button>
-                    <button @click="confirmDeleteConversation(item,index)" id="delete-conversation-button">鍒犻櫎</button>
+                    <button @click.stop="confirmDeleteConversation(item,index)" id="delete-conversation-button">鍒犻櫎
+                    </button>
                   </div>
                 </div>
               </template>
               <template v-if="!item.inputVisible">
-                <div class="conversation-title">{{item.title}}</div>
-                <div class="icon-container hover-icon-container" v-show="!isDeletingBatch">
+                <div class="conversation-title">{{item.problem.slice(0,15)}}</div>
+                <div class="icon-container hover-icon-container" v-show="!isDeletingBatch&&!isModelResponding">
                   <a-icon type="edit" @click.stop="editConversationTitle(item)"/>
                   <a-icon type="delete" @click.stop="deleteConversation(item)"
                           @blur="cancelDeleteConversation(item,$event)"/>
@@ -102,28 +115,33 @@
         </div>
       </div>
 
+      <!--鍙充晶浼氳瘽鍐呭鍖哄煙-->
       <div class="right-container">
+        <!--浼氳瘽鍐呭鍒楄〃鍖哄煙-->
         <div class="conversation-container">
           <div v-for="item in currentConversation.messages" class="single-conversation" :id="'id'+item.index">
             <div v-if="item.role==='user'" class="user-question">
               <div class="avatar">
                 <a-avatar :src="getAvatar()"/>
               </div>
-              <div class="content">{{item.content}}</div>
+              <div class="conversation-content">{{item.content}}</div>
             </div>
             <div v-else class="assistant-answer">
               <div class="avatar">
                 <img src="@/assets/page/languageModel/ai-avatar.png"/>
               </div>
-              <div class="content">{{item.content}}</div>
+              <div class="conversation-content" v-html="item.content.replace(/\n/g,'<br>')"></div>
             </div>
           </div>
         </div>
+
+        <!--鎻愰棶杈撳叆鍖哄煙-->
         <div class="input-container" :class="[textareaFocused?'input-container-active':'']">
           <textarea v-model="inputQuestion" :placeholder="textareaPlaceholder"
                     @keydown.enter="sendQuestion($event)" @focus="textareaFocused=true"
                     @blur="textareaFocused=false"></textarea>
-          <img src="@/assets/page/languageModel/send-message.png" @click="sendQuestion($event)" v-if="!isResponding">
+          <img src="@/assets/page/languageModel/send-message.png" @click="sendQuestion($event)"
+               v-if="!isModelResponding">
           <a-icon type="loading" class="loading-icon" v-else/>
         </div>
       </div>
@@ -136,6 +154,16 @@
   import { mapGetters } from 'vuex'
   import { message } from 'ant-design-vue'
   import { randomUUID } from '@/utils/util'
+  import {
+    addNewConversationApi,
+    getChatHistoryListApi,
+    getCurrentConversationApi,
+    deleteSingleChatHistoryApi,
+    askToLanguageModelApi
+  } from '@/api/ai'
+  import { EventSourcePolyfill } from 'event-source-polyfill'
+  import Vue from 'vue'
+  import { ACCESS_TOKEN, TENANT_ID } from '@/store/mutation-types'
 
   message.config({
     maxCount: 1,
@@ -151,62 +179,22 @@
         checkedConversationIdList: [],
         deleteBatchPopVisible: false,
         currentConversation: {
-          id: '683a65fd-8feb-4446-ad32-714c4785f667',
-          messages: [
-            {
-              'role': 'user',
-              'content': '浣犳槸璋侊紵浣犳槸璋佷綘鏄皝浣犳槸璋佷綘鏄皝浣犳槸璋佷綘鏄皝浣犳槸璋佷綘鏄皝浣犳槸璋佷綘鏄皝浣犳槸璋佷綘鏄皝浣犳槸璋佷綘鏄皝浣犳槸璋佷綘鏄皝浣犳槸璋�'
-            },
-            {
-              'role': 'assistant',
-              'content': '鎴戞槸26涓敓娑寚瀵煎笀灏忕埍'
-            },
-            {
-              'role': 'user',
-              'content': '浣犻兘鑳藉仛浜涗粈涔堬紵'
-            },
-            {
-              'role': 'assistant',
-              'content': '鎴戣兘绔欏湪鏈潵瑙嗚甯姪鍚屽浠仛濂界敓娑鍒掓寚瀵笺��'
-            },
-            {
-              'role': 'user',
-              'content': '浠婂ぉ澶╂皵濡備綍锛�'
-            },
-            {
-              'role': 'assistant',
-              'content': '鎴戞槸26涓敓娑寚瀵煎笀灏忕埍'
-            },
-            {
-              'role': 'user',
-              'content': '浣犻兘鑳藉仛浜涗粈涔堬紵'
-            },
-            {
-              'role': 'assistant',
-              'content': '鎴戣兘绔欏湪鏈潵瑙嗚甯姪鍚屽浠仛濂界敓娑鍒掓寚瀵笺��'
-            }
-          ],
-          stream: false,
-          max_tokens: 500,
-          iconVisible: false,
-          inputVisible: false,
-          deletePopVisible: false
+          id: '',
+          messages: [],
+          stream: true,
+          max_tokens: 500
         },
-        // currentConversation: {},
         isAtNewConversation: false,
         isDeletingBatch: false,
         activeHistoryIndex: null,
         editingHistoryIndex: null,
         deletingHistoryIndex: null,
-        iconVisible: false,
-        inputVisible: false,
         editedConversationTitle: '',
-        deletePopVisible: false,
         conversationContainer: null,
         inputQuestion: '',
-        textareaPlaceholder: 'Enter鍙戦�侊紝Shift+Enter鎹㈣',
+        textareaPlaceholder: '',
         textareaFocused: false,
-        isResponding: false
+        isModelResponding: false
       }
     },
 
@@ -219,40 +207,265 @@
             document.removeEventListener('click', this.handleDocumentClick)
           }
         }
+      },
+      isAtNewConversation: {
+        handler(val) {
+          if (val) {
+            this.textareaPlaceholder = '璇峰皾璇曢棶鎴戯細浣犳槸璋侊紵'
+          } else {
+            this.textareaPlaceholder = 'Enter鍙戦�侊紝Shift+Enter鎹㈣'
+          }
+        },
+        immediate: true
       }
     },
+    created() {
+      this.getChatHistoryListByApi()
+    },
     mounted() {
-      this.getConversationByApi()
       this.conversationContainer = document.querySelector('.conversation-container')
     },
     methods: {
       ...mapGetters(['avatar']),
 
-      /* 璋冪敤鎺ュ彛鑾峰彇褰撳墠浼氳瘽璁板綍 */
-      getConversationByApi() {
-        this.currentConversation.title = this.currentConversation.messages[0].content.slice(0, 15)
-        this.chatHistoryList.push(this.currentConversation)
-        this.activeHistoryIndex = this.chatHistoryList[0].id
-        if (!this.chatHistoryList.length) this.textareaPlaceholder = '璇峰皾璇曢棶鎴戯細浣犳槸璋侊紵'
+      getChatHistoryListByApi() {
+        //  TODO 璋冪敤鎺ュ彛鑾峰彇鍘嗗彶浼氳瘽鍒楄〃,濡傛灉鍘嗗彶浼氳瘽涓嶄负绌哄垯璺宠浆鑷崇涓�鏉″巻鍙蹭細璇濆唴瀹逛腑
+        getChatHistoryListApi()
+          .then(res => {
+            console.log('res', res)
+            if (res.success && res.result && res.result.length > 0) {
+              this.chatHistoryList = res.result.map(item => {
+                return {
+                  ...item,
+                  iconVisible: false,
+                  inputVisible: false,
+                  deletePopVisible: false
+                }
+              })
+              if (!this.activeHistoryIndex) this.switchToCurrentConversation(this.chatHistoryList[0])
+              if (this.isDeletingBatch) this.singleHistoryCheckedChange()
+            } else {
+              this.chatHistoryList = []
+              this.createNewConversation()
+            }
+          })
+          .catch(err => {
+            this.chatHistoryList = []
+            this.createNewConversation()
+            console.log('err', err)
+          })
       },
 
-      /* 鍒涘缓涓�涓柊浼氳瘽 */
+      /* 鐐瑰嚮鏂板浼氳瘽鍚庤Е鍙� */
       createNewConversation() {
         if (this.isAtNewConversation) this.$message.info('褰撳墠宸叉槸鏈�鏂板璇�')
+        if (this.isModelResponding) return // 妯″瀷鍥炵瓟鏈熼棿绂佹鏂板浼氳瘽
         this.isAtNewConversation = true
         this.currentConversation = {
-          id: randomUUID(),
-          title: '',
+          id: '',
           messages: [],
           stream: true,
-          max_tokens: 500,
-          iconVisible: false,
-          inputVisible: false,
-          deletePopVisible: false
+          max_tokens: 500
         }
         // 鏂板缓浼氳瘽鏃跺彇娑堝師鍏堣閫変腑鐨勫巻鍙插璇濓紝鏇存竻鏅板憡璇夌敤鎴风幇鍦ㄧ晫闈㈠浜庢柊寤哄璇濅腑
         if (this.activeHistoryIndex !== null) this.activeHistoryIndex = null
-        this.textareaPlaceholder = '璇峰皾璇曢棶鎴戯細浣犳槸璋侊紵'
+      },
+
+      /* 璋冪敤鎺ュ彛鑾峰彇褰撳墠浼氳瘽璁板綍 */
+      getConversationByApi(id) {
+        // TODO 鏍规嵁鐐瑰嚮鐨勫巻鍙蹭細璇滻D鑾峰彇瀵瑰簲鍘嗗彶浼氳瘽鐨勫璇濊褰曞垪琛�
+        getCurrentConversationApi({ id })
+          .then(res => {
+            console.log('currentRes', res)
+            if (res.success && res.result) {
+              this.currentConversation.messages = res.result.map(item => {
+                return {
+                  id: item.id,
+                  role: item.aiType === 2 ? 'user' : 'assistant',
+                  content: item.aiType === 2 ? item.problem : item.answer
+                }
+              })
+              this.scrollToConversationContainerBottom()
+              this.currentConversation.id = res.result[0].parentId
+              if (this.isModelResponding) this.isModelResponding = false
+              if (res.result[res.result.length - 1].aiType === 2) {
+                console.log('瑙﹀彂鍚戞ā鍨嬫彁闂�', res.result)
+                this.askToLanguageModel()
+              }
+            }
+          })
+      },
+
+      addNewConversationByApi(params) {
+        this.inputQuestion = ''
+        // TODO 璋冪敤鍚庣鎺ュ彛淇濆瓨褰撳墠闂涓斿垱寤轰竴鏉″巻鍙蹭細璇濊褰曪紝鐒跺悗鍐嶉噸鏂拌皟鐢ㄨ幏鍙栧巻鍙茶褰曞垪琛ㄦ帴鍙e埛鏂板垪琛�
+        addNewConversationApi(params)
+          .then(res => {
+            if (res.success) {
+              switch (+params.aiType) {
+                case 1:
+                  this.getChatHistoryListByApi()
+                  this.$message.success('浼氳瘽鍒楄〃璁板綍' + res.message)
+                  break
+                case 2:
+                  this.getConversationByApi(this.activeHistoryIndex)
+                  this.$message.success('鏂板浼氳瘽鍐呭闂璁板綍' + res.message)
+                  break
+                case 3:
+                  this.getConversationByApi(this.activeHistoryIndex)
+                  // this.currentConversation.messages[this.currentConversation.messages.length - 1].content += '\n' + '瀵硅瘽缁撴潫'
+                  this.$message.success('鏂板浼氳瘽鍐呭绛旀璁板綍' + res.message)
+                  break
+              }
+            } else {
+              this.$message.error(res.message)
+            }
+          })
+      },
+
+      /* 鍚戞ā鍨嬫彁闂� */
+      sendQuestion(event) {
+        //鐩戞祴鏄惁鎸変笅shift閿�
+        if (!event.shiftKey) {
+          event.preventDefault()
+          if (this.isModelResponding) {
+            this.$message.error('璇风瓑寰呮満鍣ㄤ汉鍥炲鍚庡啀鍙戦�佸摝~')
+            return
+          }
+          if (!this.inputQuestion) {
+            this.$message.error('浣犳病鏈夎緭鍏ュ唴瀹瑰摝')
+            return
+          }
+
+          const params = {
+            problem: this.inputQuestion,
+            aiType: ''
+          }
+          if (this.isAtNewConversation) {
+            params.aiType = 1
+            params.parentId = ''
+          } else {
+            params.aiType = 2
+            params.parentId = this.activeHistoryIndex
+          }
+          this.addNewConversationByApi(params)
+        }
+      },
+
+      askToLanguageModel() {
+        const messages = JSON.parse(JSON.stringify(this.currentConversation))
+        const answer = {
+          id: '',
+          role: 'assistant',
+          content: ''
+        }
+        this.currentConversation.messages.push(answer)
+        let lastElement
+        this.$nextTick(() => {
+          const elementArr = document.querySelectorAll('.single-conversation')
+          lastElement = elementArr[elementArr.length - 1]
+          console.log('elementArr', elementArr)
+        })
+        console.log('beforeAnswerConversation', messages)
+        console.log('this.currentConversation', this.currentConversation)
+        this.isModelResponding = true
+        // 鍙戦�丳OST璇锋眰鍒版ā鍨嬶紝鑾峰彇鍝嶅簲娴�
+        askToLanguageModelApi(messages)
+          .then(async (response) => {
+            if (!response.body) return
+
+            const reader = response.body.pipeThrough(new TextDecoderStream()).getReader()
+            // const decoder = new TextDecoder()
+            // console.log(reader)
+            let discontinuousJsonArray = []
+            let isContinuous = null
+
+            while (true) {
+              const { value, done } = await reader.read()
+              if (done) {
+                const params = {
+                  parentId: this.activeHistoryIndex,
+                  answer: this.currentConversation.messages.find(item => !item.id && item.role === 'assistant').content,
+                  aiType: 3
+                }
+                this.addNewConversationByApi(params)
+                break
+              }
+
+              this.scrollToConversationContainerBottom()
+              const objectArray = parsePack(value)
+              // console.log('objectArray', objectArray)
+              if (Array.isArray(objectArray) && objectArray.length > 0) {
+                if (discontinuousJsonArray.length === 2) discontinuousJsonArray = []
+                objectArray.forEach(json => {
+                  if (!json.choices || json.choices.length === 0) {
+                    return
+                  }
+                  const text = json.choices[0].delta.content
+                  this.currentConversation.messages.find(item => !item.id && item.role === 'assistant').content += text
+                })
+                if (isContinuous) {
+                  discontinuousJsonArray = []
+                  isContinuous = null
+                }
+              }
+            }
+
+            // 閫掑綊鎵惧埌DOM涓嬫渶鍚庝竴涓厓绱犺妭鐐�
+            function parsePack(str) {
+              const pattern = /data:\s*(?!\[DONE\])(\{.*?\})\s*\n/g
+              const result = []
+              let match
+              while ((match = pattern.exec(str)) !== null) {
+                const jsonStr = match[1]
+                console.log('jsonStr', jsonStr)
+                try {
+                  const object = JSON.parse(jsonStr)
+                  if (object) result.push(object)
+                } catch (err) {
+                  console.log('err', err)
+                }
+              }
+
+              // 姝ゅ垽鏂鐞嗚繑鍥炵殑涓嶅畬鏁寸殑鏁扮粍
+              if (match = pattern.exec(str) === null) {
+                isContinuous = false
+                // console.log('str', str)
+                // 姝ゅ涓哄睆钄借繑鍥炲甫鏈塸ing瀛楃涓�
+                if (!str.includes('ping')) {
+                  discontinuousJsonArray.push(str)
+                  // 鍒ゆ柇鏉′欢涓�2鏄敱浜庝笉瀹屾暣鏁扮粍浠呯粡杩�2娆¤繑鍥炲�煎氨鍙互鎷兼帴瀹屾暣锛屼絾杩樻槸涓嶅簲璇ョ敤鏁板瓧浣滀负鍒ゆ柇鏉′欢锛屼互闃蹭笉姝�2娆�
+                  if (discontinuousJsonArray.length === 2) {
+                    // console.log('discontinuousJsonArray', discontinuousJsonArray[0], '---', discontinuousJsonArray[1])
+                    const discontinuousMatch = pattern.exec(discontinuousJsonArray[0] + discontinuousJsonArray[1])
+                    discontinuousJsonArray = [JSON.parse(discontinuousMatch[1])]
+                    isContinuous = true
+                    return discontinuousJsonArray
+                  }
+                }
+              }
+              return result
+            }
+          })
+          .catch(error => {
+            console.error('璇锋眰澶辫触:', error)
+          })
+      },
+
+      /* 鍒囨崲鑷冲綋鍓嶇偣鍑讳細璇� */
+      switchToCurrentConversation(record, event = {}) {
+        if (record.id === this.activeHistoryIndex) return // 閬垮厤閲嶅鐐瑰嚮
+        if (event.target && event.target.type === 'checkbox') return //鐐瑰嚮澶氶�夋寜閽伩鍏嶄紶閫掔粰姝や簨浠�
+        if (record.inputVisible) return // 褰撴潯浼氳瘽姝e湪琚慨鏀规椂鍐嶆鐐瑰嚮鏈潯浼氳瘽鏃犲弽棣�
+        // 鍏抽棴鐐瑰嚮缂栬緫鎸夐挳鍚庣殑杈撳叆妗�
+        if (this.editingHistoryIndex !== null && this.editingHistoryIndex !== record.id) this.cancelEditConversationTitle(this.chatHistoryList.find(item => item.id === this.editingHistoryIndex))
+        // 鍏抽棴鎵�鏈夌‘璁ゅ垹闄ゅ脊绐�
+        if (this.deletingHistoryIndex !== null) this.cancelDeleteConversation(this.chatHistoryList.find(item => item.id === this.deletingHistoryIndex))
+        if (this.isAtNewConversation) this.isAtNewConversation = false // 濡傛灉鍦ㄥ垱寤烘柊瀵硅瘽鐣岄潰鍒欏皢鏂板璇濈晫闈㈠叧闂�
+        if (this.isModelResponding) return // 妯″瀷鍥炵瓟鏈熼棿绂佹鍒囨崲浼氳瘽
+
+        this.activeHistoryIndex = record.id
+        this.getConversationByApi(record.id)
       },
 
       /* 鐐瑰嚮鍏ㄩ�夋寜閽悗鏀瑰彉鍕鹃�夊悗瑙﹀彂 */
@@ -263,7 +476,7 @@
         } else {
           this.checkedConversationIdList = []
         }
-        console.log('瑙﹀彂鍏ㄩ��', event.target.checked)
+        console.log('瑙﹀彂鍏ㄩ��', this.checkedConversationIdList)
       },
 
       /* 鐐瑰嚮鍘嗗彶璁板綍涓閫夋鏀瑰彉鍕鹃�夊悗瑙﹀彂 */
@@ -298,6 +511,7 @@
       /* 鐐瑰嚮绾㈣壊鍥炬爣鎵归噺鍒犻櫎鎸夐挳鍚庤Е鍙� */
       deleteBatchConversation() {
         if (!this.checkedConversationIdList.length) return
+        if (this.isModelResponding) return // 妯″瀷鍥炵瓟鏈熼棿绂佹鍒犻櫎浼氳瘽
         this.deleteBatchPopVisible = !this.deleteBatchPopVisible
       },
 
@@ -326,23 +540,6 @@
         this.checkedConversationIdList = []
       },
 
-      /* 鍒囨崲鑷冲綋鍓嶇偣鍑讳細璇� */
-      switchToCurrentConversation(record, event = {}) {
-        if (event.target && event.target.type === 'checkbox') return //鐐瑰嚮澶氶�夋寜閽伩鍏嶄紶閫掔粰姝や簨浠�
-        if (record.inputVisible) return // 褰撴潯浼氳瘽姝e湪琚慨鏀规椂鍐嶆鐐瑰嚮鏈潯浼氳瘽鏃犲弽棣�
-        // 鍏抽棴鐐瑰嚮缂栬緫鎸夐挳鍚庣殑杈撳叆妗�
-        if (this.editingHistoryIndex !== null && this.editingHistoryIndex !== record.id) this.cancelEditConversationTitle(this.chatHistoryList.find(item => item.id === this.editingHistoryIndex))
-        // 鍏抽棴鎵�鏈夌‘璁ゅ垹闄ゅ脊绐�
-        if (this.deletingHistoryIndex !== null) this.cancelDeleteConversation(this.chatHistoryList.find(item => item.id === this.deletingHistoryIndex))
-
-        this.activeHistoryIndex = record.id
-        this.currentConversation = this.chatHistoryList.find(item => item.id === record.id)
-        this.isAtNewConversation = false
-
-        // 鍒囨崲瀵硅瘽鏃舵洿鏀规彁闂緭鍏ユ鎻愮ず鏂囧瓧
-        if (record.messages.length > 0) this.textareaPlaceholder = 'Enter鍙戦�侊紝Shift+Enter鎹㈣'
-      },
-
       /* 鐐瑰嚮缂栬緫浼氳瘽鏍囬鎸夐挳鏃惰Е鍙� */
       editConversationTitle(record) {
         // 浠呭紑鍚渶鍚庝竴娆$偣鍑荤紪杈戞寜閽悗鐨勮緭鍏ユ
@@ -352,7 +549,7 @@
 
         this.editingHistoryIndex = record.id
         record.inputVisible = true
-        this.editedConversationTitle = record.title
+        this.editedConversationTitle = record.problem
         this.$nextTick(() => document.getElementById('edit-input').focus())
       },
 
@@ -365,42 +562,49 @@
         }
         // 浠呭彲浣跨敤鏈�鍚庝竴娆$偣鍑诲垹闄ゆ寜閽殑鍔熻兘
         if (this.deletingHistoryIndex !== null && this.deletingHistoryIndex !== record.id) this.cancelDeleteConversation(this.chatHistoryList.find(item => item.id === this.deletingHistoryIndex))
-
+        if (this.isModelResponding) return // 妯″瀷鍥炵瓟鏈熼棿绂佹鍒犻櫎浼氳瘽
         record.deletePopVisible = !record.deletePopVisible
         this.deletingHistoryIndex = record.id
       },
 
       /* 纭缂栬緫浼氳瘽鏍囬 */
       confirmEditConversationTitle(record, event) {
+        // TODO 璋冪敤缂栬緫浼氳瘽鎺ュ彛骞堕噸鏂拌幏鍙栧巻鍙蹭細璇濇暟鎹�
         record.title = this.editedConversationTitle
         this.cancelEditConversationTitle(record, event)
       },
 
       /* 纭鍒犻櫎浼氳瘽鏃惰Е鍙� */
       confirmDeleteConversation(record, index) {
-        this.chatHistoryList = this.chatHistoryList.filter(item => item.id !== this.deletingHistoryIndex)
-
-        if (this.chatHistoryList.length > 0) {
-          // 鍒ゆ柇褰撳墠浼氳瘽鏄笉鏄鍒犻櫎鐨勪細璇�
-          if (this.activeHistoryIndex === record.id) {
-            if (this.chatHistoryList[index]) {
-              console.log('鍒犻櫎闈炴渶鍚庝竴鏉�')
-              this.currentConversation = this.chatHistoryList[index]
-              this.activeHistoryIndex = this.chatHistoryList[index].id
-            } else {
-              console.log('鍒犻櫎鏈�鍚庝竴鏉�')
-              this.currentConversation = this.chatHistoryList[this.chatHistoryList.length - 1]
-              this.activeHistoryIndex = this.chatHistoryList[this.chatHistoryList.length - 1].id
+        deleteSingleChatHistoryApi({ id: record.id })
+          .then(res => {
+            if (res.success) {
+              if (this.chatHistoryList.length !== 1) {
+                // 鍒ゆ柇褰撳墠浼氳瘽鏄笉鏄鍒犻櫎鐨勪細璇�
+                console.log('record', record)
+                console.log('activeHistoryIndex', this.activeHistoryIndex)
+                if (this.activeHistoryIndex === record.id) {
+                  if (index !== 0) {
+                    console.log('鍒犻櫎闈炵涓�鏉¤褰�')
+                    this.switchToCurrentConversation(this.chatHistoryList[index - 1])
+                  } else {
+                    console.log('鍒犻櫎绗竴鏉¤褰�')
+                    this.switchToCurrentConversation(this.chatHistoryList[index + 1])
+                  }
+                }
+              } else {
+                console.log('鍒犻櫎鏈�鍚庝竴鏉¤褰�')
+                this.activeHistoryIndex = null
+              }
+              record.deletePopVisible = false
+              this.deletingHistoryIndex = null
+              this.getChatHistoryListByApi()
+              this.$message.success(res.message)
             }
-          }
-        } else {
-          console.log('鍒犻櫎鍓嶅彧鏈変竴鏉�')
-          this.activeHistoryIndex = null
-          this.createNewConversation()
-        }
-        record.deletePopVisible = false
-        this.deletingHistoryIndex = null
-        this.$message.success('鍒犻櫎鎴愬姛锛�')
+          })
+          .catch(err => {
+            this.$message.error(err.message)
+          })
       },
 
       /* 鍙栨秷缂栬緫浼氳瘽鏍囬鏃惰Е鍙� */
@@ -414,7 +618,7 @@
       /* 鍙栨秷鍒犻櫎浼氳瘽鏃惰Е鍙� */
       cancelDeleteConversation(record, event) {
         // 澶卞幓鐒︾偣浜嬩欢鏃惰嫢鐐瑰嚮鐨勫厓绱犳槸纭鍒犻櫎鎸夐挳鍒欎笉杩涜澶卞幓鐒︾偣浜嬩欢锛岀洿鎺ヨ繘鍏ョ‘璁ゅ垹闄や簨浠�
-        if (event.relatedTarget && event.relatedTarget.id === 'delete-conversation-button') return
+        if (event && event.relatedTarget && event.relatedTarget.id === 'delete-conversation-button') return
         record.deletePopVisible = false
         this.deletingHistoryIndex = null
       },
@@ -424,55 +628,20 @@
         return getFileAccessHttpUrl(this.avatar())
       },
 
-      /* 鍚戞ā鍨嬫彁闂� */
-      sendQuestion(e) {
-        //鐩戞祴鏄惁鎸変笅shift閿�
-        if (!e.shiftKey) {
-          e.preventDefault()
-          if (this.isResponding) {
-            this.$message.error('璇风瓑寰呮満鍣ㄤ汉鍥炲鍚庡啀鍙戦�佸摝~')
-            return
-          }
-          if (!this.inputQuestion) {
-            this.$message.error('浣犳病鏈夎緭鍏ュ唴瀹瑰摝')
-            return
-          }
-
-          const newQuestion = {
-            role: 'user',
-            content: this.inputQuestion
-          }
-          this.currentConversation.messages.push(newQuestion)
-
-          // 褰撴柊寤哄璇濇椂闇�鍏堟彁闂啀璁插璇濆姞鍏ュ埌鍘嗗彶璁板綍涓�
-          if (this.currentConversation.messages.length === 1) {
-            this.currentConversation.title = newQuestion.content.slice(0, 15)
-            this.chatHistoryList.unshift(this.currentConversation)
-            if (this.isDeletingBatch) this.singleHistoryCheckedChange()
-            this.switchToCurrentConversation(this.currentConversation)
-          }
-
-          this.isResponding = true
-          const response = {
-            role: 'assistant',
-            content: '杩欎釜闂鎴戜篃涓嶅お娓呮'
-          }
-          setTimeout(() => {
-            this.currentConversation.messages.push(response)
-            this.inputQuestion = ''
-            this.isResponding = false
-            this.$nextTick(() => {
-              this.conversationContainer.scrollTo({ top: 9999999999999999999999999999, behavior: 'smooth' })
-            })
-          }, 1000)
-        }
+      scrollToConversationContainerBottom(scrollBehavior = 'auto') {
+        this.$nextTick(() => {
+          this.conversationContainer.scrollTo({
+            top: this.conversationContainer.scrollHeight,
+            behavior: scrollBehavior
+          })
+        })
       }
     }
   }
 </script>
 
 <style scoped lang="less">
-  @main-container-background: rgba(255, 255, 255, .8);
+  @main-container-background: rgba(255, 255, 255, .7);
   @container-border-radius: 12px;
   @container-padding: 10px;
   @single-history-edit-border: 3px solid #ABC0CC;
@@ -564,6 +733,13 @@
                 margin-right: 10px;
               }
             }
+
+            &.disable-expand {
+              cursor: not-allowed;
+              &:hover {
+                box-shadow: none;
+              }
+            }
           }
 
           .delete-batch-container {
@@ -633,7 +809,14 @@
           flex: 1;
           overflow: auto;
 
-          & > div {
+          .ant-empty {
+            height: 100%;
+            display: flex;
+            flex-direction: column;
+            justify-content: center;
+          }
+
+          & > div:not(.ant-empty) {
             border: 3px solid transparent;
             border-radius: 10px;
             padding: 10px 20px;
@@ -714,6 +897,14 @@
                 }
               }
 
+            }
+
+            &.disable-switch {
+              cursor: not-allowed;
+
+              &:not(.single-history-active):hover {
+                background-color: transparent;
+              }
             }
           }
         }
@@ -866,16 +1057,20 @@
 
               &.user-question {
                 align-items: flex-end;
-                .content {
+                .conversation-content {
                   background-color: @user-question-background;
+                  text-align: justify;
+                  text-align-last: left;
                 }
               }
 
               &.assistant-answer {
                 align-items: flex-start;
 
-                .content {
+                .conversation-content {
                   background-color: @assistant-answer-background;
+                  text-align: justify;
+                  text-align-last: left;
                 }
               }
 
@@ -889,7 +1084,7 @@
                 }
               }
 
-              .content {
+              .conversation-content {
                 max-width: 80%;
                 box-shadow: @conversation-content-container-box-shadow;
                 border-radius: @container-border-radius;

--
Gitblit v1.9.3