|
|
@@ -1,244 +0,0 @@
|
|
|
-<template>
|
|
|
- <div class="chat-dialog">
|
|
|
- <div class="chat-header">
|
|
|
- <el-button text @click="$emit('close')">
|
|
|
- <el-icon><ArrowLeft /></el-icon>
|
|
|
- 返回
|
|
|
- </el-button>
|
|
|
- </div>
|
|
|
-
|
|
|
- <div class="chat-content">
|
|
|
- <div v-for="(message, index) in messages" :key="index" :class="['message', message.type === 'ai' ? 'ai-message' : 'user-message']">
|
|
|
- <div class="message-text">
|
|
|
- {{ message.text }}
|
|
|
- <div v-if="message.hasQuickQuestions" class="quick-questions">
|
|
|
- <div class="question-item">😴 我最近总是失眠,有什么办法可以解决吗?</div>
|
|
|
- <div class="question-item">🛏️ 怎么改善晚上睡不着、早上睡不醒的问题?</div>
|
|
|
- <div class="question-item">🚀 超过半小时才睡着是正常的吗?</div>
|
|
|
- </div>
|
|
|
- <el-icon v-if="message.type === 'user' && isAiSpeaking" class="pause-icon"><VideoPlay /></el-icon>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
-
|
|
|
- <div class="chat-footer">
|
|
|
- <el-button circle class="emoji-btn">
|
|
|
- <el-icon><ChatDotRound /></el-icon>
|
|
|
- </el-button>
|
|
|
-
|
|
|
- <el-button circle class="mic-btn" :class="{ recording: isRecording }" @click="handleMicClick">
|
|
|
- <el-icon><Microphone /></el-icon>
|
|
|
- </el-button>
|
|
|
-
|
|
|
- <div class="input-placeholder">
|
|
|
- <span v-if="isRecording" class="recording-text">{{ currentTranscription || '正在录音...' }}</span>
|
|
|
- </div>
|
|
|
-
|
|
|
- <el-button circle class="hangup-btn" @click="handleHangup">
|
|
|
- <el-icon><PhoneFilled /></el-icon>
|
|
|
- </el-button>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
-</template>
|
|
|
-
|
|
|
-<script setup>
|
|
|
-import { ref, watch } from 'vue'
|
|
|
-import { ArrowLeft, ChatDotRound, Microphone, PhoneFilled, VideoPlay } from '@element-plus/icons-vue'
|
|
|
-import { useStreamChat } from './composables/useStreamChat'
|
|
|
-import { useVoiceRecognition } from './composables/useVoiceRecognition'
|
|
|
-
|
|
|
-const emit = defineEmits(['close'])
|
|
|
-
|
|
|
-const { displayText, conversationId, sendMessage, stopAudio } = useStreamChat()
|
|
|
-const { isRecording, currentTranscription, startRecording, stopRecording } = useVoiceRecognition()
|
|
|
-
|
|
|
-const messages = ref([
|
|
|
- {
|
|
|
- type: 'ai',
|
|
|
- text: '你好,我是你的腾讯云音视频 AI 助手!你可以问我:',
|
|
|
- hasQuickQuestions: true
|
|
|
- }
|
|
|
-])
|
|
|
-
|
|
|
-const isAiSpeaking = ref(false)
|
|
|
-
|
|
|
-// 监听displayText变化,实时更新消息
|
|
|
-watch(displayText, (newText) => {
|
|
|
- if (newText) {
|
|
|
- const lastMessage = messages.value[messages.value.length - 1]
|
|
|
- if (lastMessage && lastMessage.type === 'ai' && !lastMessage.hasQuickQuestions) {
|
|
|
- lastMessage.text = newText
|
|
|
- } else {
|
|
|
- messages.value.push({
|
|
|
- type: 'ai',
|
|
|
- text: newText
|
|
|
- })
|
|
|
- }
|
|
|
- isAiSpeaking.value = true
|
|
|
- }
|
|
|
-})
|
|
|
-
|
|
|
-// 处理语音识别
|
|
|
-const handleMicClick = async () => {
|
|
|
- if (isRecording.value) {
|
|
|
- stopRecording()
|
|
|
- if (currentTranscription.value) {
|
|
|
- await handleSendMessage(currentTranscription.value)
|
|
|
- }
|
|
|
- } else {
|
|
|
- await startRecording()
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-// 发送消息
|
|
|
-const handleSendMessage = async (text) => {
|
|
|
- messages.value.push({
|
|
|
- type: 'user',
|
|
|
- text
|
|
|
- })
|
|
|
-
|
|
|
- try {
|
|
|
- await sendMessage(text, null, '1', [], false)
|
|
|
- isAiSpeaking.value = false
|
|
|
- } catch (error) {
|
|
|
- console.error('发送消息失败:', error)
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-// 挂断电话
|
|
|
-const handleHangup = () => {
|
|
|
- stopAudio()
|
|
|
- emit('close')
|
|
|
-}
|
|
|
-</script>
|
|
|
-
|
|
|
-<style scoped>
|
|
|
-.chat-dialog {
|
|
|
- position: fixed;
|
|
|
- top: 0;
|
|
|
- left: 0;
|
|
|
- right: 0;
|
|
|
- bottom: 0;
|
|
|
- background: #f5f5f5;
|
|
|
- display: flex;
|
|
|
- flex-direction: column;
|
|
|
- z-index: 1000;
|
|
|
-}
|
|
|
-
|
|
|
-.chat-header {
|
|
|
- padding: 16px;
|
|
|
- background: white;
|
|
|
- border-bottom: 1px solid #e5e7eb;
|
|
|
-}
|
|
|
-
|
|
|
-.chat-content {
|
|
|
- flex: 1;
|
|
|
- overflow-y: auto;
|
|
|
- padding: 20px;
|
|
|
-}
|
|
|
-
|
|
|
-.message {
|
|
|
- margin-bottom: 16px;
|
|
|
-}
|
|
|
-
|
|
|
-.ai-message .message-text {
|
|
|
- background: white;
|
|
|
- padding: 16px;
|
|
|
- border-radius: 12px;
|
|
|
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
|
|
|
- max-width: 80%;
|
|
|
-}
|
|
|
-
|
|
|
-.user-message {
|
|
|
- display: flex;
|
|
|
- justify-content: flex-end;
|
|
|
-}
|
|
|
-
|
|
|
-.user-message .message-text {
|
|
|
- background: white;
|
|
|
- padding: 16px;
|
|
|
- border-radius: 12px;
|
|
|
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
|
|
|
- max-width: 80%;
|
|
|
- position: relative;
|
|
|
-}
|
|
|
-
|
|
|
-.quick-questions {
|
|
|
- margin-top: 12px;
|
|
|
-}
|
|
|
-
|
|
|
-.question-item {
|
|
|
- padding: 8px 0;
|
|
|
- font-size: 14px;
|
|
|
- color: #333;
|
|
|
-}
|
|
|
-
|
|
|
-.pause-icon {
|
|
|
- position: absolute;
|
|
|
- right: 12px;
|
|
|
- bottom: 12px;
|
|
|
- color: #3b82f6;
|
|
|
-}
|
|
|
-
|
|
|
-.chat-footer {
|
|
|
- padding: 16px;
|
|
|
- background: white;
|
|
|
- border-top: 1px solid #e5e7eb;
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- gap: 12px;
|
|
|
-}
|
|
|
-
|
|
|
-.emoji-btn,
|
|
|
-.mic-btn {
|
|
|
- width: 40px;
|
|
|
- height: 40px;
|
|
|
- border: none;
|
|
|
- background: transparent;
|
|
|
-}
|
|
|
-
|
|
|
-.input-placeholder {
|
|
|
- flex: 1;
|
|
|
- height: 40px;
|
|
|
- border-bottom: 2px dotted #d1d5db;
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- padding: 0 12px;
|
|
|
-}
|
|
|
-
|
|
|
-.recording-text {
|
|
|
- color: #ef4444;
|
|
|
- font-size: 14px;
|
|
|
-}
|
|
|
-
|
|
|
-.mic-btn.recording {
|
|
|
- background: #ef4444;
|
|
|
- color: white;
|
|
|
- animation: pulse 1.5s infinite;
|
|
|
-}
|
|
|
-
|
|
|
-@keyframes pulse {
|
|
|
- 0%, 100% {
|
|
|
- opacity: 1;
|
|
|
- }
|
|
|
- 50% {
|
|
|
- opacity: 0.5;
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-.hangup-btn {
|
|
|
- width: 56px;
|
|
|
- height: 56px;
|
|
|
- background: #ef4444;
|
|
|
- border: none;
|
|
|
- color: white;
|
|
|
-}
|
|
|
-
|
|
|
-.hangup-btn:hover {
|
|
|
- background: #dc2626;
|
|
|
-}
|
|
|
-
|
|
|
-:deep(.el-button) {
|
|
|
- font-size: 16px;
|
|
|
-}
|
|
|
-</style>
|