From e7d3a8e2e14985272231aad25323bdcab9545974 Mon Sep 17 00:00:00 2001 From: archer <545436317@qq.com> Date: Mon, 15 May 2023 13:43:17 +0800 Subject: [PATCH] perf: http recognition and input textarea --- package.json | 1 + pnpm-lock.yaml | 215 ++++++++++++++++++++++++++++-- src/components/Markdown/index.tsx | 13 +- src/constants/theme.ts | 3 + src/pages/chat/index.tsx | 24 ++-- src/utils/tools.ts | 6 + 6 files changed, 238 insertions(+), 24 deletions(-) diff --git a/package.json b/package.json index 000ed0323..d159fe0e0 100644 --- a/package.json +++ b/package.json @@ -51,6 +51,7 @@ "react-syntax-highlighter": "^15.5.0", "redis": "^4.6.5", "rehype-katex": "^6.0.2", + "rehype-raw": "^6.1.1", "remark-gfm": "^3.0.1", "remark-math": "^5.1.1", "sass": "^1.58.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 60b4cd872..ce568375d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -59,6 +59,7 @@ specifiers: react-syntax-highlighter: ^15.5.0 redis: ^4.6.5 rehype-katex: ^6.0.2 + rehype-raw: ^6.1.1 remark-gfm: ^3.0.1 remark-math: ^5.1.1 sass: ^1.58.3 @@ -109,6 +110,7 @@ dependencies: react-syntax-highlighter: registry.npmmirror.com/react-syntax-highlighter/15.5.0_react@18.2.0 redis: registry.npmmirror.com/redis/4.6.5 rehype-katex: registry.npmmirror.com/rehype-katex/6.0.2 + rehype-raw: 6.1.1 remark-gfm: registry.npmmirror.com/remark-gfm/3.0.1 remark-math: registry.npmmirror.com/remark-math/5.1.1 sass: registry.npmmirror.com/sass/1.58.3 @@ -294,11 +296,37 @@ packages: resolution: {integrity: sha512-COUnqfB2+ckwXXSFInsFdOAWQzCCx+a5hq2ruyj+Vjund94RJQd4LG2u9hnvJrTgunKAaax7ancBYlDrNYxA0g==} dev: true + /@types/hast/2.3.4: + resolution: {integrity: sha512-wLEm0QvaoawEDoTRwzTXp4b4jpwiJDvR5KMnFnVodm3scufTlBOWRD6N1OBf9TZMhjlNsSfcO5V+7AF4+Vy+9g==} + dependencies: + '@types/unist': 2.0.6 + dev: false + + /@types/parse5/6.0.3: + resolution: {integrity: sha512-SuT16Q1K51EAVPz1K29DJ/sXjhSQ0zjvsypYJ6tlwVsRV9jwW5Adq2ch8Dq8kDBCkYnELS7N7VNCSB5nC56t/g==} + dev: false + + /@types/unist/2.0.6: + resolution: {integrity: sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ==} + dev: false + + /bail/2.0.2: + resolution: {integrity: sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==} + dev: false + + /comma-separated-tokens/2.0.3: + resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==} + dev: false + /cookie/0.5.0: resolution: {integrity: sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==} engines: {node: '>= 0.6'} dev: false + /extend/3.0.2: + resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} + dev: false + /fsevents/2.3.2: resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} @@ -309,9 +337,95 @@ packages: /graceful-fs/4.2.10: resolution: {integrity: sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==} + requiresBuild: true dev: false optional: true + /hast-util-from-parse5/7.1.2: + resolution: {integrity: sha512-Nz7FfPBuljzsN3tCQ4kCBKqdNhQE2l0Tn+X1ubgKBPRoiDIu1mL08Cfw4k7q71+Duyaw7DXDN+VTAp4Vh3oCOw==} + dependencies: + '@types/hast': 2.3.4 + '@types/unist': 2.0.6 + hastscript: 7.2.0 + property-information: 6.2.0 + vfile: 5.3.7 + vfile-location: 4.1.0 + web-namespaces: 2.0.1 + dev: false + + /hast-util-parse-selector/3.1.1: + resolution: {integrity: sha512-jdlwBjEexy1oGz0aJ2f4GKMaVKkA9jwjr4MjAAI22E5fM/TXVZHuS5OpONtdeIkRKqAaryQ2E9xNQxijoThSZA==} + dependencies: + '@types/hast': 2.3.4 + dev: false + + /hast-util-raw/7.2.3: + resolution: {integrity: sha512-RujVQfVsOrxzPOPSzZFiwofMArbQke6DJjnFfceiEbFh7S05CbPt0cYN+A5YeD3pso0JQk6O1aHBnx9+Pm2uqg==} + dependencies: + '@types/hast': 2.3.4 + '@types/parse5': 6.0.3 + hast-util-from-parse5: 7.1.2 + hast-util-to-parse5: 7.1.0 + html-void-elements: 2.0.1 + parse5: 6.0.1 + unist-util-position: 4.0.4 + unist-util-visit: 4.1.2 + vfile: 5.3.7 + web-namespaces: 2.0.1 + zwitch: 2.0.4 + dev: false + + /hast-util-to-parse5/7.1.0: + resolution: {integrity: sha512-YNRgAJkH2Jky5ySkIqFXTQiaqcAtJyVE+D5lkN6CdtOqrnkLfGYYrEcKuHOJZlp+MwjSwuD3fZuawI+sic/RBw==} + dependencies: + '@types/hast': 2.3.4 + comma-separated-tokens: 2.0.3 + property-information: 6.2.0 + space-separated-tokens: 2.0.2 + web-namespaces: 2.0.1 + zwitch: 2.0.4 + dev: false + + /hastscript/7.2.0: + resolution: {integrity: sha512-TtYPq24IldU8iKoJQqvZOuhi5CyCQRAbvDOX0x1eW6rsHSxa/1i2CCiptNTotGHJ3VoHRGmqiv6/D3q113ikkw==} + dependencies: + '@types/hast': 2.3.4 + comma-separated-tokens: 2.0.3 + hast-util-parse-selector: 3.1.1 + property-information: 6.2.0 + space-separated-tokens: 2.0.2 + dev: false + + /html-void-elements/2.0.1: + resolution: {integrity: sha512-0quDb7s97CfemeJAnW9wC0hw78MtW7NU3hqtCD75g2vFlDLt36llsYD7uB7SUzojLMP24N5IatXf7ylGXiGG9A==} + dev: false + + /is-buffer/2.0.5: + resolution: {integrity: sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==} + engines: {node: '>=4'} + dev: false + + /is-plain-obj/4.1.0: + resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==} + engines: {node: '>=12'} + dev: false + + /parse5/6.0.1: + resolution: {integrity: sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==} + dev: false + + /property-information/6.2.0: + resolution: {integrity: sha512-kma4U7AFCTwpqq5twzC1YVIDXSqg6qQK6JN0smOw8fgRy1OkMi0CYSzFmsy6dnqSenamAtj0CyXMUJ1Mf6oROg==} + dev: false + + /rehype-raw/6.1.1: + resolution: {integrity: sha512-d6AKtisSRtDRX4aSPsJGTfnzrX2ZkHQLE5kiUuGOeEoLpbEulFF4hj0mLPbsa+7vmguDKOVVEQdHKDSwoaIDsQ==} + dependencies: + '@types/hast': 2.3.4 + hast-util-raw: 7.2.3 + unified: 10.1.2 + dev: false + /saslprep/1.0.3: resolution: {integrity: sha512-/MY/PEMbk2SuY5sScONwhUDsV2p77Znkb/q3nSVstq/yQzYJOH/Azh29p9oJLsl3LnQwSvZDKagDGBsBwSooag==} engines: {node: '>=6'} @@ -324,9 +438,92 @@ packages: /source-map/0.6.1: resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} engines: {node: '>=0.10.0'} + requiresBuild: true dev: false optional: true + /space-separated-tokens/2.0.2: + resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==} + dev: false + + /trough/2.1.0: + resolution: {integrity: sha512-AqTiAOLcj85xS7vQ8QkAV41hPDIJ71XJB4RCUrzo/1GM2CQwhkJGaf9Hgr7BOugMRpgGUrqRg/DrBDl4H40+8g==} + dev: false + + /unified/10.1.2: + resolution: {integrity: sha512-pUSWAi/RAnVy1Pif2kAoeWNBa3JVrx0MId2LASj8G+7AiHWoKZNTomq6LG326T68U7/e263X6fTdcXIy7XnF7Q==} + dependencies: + '@types/unist': 2.0.6 + bail: 2.0.2 + extend: 3.0.2 + is-buffer: 2.0.5 + is-plain-obj: 4.1.0 + trough: 2.1.0 + vfile: 5.3.7 + dev: false + + /unist-util-is/5.2.0: + resolution: {integrity: sha512-Glt17jWwZeyqrFqOK0pF1Ded5U3yzJnFr8CG1GMjCWTp9zDo2p+cmD6pWbZU8AgM5WU3IzRv6+rBwhzsGh6hBQ==} + dev: false + + /unist-util-position/4.0.4: + resolution: {integrity: sha512-kUBE91efOWfIVBo8xzh/uZQ7p9ffYRtUbMRZBNFYwf0RK8koUMx6dGUfwylLOKmaT2cs4wSW96QoYUSXAyEtpg==} + dependencies: + '@types/unist': 2.0.6 + dev: false + + /unist-util-stringify-position/3.0.3: + resolution: {integrity: sha512-k5GzIBZ/QatR8N5X2y+drfpWG8IDBzdnVj6OInRNWm1oXrzydiaAT2OQiA8DPRRZyAKb9b6I2a6PxYklZD0gKg==} + dependencies: + '@types/unist': 2.0.6 + dev: false + + /unist-util-visit-parents/5.1.3: + resolution: {integrity: sha512-x6+y8g7wWMyQhL1iZfhIPhDAs7Xwbn9nRosDXl7qoPTSCy0yNxnKc+hWokFifWQIDGi154rdUqKvbCa4+1kLhg==} + dependencies: + '@types/unist': 2.0.6 + unist-util-is: 5.2.0 + dev: false + + /unist-util-visit/4.1.2: + resolution: {integrity: sha512-MSd8OUGISqHdVvfY9TPhyK2VdUrPgxkUtWSuMHF6XAAFuL4LokseigBnZtPnJMu+FbynTkFNnFlyjxpVKujMRg==} + dependencies: + '@types/unist': 2.0.6 + unist-util-is: 5.2.0 + unist-util-visit-parents: 5.1.3 + dev: false + + /vfile-location/4.1.0: + resolution: {integrity: sha512-YF23YMyASIIJXpktBa4vIGLJ5Gs88UB/XePgqPmTa7cDA+JeO3yclbpheQYCHjVHBn/yePzrXuygIL+xbvRYHw==} + dependencies: + '@types/unist': 2.0.6 + vfile: 5.3.7 + dev: false + + /vfile-message/3.1.4: + resolution: {integrity: sha512-fa0Z6P8HUrQN4BZaX05SIVXic+7kE3b05PWAtPuYP9QLHsLKYR7/AlLW3NtOrpXRLeawpDLMsVkmk5DG0NXgWw==} + dependencies: + '@types/unist': 2.0.6 + unist-util-stringify-position: 3.0.3 + dev: false + + /vfile/5.3.7: + resolution: {integrity: sha512-r7qlzkgErKjobAmyNIkkSpizsFPYiUPuJb5pNW1RB4JcYVZhs4lIbVqk8XPk033CV/1z8ss5pkax8SuhGpcG8g==} + dependencies: + '@types/unist': 2.0.6 + is-buffer: 2.0.5 + unist-util-stringify-position: 3.0.3 + vfile-message: 3.1.4 + dev: false + + /web-namespaces/2.0.1: + resolution: {integrity: sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==} + dev: false + + /zwitch/2.0.4: + resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} + dev: false + registry.npmmirror.com/@alicloud/credentials/2.2.6: resolution: {integrity: sha512-jG+msY77dHmAF3x+8VTy7fEgORyXLHmDci8t92HeipBdCHsPptDegA++GEwKgR7f6G4wvafYt+aqMZ1iligdrQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@alicloud/credentials/-/credentials-2.2.6.tgz} name: '@alicloud/credentials' @@ -7742,7 +7939,7 @@ packages: name: hast-util-from-parse5 version: 7.1.2 dependencies: - '@types/hast': registry.npmmirror.com/@types/hast/2.3.4 + '@types/hast': 2.3.4 '@types/unist': registry.npmmirror.com/@types/unist/2.0.6 hastscript: registry.npmmirror.com/hastscript/7.2.0 property-information: registry.npmmirror.com/property-information/6.2.0 @@ -7756,7 +7953,7 @@ packages: name: hast-util-is-element version: 2.1.3 dependencies: - '@types/hast': registry.npmmirror.com/@types/hast/2.3.4 + '@types/hast': 2.3.4 '@types/unist': registry.npmmirror.com/@types/unist/2.0.6 dev: false @@ -7771,7 +7968,7 @@ packages: name: hast-util-parse-selector version: 3.1.1 dependencies: - '@types/hast': registry.npmmirror.com/@types/hast/2.3.4 + '@types/hast': 2.3.4 dev: false registry.npmmirror.com/hast-util-to-text/3.1.2: @@ -7796,7 +7993,7 @@ packages: name: hastscript version: 6.0.0 dependencies: - '@types/hast': registry.npmmirror.com/@types/hast/2.3.4 + '@types/hast': 2.3.4 comma-separated-tokens: registry.npmmirror.com/comma-separated-tokens/1.0.8 hast-util-parse-selector: registry.npmmirror.com/hast-util-parse-selector/2.2.5 property-information: registry.npmmirror.com/property-information/5.6.0 @@ -7808,7 +8005,7 @@ packages: name: hastscript version: 7.2.0 dependencies: - '@types/hast': registry.npmmirror.com/@types/hast/2.3.4 + '@types/hast': 2.3.4 comma-separated-tokens: registry.npmmirror.com/comma-separated-tokens/2.0.3 hast-util-parse-selector: registry.npmmirror.com/hast-util-parse-selector/3.1.1 property-information: registry.npmmirror.com/property-information/6.2.0 @@ -8762,7 +8959,7 @@ packages: version: 5.1.2 dependencies: '@types/mdast': registry.npmmirror.com/@types/mdast/3.0.10 - '@types/unist': registry.npmmirror.com/@types/unist/2.0.6 + '@types/unist': 2.0.6 unist-util-visit: registry.npmmirror.com/unist-util-visit/4.1.2 dev: false @@ -8890,7 +9087,7 @@ packages: name: mdast-util-to-hast version: 12.3.0 dependencies: - '@types/hast': registry.npmmirror.com/@types/hast/2.3.4 + '@types/hast': 2.3.4 '@types/mdast': registry.npmmirror.com/@types/mdast/3.0.10 mdast-util-definitions: registry.npmmirror.com/mdast-util-definitions/5.1.2 micromark-util-sanitize-uri: registry.npmmirror.com/micromark-util-sanitize-uri/1.1.0 @@ -11624,7 +11821,7 @@ packages: name: unist-util-position version: 4.0.4 dependencies: - '@types/unist': registry.npmmirror.com/@types/unist/2.0.6 + '@types/unist': 2.0.6 dev: false registry.npmmirror.com/unist-util-remove-position/4.0.2: @@ -11817,7 +12014,7 @@ packages: name: vfile-location version: 4.1.0 dependencies: - '@types/unist': registry.npmmirror.com/@types/unist/2.0.6 + '@types/unist': 2.0.6 vfile: registry.npmmirror.com/vfile/5.3.7 dev: false diff --git a/src/components/Markdown/index.tsx b/src/components/Markdown/index.tsx index 0386c9167..e86d51933 100644 --- a/src/components/Markdown/index.tsx +++ b/src/components/Markdown/index.tsx @@ -1,12 +1,13 @@ -import React, { memo } from 'react'; +import React, { memo, useMemo } from 'react'; import ReactMarkdown from 'react-markdown'; import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter'; import { Box, Flex, useColorModeValue } from '@chakra-ui/react'; -import { useCopyData } from '@/utils/tools'; +import { useCopyData, formatLinkTextToHtml } from '@/utils/tools'; import Icon from '@/components/Icon'; import remarkGfm from 'remark-gfm'; import remarkMath from 'remark-math'; import rehypeKatex from 'rehype-katex'; +import rehypeRaw from 'rehype-raw'; import 'katex/dist/katex.min.css'; import styles from './index.module.scss'; @@ -15,13 +16,17 @@ import { codeLight } from './codeLight'; const Markdown = ({ source, isChatting = false }: { source: string; isChatting?: boolean }) => { const { copyData } = useCopyData(); + const formatSource = useMemo(() => { + return formatLinkTextToHtml(source); + }, [source]); + return ( - {source} + {formatSource} ); }; diff --git a/src/constants/theme.ts b/src/constants/theme.ts index cdecac711..46d290d05 100644 --- a/src/constants/theme.ts +++ b/src/constants/theme.ts @@ -171,6 +171,9 @@ export const theme = extendTheme({ fontWeight: 400, height: '100%', overflow: 'hidden' + }, + a: { + color: 'myBlue.700' } } }, diff --git a/src/pages/chat/index.tsx b/src/pages/chat/index.tsx index 712cfe33a..c119b0b6d 100644 --- a/src/pages/chat/index.tsx +++ b/src/pages/chat/index.tsx @@ -36,7 +36,7 @@ import { useToast } from '@/hooks/useToast'; import { useScreen } from '@/hooks/useScreen'; import { useQuery } from '@tanstack/react-query'; import dynamic from 'next/dynamic'; -import { useCopyData, voiceBroadcast } from '@/utils/tools'; +import { useCopyData, voiceBroadcast, formatLinkTextToHtml } from '@/utils/tools'; import { streamFetch } from '@/api/fetch'; import MyIcon from '@/components/Icon'; import { throttle } from 'lodash'; @@ -90,7 +90,6 @@ const Chat = ({ const controller = useRef(new AbortController()); const isLeavePage = useRef(false); - const [inputVal, setInputVal] = useState(''); // user input prompt const [showSystemPrompt, setShowSystemPrompt] = useState(''); const [messageContextMenuData, setMessageContextMenuData] = useState<{ // message messageContextMenuData @@ -168,7 +167,8 @@ const Chat = ({ // 重置输入内容 const resetInputVal = useCallback((val: string) => { - setInputVal(val); + if (!TextareaDom.current) return; + TextareaDom.current.value = val; setTimeout(() => { /* 回到最小高度 */ if (TextareaDom.current) { @@ -289,6 +289,7 @@ const Chat = ({ * 发送一个内容 */ const sendPrompt = useCallback(async () => { + // get value if (isChatting) { toast({ title: '正在聊天中...请等待结束', @@ -296,9 +297,10 @@ const Chat = ({ }); return; } - const storeInput = inputVal; - // 去除空行 - const val = inputVal.trim().replace(/\n\s*/g, '\n'); + + // get input value + const value = TextareaDom.current?.value || ''; + const val = value.trim().replace(/\n\s*/g, '\n'); if (!val) { toast({ @@ -346,7 +348,7 @@ const Chat = ({ isClosable: true }); - resetInputVal(storeInput); + resetInputVal(value); setChatData((state) => ({ ...state, @@ -355,7 +357,6 @@ const Chat = ({ } }, [ isChatting, - inputVal, chatData.history, setChatData, resetInputVal, @@ -855,7 +856,10 @@ const Chat = ({ bg={'myBlue.300'} onContextMenu={(e) => onclickContextMenu(e, item)} > - {item.value} + )} @@ -888,7 +892,6 @@ const Chat = ({ }} placeholder="提问" resize={'none'} - value={inputVal} rows={1} height={'22px'} lineHeight={'22px'} @@ -901,7 +904,6 @@ const Chat = ({ color={useColorModeValue('blackAlpha.700', 'white')} onChange={(e) => { const textarea = e.target; - setInputVal(textarea.value); textarea.style.height = textareaMinH; textarea.style.height = `${textarea.scrollHeight}px`; }} diff --git a/src/utils/tools.ts b/src/utils/tools.ts index 28f03e6a2..780369597 100644 --- a/src/utils/tools.ts +++ b/src/utils/tools.ts @@ -113,3 +113,9 @@ export const voiceBroadcast = ({ text }: { text: string }) => { cancel: () => window.speechSynthesis?.cancel() }; }; + +export const formatLinkTextToHtml = (text: string) => { + const httpReg = + /(?$&'); +};