mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2026-01-03 19:30:04 +08:00
parent
662742c958
commit
348d0fb06a
@ -15,6 +15,7 @@ import {
|
|||||||
renameBase,
|
renameBase,
|
||||||
updateBase,
|
updateBase,
|
||||||
updateBases,
|
updateBases,
|
||||||
|
updateItem as updateItemAction,
|
||||||
updateItemProcessingStatus,
|
updateItemProcessingStatus,
|
||||||
updateNotes
|
updateNotes
|
||||||
} from '@renderer/store/knowledge'
|
} from '@renderer/store/knowledge'
|
||||||
@ -117,7 +118,8 @@ export const useKnowledge = (baseId: string) => {
|
|||||||
await db.knowledge_notes.put(updatedNote)
|
await db.knowledge_notes.put(updatedNote)
|
||||||
dispatch(updateNotes({ baseId, item: updatedNote }))
|
dispatch(updateNotes({ baseId, item: updatedNote }))
|
||||||
}
|
}
|
||||||
setTimeout(() => KnowledgeQueue.checkAllBases(), 0)
|
const noteItem = base?.items.find((item) => item.id === noteId)
|
||||||
|
noteItem && refreshItem(noteItem)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取笔记内容
|
// 获取笔记内容
|
||||||
@ -125,6 +127,10 @@ export const useKnowledge = (baseId: string) => {
|
|||||||
return await db.knowledge_notes.get(noteId)
|
return await db.knowledge_notes.get(noteId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const updateItem = (item: KnowledgeItem) => {
|
||||||
|
dispatch(updateItemAction({ baseId, item }))
|
||||||
|
}
|
||||||
|
|
||||||
// 移除项目
|
// 移除项目
|
||||||
const removeItem = async (item: KnowledgeItem) => {
|
const removeItem = async (item: KnowledgeItem) => {
|
||||||
dispatch(removeItemAction({ baseId, item }))
|
dispatch(removeItemAction({ baseId, item }))
|
||||||
@ -138,6 +144,27 @@ export const useKnowledge = (baseId: string) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 刷新项目
|
||||||
|
const refreshItem = async (item: KnowledgeItem) => {
|
||||||
|
const status = getProcessingStatus(item.id)
|
||||||
|
|
||||||
|
if (status === 'pending' || status === 'processing') {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (base && item.uniqueId) {
|
||||||
|
await window.api.knowledgeBase.remove({ uniqueId: item.uniqueId, base: getKnowledgeBaseParams(base) })
|
||||||
|
updateItem({
|
||||||
|
...item,
|
||||||
|
processingStatus: 'pending',
|
||||||
|
processingProgress: 0,
|
||||||
|
processingError: '',
|
||||||
|
uniqueId: undefined
|
||||||
|
})
|
||||||
|
setTimeout(() => KnowledgeQueue.checkAllBases(), 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 更新处理状态
|
// 更新处理状态
|
||||||
const updateItemStatus = (itemId: string, status: ProcessingStatus, progress?: number, error?: string) => {
|
const updateItemStatus = (itemId: string, status: ProcessingStatus, progress?: number, error?: string) => {
|
||||||
dispatch(
|
dispatch(
|
||||||
@ -238,7 +265,9 @@ export const useKnowledge = (baseId: string) => {
|
|||||||
addNote,
|
addNote,
|
||||||
updateNoteContent,
|
updateNoteContent,
|
||||||
getNoteContent,
|
getNoteContent,
|
||||||
|
updateItem,
|
||||||
updateItemStatus,
|
updateItemStatus,
|
||||||
|
refreshItem,
|
||||||
getProcessingStatus,
|
getProcessingStatus,
|
||||||
getProcessingItemsByType,
|
getProcessingItemsByType,
|
||||||
clearCompleted,
|
clearCompleted,
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import {
|
|||||||
GlobalOutlined,
|
GlobalOutlined,
|
||||||
LinkOutlined,
|
LinkOutlined,
|
||||||
PlusOutlined,
|
PlusOutlined,
|
||||||
|
RedoOutlined,
|
||||||
SearchOutlined
|
SearchOutlined
|
||||||
} from '@ant-design/icons'
|
} from '@ant-design/icons'
|
||||||
import PromptPopup from '@renderer/components/Popups/PromptPopup'
|
import PromptPopup from '@renderer/components/Popups/PromptPopup'
|
||||||
@ -32,30 +33,6 @@ interface KnowledgeContentProps {
|
|||||||
|
|
||||||
const fileTypes = ['.pdf', '.docx', '.pptx', '.xlsx', '.txt', '.md']
|
const fileTypes = ['.pdf', '.docx', '.pptx', '.xlsx', '.txt', '.md']
|
||||||
|
|
||||||
const FlexColumn = styled.div`
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 8px;
|
|
||||||
`
|
|
||||||
|
|
||||||
const FlexAlignCenter = styled.div`
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 16px;
|
|
||||||
`
|
|
||||||
|
|
||||||
const ClickableSpan = styled.span`
|
|
||||||
cursor: pointer;
|
|
||||||
`
|
|
||||||
|
|
||||||
const FileIcon = styled(FileTextOutlined)`
|
|
||||||
font-size: 16px;
|
|
||||||
`
|
|
||||||
|
|
||||||
const BottomSpacer = styled.div`
|
|
||||||
min-height: 20px;
|
|
||||||
`
|
|
||||||
|
|
||||||
const KnowledgeContent: FC<KnowledgeContentProps> = ({ selectedBase }) => {
|
const KnowledgeContent: FC<KnowledgeContentProps> = ({ selectedBase }) => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const {
|
const {
|
||||||
@ -67,6 +44,7 @@ const KnowledgeContent: FC<KnowledgeContentProps> = ({ selectedBase }) => {
|
|||||||
directoryItems,
|
directoryItems,
|
||||||
addFiles,
|
addFiles,
|
||||||
updateNoteContent,
|
updateNoteContent,
|
||||||
|
refreshItem,
|
||||||
addUrl,
|
addUrl,
|
||||||
addSitemap,
|
addSitemap,
|
||||||
removeItem,
|
removeItem,
|
||||||
@ -245,7 +223,10 @@ const KnowledgeContent: FC<KnowledgeContentProps> = ({ selectedBase }) => {
|
|||||||
<ClickableSpan onClick={() => window.api.file.openPath(file.path)}>{file.origin_name}</ClickableSpan>
|
<ClickableSpan onClick={() => window.api.file.openPath(file.path)}>{file.origin_name}</ClickableSpan>
|
||||||
</ItemInfo>
|
</ItemInfo>
|
||||||
<FlexAlignCenter>
|
<FlexAlignCenter>
|
||||||
<StatusIcon sourceId={item.id} base={base} getProcessingStatus={getProcessingStatus} />
|
{item.uniqueId && <Button type="text" icon={<RefreshIcon />} onClick={() => refreshItem(item)} />}
|
||||||
|
<StatusIconWrapper>
|
||||||
|
<StatusIcon sourceId={item.id} base={base} getProcessingStatus={getProcessingStatus} />
|
||||||
|
</StatusIconWrapper>
|
||||||
<Button type="text" danger onClick={() => removeItem(item)} icon={<DeleteOutlined />} />
|
<Button type="text" danger onClick={() => removeItem(item)} icon={<DeleteOutlined />} />
|
||||||
</FlexAlignCenter>
|
</FlexAlignCenter>
|
||||||
</ItemContent>
|
</ItemContent>
|
||||||
@ -272,7 +253,10 @@ const KnowledgeContent: FC<KnowledgeContentProps> = ({ selectedBase }) => {
|
|||||||
</ClickableSpan>
|
</ClickableSpan>
|
||||||
</ItemInfo>
|
</ItemInfo>
|
||||||
<FlexAlignCenter>
|
<FlexAlignCenter>
|
||||||
<StatusIcon sourceId={item.id} base={base} getProcessingStatus={getProcessingStatus} />
|
{item.uniqueId && <Button type="text" icon={<RefreshIcon />} onClick={() => refreshItem(item)} />}
|
||||||
|
<StatusIconWrapper>
|
||||||
|
<StatusIcon sourceId={item.id} base={base} getProcessingStatus={getProcessingStatus} />
|
||||||
|
</StatusIconWrapper>
|
||||||
<Button type="text" danger onClick={() => removeItem(item)} icon={<DeleteOutlined />} />
|
<Button type="text" danger onClick={() => removeItem(item)} icon={<DeleteOutlined />} />
|
||||||
</FlexAlignCenter>
|
</FlexAlignCenter>
|
||||||
</ItemContent>
|
</ItemContent>
|
||||||
@ -299,7 +283,10 @@ const KnowledgeContent: FC<KnowledgeContentProps> = ({ selectedBase }) => {
|
|||||||
</a>
|
</a>
|
||||||
</ItemInfo>
|
</ItemInfo>
|
||||||
<FlexAlignCenter>
|
<FlexAlignCenter>
|
||||||
<StatusIcon sourceId={item.id} base={base} getProcessingStatus={getProcessingStatus} />
|
{item.uniqueId && <Button type="text" icon={<RefreshIcon />} onClick={() => refreshItem(item)} />}
|
||||||
|
<StatusIconWrapper>
|
||||||
|
<StatusIcon sourceId={item.id} base={base} getProcessingStatus={getProcessingStatus} />
|
||||||
|
</StatusIconWrapper>
|
||||||
<Button type="text" danger onClick={() => removeItem(item)} icon={<DeleteOutlined />} />
|
<Button type="text" danger onClick={() => removeItem(item)} icon={<DeleteOutlined />} />
|
||||||
</FlexAlignCenter>
|
</FlexAlignCenter>
|
||||||
</ItemContent>
|
</ItemContent>
|
||||||
@ -326,7 +313,10 @@ const KnowledgeContent: FC<KnowledgeContentProps> = ({ selectedBase }) => {
|
|||||||
</a>
|
</a>
|
||||||
</ItemInfo>
|
</ItemInfo>
|
||||||
<FlexAlignCenter>
|
<FlexAlignCenter>
|
||||||
<StatusIcon sourceId={item.id} base={base} getProcessingStatus={getProcessingStatus} />
|
{item.uniqueId && <Button type="text" icon={<RefreshIcon />} onClick={() => refreshItem(item)} />}
|
||||||
|
<StatusIconWrapper>
|
||||||
|
<StatusIcon sourceId={item.id} base={base} getProcessingStatus={getProcessingStatus} />
|
||||||
|
</StatusIconWrapper>
|
||||||
<Button type="text" danger onClick={() => removeItem(item)} icon={<DeleteOutlined />} />
|
<Button type="text" danger onClick={() => removeItem(item)} icon={<DeleteOutlined />} />
|
||||||
</FlexAlignCenter>
|
</FlexAlignCenter>
|
||||||
</ItemContent>
|
</ItemContent>
|
||||||
@ -351,7 +341,9 @@ const KnowledgeContent: FC<KnowledgeContentProps> = ({ selectedBase }) => {
|
|||||||
</ItemInfo>
|
</ItemInfo>
|
||||||
<FlexAlignCenter>
|
<FlexAlignCenter>
|
||||||
<Button type="text" onClick={() => handleEditNote(note)} icon={<EditOutlined />} />
|
<Button type="text" onClick={() => handleEditNote(note)} icon={<EditOutlined />} />
|
||||||
<StatusIcon sourceId={note.id} base={base} getProcessingStatus={getProcessingStatus} />
|
<StatusIconWrapper>
|
||||||
|
<StatusIcon sourceId={note.id} base={base} getProcessingStatus={getProcessingStatus} />
|
||||||
|
</StatusIconWrapper>
|
||||||
<Button type="text" danger onClick={() => removeItem(note)} icon={<DeleteOutlined />} />
|
<Button type="text" danger onClick={() => removeItem(note)} icon={<DeleteOutlined />} />
|
||||||
</FlexAlignCenter>
|
</FlexAlignCenter>
|
||||||
</ItemContent>
|
</ItemContent>
|
||||||
@ -478,4 +470,42 @@ const ModelInfo = styled.div`
|
|||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
|
const FlexColumn = styled.div`
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 8px;
|
||||||
|
`
|
||||||
|
|
||||||
|
const FlexAlignCenter = styled.div`
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
`
|
||||||
|
|
||||||
|
const ClickableSpan = styled.span`
|
||||||
|
cursor: pointer;
|
||||||
|
`
|
||||||
|
|
||||||
|
const FileIcon = styled(FileTextOutlined)`
|
||||||
|
font-size: 16px;
|
||||||
|
`
|
||||||
|
|
||||||
|
const BottomSpacer = styled.div`
|
||||||
|
min-height: 20px;
|
||||||
|
`
|
||||||
|
|
||||||
|
const StatusIconWrapper = styled.div`
|
||||||
|
width: 36px;
|
||||||
|
height: 36px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding-top: 2px;
|
||||||
|
`
|
||||||
|
|
||||||
|
const RefreshIcon = styled(RedoOutlined)`
|
||||||
|
font-size: 15px !important;
|
||||||
|
color: var(--color-text-2);
|
||||||
|
`
|
||||||
|
|
||||||
export default KnowledgeContent
|
export default KnowledgeContent
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
import { CheckCircleOutlined, CloseCircleOutlined } from '@ant-design/icons'
|
import { CheckCircleOutlined, CloseCircleOutlined } from '@ant-design/icons'
|
||||||
import { Center } from '@renderer/components/Layout'
|
|
||||||
import { KnowledgeBase, ProcessingStatus } from '@renderer/types'
|
import { KnowledgeBase, ProcessingStatus } from '@renderer/types'
|
||||||
import { Tooltip } from 'antd'
|
import { Tooltip } from 'antd'
|
||||||
import { FC } from 'react'
|
import { FC } from 'react'
|
||||||
@ -28,9 +27,7 @@ const StatusIcon: FC<StatusIconProps> = ({ sourceId, base, getProcessingStatus }
|
|||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<Tooltip title={t('knowledge.status_new')} placement="left">
|
<Tooltip title={t('knowledge.status_new')} placement="left">
|
||||||
<Center style={{ width: '16px', height: '16px' }}>
|
<StatusDot $status="new" />
|
||||||
<StatusDot $status="new" />
|
|
||||||
</Center>
|
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -66,8 +63,8 @@ const StatusIcon: FC<StatusIconProps> = ({ sourceId, base, getProcessingStatus }
|
|||||||
}
|
}
|
||||||
|
|
||||||
const StatusDot = styled.div<{ $status: 'pending' | 'processing' | 'new' }>`
|
const StatusDot = styled.div<{ $status: 'pending' | 'processing' | 'new' }>`
|
||||||
width: 8px;
|
width: 10px;
|
||||||
height: 8px;
|
height: 10px;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
background-color: ${(props) =>
|
background-color: ${(props) =>
|
||||||
props.$status === 'pending' ? '#faad14' : props.$status === 'new' ? '#918999' : '#1890ff'};
|
props.$status === 'pending' ? '#faad14' : props.$status === 'new' ? '#918999' : '#1890ff'};
|
||||||
|
|||||||
@ -89,6 +89,16 @@ const knowledgeSlice = createSlice({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
updateItem(state, action: PayloadAction<{ baseId: string; item: KnowledgeItem }>) {
|
||||||
|
const base = state.bases.find((b) => b.id === action.payload.baseId)
|
||||||
|
if (base) {
|
||||||
|
const index = base.items.findIndex((item) => item.id === action.payload.item.id)
|
||||||
|
if (index !== -1) {
|
||||||
|
base.items[index] = action.payload.item
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
addFiles(state, action: PayloadAction<{ baseId: string; items: KnowledgeItem[] }>) {
|
addFiles(state, action: PayloadAction<{ baseId: string; items: KnowledgeItem[] }>) {
|
||||||
const base = state.bases.find((b) => b.id === action.payload.baseId)
|
const base = state.bases.find((b) => b.id === action.payload.baseId)
|
||||||
if (base) {
|
if (base) {
|
||||||
@ -183,6 +193,7 @@ export const {
|
|||||||
addFiles,
|
addFiles,
|
||||||
updateNotes,
|
updateNotes,
|
||||||
removeItem,
|
removeItem,
|
||||||
|
updateItem,
|
||||||
updateItemProcessingStatus,
|
updateItemProcessingStatus,
|
||||||
clearCompletedProcessing,
|
clearCompletedProcessing,
|
||||||
clearAllProcessing,
|
clearAllProcessing,
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user