fix: citation list loading (#5742)
* fix: citation loading Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com> * fix: remove unused import & cleanup some code --------- Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>
This commit is contained in:
@@ -167,7 +167,7 @@ interface ChatFlowHistoryProps {
|
||||
}
|
||||
|
||||
// 定义节点和边的类型
|
||||
type FlowNode = Node<any, string>
|
||||
type FlowNode = Node<any>
|
||||
type FlowEdge = Edge<any>
|
||||
|
||||
// 统一的边样式
|
||||
|
||||
@@ -5,6 +5,7 @@ import { Button, Drawer } from 'antd'
|
||||
import { FileSearch } from 'lucide-react'
|
||||
import React, { useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { QueryClient, QueryClientProvider } from 'react-query'
|
||||
import styled from 'styled-components'
|
||||
|
||||
export interface Citation {
|
||||
@@ -21,6 +22,17 @@ interface CitationsListProps {
|
||||
citations: Citation[]
|
||||
}
|
||||
|
||||
const queryClient = new QueryClient({
|
||||
defaultOptions: {
|
||||
queries: {
|
||||
staleTime: Infinity,
|
||||
cacheTime: Infinity,
|
||||
refetchOnWindowFocus: false,
|
||||
retry: false
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
/**
|
||||
* 限制文本长度
|
||||
* @param text
|
||||
@@ -50,61 +62,49 @@ const CitationsList: React.FC<CitationsListProps> = ({ citations }) => {
|
||||
const { t } = useTranslation()
|
||||
const [open, setOpen] = useState(false)
|
||||
|
||||
const hasCitations = citations.length > 0
|
||||
const count = citations.length
|
||||
const previewItems = citations.slice(0, 3)
|
||||
|
||||
if (!hasCitations) return null
|
||||
|
||||
const handleOpen = () => {
|
||||
setOpen(true)
|
||||
}
|
||||
|
||||
const handleClose = () => {
|
||||
setOpen(false)
|
||||
}
|
||||
const count = citations.length
|
||||
if (!count) return null
|
||||
|
||||
return (
|
||||
<>
|
||||
<OpenButton type="text" onClick={handleOpen}>
|
||||
<PreviewIcons>
|
||||
{previewItems.map((c, i) => (
|
||||
<PreviewIcon key={i} style={{ zIndex: previewItems.length - i }}>
|
||||
{c.type === 'websearch' && c.url ? (
|
||||
<Favicon hostname={new URL(c.url).hostname} alt={''} />
|
||||
) : (
|
||||
<FileSearch width={16} />
|
||||
)}
|
||||
</PreviewIcon>
|
||||
))}
|
||||
</PreviewIcons>
|
||||
{t('message.citation', { count: count })}
|
||||
</OpenButton>
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<>
|
||||
<OpenButton type="text" onClick={() => setOpen(true)}>
|
||||
<PreviewIcons>
|
||||
{previewItems.map((c, i) => (
|
||||
<PreviewIcon key={i} style={{ zIndex: previewItems.length - i }}>
|
||||
{c.type === 'websearch' && c.url ? (
|
||||
<Favicon hostname={new URL(c.url).hostname} alt={c.title || ''} />
|
||||
) : (
|
||||
<FileSearch width={16} />
|
||||
)}
|
||||
</PreviewIcon>
|
||||
))}
|
||||
</PreviewIcons>
|
||||
{t('message.citation', { count })}
|
||||
</OpenButton>
|
||||
|
||||
<Drawer
|
||||
title={t('message.citations')}
|
||||
placement="right"
|
||||
onClose={handleClose}
|
||||
open={open}
|
||||
width={680}
|
||||
destroyOnClose
|
||||
styles={{
|
||||
body: {
|
||||
padding: 16,
|
||||
height: 'calc(100% - 55px)'
|
||||
}
|
||||
}}>
|
||||
{citations.map((citation) => (
|
||||
<HStack key={citation.url || citation.number} style={{ alignItems: 'center', gap: 8, marginBottom: 12 }}>
|
||||
{citation.type === 'websearch' ? (
|
||||
<WebSearchCitation citation={citation} />
|
||||
) : (
|
||||
<KnowledgeCitation citation={citation} />
|
||||
)}
|
||||
</HStack>
|
||||
))}
|
||||
</Drawer>
|
||||
</>
|
||||
<Drawer
|
||||
title={t('message.citations')}
|
||||
placement="right"
|
||||
onClose={() => setOpen(false)}
|
||||
open={open}
|
||||
width={680}
|
||||
destroyOnClose={true} // unmount on close
|
||||
>
|
||||
{open &&
|
||||
citations.map((citation) => (
|
||||
<HStack key={citation.url || citation.number} style={{ alignItems: 'center', gap: 8, marginBottom: 12 }}>
|
||||
{citation.type === 'websearch' ? (
|
||||
<WebSearchCitation citation={citation} />
|
||||
) : (
|
||||
<KnowledgeCitation citation={citation} />
|
||||
)}
|
||||
</HStack>
|
||||
))}
|
||||
</Drawer>
|
||||
</>
|
||||
</QueryClientProvider>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -212,14 +212,14 @@ const WebSearchCard = styled.div`
|
||||
padding: 12px;
|
||||
margin-bottom: 8px;
|
||||
border-radius: 8px;
|
||||
border: 1px solid var(--color-border);
|
||||
background-color: var(--color-bg-2);
|
||||
border: 1px solid #e5e6eb;
|
||||
background-color: #f8f9fa;
|
||||
transition: all 0.3s ease;
|
||||
|
||||
&:hover {
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
||||
background-color: var(--color-bg-3);
|
||||
border-color: var(--color-primary-light);
|
||||
background-color: #f1f3f5;
|
||||
border-color: rgba(24, 144, 255, 0.1);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
`
|
||||
|
||||
@@ -264,22 +264,22 @@ const Topics: FC<Props> = ({ assistant: _assistant, activeTopic, setActiveTopic
|
||||
key: 'export',
|
||||
icon: <UploadOutlined />,
|
||||
children: [
|
||||
exportMenuOptions.image !== false && {
|
||||
exportMenuOptions.image && {
|
||||
label: t('chat.topics.export.image'),
|
||||
key: 'image',
|
||||
onClick: () => EventEmitter.emit(EVENT_NAMES.EXPORT_TOPIC_IMAGE, topic)
|
||||
},
|
||||
exportMenuOptions.markdown !== false && {
|
||||
exportMenuOptions.markdown && {
|
||||
label: t('chat.topics.export.md'),
|
||||
key: 'markdown',
|
||||
onClick: () => exportTopicAsMarkdown(topic)
|
||||
},
|
||||
exportMenuOptions.markdown_reason !== false && {
|
||||
exportMenuOptions.markdown_reason && {
|
||||
label: t('chat.topics.export.md.reason'),
|
||||
key: 'markdown_reason',
|
||||
onClick: () => exportTopicAsMarkdown(topic, true)
|
||||
},
|
||||
exportMenuOptions.docx !== false && {
|
||||
exportMenuOptions.docx && {
|
||||
label: t('chat.topics.export.word'),
|
||||
key: 'word',
|
||||
onClick: async () => {
|
||||
@@ -287,14 +287,14 @@ const Topics: FC<Props> = ({ assistant: _assistant, activeTopic, setActiveTopic
|
||||
window.api.export.toWord(markdown, removeSpecialCharactersForFileName(topic.name))
|
||||
}
|
||||
},
|
||||
exportMenuOptions.notion !== false && {
|
||||
exportMenuOptions.notion && {
|
||||
label: t('chat.topics.export.notion'),
|
||||
key: 'notion',
|
||||
onClick: async () => {
|
||||
exportTopicToNotion(topic)
|
||||
}
|
||||
},
|
||||
exportMenuOptions.yuque !== false && {
|
||||
exportMenuOptions.yuque && {
|
||||
label: t('chat.topics.export.yuque'),
|
||||
key: 'yuque',
|
||||
onClick: async () => {
|
||||
@@ -302,7 +302,7 @@ const Topics: FC<Props> = ({ assistant: _assistant, activeTopic, setActiveTopic
|
||||
exportMarkdownToYuque(topic.name, markdown)
|
||||
}
|
||||
},
|
||||
exportMenuOptions.obsidian !== false && {
|
||||
exportMenuOptions.obsidian && {
|
||||
label: t('chat.topics.export.obsidian'),
|
||||
key: 'obsidian',
|
||||
onClick: async () => {
|
||||
@@ -310,7 +310,7 @@ const Topics: FC<Props> = ({ assistant: _assistant, activeTopic, setActiveTopic
|
||||
await ObsidianExportPopup.show({ title: topic.name, markdown, processingMethod: '3' })
|
||||
}
|
||||
},
|
||||
exportMenuOptions.joplin !== false && {
|
||||
exportMenuOptions.joplin && {
|
||||
label: t('chat.topics.export.joplin'),
|
||||
key: 'joplin',
|
||||
onClick: async () => {
|
||||
@@ -318,7 +318,7 @@ const Topics: FC<Props> = ({ assistant: _assistant, activeTopic, setActiveTopic
|
||||
exportMarkdownToJoplin(topic.name, markdown)
|
||||
}
|
||||
},
|
||||
exportMenuOptions.siyuan !== false && {
|
||||
exportMenuOptions.siyuan && {
|
||||
label: t('chat.topics.export.siyuan'),
|
||||
key: 'siyuan',
|
||||
onClick: async () => {
|
||||
|
||||
@@ -193,7 +193,7 @@ const formatCitationsFromBlock = (block: CitationMessageBlock | undefined): Cita
|
||||
|
||||
let url = result.sourceUrl
|
||||
let title = result.sourceUrl
|
||||
let showFavicon = true
|
||||
const showFavicon = true
|
||||
|
||||
// 如果匹配文件链接格式 [filename](http://file/xxx)
|
||||
if (fileMatch) {
|
||||
|
||||
Reference in New Issue
Block a user