99 lines
3.2 KiB
JavaScript
99 lines
3.2 KiB
JavaScript
const recordButton = document.getElementById('recordButton');
|
|
const sendTextButton = document.getElementById('sendTextButton');
|
|
const textInput = document.getElementById('textInput');
|
|
const statusEl = document.getElementById('status');
|
|
const transcriptEl = document.getElementById('transcript');
|
|
const replyEl = document.getElementById('reply');
|
|
const audioReply = document.getElementById('audioReply');
|
|
|
|
let recorder;
|
|
let chunks = [];
|
|
|
|
function setStatus(text) {
|
|
statusEl.textContent = text;
|
|
}
|
|
|
|
async function askFriday(text) {
|
|
setStatus('Asking FRIDAY...');
|
|
const response = await fetch('/api/ask', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ text, speaker_id: null, confidence: 0 })
|
|
});
|
|
if (!response.ok) throw new Error(await response.text());
|
|
const data = await response.json();
|
|
replyEl.textContent = data.reply;
|
|
setStatus(`Authorization: ${data.authorization_level}; ${data.reason}`);
|
|
await speak(data.reply);
|
|
}
|
|
|
|
async function speak(text) {
|
|
const response = await fetch('/api/speak', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ text })
|
|
});
|
|
if (!response.ok) return;
|
|
const blob = await response.blob();
|
|
audioReply.src = URL.createObjectURL(blob);
|
|
await audioReply.play().catch(() => {});
|
|
}
|
|
|
|
async function transcribe(blob) {
|
|
setStatus('Transcribing...');
|
|
const form = new FormData();
|
|
form.append('audio', blob, 'utterance.webm');
|
|
const response = await fetch('/api/transcribe', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'audio/webm' },
|
|
body: blob
|
|
});
|
|
if (!response.ok) throw new Error(await response.text());
|
|
const data = await response.json();
|
|
transcriptEl.textContent = data.text;
|
|
textInput.value = data.text;
|
|
return data.text;
|
|
}
|
|
|
|
async function startRecording() {
|
|
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
|
|
chunks = [];
|
|
recorder = new MediaRecorder(stream, { mimeType: 'audio/webm' });
|
|
recorder.addEventListener('dataavailable', event => {
|
|
if (event.data.size > 0) chunks.push(event.data);
|
|
});
|
|
recorder.addEventListener('stop', async () => {
|
|
stream.getTracks().forEach(track => track.stop());
|
|
recordButton.classList.remove('recording');
|
|
recordButton.textContent = 'Hold to Talk';
|
|
try {
|
|
const text = await transcribe(new Blob(chunks, { type: 'audio/webm' }));
|
|
if (text.trim()) await askFriday(text);
|
|
} catch (error) {
|
|
setStatus(`Error: ${error.message}`);
|
|
}
|
|
});
|
|
recorder.start();
|
|
recordButton.classList.add('recording');
|
|
recordButton.textContent = 'Listening... release to send';
|
|
setStatus('Listening...');
|
|
}
|
|
|
|
function stopRecording() {
|
|
if (recorder && recorder.state === 'recording') recorder.stop();
|
|
}
|
|
|
|
recordButton.addEventListener('pointerdown', startRecording);
|
|
recordButton.addEventListener('pointerup', stopRecording);
|
|
recordButton.addEventListener('pointerleave', stopRecording);
|
|
sendTextButton.addEventListener('click', async () => {
|
|
const text = textInput.value.trim();
|
|
if (!text) return;
|
|
transcriptEl.textContent = text;
|
|
try {
|
|
await askFriday(text);
|
|
} catch (error) {
|
|
setStatus(`Error: ${error.message}`);
|
|
}
|
|
});
|