switch to realtime api
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful

This commit is contained in:
Late Night Defender 2025-05-27 14:18:57 +07:00
parent 981945a0f0
commit 233d26ae90

View file

@ -11,7 +11,6 @@ function App() {
const mediaRecorderRef = useRef(null); const mediaRecorderRef = useRef(null);
const audioChunksRef = useRef([]); const audioChunksRef = useRef([]);
const audioStreamRef = useRef(null); const audioStreamRef = useRef(null);
const silenceTimerRef = useRef(null);
const canvasRef = useRef(null); const canvasRef = useRef(null);
const analyserRef = useRef(null); const analyserRef = useRef(null);
const dataArrayRef = useRef(null); const dataArrayRef = useRef(null);
@ -114,7 +113,10 @@ Teacher: Good job! How about Magic something special and powerful.
const { text } = await whisperRes.json(); const { text } = await whisperRes.json();
setTranscript(text); setTranscript(text);
const chatRes = await fetch('https://api.openai.com/v1/chat/completions', { setAiReply(''); // Clear previous reply
let fullText = '';
const response = await fetch('https://api.openai.com/v1/chat/completions', {
method: 'POST', method: 'POST',
headers: { headers: {
'Authorization': `Bearer ${OPENAI_API_KEY}`, 'Authorization': `Bearer ${OPENAI_API_KEY}`,
@ -122,21 +124,29 @@ Teacher: Good job! How about Magic something special and powerful.
}, },
body: JSON.stringify({ body: JSON.stringify({
model: 'gpt-4o', model: 'gpt-4o',
stream: true,
messages: [ messages: [
{ role: 'system', content: systemContent }, { role: 'system', content: systemContent },
{ role: 'user', content: text } { role: 'user', content: text }
] ]
}) })
}); });
const chatData = await chatRes.json();
if (!chatData.choices || !chatData.choices[0]) {
console.error('Chat API response error:', chatData);
setAiReply('Sorry, something went wrong with the AI response.');
return;
}
const reply = chatData.choices[0].message.content;
setAiReply(reply);
const reader = response.body.getReader();
const decoder = new TextDecoder("utf-8");
while (true) {
const { done, value } = await reader.read();
if (done) break;
const chunk = decoder.decode(value);
const lines = chunk.split('\n').filter(line => line.trim() !== '');
for (const line of lines) {
if (line.startsWith('data: ')) {
const data = line.replace('data: ', '');
if (data === '[DONE]') {
// After full reply received, synthesize speech
const speechRes = await fetch('https://api.openai.com/v1/audio/speech', { const speechRes = await fetch('https://api.openai.com/v1/audio/speech', {
method: 'POST', method: 'POST',
headers: { headers: {
@ -146,17 +156,47 @@ Teacher: Good job! How about Magic something special and powerful.
body: JSON.stringify({ body: JSON.stringify({
model: 'tts-1-hd', model: 'tts-1-hd',
voice: 'nova', voice: 'nova',
input: reply input: fullText
}) })
}); });
const outputAudioBlob = await speechRes.blob(); const outputAudioBlob = await speechRes.blob();
const audioUrl = URL.createObjectURL(outputAudioBlob); const audioUrl = URL.createObjectURL(outputAudioBlob);
const audio = new Audio(audioUrl); const audio = new Audio(audioUrl);
audio.play(); audio.play();
return;
}
audio.onended = () => { const parsed = JSON.parse(data);
// Do nothing here wait for user to press the button const delta = parsed.choices?.[0]?.delta?.content;
}; if (delta) {
fullText += delta;
setAiReply(prev => prev + delta);
}
}
}
}
// const speechRes = await fetch('https://api.openai.com/v1/audio/speech', {
// method: 'POST',
// headers: {
// 'Authorization': `Bearer ${OPENAI_API_KEY}`,
// 'Content-Type': 'application/json'
// },
// body: JSON.stringify({
// model: 'tts-1-hd',
// voice: 'nova',
// input: reply
// })
// });
// const outputAudioBlob = await speechRes.blob();
// const audioUrl = URL.createObjectURL(outputAudioBlob);
// const audio = new Audio(audioUrl);
// audio.play();
// audio.onended = () => {
// // Do nothing here wait for user to press the button
// };
}; };
}; };