parent
a894548c78
commit
742a52d293
10 changed files with 353 additions and 141 deletions
Binary file not shown.
Binary file not shown.
@ -0,0 +1,124 @@ |
|||||||
|
import { createContext, useContext, useRef, useState } from "react"; |
||||||
|
import { sendChatMessage } from "./chat"; |
||||||
|
import { textToSpeech } from "./tts"; |
||||||
|
|
||||||
|
const chatContext=createContext(); |
||||||
|
|
||||||
|
export const Status= { |
||||||
|
IDLE: 'idle', |
||||||
|
|
||||||
|
PROCESSING_TEXT: 'processing', |
||||||
|
PROCESSING_AUDIO: 'processing_audio', |
||||||
|
|
||||||
|
AUDIO_ENDED: 'audio_ended', |
||||||
|
|
||||||
|
ERROR: 'error', |
||||||
|
SUCCESS: 'success' |
||||||
|
}; |
||||||
|
|
||||||
|
export function ChatProvider({children}){ |
||||||
|
|
||||||
|
const [history, setHistory] = useState([]); |
||||||
|
const [status, setStatus] = useState(Status.IDLE); |
||||||
|
|
||||||
|
const [audioOutput, setAudioOutput] = useState(true); |
||||||
|
|
||||||
|
const refAudio=useRef(); |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function addMessage(message) { |
||||||
|
setHistory(prev => [...prev, message]); |
||||||
|
} |
||||||
|
function reset() { |
||||||
|
setHistory([]); |
||||||
|
if(refAudio.current) { |
||||||
|
refAudio.current.pause(); // Stop any currently playing audio |
||||||
|
refAudio.current = null; // Reset the audio reference |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
function sendMessage(message, force_no_audio=false) { |
||||||
|
console.log('Sending chat message:', message); |
||||||
|
setStatus(Status.PROCESSING_TEXT); |
||||||
|
|
||||||
|
let historyCopy = [...history]; |
||||||
|
if(message && message.trim() !== '') { |
||||||
|
historyCopy=[...historyCopy, { role: 'user', content: message }]; |
||||||
|
addMessage({ |
||||||
|
role: 'user', |
||||||
|
content: message |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
sendChatMessage(historyCopy).then(response => { |
||||||
|
|
||||||
|
|
||||||
|
addMessage({ |
||||||
|
role: 'assistant', |
||||||
|
content: response.output_text, |
||||||
|
prompt: response.prompt |
||||||
|
}); |
||||||
|
|
||||||
|
|
||||||
|
if(response.output_text && (!force_no_audio && audioOutput)){ |
||||||
|
setStatus(Status.PROCESSING_AUDIO); |
||||||
|
textToSpeech(response.output_text).then(audioUrl => { |
||||||
|
setStatus(Status.SUCCESS); |
||||||
|
|
||||||
|
|
||||||
|
if(refAudio.current) { |
||||||
|
refAudio.current.pause(); // Stop any currently playing audio |
||||||
|
} |
||||||
|
|
||||||
|
// play the audio |
||||||
|
const audio = new Audio(audioUrl); |
||||||
|
audio.play().catch(error => { |
||||||
|
console.error("Audio playback error:", error); |
||||||
|
setStatus(Status.ERROR); |
||||||
|
}); |
||||||
|
|
||||||
|
audio.onended = () => { |
||||||
|
setStatus(Status.AUDIO_ENDED); |
||||||
|
} |
||||||
|
|
||||||
|
refAudio.current = audio; // Store the new audio reference |
||||||
|
|
||||||
|
}); |
||||||
|
}else{ |
||||||
|
setStatus(Status.SUCCESS); |
||||||
|
} |
||||||
|
|
||||||
|
}).catch(error => { |
||||||
|
console.error("Chat error:", error); |
||||||
|
setStatus(Status.ERROR); |
||||||
|
}); |
||||||
|
|
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
return ( |
||||||
|
<chatContext.Provider value={{ |
||||||
|
history, status, setStatus, reset, sendMessage, setAudioOutput, audioOutput, |
||||||
|
stop: () => { |
||||||
|
if(refAudio.current) { |
||||||
|
refAudio.current.pause(); // Stop any currently playing audio |
||||||
|
refAudio.current = null; // Reset the audio reference |
||||||
|
} |
||||||
|
setStatus(Status.IDLE); |
||||||
|
} |
||||||
|
}}> |
||||||
|
{children} |
||||||
|
</chatContext.Provider> |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
export function useChat(){ |
||||||
|
const context=useContext(chatContext); |
||||||
|
if(!context){ |
||||||
|
throw new Error("useChat must be used within a ChatProvider"); |
||||||
|
} |
||||||
|
return context; |
||||||
|
} |
||||||
Loading…
Reference in new issue