From f14b4c3ef78aca70292895924a74c7831c6ca493 Mon Sep 17 00:00:00 2001 From: YanceyOfficial Date: Mon, 6 Jan 2025 02:52:50 +0800 Subject: [PATCH] feat: support katex --- index.html | 6 ++++ package-lock.json | 38 ++++++++++++++++++++++++++ package.json | 1 + src/components/ChatBox/InputBox.tsx | 9 +----- src/components/ChatBox/Markdown.tsx | 9 ++++-- src/components/ChatBox/TokenCount.tsx | 2 +- src/components/Configuration/index.tsx | 7 +---- 7 files changed, 54 insertions(+), 18 deletions(-) diff --git a/index.html b/index.html index d59ebe9..6af28c0 100644 --- a/index.html +++ b/index.html @@ -3,6 +3,12 @@ Hyper Chat +
diff --git a/package-lock.json b/package-lock.json index 6fc0654..d1514e6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -33,6 +33,7 @@ "js-tiktoken": "^1.0.15", "luxon": "^3.5.0", "marked": "^15.0.3", + "marked-katex-extension": "^5.1.4", "notistack": "^3.0.1", "openai": "^4.76.0", "react": "^18.3.1", @@ -10128,6 +10129,33 @@ "node": ">=8" } }, + "node_modules/katex": { + "version": "0.16.19", + "resolved": "https://registry.npmjs.org/katex/-/katex-0.16.19.tgz", + "integrity": "sha512-3IA6DYVhxhBabjSLTNO9S4+OliA3Qvb8pBQXMfC4WxXJgLwZgnfDl0BmB4z6nBMdznBsZ+CGM8DrGZ5hcguDZg==", + "funding": [ + "https://opencollective.com/katex", + "https://github.com/sponsors/katex" + ], + "license": "MIT", + "peer": true, + "dependencies": { + "commander": "^8.3.0" + }, + "bin": { + "katex": "cli.js" + } + }, + "node_modules/katex/node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 12" + } + }, "node_modules/keyv": { "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", @@ -10831,6 +10859,16 @@ "node": ">= 18" } }, + "node_modules/marked-katex-extension": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/marked-katex-extension/-/marked-katex-extension-5.1.4.tgz", + "integrity": "sha512-GQOio4vCp0laxB1IY+2oNVo5nbn82yWMDP/jILRYHmyu2WXMVlXCB+krq2/U2fQn+V9j8aqDmnNdrsgqG2AkGQ==", + "license": "MIT", + "peerDependencies": { + "katex": ">=0.16 <0.17", + "marked": ">=4 <16" + } + }, "node_modules/matcher": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/matcher/-/matcher-3.0.0.tgz", diff --git a/package.json b/package.json index 114277a..bc507cc 100644 --- a/package.json +++ b/package.json @@ -40,6 +40,7 @@ "js-tiktoken": "^1.0.15", "luxon": "^3.5.0", "marked": "^15.0.3", + "marked-katex-extension": "^5.1.4", "notistack": "^3.0.1", "openai": "^4.76.0", "react": "^18.3.1", diff --git a/src/components/ChatBox/InputBox.tsx b/src/components/ChatBox/InputBox.tsx index 19924ad..aa1321b 100644 --- a/src/components/ChatBox/InputBox.tsx +++ b/src/components/ChatBox/InputBox.tsx @@ -2,11 +2,7 @@ import classNames from 'classnames' import { useAtom, useAtomValue } from 'jotai' import { FC, memo, useEffect, useRef, useState } from 'react' import { useChatCompletion } from 'src/hooks' -import { - base64FilePromptAtom, - conversationAtom, - inputTextAtom -} from 'src/stores/conversation' +import { base64FilePromptAtom, inputTextAtom } from 'src/stores/conversation' import { loadingAtom, settingsAtom } from 'src/stores/global' import { ContentPartType, TextPrompt } from 'src/types/conversation' import { LoadingIcon, SolidSendIcon } from '../Icons' @@ -16,7 +12,6 @@ import AudioRecorder from './Recorder' import TokenCount from './TokenCount' const InputBox: FC = () => { - const conversation = useAtomValue(conversationAtom) const settings = useAtomValue(settingsAtom) const loading = useAtomValue(loadingAtom) const [inputText, setInputText] = useAtom(inputTextAtom) @@ -80,8 +75,6 @@ const InputBox: FC = () => { } }, [inputText]) - if (!conversation) return null - return (
diff --git a/src/components/ChatBox/Markdown.tsx b/src/components/ChatBox/Markdown.tsx index 65c45cf..77fec09 100644 --- a/src/components/ChatBox/Markdown.tsx +++ b/src/components/ChatBox/Markdown.tsx @@ -1,13 +1,14 @@ import hljs from 'highlight.js' import 'highlight.js/styles/atom-one-dark.css' import { Marked, Renderer, Tokens } from 'marked' +import markedKatex from 'marked-katex-extension' import { FC, memo, useCallback } from 'react' interface Props { src: string } -const Markdown: FC = memo(({ src }) => { +const Markdown: FC = ({ src }) => { const parseMarkdown = useCallback(() => { const renderer = new Renderer() @@ -42,6 +43,8 @@ const Markdown: FC = memo(({ src }) => { } }) + marked.use(markedKatex()) + return marked.parse(src) }, [src]) @@ -51,6 +54,6 @@ const Markdown: FC = memo(({ src }) => { dangerouslySetInnerHTML={{ __html: parseMarkdown() }} /> ) -}) +} -export default Markdown +export default memo(Markdown) diff --git a/src/components/ChatBox/TokenCount.tsx b/src/components/ChatBox/TokenCount.tsx index 6b3c4f3..06f5075 100644 --- a/src/components/ChatBox/TokenCount.tsx +++ b/src/components/ChatBox/TokenCount.tsx @@ -12,7 +12,7 @@ const TokenCount: FC = () => { const { maxInput } = models.find((m) => m.modelName === configuration.model) ?? {} const usedTokenCount = - conversation.messages.reduce((acc, val) => acc + val.tokenCount, 0) + + conversation?.messages.reduce((acc, val) => acc + val.tokenCount, 0) + configuration.systemMessageTokensCount return ( diff --git a/src/components/Configuration/index.tsx b/src/components/Configuration/index.tsx index 35d767f..9765a23 100644 --- a/src/components/Configuration/index.tsx +++ b/src/components/Configuration/index.tsx @@ -12,14 +12,13 @@ import { useAtomValue } from 'jotai' import { FC } from 'react' import configurations from 'src/configurations' import { useDB } from 'src/hooks' -import { configurationAtom, conversationAtom } from 'src/stores/conversation' +import { configurationAtom } from 'src/stores/conversation' import { companyAtom } from 'src/stores/global' import { Configuration as IConfiguration } from 'src/types/conversation' import Divider from '../Divider' import InputSlider from '../InputSlider' const Configuration: FC = () => { - const conversation = useAtomValue(conversationAtom) const company = useAtomValue(companyAtom) const configuration = useAtomValue(configurationAtom) const { updateOneById } = useDB('configurations') @@ -29,10 +28,6 @@ const Configuration: FC = () => { await updateOneById(configuration.company, configuration) } - if (!conversation) { - return null - } - return (