mirror of
https://github.com/EthanMarti/infio-copilot.git
synced 2026-01-16 08:21:55 +00:00
添加清理过时对话的功能,更新聊天管理器以支持删除旧版本,优化查找最新对话的逻辑,并在聊天历史视图中添加清理按钮。
This commit is contained in:
parent
923d98cae9
commit
cd65d6b3de
@ -1,4 +1,4 @@
|
||||
import { CheckSquare, Clock, Edit3, MessageSquare, Pencil, Search, Square, Trash2, CopyPlus } from 'lucide-react'
|
||||
import { CheckSquare, Clock, CopyPlus, MessageSquare, Pencil, Search, Sparkles, Square, Trash2 } from 'lucide-react'
|
||||
import { Notice } from 'obsidian'
|
||||
import React, { useMemo, useRef, useState } from 'react'
|
||||
|
||||
@ -23,6 +23,7 @@ const ChatHistoryView = ({
|
||||
deleteConversation,
|
||||
updateConversationTitle,
|
||||
chatList,
|
||||
cleanupOutdatedChats,
|
||||
} = useChatHistory()
|
||||
|
||||
// search term
|
||||
@ -37,6 +38,25 @@ const ChatHistoryView = ({
|
||||
|
||||
const titleInputRefs = useRef<Map<string, HTMLInputElement>>(new Map())
|
||||
|
||||
const handleCleanup = async () => {
|
||||
const confirmed = confirm('此操作将永久删除所有对话的历史版本,只保留最新版。这有助于清理数据,但操作不可撤销。确定要继续吗?')
|
||||
if (!confirmed) {
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
const count = await cleanupOutdatedChats()
|
||||
if (count > 0) {
|
||||
new Notice(`成功清理了 ${count} 个过时的对话文件。`)
|
||||
} else {
|
||||
new Notice('没有需要清理的对话文件。')
|
||||
}
|
||||
} catch (error) {
|
||||
new Notice('清理失败,请检查开发者控制台获取更多信息。')
|
||||
console.error('Failed to cleanup outdated chats', error)
|
||||
}
|
||||
}
|
||||
|
||||
// handle search
|
||||
const handleSearch = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setSearchTerm(e.target.value)
|
||||
@ -192,6 +212,14 @@ const ChatHistoryView = ({
|
||||
<h2>{t('chat.history.title')}</h2>
|
||||
</div>
|
||||
<div className="infio-chat-history-header-actions">
|
||||
<button
|
||||
onClick={handleCleanup}
|
||||
className="infio-chat-history-cleanup-btn"
|
||||
title={'清理历史版本'}
|
||||
>
|
||||
<Sparkles size={16} />
|
||||
清理
|
||||
</button>
|
||||
<button
|
||||
onClick={toggleSelectionMode}
|
||||
className={`infio-chat-history-selection-btn ${selectionMode ? 'active' : ''}`}
|
||||
@ -398,6 +426,7 @@ const ChatHistoryView = ({
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.infio-chat-history-cleanup-btn,
|
||||
.infio-chat-history-selection-btn {
|
||||
display: flex !important;
|
||||
align-items: center;
|
||||
@ -415,6 +444,7 @@ const ChatHistoryView = ({
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.infio-chat-history-cleanup-btn:hover,
|
||||
.infio-chat-history-selection-btn:hover {
|
||||
background-color: var(--background-modifier-hover, #f5f5f5);
|
||||
border-color: var(--background-modifier-border-hover, #d0d0d0);
|
||||
|
||||
@ -71,11 +71,15 @@ export class ChatManager extends AbstractJsonRepository<
|
||||
|
||||
public async findById(id: string): Promise<ChatConversation | null> {
|
||||
const allMetadata = await this.listMetadata()
|
||||
const targetMetadata = allMetadata.find((meta) => meta.id === id)
|
||||
const targetMetadatas = allMetadata.filter((meta) => meta.id === id)
|
||||
|
||||
if (!targetMetadata) return null
|
||||
if (targetMetadatas.length === 0) return null
|
||||
|
||||
return this.read(targetMetadata.fileName)
|
||||
// Sort by updatedAt descending to find the latest version
|
||||
targetMetadatas.sort((a, b) => b.updatedAt - a.updatedAt)
|
||||
const latestMetadata = targetMetadatas[0]
|
||||
|
||||
return this.read(latestMetadata.fileName)
|
||||
}
|
||||
|
||||
public async updateChat(
|
||||
@ -103,16 +107,65 @@ export class ChatManager extends AbstractJsonRepository<
|
||||
|
||||
public async deleteChat(id: string): Promise<boolean> {
|
||||
const allMetadata = await this.listMetadata()
|
||||
const targetMetadata = allMetadata.find((meta) => meta.id === id)
|
||||
if (!targetMetadata) return false
|
||||
const targetsToDelete = allMetadata.filter((meta) => meta.id === id)
|
||||
|
||||
if (targetsToDelete.length === 0) return false
|
||||
|
||||
// Delete all files associated with this ID
|
||||
await Promise.all(targetsToDelete.map(meta => this.delete(meta.fileName)))
|
||||
|
||||
await this.delete(targetMetadata.fileName)
|
||||
return true
|
||||
}
|
||||
|
||||
public async cleanupOutdatedChats(): Promise<number> {
|
||||
const allMetadata = await this.listMetadata()
|
||||
const chatsById = new Map<string, (ChatConversationMeta & { fileName: string })[]>()
|
||||
|
||||
// Group chats by ID
|
||||
for (const meta of allMetadata) {
|
||||
if (!chatsById.has(meta.id)) {
|
||||
chatsById.set(meta.id, [])
|
||||
}
|
||||
chatsById.get(meta.id)!.push(meta)
|
||||
}
|
||||
|
||||
const filesToDelete: string[] = []
|
||||
|
||||
// Find outdated files for each ID
|
||||
for (const chatGroup of chatsById.values()) {
|
||||
if (chatGroup.length > 1) {
|
||||
// Sort by date to find the newest
|
||||
chatGroup.sort((a, b) => b.updatedAt - a.updatedAt)
|
||||
// The first one is the latest, the rest are outdated
|
||||
const outdatedFiles = chatGroup.slice(1)
|
||||
for (const outdated of outdatedFiles) {
|
||||
filesToDelete.push(outdated.fileName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (filesToDelete.length > 0) {
|
||||
await Promise.all(filesToDelete.map(fileName => this.delete(fileName)))
|
||||
}
|
||||
|
||||
return filesToDelete.length
|
||||
}
|
||||
|
||||
public async listChats(): Promise<ChatConversationMeta[]> {
|
||||
const metadata = await this.listMetadata()
|
||||
const sorted = metadata.sort((a, b) => b.updatedAt - a.updatedAt)
|
||||
|
||||
// Use a Map to store the latest version of each chat by ID.
|
||||
const latestChats = new Map<string, ChatConversationMeta>()
|
||||
|
||||
for (const meta of metadata) {
|
||||
const existing = latestChats.get(meta.id)
|
||||
if (!existing || meta.updatedAt > existing.updatedAt) {
|
||||
latestChats.set(meta.id, meta)
|
||||
}
|
||||
}
|
||||
|
||||
const uniqueMetadata = Array.from(latestChats.values())
|
||||
const sorted = uniqueMetadata.sort((a, b) => b.updatedAt - a.updatedAt)
|
||||
return sorted
|
||||
}
|
||||
}
|
||||
|
||||
@ -17,6 +17,7 @@ type UseChatHistory = {
|
||||
getChatMessagesById: (id: string) => Promise<ChatMessage[] | null>
|
||||
updateConversationTitle: (id: string, title: string) => Promise<void>
|
||||
chatList: ChatConversationMeta[]
|
||||
cleanupOutdatedChats: () => Promise<number>
|
||||
}
|
||||
|
||||
export function useChatHistory(): UseChatHistory {
|
||||
@ -111,11 +112,18 @@ export function useChatHistory(): UseChatHistory {
|
||||
[chatManager, fetchChatList],
|
||||
)
|
||||
|
||||
const cleanupOutdatedChats = useCallback(async (): Promise<number> => {
|
||||
const count = await chatManager.cleanupOutdatedChats()
|
||||
await fetchChatList()
|
||||
return count
|
||||
}, [chatManager, fetchChatList])
|
||||
|
||||
return {
|
||||
createOrUpdateConversation,
|
||||
deleteConversation,
|
||||
getChatMessagesById,
|
||||
updateConversationTitle,
|
||||
chatList,
|
||||
cleanupOutdatedChats,
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user