diff --git a/apps/chat/src/hooks/useTokenizer.ts b/apps/chat/src/hooks/useTokenizer.ts index 875d9ec1e..a7efdf548 100644 --- a/apps/chat/src/hooks/useTokenizer.ts +++ b/apps/chat/src/hooks/useTokenizer.ts @@ -1,29 +1,40 @@ -import { useCallback, useEffect, useState } from 'react'; +import { useCallback, useEffect, useRef } from 'react'; import { DialAIEntityModel } from '../types/models'; import { Tiktoken, get_encoding } from 'tiktoken'; export const useTokenizer = (tokenizer: DialAIEntityModel['tokenizer']) => { - const [encoding, setEncoding] = useState(undefined); + const encodingRef = useRef(null); useEffect(() => { - if (tokenizer?.encoding) { - setEncoding(get_encoding(tokenizer.encoding)); + // clean up if tokenizer changed + if (encodingRef.current) { + encodingRef.current.free(); + encodingRef.current = null; } + + // use microtask to not block the thread and isMounted variable to prevent task execution if component unmounted + let isMounted = true; + Promise.resolve().then(() => { + if (isMounted && tokenizer?.encoding) { + encodingRef.current = get_encoding(tokenizer.encoding); + } + }); + + return () => { + isMounted = false; + if (encodingRef.current) { + encodingRef.current.free(); + encodingRef.current = null; + } + }; }, [tokenizer]); - useEffect(() => { - return () => encoding?.free(); + const getTokensLength = useCallback((str: string) => { + return encodingRef.current?.encode(str).length ?? new Blob([str]).size; }, []); - const getTokensLength = useCallback( - (str: string) => { - return encoding?.encode(str).length ?? new Blob([str]).size; - }, - [encoding], - ); - return { getTokensLength, };