feat: 实现 session 导入功能

This commit is contained in:
arvinxx
2023-07-30 14:02:57 +08:00
parent c1f73fed84
commit 5650167ef6
4 changed files with 79 additions and 15 deletions

View File

@@ -1,5 +1,5 @@
import { ActionIcon, Icon } from '@lobehub/ui';
import { Dropdown, MenuProps } from 'antd';
import { Dropdown, MenuProps, Upload } from 'antd';
import {
Feather,
FileClock,
@@ -14,6 +14,7 @@ import { ReactNode, memo, useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import { useExportConfig } from '@/hooks/useExportConfig';
import { useImportConfig } from '@/hooks/useImportConfig';
import pkg from '../../../package.json';
@@ -21,12 +22,18 @@ const BottomAction = memo<{ children: ReactNode }>(({ children }) => {
const { t } = useTranslation('common');
const { exportSessions, exportSettings, exportAll, exportAgents } = useExportConfig();
const { importConfig } = useImportConfig();
const items: MenuProps['items'] = useMemo(
() => [
{
icon: <Icon icon={FolderInput} />,
key: 'import',
label: <div>{t('import')}</div>,
label: (
<Upload maxCount={1} onChange={importConfig} showUploadList={false}>
{t('import')}
</Upload>
),
},
{
children: [

View File

@@ -0,0 +1,36 @@
import { useMemo } from 'react';
import { useSessionStore } from '@/store/session';
import { useSettings } from '@/store/settings';
import { importConfigFile } from '@/utils/config';
export const useImportConfig = () => {
const importSessions = useSessionStore((s) => s.importSessions);
const importSettings = useSettings((s) => s.importSettings);
const importConfig = (info: any) => {
importConfigFile(info, (config) => {
switch (config.exportType) {
case 'settings': {
importSettings(config.state.settings);
break;
}
case 'sessions':
case 'agents': {
importSessions(config.state.sessions);
break;
}
case 'all': {
importSessions(config.state.sessions);
importSettings(config.state.settings);
break;
}
}
});
};
return useMemo(() => ({ importConfig }), []);
};

View File

@@ -1,9 +1,10 @@
import { produce } from 'immer';
import { merge } from 'lodash-es';
import Router from 'next/router';
import { StateCreator } from 'zustand/vanilla';
import { SessionStore, initLobeSession } from '@/store/session';
import { LobeAgentSession } from '@/types/session';
import { LobeAgentSession, LobeSessions } from '@/types/session';
import { uuid } from '@/utils/uuid';
import { SessionDispatch, sessionsReducer } from './reducers/session';
@@ -18,10 +19,22 @@ export interface SessionAction {
createSession: () => Promise<string>;
/**
* 分发聊天记录
* 变更session
* @param payload - 聊天记录
*/
dispatchSession: (payload: SessionDispatch) => void;
/**
* 导入会话
* @param sessions
*/
importSessions: (sessions: LobeSessions) => void;
/**
* 生成压缩后的消息
* @returns 压缩后的消息
*/
// genShareUrl: () => string;
/**
* @title 删除会话
* @param index - 会话索引
@@ -35,12 +48,6 @@ export interface SessionAction {
* @returns void
*/
switchSession: (sessionId?: string | 'new') => Promise<void>;
/**
* 生成压缩后的消息
* @returns 压缩后的消息
*/
// genShareUrl: () => string;
}
export const createSessionSlice: StateCreator<
@@ -80,6 +87,20 @@ export const createSessionSlice: StateCreator<
});
},
importSessions: (importSessions) => {
const { sessions } = get();
set({
sessions: produce(sessions, (draft) => {
for (const [id, session] of Object.entries(importSessions)) {
// 如果已经存在,则跳过
if (draft[id]) continue;
draft[id] = session;
}
}),
});
},
removeSession: (sessionId) => {
get().dispatchSession({ id: sessionId, type: 'removeSession' });
@@ -87,7 +108,6 @@ export const createSessionSlice: StateCreator<
Router.push('/');
}
},
switchSession: async (sessionId) => {
if (get().activeId === sessionId) return;

View File

@@ -1,7 +1,7 @@
import { notification } from 'antd';
import { CURRENT_CONFIG_VERSION, Migration } from '@/migrations';
import { ConfigState } from '@/types/exportConfig';
import { ConfigFile } from '@/types/exportConfig';
export const exportConfigFile = (config: object, fileName?: string) => {
const file = `LobeChat-${fileName || '-config'}-v${CURRENT_CONFIG_VERSION}.json`;
@@ -26,7 +26,7 @@ export const exportConfigFile = (config: object, fileName?: string) => {
a.remove();
};
export const handleImport = (info: any, onConfigImport: (config: ConfigState) => void) => {
export const importConfigFile = (info: any, onConfigImport: (config: ConfigFile) => void) => {
const reader = new FileReader();
//读取完文件之后的回调函数
reader.onloadend = function (evt) {
@@ -34,9 +34,10 @@ export const handleImport = (info: any, onConfigImport: (config: ConfigState) =>
const fileJson = fileString as string;
try {
const { state } = Migration.migrate(JSON.parse(fileJson));
const config = JSON.parse(fileJson);
const { state } = Migration.migrate(config);
onConfigImport(state);
onConfigImport({ ...config, state });
} catch (error) {
notification.error({
description: `出错原因: ${(error as Error).message}`,