聊天室和会议初始化
This commit is contained in:
161
urbanLifelineWeb/example/jitsi-meet/useJitsiTranscription.js
Normal file
161
urbanLifelineWeb/example/jitsi-meet/useJitsiTranscription.js
Normal file
@@ -0,0 +1,161 @@
|
||||
// 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<string | null>(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
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user