Files
mars-ui/src/stores/chat.js
2025-03-22 21:12:27 +08:00

270 lines
7.0 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { defineStore } from 'pinia';
import apiService from '../services/api.js';
import agoraService from '../services/agora.js';
export const useChatStore = defineStore('chat', {
state: () => ({
messages: [],
isConnected: false,
isListening: false,
isSpeaking: false,
isProcessing: false,
currentTranscript: '',
error: null,
audioLevel: 0,
inConversation: false, // 是否在对话状态中
}),
getters: {
lastMessage: (state) => state.messages.length > 0 ? state.messages[state.messages.length - 1] : null,
isReady: (state) => state.isConnected && !state.error,
hasMessages: (state) => state.messages.length > 0,
},
actions: {
async initialize() {
try {
agoraService.init();
const response = await apiService.joinProject();
const agent_id = response.agent_id;
const create_ts =response.create_ts;
const status =response.status;
apiService.setAgentId(agent_id);
await agoraService.join(agent_id, create_ts, status)
this.isConnected = true;
this.error = null;
// Add greeting message
const greetingMessage = "你好呀,有什么可以帮您?";
if (greetingMessage) {
this.addMessage({
id: Date.now(),
content: greetingMessage,
sender: 'ai',
timestamp: new Date().toISOString(),
});
}
return true;
} catch (error) {
this.error = error.message || 'Failed to initialize chat';
console.error('Error initializing chat:', error);
return false;
}
},
/**
* 开始对话状态,启动持续监听
*/
startConversation() {
if (!this.isConnected) return false;
this.inConversation = true;
this.isListening = true;
this.currentTranscript = '';
// 设置语音段落回调和可读文本回调
agoraService.startConversation(
this.handleSpeechSegment.bind(this),
this.handleReadableText.bind(this)
);
// 启动音频发布
if (!agoraService.localAudioTrack) {
agoraService.startAudioPublishing();
}
return true;
},
/**
* 处理可读文本
*/
handleReadableText(text) {
if (!text || !text.trim()) return;
const isFromAI = text.includes('\n\n') || text.includes('<think>\n');
const currentTime = new Date();
const sender = isFromAI ? 'ai' : 'user';
// 获取最后一条消息
const lastMessage = this.lastMessage;
// 检查是否需要创建新消息或更新现有消息
if (lastMessage && lastMessage.sender === sender) {
// 计算时间差(毫秒)
const timeDiff = currentTime - new Date(lastMessage.timestamp);
// 如果时间差小于3秒更新最后一条消息
if (timeDiff < 5000) {
// 更新最后一条消息的内容
lastMessage.content = text;
// 更新时间戳
lastMessage.timestamp = currentTime.toISOString();
return;
}
}
// 如果时间差大于3秒或者是不同发送者添加新消息
this.addMessage({
id: Date.now(),
content: text,
sender: sender,
timestamp: currentTime.toISOString(),
});
},
/**
* 结束对话状态,停止持续监听
*/
endConversation() {
this.inConversation = false;
this.isListening = false;
// 移除语音事件监听
// this.removeSpeechEventListeners();
// 结束Agora对话状态
agoraService.endConversation();
return true;
},
/**
* 处理语音更新事件
* @param {CustomEvent} event - 包含语音文本的事件
*/
handleSpeechUpdate(event) {
if (event.detail && event.detail.text) {
this.updateTranscript(event.detail.text);
}
},
/**
* 处理语音段落
* @param {string} text - 语音段落文本
*/
handleSpeechSegment(text) {
console.log("处理语音段落:", text);
if (!text || !text.trim()) return;
// 更新当前转写
this.updateTranscript(text);
// 使用与handleReadableText相同的逻辑处理消息
const currentTime = new Date();
const sender = 'user'; // 语音段落总是来自用户
// 获取最后一条消息
const lastMessage = this.lastMessage;
// 检查是否需要创建新消息或更新现有消息
if (lastMessage && lastMessage.sender === sender) {
// 计算时间差(毫秒)
const timeDiff = currentTime - new Date(lastMessage.timestamp);
// 如果时间差小于3秒更新最后一条消息
if (timeDiff < 3000) {
// 更新最后一条消息的内容
lastMessage.content = text;
// 更新时间戳
lastMessage.timestamp = currentTime.toISOString();
return;
}
}
// 如果时间差大于3秒或者是不同发送者添加新消息
this.addMessage({
id: Date.now(),
content: text,
sender: sender,
timestamp: currentTime.toISOString(),
});
},
/**
* 开始监听(兼容旧接口)
*/
startListening() {
if (this.inConversation) return;
this.startConversation();
},
/**
* 停止监听(兼容旧接口)
*/
stopListening() {
if (!this.inConversation) return;
// 如果有转写内容使用handleSpeechSegment处理消息
if (this.currentTranscript.trim()) {
this.handleSpeechSegment(this.currentTranscript.trim());
}
this.endConversation();
},
/**
* Update the current transcript
* @param {string} transcript - The current transcript
*/
updateTranscript(transcript) {
this.currentTranscript = transcript;
},
/**
* Add a message to the list
*/
addMessage(message) {
this.messages.push(message);
},
/**
* Clear all messages
*/
clearMessages() {
this.messages = [];
},
/**
* Update the audio level
*/
updateAudioLevel(level) {
this.audioLevel = level;
},
/**
* End the chat session
*/
async endSession() {
try {
// 如果在对话状态中,先结束对话
if (this.inConversation) {
this.endConversation();
}
// Leave the Agora channel
await agoraService.leave();
// End the API session
await apiService.endSession();
this.isConnected = false;
this.isListening = false;
this.isProcessing = false;
this.currentTranscript = '';
this.inConversation = false;
this.error = null;
return true;
} catch (error) {
this.error = error.message || 'Failed to end session';
console.error('Error ending session:', error);
return false;
}
}
}
});