// src/composables/useJitsiTranscription.ts import { ref } from 'vue'; import { XunfeiTranscription } from '@/utils/xunfei'; export function useJitsiTranscription(meetingId: string) { const isRecording = ref(false); const currentSpeaker = ref(null); let mediaRecorder: MediaRecorder | null = null; let xunfeiWs: XunfeiTranscription | null = null; // 初始化Jitsi API const initJitsiApi = (domain: string, roomName: string) => { const api = new JitsiMeetExternalAPI(domain, { roomName: roomName, width: '100%', height: '100%', parentNode: document.querySelector('#jitsi-container'), userInfo: { displayName: '张三', email: 'zhangsan@example.com' } }); // 监听主讲人变化(核心:识别说话人) api.addEventListener('dominantSpeakerChanged', (event) => { const speakerId = event.id; console.log('主讲人切换:', speakerId); // 获取说话人信息 api.getParticipantsInfo().then(participants => { const speaker = participants.find(p => p.participantId === speakerId); if (speaker) { currentSpeaker.value = speaker.displayName; console.log('当前说话人:', speaker.displayName); // 开始录制该说话人的音频 startRecording(speakerId, speaker.displayName); } }); }); // 监听音频轨道添加 api.addEventListener('trackAdded', (event) => { if (event.track.getType() === 'audio') { console.log('音频轨道添加:', event.track.getParticipantId()); } }); return api; }; // 开始录制音频 const startRecording = async (speakerId: string, speakerName: string) => { try { // 获取会议音频流 const stream = await navigator.mediaDevices.getUserMedia({ audio: true }); mediaRecorder = new MediaRecorder(stream, { mimeType: 'audio/webm' }); let audioChunks: Blob[] = []; mediaRecorder.ondataavailable = (event) => { if (event.data.size > 0) { audioChunks.push(event.data); } }; // 每3秒发送一次音频数据进行转写 mediaRecorder.onstop = async () => { const audioBlob = new Blob(audioChunks, { type: 'audio/webm' }); // 发送到讯飞/阿里云进行转写 const transcription = await transcribeAudio(audioBlob, speakerId, speakerName); // 保存转录结果 await saveTranscription(meetingId, { speakerId: speakerId, speakerName: speakerName, content: transcription.text, confidence: transcription.confidence, startTime: new Date().toISOString(), endTime: new Date().toISOString() }); audioChunks = []; }; mediaRecorder.start(); isRecording.value = true; // 每3秒停止并重新开始,实现分段录制 setInterval(() => { if (mediaRecorder && mediaRecorder.state === 'recording') { mediaRecorder.stop(); setTimeout(() => mediaRecorder?.start(), 100); } }, 3000); } catch (error) { console.error('录制失败:', error); } }; // 使用讯飞实时转写 const transcribeAudio = async (audioBlob: Blob, speakerId: string, speakerName: string) => { // 连接讯飞WebSocket if (!xunfeiWs) { xunfeiWs = new XunfeiTranscription({ appId: 'YOUR_APP_ID', apiKey: 'YOUR_API_KEY', onResult: (result) => { console.log('实时转写结果:', result); // 实时保存到数据库 saveTranscription(meetingId, { speakerId: speakerId, speakerName: speakerName, content: result.text, confidence: result.confidence, startTime: result.startTime, endTime: result.endTime, isFinal: result.isFinal }); } }); } // 发送音频数据 const arrayBuffer = await audioBlob.arrayBuffer(); xunfeiWs.send(arrayBuffer); return { text: '转写结果(异步返回)', confidence: 0.95 }; }; // 保存转录结果到后端 const saveTranscription = async (meetingId: string, data: any) => { try { await fetch('/api/workcase/meeting/transcription/save', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ meetingId: meetingId, ...data }) }); } catch (error) { console.error('保存转录失败:', error); } }; return { initJitsiApi, isRecording, currentSpeaker }; }