| import { useDeleteMessage, useFeedback } from '@/hooks/chat-hooks'; | |
| import { useSetModalState } from '@/hooks/common-hooks'; | |
| import { IRemoveMessageById, useSpeechWithSse } from '@/hooks/logic-hooks'; | |
| import { IFeedbackRequestBody } from '@/interfaces/request/chat'; | |
| import { getMessagePureId } from '@/utils/chat'; | |
| import { hexStringToUint8Array } from '@/utils/common-util'; | |
| import { SpeechPlayer } from 'openai-speech-stream-player'; | |
| import { useCallback, useEffect, useRef, useState } from 'react'; | |
| export const useSendFeedback = (messageId: string) => { | |
| const { visible, hideModal, showModal } = useSetModalState(); | |
| const { feedback, loading } = useFeedback(); | |
| const onFeedbackOk = useCallback( | |
| async (params: IFeedbackRequestBody) => { | |
| const ret = await feedback({ | |
| ...params, | |
| messageId: getMessagePureId(messageId), | |
| }); | |
| if (ret === 0) { | |
| hideModal(); | |
| } | |
| }, | |
| [feedback, hideModal, messageId], | |
| ); | |
| return { | |
| loading, | |
| onFeedbackOk, | |
| visible, | |
| hideModal, | |
| showModal, | |
| }; | |
| }; | |
| export const useRemoveMessage = ( | |
| messageId: string, | |
| removeMessageById?: IRemoveMessageById['removeMessageById'], | |
| ) => { | |
| const { deleteMessage, loading } = useDeleteMessage(); | |
| const onRemoveMessage = useCallback(async () => { | |
| const pureId = getMessagePureId(messageId); | |
| if (pureId) { | |
| const code = await deleteMessage(pureId); | |
| if (code === 0) { | |
| removeMessageById?.(messageId); | |
| } | |
| } | |
| }, [deleteMessage, messageId, removeMessageById]); | |
| return { onRemoveMessage, loading }; | |
| }; | |
| export const useSpeech = (content: string, audioBinary?: string) => { | |
| const ref = useRef<HTMLAudioElement>(null); | |
| const { read } = useSpeechWithSse(); | |
| const player = useRef<SpeechPlayer>(); | |
| const [isPlaying, setIsPlaying] = useState<boolean>(false); | |
| const initialize = useCallback(async () => { | |
| player.current = new SpeechPlayer({ | |
| audio: ref.current!, | |
| onPlaying: () => { | |
| setIsPlaying(true); | |
| }, | |
| onPause: () => { | |
| setIsPlaying(false); | |
| }, | |
| onChunkEnd: () => {}, | |
| mimeType: 'audio/mpeg', | |
| }); | |
| await player.current.init(); | |
| }, []); | |
| const pause = useCallback(() => { | |
| player.current?.pause(); | |
| }, []); | |
| const speech = useCallback(async () => { | |
| const response = await read({ text: content }); | |
| if (response) { | |
| player?.current?.feedWithResponse(response); | |
| } | |
| }, [read, content]); | |
| const handleRead = useCallback(async () => { | |
| if (isPlaying) { | |
| setIsPlaying(false); | |
| pause(); | |
| } else { | |
| setIsPlaying(true); | |
| speech(); | |
| } | |
| }, [setIsPlaying, speech, isPlaying, pause]); | |
| useEffect(() => { | |
| if (audioBinary) { | |
| const units = hexStringToUint8Array(audioBinary); | |
| if (units) { | |
| try { | |
| player.current?.feed(units); | |
| } catch (error) { | |
| console.warn(error); | |
| } | |
| } | |
| } | |
| }, [audioBinary]); | |
| useEffect(() => { | |
| initialize(); | |
| }, [initialize]); | |
| return { ref, handleRead, isPlaying }; | |
| }; | |