From 33dbc88d60357d1b2ab79cc9db9228d3dc24d6b5 Mon Sep 17 00:00:00 2001 From: kangfenmao Date: Fri, 28 Jun 2024 15:19:04 +0800 Subject: [PATCH] refactor: thread -> agent --- src/renderer/src/hooks/useAgents.ts | 31 +++++++++++ src/renderer/src/hooks/useThreads.ts | 31 ----------- src/renderer/src/pages/home/HomePage.tsx | 22 ++++---- .../components/{Threads.tsx => Agents.tsx} | 33 ++++++------ .../src/pages/home/components/Chat.tsx | 14 ++--- .../pages/home/components/Conversations.tsx | 14 ++--- .../src/pages/home/components/Inputbar.tsx | 10 ++-- .../src/services/{thread.ts => agent.ts} | 2 +- src/renderer/src/store/agents.ts | 52 +++++++++++++++++++ src/renderer/src/store/index.ts | 4 +- src/renderer/src/store/threads.ts | 52 ------------------- src/renderer/src/types/index.ts | 4 +- 12 files changed, 133 insertions(+), 136 deletions(-) create mode 100644 src/renderer/src/hooks/useAgents.ts delete mode 100644 src/renderer/src/hooks/useThreads.ts rename src/renderer/src/pages/home/components/{Threads.tsx => Agents.tsx} (66%) rename src/renderer/src/services/{thread.ts => agent.ts} (85%) create mode 100644 src/renderer/src/store/agents.ts delete mode 100644 src/renderer/src/store/threads.ts diff --git a/src/renderer/src/hooks/useAgents.ts b/src/renderer/src/hooks/useAgents.ts new file mode 100644 index 00000000..25178d1b --- /dev/null +++ b/src/renderer/src/hooks/useAgents.ts @@ -0,0 +1,31 @@ +import { useAppDispatch, useAppSelector } from '@renderer/store' +import { + addAgent, + addConversationToAgent, + removeAgent, + removeConversationFromAgent, + updateAgent +} from '@renderer/store/agents' +import { Agent } from '@renderer/types' +import { useState } from 'react' + +export default function useAgents() { + const { agents } = useAppSelector((state) => state.agents) + const [agentId, setAgentId] = useState(agents[0]?.id) + const dispatch = useAppDispatch() + + return { + agents, + agent: agents.find((t) => t.id === agentId), + setAgent: (agent: Agent) => setAgentId(agent.id), + addAgent: (agent: Agent) => dispatch(addAgent(agent)), + removeAgent: (id: string) => dispatch(removeAgent({ id })), + updateAgent: (agent: Agent) => dispatch(updateAgent(agent)), + addConversation: (agentId: string, conversationId: string) => { + dispatch(addConversationToAgent({ agentId, conversationId })) + }, + removeConversation: (agentId: string, conversationId: string) => { + dispatch(removeConversationFromAgent({ agentId, conversationId })) + } + } +} diff --git a/src/renderer/src/hooks/useThreads.ts b/src/renderer/src/hooks/useThreads.ts deleted file mode 100644 index 34d55ecb..00000000 --- a/src/renderer/src/hooks/useThreads.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { useAppDispatch, useAppSelector } from '@renderer/store' -import { - addConversationToThread, - addThread, - removeConversationFromThread, - removeThread, - updateThread -} from '@renderer/store/threads' -import { Thread } from '@renderer/types' -import { useState } from 'react' - -export default function useThreads() { - const { threads } = useAppSelector((state) => state.threads) - const [threadId, setThreadId] = useState(threads[0]?.id) - const dispatch = useAppDispatch() - - return { - threads, - thread: threads.find((t) => t.id === threadId), - setThread: (thread: Thread) => setThreadId(thread.id), - addThread: (thread: Thread) => dispatch(addThread(thread)), - removeThread: (id: string) => dispatch(removeThread({ id })), - updateThread: (thread: Thread) => dispatch(updateThread(thread)), - addConversation: (threadId: string, conversationId: string) => { - dispatch(addConversationToThread({ threadId, conversationId })) - }, - removeConversation: (threadId: string, conversationId: string) => { - dispatch(removeConversationFromThread({ threadId, conversationId })) - } - } -} diff --git a/src/renderer/src/pages/home/HomePage.tsx b/src/renderer/src/pages/home/HomePage.tsx index 6b507909..6a67052e 100644 --- a/src/renderer/src/pages/home/HomePage.tsx +++ b/src/renderer/src/pages/home/HomePage.tsx @@ -1,20 +1,20 @@ import { Navbar, NavbarCenter, NavbarLeft, NavbarRight } from '@renderer/components/app/Navbar' -import useThreads from '@renderer/hooks/useThreads' +import useAgents from '@renderer/hooks/useAgents' import { FC, useEffect } from 'react' import styled from 'styled-components' import Chat from './components/Chat' -import Threads from './components/Threads' +import Agents from './components/Agents' import { uuid } from '@renderer/utils' const HomePage: FC = () => { - const { threads, thread, setThread, addThread } = useThreads() + const { agents, agent, setAgent, addAgent } = useAgents() useEffect(() => { - !thread && threads[0] && setThread(threads[0]) - }, [thread, threads]) + !agent && agents[0] && setAgent(agents[0]) + }, [agent, agents]) const onCreateConversation = () => { - const _thread = { + const _agent = { id: uuid(), name: 'New conversation', avatar: 'https://www.gravatar.com/avatar/00000000000000000000000000000000?d=mp&f=y', @@ -22,8 +22,8 @@ const HomePage: FC = () => { lastMessageAt: 'now', conversations: [] } - addThread(_thread) - setThread(_thread) + addAgent(_agent) + setAgent(_agent) } return ( @@ -34,7 +34,7 @@ const HomePage: FC = () => { - {thread?.name} + {agent?.name} @@ -42,8 +42,8 @@ const HomePage: FC = () => { - - {thread && } + + {agent && } ) diff --git a/src/renderer/src/pages/home/components/Threads.tsx b/src/renderer/src/pages/home/components/Agents.tsx similarity index 66% rename from src/renderer/src/pages/home/components/Threads.tsx rename to src/renderer/src/pages/home/components/Agents.tsx index 1ae95ef0..99d0ad4f 100644 --- a/src/renderer/src/pages/home/components/Threads.tsx +++ b/src/renderer/src/pages/home/components/Agents.tsx @@ -2,32 +2,29 @@ import { FC } from 'react' import styled from 'styled-components' import { IconMore } from '@douyinfe/semi-icons' import { Dropdown } from '@douyinfe/semi-ui' -import useThreads from '@renderer/hooks/useThreads' +import useAgents from '@renderer/hooks/useAgents' -const Threads: FC = () => { - const { threads, thread, setThread, removeThread } = useThreads() +const Agents: FC = () => { + const { agents, setAgent, removeAgent } = useAgents() return ( - {threads.map((thread) => ( - setThread(thread)} - className={thread.id === thread?.id ? 'active' : ''}> + {agents.map((agent) => ( + setAgent(agent)} className={agent.id === agent?.id ? 'active' : ''}> - removeThread(thread.id)}>Delete + removeAgent(agent.id)}>Delete }> - {thread.name} - {thread.lastMessage} - {thread.lastMessageAt} - + {agent.name} + {agent.lastMessage} + {agent.lastMessageAt} + ))} ) @@ -47,7 +44,7 @@ const Container = styled.div` } ` -const ThreadItem = styled.div` +const AgentItem = styled.div` display: flex; flex-direction: column; padding: 10px; @@ -70,18 +67,18 @@ const ThreadItem = styled.div` margin-bottom: 10px; ` -const ThreadTime = styled.div` +const AgentTime = styled.div` font-size: 12px; color: var(--color-text-2); ` -const ThreadName = styled.div` +const AgentName = styled.div` font-size: 14px; color: var(--color-text-1); font-weight: bold; ` -const ThreadLastMessage = styled.div` +const AgentLastMessage = styled.div` font-size: 12px; line-height: 20px; color: var(--color-text-2); @@ -93,4 +90,4 @@ const ThreadLastMessage = styled.div` height: 20px; ` -export default Threads +export default Agents diff --git a/src/renderer/src/pages/home/components/Chat.tsx b/src/renderer/src/pages/home/components/Chat.tsx index feb1db44..d9b3c126 100644 --- a/src/renderer/src/pages/home/components/Chat.tsx +++ b/src/renderer/src/pages/home/components/Chat.tsx @@ -1,24 +1,24 @@ -import { Message, Thread } from '@renderer/types' +import { Message, Agent } from '@renderer/types' import { FC, useState } from 'react' import styled from 'styled-components' import Inputbar from './Inputbar' import Conversations from './Conversations' -import useThreads from '@renderer/hooks/useThreads' +import useAgents from '@renderer/hooks/useAgents' import { isEmpty } from 'lodash' import localforage from 'localforage' import { uuid } from '@renderer/utils' interface Props { - thread: Thread + agent: Agent } -const Chat: FC = ({ thread }) => { - const [conversationId] = useState(thread.conversations[0] || uuid()) +const Chat: FC = ({ agent }) => { + const [conversationId] = useState(agent.conversations[0] || uuid()) return ( - - + + ) } diff --git a/src/renderer/src/pages/home/components/Conversations.tsx b/src/renderer/src/pages/home/components/Conversations.tsx index 0fd9966d..fe33eb23 100644 --- a/src/renderer/src/pages/home/components/Conversations.tsx +++ b/src/renderer/src/pages/home/components/Conversations.tsx @@ -1,7 +1,7 @@ import { Avatar } from '@douyinfe/semi-ui' -import useThreads from '@renderer/hooks/useThreads' +import useAgents from '@renderer/hooks/useAgents' import { EVENT_NAMES, EventEmitter } from '@renderer/services/event' -import { Conversation, Message, Thread } from '@renderer/types' +import { Conversation, Message, Agent } from '@renderer/types' import { runAsyncFunction } from '@renderer/utils' import localforage from 'localforage' import { isEmpty } from 'lodash' @@ -9,19 +9,19 @@ import { FC, useEffect, useState } from 'react' import styled from 'styled-components' interface Props { - thread: Thread + agent: Agent conversationId: string } -const Conversations: FC = ({ thread, conversationId }) => { +const Conversations: FC = ({ agent, conversationId }) => { const [messages, setMessages] = useState([]) - const { addConversation } = useThreads() + const { addConversation } = useAgents() const onSendMessage = (message: Message) => { setMessages([...messages, message]) - if (isEmpty(thread?.conversations)) { - addConversation(thread.id, conversationId) + if (isEmpty(agent?.conversations)) { + addConversation(agent.id, conversationId) } localforage.setItem(`conversation:${conversationId}`, { diff --git a/src/renderer/src/pages/home/components/Inputbar.tsx b/src/renderer/src/pages/home/components/Inputbar.tsx index d8ce4c7b..b23cb45d 100644 --- a/src/renderer/src/pages/home/components/Inputbar.tsx +++ b/src/renderer/src/pages/home/components/Inputbar.tsx @@ -1,24 +1,24 @@ import { EVENT_NAMES, EventEmitter } from '@renderer/services/event' -import { Message, Thread } from '@renderer/types' +import { Message, Agent } from '@renderer/types' import { uuid } from '@renderer/utils' import { FC, useState } from 'react' import styled from 'styled-components' interface Props { - thread: Thread + agent: Agent } -const Inputbar: FC = ({ thread }) => { +const Inputbar: FC = ({ agent }) => { const [text, setText] = useState('') const handleKeyDown = (event: React.KeyboardEvent) => { if (event.key === 'Enter') { - const conversationId = thread.conversations[0] ? thread.conversations[0] : uuid() + const conversationId = agent.conversations[0] ? agent.conversations[0] : uuid() const message: Message = { id: uuid(), content: text, - threadId: thread.id, + agentId: agent.id, conversationId, createdAt: 'now' } diff --git a/src/renderer/src/services/thread.ts b/src/renderer/src/services/agent.ts similarity index 85% rename from src/renderer/src/services/thread.ts rename to src/renderer/src/services/agent.ts index d9db411f..78725c25 100644 --- a/src/renderer/src/services/thread.ts +++ b/src/renderer/src/services/agent.ts @@ -1,4 +1,4 @@ -export function getDefaultThread() { +export function getDefaultAgent() { return { id: 'default', name: 'Chat Assistant', diff --git a/src/renderer/src/store/agents.ts b/src/renderer/src/store/agents.ts new file mode 100644 index 00000000..555ff218 --- /dev/null +++ b/src/renderer/src/store/agents.ts @@ -0,0 +1,52 @@ +import { createSlice, PayloadAction } from '@reduxjs/toolkit' +import { getDefaultAgent } from '@renderer/services/agent' +import { Agent } from '@renderer/types' + +export interface AgentsState { + agents: Agent[] +} + +const initialState: AgentsState = { + agents: [getDefaultAgent()] +} + +const agentsSlice = createSlice({ + name: 'agents', + initialState, + reducers: { + addAgent: (state, action: PayloadAction) => { + state.agents.push(action.payload) + }, + removeAgent: (state, action: PayloadAction<{ id: string }>) => { + state.agents = state.agents.filter((c) => c.id !== action.payload.id) + }, + updateAgent: (state, action: PayloadAction) => { + state.agents = state.agents.map((c) => (c.id === action.payload.id ? action.payload : c)) + }, + addConversationToAgent: (state, action: PayloadAction<{ agentId: string; conversationId: string }>) => { + state.agents = state.agents.map((c) => + c.id === action.payload.agentId + ? { + ...c, + conversations: [...c.conversations, action.payload.conversationId] + } + : c + ) + }, + removeConversationFromAgent: (state, action: PayloadAction<{ agentId: string; conversationId: string }>) => { + state.agents = state.agents.map((c) => + c.id === action.payload.agentId + ? { + ...c, + conversations: c.conversations.filter((id) => id !== action.payload.conversationId) + } + : c + ) + } + } +}) + +export const { addAgent, removeAgent, updateAgent, addConversationToAgent, removeConversationFromAgent } = + agentsSlice.actions + +export default agentsSlice.reducer diff --git a/src/renderer/src/store/index.ts b/src/renderer/src/store/index.ts index e5674f6f..04ca1d4f 100644 --- a/src/renderer/src/store/index.ts +++ b/src/renderer/src/store/index.ts @@ -2,7 +2,7 @@ import { combineReducers, configureStore } from '@reduxjs/toolkit' import { useDispatch, useSelector, useStore } from 'react-redux' import { FLUSH, PAUSE, PERSIST, persistReducer, persistStore, PURGE, REGISTER, REHYDRATE } from 'redux-persist' import storage from 'redux-persist/lib/storage' -import threads from './threads' +import agents from './agents' const store = configureStore({ reducer: persistReducer( @@ -12,7 +12,7 @@ const store = configureStore({ version: 1 }, combineReducers({ - threads + agents }) ), middleware: (getDefaultMiddleware) => { diff --git a/src/renderer/src/store/threads.ts b/src/renderer/src/store/threads.ts deleted file mode 100644 index f84652b7..00000000 --- a/src/renderer/src/store/threads.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { createSlice, PayloadAction } from '@reduxjs/toolkit' -import { getDefaultThread } from '@renderer/services/thread' -import { Thread } from '@renderer/types' - -export interface ThreadsState { - threads: Thread[] -} - -const initialState: ThreadsState = { - threads: [getDefaultThread()] -} - -const threadsSlice = createSlice({ - name: 'threads', - initialState, - reducers: { - addThread: (state, action: PayloadAction) => { - state.threads.push(action.payload) - }, - removeThread: (state, action: PayloadAction<{ id: string }>) => { - state.threads = state.threads.filter((c) => c.id !== action.payload.id) - }, - updateThread: (state, action: PayloadAction) => { - state.threads = state.threads.map((c) => (c.id === action.payload.id ? action.payload : c)) - }, - addConversationToThread: (state, action: PayloadAction<{ threadId: string; conversationId: string }>) => { - state.threads = state.threads.map((c) => - c.id === action.payload.threadId - ? { - ...c, - conversations: [...c.conversations, action.payload.conversationId] - } - : c - ) - }, - removeConversationFromThread: (state, action: PayloadAction<{ threadId: string; conversationId: string }>) => { - state.threads = state.threads.map((c) => - c.id === action.payload.threadId - ? { - ...c, - conversations: c.conversations.filter((id) => id !== action.payload.conversationId) - } - : c - ) - } - } -}) - -export const { addThread, removeThread, updateThread, addConversationToThread, removeConversationFromThread } = - threadsSlice.actions - -export default threadsSlice.reducer diff --git a/src/renderer/src/types/index.ts b/src/renderer/src/types/index.ts index 2062aa41..ad98994e 100644 --- a/src/renderer/src/types/index.ts +++ b/src/renderer/src/types/index.ts @@ -1,4 +1,4 @@ -export type Thread = { +export type Agent = { id: string name: string avatar: string @@ -10,7 +10,7 @@ export type Thread = { export type Message = { id: string content: string - threadId: string + agentId: string conversationId: string createdAt: string }