mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2025-12-24 18:50:56 +08:00
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:
parent
26bade489c
commit
266a347dd2
@ -95,6 +95,7 @@
|
||||
"officeparser": "^4.1.1",
|
||||
"os-proxy-config": "^1.1.2",
|
||||
"proxy-agent": "^6.5.0",
|
||||
"react-query": "^3.39.3",
|
||||
"tar": "^7.4.3",
|
||||
"turndown": "^7.2.0",
|
||||
"turndown-plugin-gfm": "^1.0.2",
|
||||
|
||||
@ -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) {
|
||||
|
||||
110
yarn.lock
110
yarn.lock
@ -383,6 +383,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@babel/runtime@npm:^7.23.8, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.6.2":
|
||||
version: 7.27.1
|
||||
resolution: "@babel/runtime@npm:7.27.1"
|
||||
checksum: 10c0/530a7332f86ac5a7442250456823a930906911d895c0b743bf1852efc88a20a016ed4cd26d442d0ca40ae6d5448111e02a08dd638a4f1064b47d080e2875dc05
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@babel/template@npm:^7.26.9, @babel/template@npm:^7.27.0":
|
||||
version: 7.27.0
|
||||
resolution: "@babel/template@npm:7.27.0"
|
||||
@ -4418,6 +4425,7 @@ __metadata:
|
||||
react-i18next: "npm:^14.1.2"
|
||||
react-infinite-scroll-component: "npm:^6.1.0"
|
||||
react-markdown: "npm:^9.0.1"
|
||||
react-query: "npm:^3.39.3"
|
||||
react-redux: "npm:^9.1.2"
|
||||
react-router: "npm:6"
|
||||
react-router-dom: "npm:6"
|
||||
@ -5066,6 +5074,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"big-integer@npm:^1.6.16":
|
||||
version: 1.6.52
|
||||
resolution: "big-integer@npm:1.6.52"
|
||||
checksum: 10c0/9604224b4c2ab3c43c075d92da15863077a9f59e5d4205f4e7e76acd0cd47e8d469ec5e5dba8d9b32aa233951893b29329ca56ac80c20ce094b4a647a66abae0
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"bignumber.js@npm:^9.0.0":
|
||||
version: 9.2.1
|
||||
resolution: "bignumber.js@npm:9.2.1"
|
||||
@ -5183,6 +5198,22 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"broadcast-channel@npm:^3.4.1":
|
||||
version: 3.7.0
|
||||
resolution: "broadcast-channel@npm:3.7.0"
|
||||
dependencies:
|
||||
"@babel/runtime": "npm:^7.7.2"
|
||||
detect-node: "npm:^2.1.0"
|
||||
js-sha3: "npm:0.8.0"
|
||||
microseconds: "npm:0.2.0"
|
||||
nano-time: "npm:1.0.0"
|
||||
oblivious-set: "npm:1.0.0"
|
||||
rimraf: "npm:3.0.2"
|
||||
unload: "npm:2.2.0"
|
||||
checksum: 10c0/95978446f24c685be666f5508a91350bcd4075c08feda929d26c0c678fb24bd421901f19fa8d36cb6f5ed480a334072f3bdce48fa177a8cb29793d88693911cc
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"browser-image-compression@npm:^2.0.2":
|
||||
version: 2.0.2
|
||||
resolution: "browser-image-compression@npm:2.0.2"
|
||||
@ -6636,7 +6667,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"detect-node@npm:^2.0.4":
|
||||
"detect-node@npm:^2.0.4, detect-node@npm:^2.1.0":
|
||||
version: 2.1.0
|
||||
resolution: "detect-node@npm:2.1.0"
|
||||
checksum: 10c0/f039f601790f2e9d4654e499913259a798b1f5246ae24f86ab5e8bd4aaf3bce50484234c494f11fb00aecb0c6e2733aa7b1cf3f530865640b65fbbd65b2c4e09
|
||||
@ -10172,6 +10203,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"js-sha3@npm:0.8.0":
|
||||
version: 0.8.0
|
||||
resolution: "js-sha3@npm:0.8.0"
|
||||
checksum: 10c0/43a21dc7967c871bd2c46cb1c2ae97441a97169f324e509f382d43330d8f75cf2c96dba7c806ab08a425765a9c847efdd4bffbac2d99c3a4f3de6c0218f40533
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"js-tiktoken@npm:^1.0.12, js-tiktoken@npm:^1.0.14":
|
||||
version: 1.0.19
|
||||
resolution: "js-tiktoken@npm:1.0.19"
|
||||
@ -11075,6 +11113,16 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"match-sorter@npm:^6.0.2":
|
||||
version: 6.3.4
|
||||
resolution: "match-sorter@npm:6.3.4"
|
||||
dependencies:
|
||||
"@babel/runtime": "npm:^7.23.8"
|
||||
remove-accents: "npm:0.5.0"
|
||||
checksum: 10c0/35d2a6b6df003c677d9ec87ecd4683657638f5bce856f43f9cf90b03e357ed2f09813ebbac759defa7e7438706936dd34dc2bfe1a18771f7d2541f14d639b4ad
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"matcher@npm:^3.0.0":
|
||||
version: 3.0.0
|
||||
resolution: "matcher@npm:3.0.0"
|
||||
@ -12010,6 +12058,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"microseconds@npm:0.2.0":
|
||||
version: 0.2.0
|
||||
resolution: "microseconds@npm:0.2.0"
|
||||
checksum: 10c0/59dfae1c696c0bacd79603c4df7cd0dcc9e091b7c5556aaca9b0832017d3c0b40ad8f57ca25e0ee5709ef1973404448c4a2fea6c9c1fad7d9e197ff5c1c9c2d5
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"mime-db@npm:1.52.0":
|
||||
version: 1.52.0
|
||||
resolution: "mime-db@npm:1.52.0"
|
||||
@ -12357,6 +12412,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"nano-time@npm:1.0.0":
|
||||
version: 1.0.0
|
||||
resolution: "nano-time@npm:1.0.0"
|
||||
dependencies:
|
||||
big-integer: "npm:^1.6.16"
|
||||
checksum: 10c0/3bd12e0bcd30867178afdbe8053b3dde5fdd1c665ecd348bf879863049344fbaf05cbb1d7806a825b91efbca011ee115eee52e76fb38b7da9c97931cd9e61f15
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"nanoid@npm:^3.3.7, nanoid@npm:^3.3.8":
|
||||
version: 3.3.11
|
||||
resolution: "nanoid@npm:3.3.11"
|
||||
@ -12696,6 +12760,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"oblivious-set@npm:1.0.0":
|
||||
version: 1.0.0
|
||||
resolution: "oblivious-set@npm:1.0.0"
|
||||
checksum: 10c0/ca8640474ea1e1feb3b5c98d42f5649f114ac4513ef84774e724f22fc7e529f1de3e7f26a0d9593097ab8942ca0bb8c241f7c1bd63c3e33047dd49de3aca9805
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"office-text-extractor@npm:^3.0.3":
|
||||
version: 3.0.3
|
||||
resolution: "office-text-extractor@npm:3.0.3"
|
||||
@ -14503,6 +14574,24 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"react-query@npm:^3.39.3":
|
||||
version: 3.39.3
|
||||
resolution: "react-query@npm:3.39.3"
|
||||
dependencies:
|
||||
"@babel/runtime": "npm:^7.5.5"
|
||||
broadcast-channel: "npm:^3.4.1"
|
||||
match-sorter: "npm:^6.0.2"
|
||||
peerDependencies:
|
||||
react: ^16.8.0 || ^17.0.0 || ^18.0.0
|
||||
peerDependenciesMeta:
|
||||
react-dom:
|
||||
optional: true
|
||||
react-native:
|
||||
optional: true
|
||||
checksum: 10c0/319045ef31b9b02aa9b5446169a8c6f95cfe49406466b819cc85e41c29bfe5032d3732577efe56511278db41514772375d416a3e3976e8967c6e0972ff04dd2e
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"react-redux@npm:^8.1.3":
|
||||
version: 8.1.3
|
||||
resolution: "react-redux@npm:8.1.3"
|
||||
@ -14923,6 +15012,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"remove-accents@npm:0.5.0":
|
||||
version: 0.5.0
|
||||
resolution: "remove-accents@npm:0.5.0"
|
||||
checksum: 10c0/a75321aa1b53d9abe82637115a492770bfe42bb38ed258be748bf6795871202bc8b4badff22013494a7029f5a241057ad8d3f72adf67884dbe15a9e37e87adc4
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"repeat-string@npm:^1.0.0":
|
||||
version: 1.6.1
|
||||
resolution: "repeat-string@npm:1.6.1"
|
||||
@ -15124,7 +15220,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"rimraf@npm:^3.0.2":
|
||||
"rimraf@npm:3.0.2, rimraf@npm:^3.0.2":
|
||||
version: 3.0.2
|
||||
resolution: "rimraf@npm:3.0.2"
|
||||
dependencies:
|
||||
@ -17032,6 +17128,16 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"unload@npm:2.2.0":
|
||||
version: 2.2.0
|
||||
resolution: "unload@npm:2.2.0"
|
||||
dependencies:
|
||||
"@babel/runtime": "npm:^7.6.2"
|
||||
detect-node: "npm:^2.0.4"
|
||||
checksum: 10c0/0a4f86b502e7aa35d39c27373ebeaad4f2b7da793fb3d6308e5337aab541885cfe7b339ea4a1963477bf73fddabd5d69f4f47023dad71224b4b4a25611ef7dd8
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"unpipe@npm:1.0.0":
|
||||
version: 1.0.0
|
||||
resolution: "unpipe@npm:1.0.0"
|
||||
|
||||
Loading…
Reference in New Issue
Block a user