feat: delete all topic

This commit is contained in:
kangfenmao 2024-07-02 17:35:02 +08:00
parent 90e3195e29
commit 0b6d15ec65
7 changed files with 90 additions and 28 deletions

View File

@ -1,6 +1,7 @@
import { useAppDispatch, useAppSelector } from '@renderer/store' import { useAppDispatch, useAppSelector } from '@renderer/store'
import { import {
addTopic as _addTopic, addTopic as _addTopic,
removeAllTopics as _removeAllTopics,
removeTopic as _removeTopic, removeTopic as _removeTopic,
updateTopic as _updateTopic, updateTopic as _updateTopic,
addAgent, addAgent,
@ -35,13 +36,16 @@ export function useAgent(id: string) {
return { return {
agent, agent,
addTopic: (topic: Topic) => { addTopic: (topic: Topic) => {
dispatch(_addTopic({ agentId: agent?.id, topic })) dispatch(_addTopic({ agentId: agent.id, topic }))
}, },
removeTopic: (topic: Topic) => { removeTopic: (topic: Topic) => {
dispatch(_removeTopic({ agentId: agent?.id, topic })) dispatch(_removeTopic({ agentId: agent.id, topic }))
}, },
updateTopic: (topic: Topic) => { updateTopic: (topic: Topic) => {
dispatch(_updateTopic({ agentId: agent?.id, topic })) dispatch(_updateTopic({ agentId: agent.id, topic }))
},
removeAllTopics: () => {
dispatch(_removeAllTopics({ agentId: agent.id }))
} }
} }
} }

View File

@ -7,10 +7,10 @@ import MessageItem from './Message'
import { reverse } from 'lodash' import { reverse } from 'lodash'
import hljs from 'highlight.js' import hljs from 'highlight.js'
import { fetchChatCompletion, fetchConversationSummary } from '@renderer/services/api' import { fetchChatCompletion, fetchConversationSummary } from '@renderer/services/api'
import { getTopicMessages } from '@renderer/services/topic'
import { useAgent } from '@renderer/hooks/useAgents' import { useAgent } from '@renderer/hooks/useAgents'
import { DEFAULT_TOPIC_NAME } from '@renderer/config/constant' import { DEFAULT_TOPIC_NAME } from '@renderer/config/constant'
import { runAsyncFunction } from '@renderer/utils' import { runAsyncFunction } from '@renderer/utils'
import LocalStorage from '@renderer/services/storage'
interface Props { interface Props {
agent: Agent agent: Agent
@ -61,7 +61,7 @@ const Conversations: FC<Props> = ({ agent, topic }) => {
useEffect(() => { useEffect(() => {
runAsyncFunction(async () => { runAsyncFunction(async () => {
const messages = await getTopicMessages(topic.id) const messages = await LocalStorage.getTopicMessages(topic.id)
setMessages(messages) setMessages(messages)
}) })
}, [topic.id]) }, [topic.id])

View File

@ -2,11 +2,12 @@ import PromptPopup from '@renderer/components/Popups/PromptPopup'
import { useAgent } from '@renderer/hooks/useAgents' import { useAgent } from '@renderer/hooks/useAgents'
import { useShowRightSidebar } from '@renderer/hooks/useStore' import { useShowRightSidebar } from '@renderer/hooks/useStore'
import { fetchConversationSummary } from '@renderer/services/api' import { fetchConversationSummary } from '@renderer/services/api'
import { getTopicMessages } from '@renderer/services/topic'
import { Agent, Topic } from '@renderer/types' import { Agent, Topic } from '@renderer/types'
import { Dropdown, MenuProps } from 'antd' import { Button, Dropdown, MenuProps, Popconfirm } from 'antd'
import { FC, useRef } from 'react' import { FC, useRef } from 'react'
import styled from 'styled-components' import styled from 'styled-components'
import { DeleteOutlined } from '@ant-design/icons'
import LocalStorage from '@renderer/services/storage'
interface Props { interface Props {
agent: Agent agent: Agent
@ -16,16 +17,16 @@ interface Props {
const TopicList: FC<Props> = ({ agent, activeTopic, setActiveTopic }) => { const TopicList: FC<Props> = ({ agent, activeTopic, setActiveTopic }) => {
const { showRightSidebar } = useShowRightSidebar() const { showRightSidebar } = useShowRightSidebar()
const { removeTopic, updateTopic } = useAgent(agent.id) const { removeTopic, updateTopic, removeAllTopics } = useAgent(agent.id)
const currentTopic = useRef<Topic | null>(null) const currentTopic = useRef<Topic | null>(null)
const items: MenuProps['items'] = [ const topicMenuItems: MenuProps['items'] = [
{ {
label: 'AI Rename', label: 'AI Rename',
key: 'ai-rename', key: 'ai-rename',
async onClick() { async onClick() {
if (currentTopic.current) { if (currentTopic.current) {
const messages = await getTopicMessages(currentTopic.current.id) const messages = await LocalStorage.getTopicMessages(currentTopic.current.id)
if (messages.length >= 2) { if (messages.length >= 2) {
const summaryText = await fetchConversationSummary({ messages }) const summaryText = await fetchConversationSummary({ messages })
if (summaryText) { if (summaryText) {
@ -52,8 +53,8 @@ const TopicList: FC<Props> = ({ agent, activeTopic, setActiveTopic }) => {
] ]
if (agent.topics.length > 1) { if (agent.topics.length > 1) {
items.push({ type: 'divider' }) topicMenuItems.push({ type: 'divider' })
items.push({ topicMenuItems.push({
label: 'Delete', label: 'Delete',
danger: true, danger: true,
key: 'delete', key: 'delete',
@ -72,10 +73,23 @@ const TopicList: FC<Props> = ({ agent, activeTopic, setActiveTopic }) => {
return ( return (
<Container className={showRightSidebar ? '' : 'collapsed'}> <Container className={showRightSidebar ? '' : 'collapsed'}>
<TopicTitle>Topics ({agent.topics.length})</TopicTitle> <TopicTitle>
<span>Topics ({agent.topics.length})</span>
<Popconfirm
title="Delete all topic?"
description="Are you sure to delete all topics?"
placement="leftBottom"
onConfirm={removeAllTopics}
okText="Yes"
cancelText="No">
<DeleteButton type="text">
<DeleteIcon />
</DeleteButton>
</Popconfirm>
</TopicTitle>
{agent.topics.map((topic) => ( {agent.topics.map((topic) => (
<Dropdown <Dropdown
menu={{ items }} menu={{ items: topicMenuItems }}
trigger={['contextMenu']} trigger={['contextMenu']}
key={topic.id} key={topic.id}
onOpenChange={(open) => open && (currentTopic.current = topic)}> onOpenChange={(open) => open && (currentTopic.current = topic)}>
@ -118,6 +132,26 @@ const TopicTitle = styled.div`
margin-bottom: 10px; margin-bottom: 10px;
font-size: 14px; font-size: 14px;
color: var(--color-text-1); color: var(--color-text-1);
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
`
const DeleteButton = styled(Button)`
width: 30px;
height: 30px;
border-radius: 50%;
padding: 0;
&:hover {
.anticon {
color: #ff4d4f;
}
}
`
const DeleteIcon = styled(DeleteOutlined)`
font-size: 16px;
` `
export default TopicList export default TopicList

View File

@ -1,6 +1,5 @@
import { DEFAULT_TOPIC_NAME } from '@renderer/config/constant'
import { Agent } from '@renderer/types' import { Agent } from '@renderer/types'
import { uuid } from '@renderer/utils' import { getDefaultTopic } from './topic'
export function getDefaultAgent(): Agent { export function getDefaultAgent(): Agent {
return { return {
@ -8,12 +7,6 @@ export function getDefaultAgent(): Agent {
name: 'Default Agent', name: 'Default Agent',
description: "Hello, I'm Default Agent.", description: "Hello, I'm Default Agent.",
prompt: '', prompt: '',
topics: [ topics: [getDefaultTopic()]
{
id: uuid(),
name: DEFAULT_TOPIC_NAME,
messages: []
}
]
} }
} }

View File

@ -0,0 +1,13 @@
import { Topic } from '@renderer/types'
import localforage from 'localforage'
export default class LocalStorage {
static async getTopicMessages(id: string) {
const topic = await localforage.getItem<Topic>(`topic:${id}`)
return topic ? topic.messages : []
}
static async removeTopic(id: string) {
localforage.removeItem(`topic:${id}`)
}
}

View File

@ -1,7 +1,10 @@
import { Topic } from '@renderer/types' import { Topic } from '@renderer/types'
import localforage from 'localforage' import { uuid } from '@renderer/utils'
export async function getTopicMessages(id: string) { export function getDefaultTopic(): Topic {
const topic = await localforage.getItem<Topic>(`topic:${id}`) return {
return topic ? topic.messages : [] id: uuid(),
name: 'Default Topic',
messages: []
}
} }

View File

@ -1,5 +1,7 @@
import { createSlice, PayloadAction } from '@reduxjs/toolkit' import { createSlice, PayloadAction } from '@reduxjs/toolkit'
import { getDefaultAgent } from '@renderer/services/agent' import { getDefaultAgent } from '@renderer/services/agent'
import LocalStorage from '@renderer/services/storage'
import { getDefaultTopic } from '@renderer/services/topic'
import { Agent, Topic } from '@renderer/types' import { Agent, Topic } from '@renderer/types'
import { uniqBy } from 'lodash' import { uniqBy } from 'lodash'
@ -53,10 +55,23 @@ const agentsSlice = createSlice({
} }
: agent : agent
) )
},
removeAllTopics: (state, action: PayloadAction<{ agentId: string }>) => {
state.agents = state.agents.map((agent) => {
if (agent.id === action.payload.agentId) {
agent.topics.forEach((topic) => LocalStorage.removeTopic(topic.id))
return {
...agent,
topics: [getDefaultTopic()]
}
}
return agent
})
} }
} }
}) })
export const { addAgent, removeAgent, updateAgent, addTopic, removeTopic, updateTopic } = agentsSlice.actions export const { addAgent, removeAgent, updateAgent, addTopic, removeTopic, updateTopic, removeAllTopics } =
agentsSlice.actions
export default agentsSlice.reducer export default agentsSlice.reducer