File size: 3,171 Bytes
7d8f5e6
d2e049e
a7e962d
d2e049e
2b66f8c
d2e049e
7b381b0
a7e962d
2b66f8c
d2e049e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7d8f5e6
 
 
0086f8a
7d8f5e6
 
 
 
 
 
 
 
0086f8a
7d8f5e6
 
 
 
 
 
a7e962d
16e3fae
a7e962d
 
 
 
2b66f8c
a7e962d
 
 
 
 
 
2b66f8c
a7e962d
 
 
2b66f8c
a7e962d
 
 
 
 
2b66f8c
a7e962d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7b381b0
 
 
 
 
 
 
 
16e3fae
a7e962d
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
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 { ConversationContext } from '@/pages/chat/context';
import { getMessagePureId } from '@/utils/chat';
import { hexStringToUint8Array } from '@/utils/common-util';
import { SpeechPlayer } from 'openai-speech-stream-player';
import { useCallback, useContext, 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 retcode = await deleteMessage(pureId);
      if (retcode === 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 callback = useContext(ConversationContext);

  const initialize = useCallback(async () => {
    player.current = new SpeechPlayer({
      audio: ref.current!,
      onPlaying: () => {
        setIsPlaying(true);
        callback?.(true);
      },
      onPause: () => {
        setIsPlaying(false);
        callback?.(false);
      },
      onChunkEnd: () => {},
      mimeType: 'audio/mpeg',
    });
    await player.current.init();
  }, [callback]);

  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) {
        player.current?.feed(units);
      }
    }
  }, [audioBinary]);

  useEffect(() => {
    initialize();
  }, [initialize]);

  return { ref, handleRead, isPlaying };
};