Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

hooks.ts 3.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. import { useDeleteMessage, useFeedback } from '@/hooks/chat-hooks';
  2. import { useSetModalState } from '@/hooks/common-hooks';
  3. import { IRemoveMessageById, useSpeechWithSse } from '@/hooks/logic-hooks';
  4. import { IFeedbackRequestBody } from '@/interfaces/request/chat';
  5. import { hexStringToUint8Array } from '@/utils/common-util';
  6. import { SpeechPlayer } from 'openai-speech-stream-player';
  7. import { useCallback, useEffect, useRef, useState } from 'react';
  8. export const useSendFeedback = (messageId: string) => {
  9. const { visible, hideModal, showModal } = useSetModalState();
  10. const { feedback, loading } = useFeedback();
  11. const onFeedbackOk = useCallback(
  12. async (params: IFeedbackRequestBody) => {
  13. const ret = await feedback({
  14. ...params,
  15. messageId: messageId,
  16. });
  17. if (ret === 0) {
  18. hideModal();
  19. }
  20. },
  21. [feedback, hideModal, messageId],
  22. );
  23. return {
  24. loading,
  25. onFeedbackOk,
  26. visible,
  27. hideModal,
  28. showModal,
  29. };
  30. };
  31. export const useRemoveMessage = (
  32. messageId: string,
  33. removeMessageById?: IRemoveMessageById['removeMessageById'],
  34. ) => {
  35. const { deleteMessage, loading } = useDeleteMessage();
  36. const onRemoveMessage = useCallback(async () => {
  37. if (messageId) {
  38. const code = await deleteMessage(messageId);
  39. if (code === 0) {
  40. removeMessageById?.(messageId);
  41. }
  42. }
  43. }, [deleteMessage, messageId, removeMessageById]);
  44. return { onRemoveMessage, loading };
  45. };
  46. export const useSpeech = (content: string, audioBinary?: string) => {
  47. const ref = useRef<HTMLAudioElement>(null);
  48. const { read } = useSpeechWithSse();
  49. const player = useRef<SpeechPlayer>();
  50. const [isPlaying, setIsPlaying] = useState<boolean>(false);
  51. const initialize = useCallback(async () => {
  52. player.current = new SpeechPlayer({
  53. audio: ref.current!,
  54. onPlaying: () => {
  55. setIsPlaying(true);
  56. },
  57. onPause: () => {
  58. setIsPlaying(false);
  59. },
  60. onChunkEnd: () => {},
  61. mimeType: MediaSource.isTypeSupported('audio/mpeg')
  62. ? 'audio/mpeg'
  63. : 'audio/mp4; codecs="mp4a.40.2"', // https://stackoverflow.com/questions/64079424/cannot-replay-mp3-in-firefox-using-mediasource-even-though-it-works-in-chrome
  64. });
  65. await player.current.init();
  66. }, []);
  67. const pause = useCallback(() => {
  68. player.current?.pause();
  69. }, []);
  70. const speech = useCallback(async () => {
  71. const response = await read({ text: content });
  72. if (response) {
  73. player?.current?.feedWithResponse(response);
  74. }
  75. }, [read, content]);
  76. const handleRead = useCallback(async () => {
  77. if (isPlaying) {
  78. setIsPlaying(false);
  79. pause();
  80. } else {
  81. setIsPlaying(true);
  82. speech();
  83. }
  84. }, [setIsPlaying, speech, isPlaying, pause]);
  85. useEffect(() => {
  86. if (audioBinary) {
  87. const units = hexStringToUint8Array(audioBinary);
  88. if (units) {
  89. try {
  90. player.current?.feed(units);
  91. } catch (error) {
  92. console.warn(error);
  93. }
  94. }
  95. }
  96. }, [audioBinary]);
  97. useEffect(() => {
  98. initialize();
  99. }, [initialize]);
  100. return { ref, handleRead, isPlaying };
  101. };