feat(AI): 优化消息组件和语音输入功能

- 修改消息组件,仅在非思考模式下显示消息文本
- 增加语音模式下的文本输入框- 优化语音录音和识别逻辑
- 更新思考模式的处理流程
- 调整界面样式,增加禁用状态的录音按钮
This commit is contained in:
陈昱达
2025-06-10 13:30:05 +08:00
parent fd43fae0f7
commit 84ea21ea1d
2 changed files with 35 additions and 7 deletions

View File

@@ -17,7 +17,7 @@
<!--开启思考--> <!--开启思考-->
<p v-html="md.render(message.think)" v-if="message.think && message.showThink" class="thinkText" /> <p v-html="md.render(message.think)" v-if="message.think && message.showThink" class="thinkText" />
</span> </span>
<div> <div v-if='!message.isThink '>
<p v-html="md.render(message.text)" v-if="message.text "></p> <p v-html="md.render(message.text)" v-if="message.text "></p>
<span class="speakLoadingToast pv10" v-else-if='!message.text && !thinkOk'> <span class="speakLoadingToast pv10" v-else-if='!message.text && !thinkOk'>
<van-loading type="spinner" color="#2e5ca9" size="20px" v-if="!message.text" /> <van-loading type="spinner" color="#2e5ca9" size="20px" v-if="!message.text" />

View File

@@ -12,6 +12,11 @@
<van-icon name="upgrade" size="2em" @click="scrollToTop" /> <van-icon name="upgrade" size="2em" @click="scrollToTop" />
</div> </div>
</main> </main>
<div v-if='isVoiceMode && newMessage' class='isVoiceModeText'>
<textarea class="textarea" placeholder="请输入内容" v-model='newMessage' ></textarea>
</div>
<section class="section"> <section class="section">
<button @click="searchInternet" :class="{ active: isSearching }"> <button @click="searchInternet" :class="{ active: isSearching }">
<svg-icon icon-class="earth" class-name="chat-icon"></svg-icon> <svg-icon icon-class="earth" class-name="chat-icon"></svg-icon>
@@ -37,13 +42,14 @@
@keyup.enter="sendMessage" @keyup.enter="sendMessage"
/> />
<div v-else class="voice-hint-container" <div v-else class="voice-hint-container"
:class="{disabled:messageStatus === 'send' }"
@mousedown="startRecording" @mousedown="startRecording"
@selectstart="() => false" @selectstart="() => false"
@mouseup="stopRecording" @mouseup="stopRecording"
@mouseleave="stopRecording" @mouseleave="stopRecording"
@touchend="stopRecording" @touchend="stopRecording"
@touchstart="startRecording"> @touchstart="startRecording">
<div class="waveform" :class="{ active: isRecording }" > <div class="waveform" :class="{ active: isRecording}" >
<span class="bar"></span> <span class="bar"></span>
<span class="bar"></span> <span class="bar"></span>
<span class="bar"></span> <span class="bar"></span>
@@ -186,6 +192,7 @@ export default {
this.scrollPosition = messageArea.scrollTop this.scrollPosition = messageArea.scrollTop
}, },
async startRecording() { async startRecording() {
if(this.messageStatus === 'send') return
if (this.isRecognizing) return if (this.isRecognizing) return
try { try {
const stream = await navigator.mediaDevices.getUserMedia({ audio: true }) const stream = await navigator.mediaDevices.getUserMedia({ audio: true })
@@ -221,7 +228,7 @@ export default {
if (text) { if (text) {
this.newMessage = text this.newMessage = text
this.messageStatus = 'stop' this.messageStatus = 'stop'
this.sendMessage() // this.sendMessage()
} }
} catch (error) { } catch (error) {
console.error('语音识别失败:', error) console.error('语音识别失败:', error)
@@ -322,8 +329,12 @@ export default {
} }
}, },
updateConversationState(data) { updateConversationState(data) {
this.conversationId = data.conversation_id || this.conversationId this.conversationId = data.conversation_id || conversationId.value
if (data.answer && data.answer.indexOf('withTo') !== -1) { if (data.answer && data.answer.indexOf('<think>') !== -1) {
this.isThink = true
}
if (data.answer && data.answer.indexOf('</think>') !== -1) {
this.isThink = false this.isThink = false
} }
}, },
@@ -368,6 +379,7 @@ $primary-trans-color: rgba(135, 162, 208, 0.5);
background: #f7f8fa; background: #f7f8fa;
position: relative; position: relative;
.button-container { .button-container {
position: fixed; position: fixed;
bottom: 120px; bottom: 120px;
@@ -384,7 +396,19 @@ $primary-trans-color: rgba(135, 162, 208, 0.5);
} }
} }
} }
.isVoiceModeText{
display: flex;
textarea{
flex:1;
max-height: 80px;
resize: none;
background: #fff;
outline: none;
overflow-y: auto;
padding: 10px;
border: none;
}
}
.section { .section {
font-size: 13px; font-size: 13px;
display: flex; display: flex;
@@ -447,6 +471,7 @@ $primary-trans-color: rgba(135, 162, 208, 0.5);
background-color: #eaeaea; background-color: #eaeaea;
} }
.waveform { .waveform {
display: flex; display: flex;
align-items: flex-end; align-items: flex-end;
@@ -454,7 +479,10 @@ $primary-trans-color: rgba(135, 162, 208, 0.5);
//height: 30px; //height: 30px;
//width: 60px; //width: 60px;
gap: 2px; gap: 2px;
&.disabled{
cursor: not-allowed;
background: red;
}
&.active .bar { &.active .bar {
animation: wave-animation 1s infinite ease-in-out; animation: wave-animation 1s infinite ease-in-out;
} }