From 6879553d806f0e2057ae1e93964c85bc29509d5d Mon Sep 17 00:00:00 2001 From: CanisMinor Date: Fri, 1 Dec 2023 11:47:50 +0800 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20feat:=20Add=20tts=20content=20clean?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 4 +++ src/core/utils/cleanContent.ts | 23 +++++++++++++++++ src/react/hooks/useAudioPlayer.ts | 30 ++++++++++++---------- src/react/hooks/useBlobUrl.ts | 1 + src/react/useOpenAISTT/useOpenAISTTCore.ts | 2 +- src/react/useTTS/index.ts | 8 ++++-- 6 files changed, 52 insertions(+), 16 deletions(-) create mode 100644 src/core/utils/cleanContent.ts diff --git a/package.json b/package.json index 1edc5d3..5e6d1d6 100644 --- a/package.json +++ b/package.json @@ -88,7 +88,10 @@ "openai": "^4.17.3", "query-string": "^8", "react-error-boundary": "^4", + "remark-gfm": "^3", + "remark-parse": "^10", "swr": "^2", + "unified": "^11", "url-join": "^5", "uuid": "^9" }, @@ -122,6 +125,7 @@ "semantic-release": "^21", "tsx": "^4.1.2", "typescript": "^5", + "unist-util-visit": "^5", "vercel": "^28" }, "peerDependencies": { diff --git a/src/core/utils/cleanContent.ts b/src/core/utils/cleanContent.ts new file mode 100644 index 0000000..3ff5139 --- /dev/null +++ b/src/core/utils/cleanContent.ts @@ -0,0 +1,23 @@ +import remarkGfm from 'remark-gfm'; +import remarkParse from 'remark-parse'; +import { unified } from 'unified'; +import { visit } from 'unist-util-visit'; + +// @ts-ignore +const convertMarkdownToMdast = async (md: string) => { + // @ts-ignore + return unified().use(remarkParse).use(remarkGfm).parse(md.trim()); +}; + +export const cleanContent = async (content: string) => { + try { + const mdast = await convertMarkdownToMdast(content.trim()); + const newContent: string[] = []; + visit(mdast, 'text', (node: any) => { + if (node?.value) newContent.push(node.value.trim()); + }); + return newContent.join(''); + } catch { + return content.trim(); + } +}; diff --git a/src/react/hooks/useAudioPlayer.ts b/src/react/hooks/useAudioPlayer.ts index ebfd59b..bcd9838 100644 --- a/src/react/hooks/useAudioPlayer.ts +++ b/src/react/hooks/useAudioPlayer.ts @@ -28,19 +28,23 @@ export const useAudioPlayer = ({ const [isPlaying, setIsPlaying] = useState(false); const [isGlobalLoading, setIsGlobalLoading] = useState(true); - const { isLoading } = useSWR(src || null, async () => { - if (!src) return; - setIsGlobalLoading(true); - const data = await fetch(src); - const arrayBuffer = await data.arrayBuffer(); - setArrayBuffers([arrayBuffer]); - const newBlob = new Blob([arrayBuffer], { type: type }); - audioRef.current.pause(); - audioRef.current.currentTime = 0; - if (audioRef.current.src) URL.revokeObjectURL(audioRef.current.src); - audioRef.current.src = URL.createObjectURL(newBlob); - audioRef.current.load(); - }); + const { isLoading } = useSWR( + src || null, + async () => { + if (!src) return; + setIsGlobalLoading(true); + const data = await fetch(src); + const arrayBuffer = await data.arrayBuffer(); + setArrayBuffers([arrayBuffer]); + const newBlob = new Blob([arrayBuffer], { type: type }); + audioRef.current.pause(); + audioRef.current.currentTime = 0; + if (audioRef.current.src) URL.revokeObjectURL(audioRef.current.src); + audioRef.current.src = URL.createObjectURL(newBlob); + audioRef.current.load(); + }, + { revalidateOnFocus: false }, + ); useEffect(() => { if (!audioRef.current) return; diff --git a/src/react/hooks/useBlobUrl.ts b/src/react/hooks/useBlobUrl.ts index 23c7e1c..58e97ee 100644 --- a/src/react/hooks/useBlobUrl.ts +++ b/src/react/hooks/useBlobUrl.ts @@ -31,6 +31,7 @@ export const useBlobUrl = (src: string) => { setAudio(newAudio.audio); setIsGlobalLoading(false); }, + revalidateOnFocus: false, }, ); diff --git a/src/react/useOpenAISTT/useOpenAISTTCore.ts b/src/react/useOpenAISTT/useOpenAISTTCore.ts index 633be6e..4c912ad 100644 --- a/src/react/useOpenAISTT/useOpenAISTTCore.ts +++ b/src/react/useOpenAISTT/useOpenAISTTCore.ts @@ -16,6 +16,6 @@ export const useOpenAISTTCore = (init: OpenAISTTCoreOptions) => { const instance = new OpenaiSTT(api); return instance.create({ options, speech }); }, - swrConfig, + { revalidateOnFocus: false, ...swrConfig }, ); }; diff --git a/src/react/useTTS/index.ts b/src/react/useTTS/index.ts index 9302a96..1e30d61 100644 --- a/src/react/useTTS/index.ts +++ b/src/react/useTTS/index.ts @@ -1,6 +1,7 @@ import { useCallback, useEffect, useState } from 'react'; import useSWR, { type SWRConfiguration, type SWRResponse } from 'swr'; +import { cleanContent } from '@/core/utils/cleanContent'; import { splitTextIntoSegments } from '@/core/utils/splitTextIntoSegments'; import { type AudioProps } from '@/react/AudioPlayer'; import { useStreamAudioPlayer } from '@/react/hooks/useStreamAudioPlayer'; @@ -65,6 +66,7 @@ export const useTTS = ( setIsGlobalLoading(false); } }, + revalidateOnFocus: false, ...restSWRConfig, }, ); @@ -78,8 +80,10 @@ export const useTTS = ( }, [text, isLoading]); useEffect(() => { - const texts = splitTextIntoSegments(text); - handleReset(texts); + cleanContent(text).then((content) => { + const texts = splitTextIntoSegments(content); + handleReset(texts); + }); return () => { handleReset(); };