refactor(Inputbar, Markdown): optimize citation handling and improve performance
- Refactored AttachmentButton to use useMemo for extensions calculation. - Simplified citation extraction in Markdown by moving logic to a new utility function. - Updated TopicsTab dependencies for better performance and reactivity.
This commit is contained in:
parent
8501ab82c6
commit
d74f05f27e
@ -3,7 +3,7 @@ import { isVisionModel } from '@renderer/config/models'
|
|||||||
import { FileType, Model } from '@renderer/types'
|
import { FileType, Model } from '@renderer/types'
|
||||||
import { documentExts, imageExts, textExts } from '@shared/config/constant'
|
import { documentExts, imageExts, textExts } from '@shared/config/constant'
|
||||||
import { Tooltip } from 'antd'
|
import { Tooltip } from 'antd'
|
||||||
import { FC, useCallback, useImperativeHandle } from 'react'
|
import { FC, useCallback, useImperativeHandle, useMemo } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
|
|
||||||
export interface AttachmentButtonRef {
|
export interface AttachmentButtonRef {
|
||||||
@ -21,9 +21,11 @@ interface Props {
|
|||||||
|
|
||||||
const AttachmentButton: FC<Props> = ({ ref, model, files, setFiles, ToolbarButton, disabled }) => {
|
const AttachmentButton: FC<Props> = ({ ref, model, files, setFiles, ToolbarButton, disabled }) => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const extensions = isVisionModel(model)
|
|
||||||
? [...imageExts, ...documentExts, ...textExts]
|
const extensions = useMemo(
|
||||||
: [...documentExts, ...textExts]
|
() => (isVisionModel(model) ? [...imageExts, ...documentExts, ...textExts] : [...documentExts, ...textExts]),
|
||||||
|
[model]
|
||||||
|
)
|
||||||
|
|
||||||
const onSelectFile = useCallback(async () => {
|
const onSelectFile = useCallback(async () => {
|
||||||
const _files = await window.api.file.select({
|
const _files = await window.api.file.select({
|
||||||
@ -39,7 +41,7 @@ const AttachmentButton: FC<Props> = ({ ref, model, files, setFiles, ToolbarButto
|
|||||||
if (_files) {
|
if (_files) {
|
||||||
setFiles([...files, ..._files])
|
setFiles([...files, ..._files])
|
||||||
}
|
}
|
||||||
}, [files, setFiles])
|
}, [extensions, files, setFiles])
|
||||||
|
|
||||||
const openQuickPanel = useCallback(() => {
|
const openQuickPanel = useCallback(() => {
|
||||||
onSelectFile()
|
onSelectFile()
|
||||||
|
|||||||
@ -5,7 +5,9 @@ import 'katex/dist/contrib/mhchem'
|
|||||||
import MarkdownShadowDOMRenderer from '@renderer/components/MarkdownShadowDOMRenderer'
|
import MarkdownShadowDOMRenderer from '@renderer/components/MarkdownShadowDOMRenderer'
|
||||||
import { useSettings } from '@renderer/hooks/useSettings'
|
import { useSettings } from '@renderer/hooks/useSettings'
|
||||||
import type { Message } from '@renderer/types'
|
import type { Message } from '@renderer/types'
|
||||||
|
import { parseJSON } from '@renderer/utils'
|
||||||
import { escapeBrackets, removeSvgEmptyLines, withGeminiGrounding } from '@renderer/utils/formats'
|
import { escapeBrackets, removeSvgEmptyLines, withGeminiGrounding } from '@renderer/utils/formats'
|
||||||
|
import { findCitationInChildren } from '@renderer/utils/markdown'
|
||||||
import { isEmpty } from 'lodash'
|
import { isEmpty } from 'lodash'
|
||||||
import { type FC, useMemo } from 'react'
|
import { type FC, useMemo } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
@ -51,44 +53,13 @@ const Markdown: FC<Props> = ({ message }) => {
|
|||||||
|
|
||||||
const components = useMemo(() => {
|
const components = useMemo(() => {
|
||||||
const baseComponents = {
|
const baseComponents = {
|
||||||
a: (props: any) => {
|
a: (props: any) => <Link {...props} citationData={parseJSON(findCitationInChildren(props.children))} />,
|
||||||
// 更彻底的查找方法,递归搜索所有子元素
|
|
||||||
const findCitationInChildren = (children) => {
|
|
||||||
if (!children) return null
|
|
||||||
|
|
||||||
// 直接搜索子元素
|
|
||||||
for (const child of Array.isArray(children) ? children : [children]) {
|
|
||||||
if (typeof child === 'object' && child?.props?.['data-citation']) {
|
|
||||||
return child.props['data-citation']
|
|
||||||
}
|
|
||||||
|
|
||||||
// 递归查找更深层次
|
|
||||||
if (typeof child === 'object' && child?.props?.children) {
|
|
||||||
const found = findCitationInChildren(child.props.children)
|
|
||||||
if (found) return found
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
// 然后在组件中使用
|
|
||||||
const citationData = findCitationInChildren(props.children)
|
|
||||||
if (citationData) {
|
|
||||||
try {
|
|
||||||
return <Link {...props} citationData={JSON.parse(citationData)} />
|
|
||||||
} catch (e) {
|
|
||||||
console.error('Failed to parse citation data', e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return <Link {...props} />
|
|
||||||
},
|
|
||||||
code: CodeBlock,
|
code: CodeBlock,
|
||||||
img: ImagePreview,
|
img: ImagePreview,
|
||||||
pre: (props: any) => <pre style={{ overflow: 'visible' }} {...props} />
|
pre: (props: any) => <pre style={{ overflow: 'visible' }} {...props} />
|
||||||
} as Partial<Components>
|
} as Partial<Components>
|
||||||
return baseComponents
|
return baseComponents
|
||||||
}, [messageContent])
|
}, [])
|
||||||
|
|
||||||
if (message.role === 'user' && !renderInputMessageAsMarkdown) {
|
if (message.role === 'user' && !renderInputMessageAsMarkdown) {
|
||||||
return <p style={{ marginBottom: 5, whiteSpace: 'pre-wrap' }}>{messageContent}</p>
|
return <p style={{ marginBottom: 5, whiteSpace: 'pre-wrap' }}>{messageContent}</p>
|
||||||
|
|||||||
@ -367,7 +367,27 @@ const Topics: FC<Props> = ({ assistant: _assistant, activeTopic, setActiveTopic
|
|||||||
|
|
||||||
return menus
|
return menus
|
||||||
},
|
},
|
||||||
[assistant, assistants, onClearMessages, onDeleteTopic, onPinTopic, onMoveTopic, t, updateTopic, exportMenuOptions]
|
[
|
||||||
|
activeTopic.id,
|
||||||
|
assistant,
|
||||||
|
assistants,
|
||||||
|
exportMenuOptions.docx,
|
||||||
|
exportMenuOptions.image,
|
||||||
|
exportMenuOptions.joplin,
|
||||||
|
exportMenuOptions.markdown,
|
||||||
|
exportMenuOptions.markdown_reason,
|
||||||
|
exportMenuOptions.notion,
|
||||||
|
exportMenuOptions.obsidian,
|
||||||
|
exportMenuOptions.siyuan,
|
||||||
|
exportMenuOptions.yuque,
|
||||||
|
onClearMessages,
|
||||||
|
onDeleteTopic,
|
||||||
|
onMoveTopic,
|
||||||
|
onPinTopic,
|
||||||
|
setActiveTopic,
|
||||||
|
t,
|
||||||
|
updateTopic
|
||||||
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
19
src/renderer/src/utils/markdown.ts
Normal file
19
src/renderer/src/utils/markdown.ts
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
// 更彻底的查找方法,递归搜索所有子元素
|
||||||
|
export const findCitationInChildren = (children) => {
|
||||||
|
if (!children) return null
|
||||||
|
|
||||||
|
// 直接搜索子元素
|
||||||
|
for (const child of Array.isArray(children) ? children : [children]) {
|
||||||
|
if (typeof child === 'object' && child?.props?.['data-citation']) {
|
||||||
|
return child.props['data-citation']
|
||||||
|
}
|
||||||
|
|
||||||
|
// 递归查找更深层次
|
||||||
|
if (typeof child === 'object' && child?.props?.children) {
|
||||||
|
const found = findCitationInChildren(child.props.children)
|
||||||
|
if (found) return found
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user