mirror of
https://github.com/lobehub/lobehub.git
synced 2026-03-27 13:29:15 +07:00
✨ feat: 实现优化重发请求功能
This commit is contained in:
@@ -12,6 +12,7 @@ const List = () => {
|
||||
shallow,
|
||||
);
|
||||
|
||||
console.log(data);
|
||||
return (
|
||||
<ChatList
|
||||
data={data}
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
import { LanguageModel } from '@/types/llm';
|
||||
import { LobeAgentConfig } from '@/types/session';
|
||||
|
||||
export interface SessionLoadingState {
|
||||
pickingEmojiAvatar: boolean;
|
||||
summarizingDescription: boolean;
|
||||
@@ -9,6 +12,14 @@ export interface AgentConfigState {
|
||||
showAgentSettings: boolean;
|
||||
}
|
||||
|
||||
export const initialLobeAgentConfig: LobeAgentConfig = {
|
||||
model: LanguageModel.GPT3_5,
|
||||
params: { temperature: 0.6 },
|
||||
systemRole: '',
|
||||
};
|
||||
|
||||
export const defaultAvatar = 'https://npm.elemecdn.com/@lobehub/assets-logo/assets/logo-3d.webp';
|
||||
|
||||
export const initialAgentConfigState: AgentConfigState = {
|
||||
// // loading 中间态
|
||||
loading: {
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import { SessionStore } from '@/store/session';
|
||||
import { LanguageModel } from '@/types/llm';
|
||||
import { LobeAgentConfig } from '@/types/session';
|
||||
|
||||
import { sessionSelectors } from '../session';
|
||||
import { defaultAvatar, initialLobeAgentConfig } from './initialState';
|
||||
|
||||
const currentAgentTitle = (s: SessionStore) => {
|
||||
const session = sessionSelectors.currentSession(s);
|
||||
@@ -12,7 +14,6 @@ const currentAgentTitle = (s: SessionStore) => {
|
||||
const currentAgentAvatar = (s: SessionStore) => {
|
||||
const session = sessionSelectors.currentSession(s);
|
||||
|
||||
const defaultAvatar = 'https://npm.elemecdn.com/@lobehub/assets-logo/assets/logo-3d.webp';
|
||||
if (!session) return defaultAvatar;
|
||||
|
||||
return session.meta.avatar || defaultAvatar;
|
||||
@@ -24,6 +25,10 @@ const currentAgentConfig = (s: SessionStore) => {
|
||||
return session?.config;
|
||||
};
|
||||
|
||||
const currentAgentConfigSafe = (s: SessionStore): LobeAgentConfig => {
|
||||
return currentAgentConfig(s) || initialLobeAgentConfig;
|
||||
};
|
||||
|
||||
const currentAgentModel = (s: SessionStore): LanguageModel => {
|
||||
const config = currentAgentConfig(s);
|
||||
|
||||
@@ -33,6 +38,7 @@ const currentAgentModel = (s: SessionStore): LanguageModel => {
|
||||
export const agentSelectors = {
|
||||
currentAgentAvatar,
|
||||
currentAgentConfig,
|
||||
currentAgentConfigSafe,
|
||||
currentAgentModel,
|
||||
currentAgentTitle,
|
||||
};
|
||||
|
||||
@@ -95,72 +95,65 @@ export const createChatSlice: StateCreator<
|
||||
set({ editingMessageId: messageId });
|
||||
},
|
||||
|
||||
resendMessage: async () => {
|
||||
// const {
|
||||
// sendMessage,
|
||||
// dispatchMessage,
|
||||
// // generateMessage
|
||||
// } = get();
|
||||
//
|
||||
// const session = sessionSelectors.currentSession(get());
|
||||
//
|
||||
// if (!session) return;
|
||||
//
|
||||
// const index = session.chats.findIndex((s) => s.id === id);
|
||||
// if (index < 0) return;
|
||||
//
|
||||
// const message = session.chats[index];
|
||||
//
|
||||
// // 用户通过手动删除,造成了他的问题是最后一条消息
|
||||
// // 这种情况下,相当于用户重新发送消息
|
||||
// if (session.chats.length === index && message.role === 'user') {
|
||||
// // 发送消息的时候会把传入的消息 message 新建一条,因此在发送前先把这条消息在记录中删除
|
||||
// dispatchMessage({ id: message.id, type: 'deleteMessage' });
|
||||
// await sendMessage(message.content);
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// // 上下文消息就是当前消息之前的消息
|
||||
// const contextMessages = session.chats.slice(0, index);
|
||||
//
|
||||
// // 上下文消息中最后一条消息
|
||||
// const userMessage = contextMessages.at(-1)?.content;
|
||||
// if (!userMessage) return;
|
||||
//
|
||||
// const targetMessage = session.chats[index];
|
||||
//
|
||||
// // 如果不是 assistant 的消息,那么需要额外插入一条消息
|
||||
// if (targetMessage.role === 'assistant') {
|
||||
// // 保存之前的消息为历史消息
|
||||
// // dispatchMessage({ type: 'updateMessage', message: botPrevMsg, index });
|
||||
// // dispatchMessage({ type: 'updateMessage', message: LOADING_FLAT, index });
|
||||
// } else {
|
||||
// // dispatchMessage({
|
||||
// // type: 'insertMessage',
|
||||
// // index,
|
||||
// // message: { role: 'assistant', content: LOADING_FLAT },
|
||||
// // });
|
||||
// }
|
||||
//
|
||||
// // 重置错误信息
|
||||
// dispatchMessage({
|
||||
// id: targetMessage.id,
|
||||
// key: 'error',
|
||||
// type: 'updateMessage',
|
||||
// value: undefined,
|
||||
// });
|
||||
//
|
||||
// // 开始更新消息
|
||||
//
|
||||
// // await generateMessage(userMessage, contextMessages, {
|
||||
// // onMessageHandle: (text) => {
|
||||
// // currentResponse = [...currentResponse, text];
|
||||
// // dispatchMessage({ type: 'updateMessage', message: currentResponse.join(''), index });
|
||||
// // },
|
||||
// // onErrorHandle: (error) => {
|
||||
// // dispatchMessage({ type: 'updateMessage' });
|
||||
// // },
|
||||
// // });
|
||||
resendMessage: async (messageId) => {
|
||||
const session = sessionSelectors.currentSession(get());
|
||||
|
||||
if (!session) return;
|
||||
|
||||
// 1. 构造所有相关的历史记录
|
||||
const chats = chatSelectors.currentChats(get());
|
||||
|
||||
const currentIndex = chats.findIndex((c) => c.id === messageId);
|
||||
|
||||
const histories = chats
|
||||
.slice(0, currentIndex + 1)
|
||||
// 如果点击重新发送的 message 其 role 是 assistant,那么需要移除
|
||||
// 如果点击重新发送的 message 其 role 是 user,则不需要移除
|
||||
.filter((c) => !(c.role === 'assistant' && c.id === messageId));
|
||||
|
||||
if (histories.length <= 0) return;
|
||||
|
||||
const { generateMessage, dispatchMessage } = get();
|
||||
|
||||
// 再添加一个空的信息用于放置 ai 响应,注意顺序不能反
|
||||
// 因为如果顺序反了,messages 中将包含新增的 ai message
|
||||
const assistantId = nanoid();
|
||||
const latestMsg = histories.filter((s) => s.role === 'user').at(-1);
|
||||
|
||||
if (!latestMsg) return;
|
||||
|
||||
dispatchMessage({
|
||||
id: assistantId,
|
||||
message: LOADING_FLAT,
|
||||
parentId: latestMsg.id,
|
||||
role: 'assistant',
|
||||
type: 'addMessage',
|
||||
});
|
||||
|
||||
let output = '';
|
||||
|
||||
// 生成 ai message
|
||||
await generateMessage(histories, {
|
||||
onErrorHandle: (error) => {
|
||||
dispatchMessage({ id: assistantId, key: 'error', type: 'updateMessage', value: error });
|
||||
},
|
||||
onMessageHandle: (text) => {
|
||||
output += text;
|
||||
|
||||
dispatchMessage({
|
||||
id: assistantId,
|
||||
key: 'content',
|
||||
type: 'updateMessage',
|
||||
value: output,
|
||||
});
|
||||
|
||||
// 滚动到最后一条消息
|
||||
const item = document.querySelector('#for-loading');
|
||||
if (!item) return;
|
||||
|
||||
item.scrollIntoView({ behavior: 'smooth' });
|
||||
},
|
||||
});
|
||||
},
|
||||
|
||||
sendMessage: async (message) => {
|
||||
@@ -194,7 +187,12 @@ export const createChatSlice: StateCreator<
|
||||
onMessageHandle: (text) => {
|
||||
output += text;
|
||||
|
||||
dispatchMessage({ id: assistantId, key: 'content', type: 'updateMessage', value: output });
|
||||
dispatchMessage({
|
||||
id: assistantId,
|
||||
key: 'content',
|
||||
type: 'updateMessage',
|
||||
value: output,
|
||||
});
|
||||
|
||||
// 滚动到最后一条消息
|
||||
const item = document.querySelector('#for-loading');
|
||||
|
||||
@@ -1,30 +1,66 @@
|
||||
import { encode } from 'gpt-tokenizer';
|
||||
|
||||
import { agentSelectors } from '@/store/session';
|
||||
import { ChatMessage } from '@/types/chatMessage';
|
||||
|
||||
import type { SessionStore } from '../../store';
|
||||
import { sessionSelectors } from '../session';
|
||||
|
||||
const currentChatsSel = (s: SessionStore): ChatMessage[] => {
|
||||
const chat = sessionSelectors.currentSession(s);
|
||||
if (!chat) return [];
|
||||
const chatArr = Object.values<ChatMessage>(chat.chats)
|
||||
// 展示在聊天框中的消息
|
||||
const currentChats = (s: SessionStore): ChatMessage[] => {
|
||||
const session = sessionSelectors.currentSession(s);
|
||||
if (!session) return [];
|
||||
|
||||
const basic = Object.values<ChatMessage>(session.chats)
|
||||
// 首先按照时间顺序排序,越早的在越前面
|
||||
.sort((pre, next) => pre.createAt - next.createAt)
|
||||
// 过滤掉已归档的消息,归档消息不应该出现在聊天框中
|
||||
.filter((m) => !m.archive);
|
||||
.filter((m) => !m.archive)
|
||||
// 映射头像关系
|
||||
.map((m) => {
|
||||
return {
|
||||
...m,
|
||||
meta:
|
||||
m.role === 'assistant'
|
||||
? {
|
||||
avatar: agentSelectors.currentAgentAvatar(s),
|
||||
title: session.meta.title,
|
||||
}
|
||||
: m.meta,
|
||||
};
|
||||
});
|
||||
|
||||
return chatArr;
|
||||
const finalList: ChatMessage[] = [];
|
||||
|
||||
const addItem = (item: ChatMessage) => {
|
||||
const isExist = finalList.findIndex((i) => item.id === i.id) > -1;
|
||||
if (!isExist) {
|
||||
finalList.push(item);
|
||||
}
|
||||
};
|
||||
|
||||
for (const item of basic) {
|
||||
// 先判存在与否,不存在就加入
|
||||
addItem(item);
|
||||
|
||||
for (const another of basic) {
|
||||
if (another.parentId === item.id) {
|
||||
addItem(another);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return finalList;
|
||||
};
|
||||
|
||||
const systemRoleSel = (s: SessionStore): string | undefined => {
|
||||
const systemRoleMessage = currentChatsSel(s);
|
||||
const systemRoleSel = (s: SessionStore): string => {
|
||||
const config = agentSelectors.currentAgentConfigSafe(s);
|
||||
|
||||
return systemRoleMessage.find((s) => s.role === 'system')?.content;
|
||||
return config.systemRole;
|
||||
};
|
||||
|
||||
const totalTokens = (s: SessionStore): number[] => {
|
||||
const chats = currentChatsSel(s);
|
||||
const chats = currentChats(s);
|
||||
return encode(chats.map((m) => m.content).join(''));
|
||||
};
|
||||
|
||||
@@ -39,8 +75,7 @@ const totalTokenCount = (s: SessionStore) => totalTokens(s).length;
|
||||
const systemRoleTokenCount = (s: SessionStore) => systemRoleTokens(s).length;
|
||||
|
||||
export const chatSelectors = {
|
||||
currentChats: currentChatsSel,
|
||||
systemRole: systemRoleSel,
|
||||
currentChats,
|
||||
systemRoleTokenCount,
|
||||
systemRoleTokens,
|
||||
totalTokenCount,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { LanguageModel } from '@/types/llm';
|
||||
import { LobeAgentConfig, LobeAgentSession, LobeSessionType } from '@/types/session';
|
||||
import { LobeAgentSession, LobeSessionType } from '@/types/session';
|
||||
|
||||
import { initialLobeAgentConfig } from '../agentConfig';
|
||||
|
||||
export interface SessionState {
|
||||
/**
|
||||
@@ -12,12 +13,6 @@ export interface SessionState {
|
||||
sessions: Record<string, LobeAgentSession>;
|
||||
}
|
||||
|
||||
export const initialLobeAgentConfig: LobeAgentConfig = {
|
||||
model: LanguageModel.GPT3_5,
|
||||
params: { temperature: 0.6 },
|
||||
systemRole: '',
|
||||
};
|
||||
|
||||
export const initLobeSession: LobeAgentSession = {
|
||||
chats: {},
|
||||
config: initialLobeAgentConfig,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { defaultAvatar } from '@/store/session/slices/agentConfig';
|
||||
import { MetaData } from '@/types/meta';
|
||||
|
||||
export const getAgentAvatar = (s: MetaData) =>
|
||||
s.avatar || 'https://npm.elemecdn.com/@lobehub/assets-logo/assets/logo-3d.webp';
|
||||
export const getAgentAvatar = (s: MetaData) => s.avatar || defaultAvatar;
|
||||
|
||||
Reference in New Issue
Block a user