diff --git a/src/views/AI/components/chat.vue b/src/views/AI/components/chat.vue index e9583ff..fed0555 100644 --- a/src/views/AI/components/chat.vue +++ b/src/views/AI/components/chat.vue @@ -90,33 +90,32 @@ export default { type: Boolean, default: false, }, - // isThink: { - // type: Boolean, - // default: false, - // }, }, data() { return { isThink: false, newMessage: '', - // 录音相关状态 isRecording: false, mediaRecorder: null, audioChunks: [], isRecognizing: false, - // 语音模式开关 isVoiceMode: false, answerMap: '', currentMessage: null, + + // 打字机相关 + typingText: '', + typingQueue: [], + isTyping: false, + typingSpeed: 50, + typingTimeout: null, } }, methods: { deepInternet() { - // this.isDeep = !this.isDeep this.$emit('update:isDeep', !this.isDeep) }, searchInternet() { - // this.isSearching = !this.isSearching this.$emit('update:isSearching', !this.isSearching) }, startNewConversation() { @@ -124,7 +123,6 @@ export default { this.$emit('update:conversationId', '') this.$emit('update:productName', '') }, - async startRecording() { if (this.messageStatus === 'send') return if (this.isRecognizing) return @@ -173,9 +171,7 @@ export default { const text = await this.callVoiceRecognitionAPI(blob) if (text) { this.newMessage = text - // this.messageStatus = 'stop' this.$emit('update:messageStatus', 'stop') - // this.sendMessage() } } catch (error) { console.error('语音识别失败:', error) @@ -223,11 +219,9 @@ export default { conversationId: this.conversationId, productName: this.productName, } - if (this.$route.query.compareId) { params.compareResult = JSON.parse(sessionStorage.getItem('results')) } - fetch(chat(), { method: 'POST', headers: { 'Content-Type': 'application/json' }, @@ -272,7 +266,6 @@ export default { const cleanLine = line.replace(/^data:\s*/, '') if (!cleanLine) return null const data = JSON.parse(cleanLine) - // console.log(data) if (data.answer) { this.answerMap += data.answer } @@ -284,52 +277,62 @@ export default { } }, updateConversationState(data) { - // this.conversationId = - this.$emit('update:conversationId', data.conversation_id || conversationId.value) + this.$emit('update:conversationId', data.conversation_id || '') if (data.answer && data.answer.indexOf('') !== -1) { this.isThink = true this.$emit('getIsThink', true) } - if (data.answer && data.answer.indexOf('') !== -1) { this.isThink = false this.$emit('getIsThink', false) - // this.$emit('update:isThink', false) } }, updateMessageContent({ answer, event }) { if (event === 'message_end') { - // this.messageStatus = 'stop' this.$emit('update:messageStatus', 'stop') } - - // console.log(answer) - // console.log(this.currentMessage) if (!this.currentMessage || !answer) return const mode = this.isThink ? 'think' : 'text' - this.currentMessage[mode] += answer + const chars = answer.split('') + this.typingQueue.push(...chars) + if (!this.isTyping) { + this.startTypingAnimation(mode) + } + }, + startTypingAnimation(mode) { + this.isTyping = true + + const typeNextChar = () => { + if (this.typingQueue.length === 0) { + this.isTyping = false + return + } + + const char = this.typingQueue.shift() + this.currentMessage[mode] += char + + this.typingTimeout = setTimeout(typeNextChar, this.getTypingDelay(char)) + } + + typeNextChar() + }, + getTypingDelay(char) { + if (['。', '!', '?', ',', '\n'].includes(char)) { + return this.typingSpeed * 3 + } + return this.typingSpeed }, sendMessage() { if (this.messageStatus === 'send') return if (this.newMessage.trim() === '') return - // 防止xss this.newMessage = this.newMessage.replace(/<[^>]+>/g, '') this.messages.push({ type: 'user', text: this.newMessage }) this.$emit('update:messageStatus', 'send') - // this.messageStatus = 'send' if (this.newMessage.includes('工具箱')) { this.hasTreasureBox() return } - - // if (this.newMessage.includes('产品对比')) { - // // this.hasTreasureBox() - // return - // } - - // this.autoScrollEnabled = true this.$emit('update:autoScrollEnabled', true) - this.axiosGetAiChat() }, },