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:
kangfenmao 2025-04-06 10:49:47 +08:00
parent 8501ab82c6
commit d74f05f27e
4 changed files with 51 additions and 39 deletions

View File

@ -3,7 +3,7 @@ import { isVisionModel } from '@renderer/config/models'
import { FileType, Model } from '@renderer/types'
import { documentExts, imageExts, textExts } from '@shared/config/constant'
import { Tooltip } from 'antd'
import { FC, useCallback, useImperativeHandle } from 'react'
import { FC, useCallback, useImperativeHandle, useMemo } from 'react'
import { useTranslation } from 'react-i18next'
export interface AttachmentButtonRef {
@ -21,9 +21,11 @@ interface Props {
const AttachmentButton: FC<Props> = ({ ref, model, files, setFiles, ToolbarButton, disabled }) => {
const { t } = useTranslation()
const extensions = isVisionModel(model)
? [...imageExts, ...documentExts, ...textExts]
: [...documentExts, ...textExts]
const extensions = useMemo(
() => (isVisionModel(model) ? [...imageExts, ...documentExts, ...textExts] : [...documentExts, ...textExts]),
[model]
)
const onSelectFile = useCallback(async () => {
const _files = await window.api.file.select({
@ -39,7 +41,7 @@ const AttachmentButton: FC<Props> = ({ ref, model, files, setFiles, ToolbarButto
if (_files) {
setFiles([...files, ..._files])
}
}, [files, setFiles])
}, [extensions, files, setFiles])
const openQuickPanel = useCallback(() => {
onSelectFile()

View File

@ -5,7 +5,9 @@ import 'katex/dist/contrib/mhchem'
import MarkdownShadowDOMRenderer from '@renderer/components/MarkdownShadowDOMRenderer'
import { useSettings } from '@renderer/hooks/useSettings'
import type { Message } from '@renderer/types'
import { parseJSON } from '@renderer/utils'
import { escapeBrackets, removeSvgEmptyLines, withGeminiGrounding } from '@renderer/utils/formats'
import { findCitationInChildren } from '@renderer/utils/markdown'
import { isEmpty } from 'lodash'
import { type FC, useMemo } from 'react'
import { useTranslation } from 'react-i18next'
@ -51,44 +53,13 @@ const Markdown: FC<Props> = ({ message }) => {
const components = useMemo(() => {
const baseComponents = {
a: (props: any) => {
// 更彻底的查找方法,递归搜索所有子元素
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} />
},
a: (props: any) => <Link {...props} citationData={parseJSON(findCitationInChildren(props.children))} />,
code: CodeBlock,
img: ImagePreview,
pre: (props: any) => <pre style={{ overflow: 'visible' }} {...props} />
} as Partial<Components>
return baseComponents
}, [messageContent])
}, [])
if (message.role === 'user' && !renderInputMessageAsMarkdown) {
return <p style={{ marginBottom: 5, whiteSpace: 'pre-wrap' }}>{messageContent}</p>

View File

@ -367,7 +367,27 @@ const Topics: FC<Props> = ({ assistant: _assistant, activeTopic, setActiveTopic
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 (

View 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
}