Skip to content

Commit

Permalink
✨ feat: 添加头像上传与设置
Browse files Browse the repository at this point in the history
  • Loading branch information
rdmclin2 committed May 19, 2024
1 parent 66a6586 commit 472918f
Show file tree
Hide file tree
Showing 18 changed files with 129 additions and 31 deletions.
3 changes: 3 additions & 0 deletions src/constants/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,6 @@ export const MAX_README_LENGTH = 800;

export const DEFAULT_USER_AVATAR_URL =
'https://registry.npmmirror.com/@lobehub/assets-logo/1.2.0/files/assets/logo-3d.webp';

export const DEFAULT_AGENT_AVATAR_URL =
'https://registry.npmmirror.com/@lobehub/assets-logo/1.2.0/files/assets/logo-3d.webp';
4 changes: 2 additions & 2 deletions src/features/Actions/Chat.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@ import { Button } from 'antd';
import { useRouter } from 'next/navigation';
import React from 'react';

import { agentListSelectors, useAgentStore } from '@/store/agent';
import { agentSelectors, useAgentStore } from '@/store/agent';
import { useSessionStore } from '@/store/session';

export default () => {
const router = useRouter();

const currentAgent = useAgentStore((s) => agentListSelectors.currentAgentItem(s));
const currentAgent = useAgentStore((s) => agentSelectors.currentAgentItem(s));
const createSession = useSessionStore((s) => s.createSession);

return (
Expand Down
4 changes: 2 additions & 2 deletions src/features/Actions/UnSubscribeButton.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { Button, Popconfirm } from 'antd';
import React from 'react';

import { agentListSelectors, useAgentStore } from '@/store/agent';
import { agentSelectors, useAgentStore } from '@/store/agent';
import { useSessionStore } from '@/store/session';

export default () => {
const currentAgent = useAgentStore((s) => agentListSelectors.currentAgentItem(s));
const currentAgent = useAgentStore((s) => agentSelectors.currentAgentItem(s));
const unsubscribe = useAgentStore((s) => s.unsubscribe);
const removeSession = useSessionStore((s) => s.removeSession);

Expand Down
6 changes: 3 additions & 3 deletions src/features/AgentViewer/Role/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import React, { memo, useCallback, useRef } from 'react';

import PageLoading from '@/components/PageLoading';
import { useLoadVrm } from '@/hooks/useLoadVrm';
import { agentListSelectors, useAgentStore } from '@/store/agent';
import { agentSelectors, useAgentStore } from '@/store/agent';
import { useViewerStore } from '@/store/viewer';

import ToolBar from '../components/ToolBar';
Expand All @@ -22,8 +22,8 @@ function AgentViewer(props: Props) {
const ref = useRef<HTMLDivElement>(null);
const viewer = useViewerStore((s) => s.viewer);
const [currentAgentModel, currentAgentId, updateAgentConfig] = useAgentStore((s) => [
agentListSelectors.currentAgentModel(s),
agentListSelectors.currentAgentId(s),
agentSelectors.currentAgentModel(s),
agentSelectors.currentAgentId(s),
s.updateAgentConfig,
]);

Expand Down
4 changes: 2 additions & 2 deletions src/features/MarketInfo/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import Author from '@/components/Author';
import AgentCard from '@/components/agent/AgentCard';
import SystemRole from '@/components/agent/SystemRole';
import { SIDEBAR_MAX_WIDTH, SIDEBAR_WIDTH } from '@/constants/token';
import { agentListSelectors, useAgentStore } from '@/store/agent';
import { agentSelectors, useAgentStore } from '@/store/agent';
import { useConfigStore } from '@/store/config';
import { marketStoreSelectors, useMarketStore } from '@/store/market';
import { useSessionStore } from '@/store/session';
Expand Down Expand Up @@ -41,7 +41,7 @@ const Header = () => {
const [subscribe, unsubscribe, subscribed] = useAgentStore((s) => [
s.subscribe,
s.unsubscribe,
agentListSelectors.subscribed(s),
agentSelectors.subscribed(s),
]);

const createSession = useSessionStore((s) => s.createSession);
Expand Down
4 changes: 2 additions & 2 deletions src/features/RoleHeader/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { Flexbox } from 'react-layout-kit';

import AgentMeta from '@/components/agent/AgentMeta';
import Chat from '@/features/Actions/Chat';
import { agentListSelectors, useAgentStore } from '@/store/agent';
import { agentSelectors, useAgentStore } from '@/store/agent';

import { useStyles } from './style';

Expand All @@ -15,7 +15,7 @@ interface Props {
export default (props: Props) => {
const { className } = props;
const { styles } = useStyles();
const [currentAgent] = useAgentStore((s) => [agentListSelectors.currentAgentItem(s)]);
const [currentAgent] = useAgentStore((s) => [agentSelectors.currentAgentItem(s)]);

return (
<Flexbox
Expand Down
6 changes: 3 additions & 3 deletions src/features/RoleInfo/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import SystemRole from '@/components/agent/SystemRole';
import { SIDEBAR_MAX_WIDTH, SIDEBAR_WIDTH } from '@/constants/token';
import Chat from '@/features/Actions/Chat';
import UnSubscribeButton from '@/features/Actions/UnSubscribeButton';
import { agentListSelectors, useAgentStore } from '@/store/agent';
import { agentSelectors, useAgentStore } from '@/store/agent';

const useStyles = createStyles(({ css, token }) => ({
content: css`
Expand All @@ -26,11 +26,11 @@ const Header = () => {
const { styles } = useStyles();
const [tempId, setTempId] = useState<string>('');
const [showAgentSidebar, activateAgent, deactivateAgent] = useAgentStore((s) => [
agentListSelectors.showSideBar(s),
agentSelectors.showSideBar(s),
s.activateAgent,
s.deactivateAgent,
]);
const currentAgent = useAgentStore((s) => agentListSelectors.currentAgentItem(s));
const currentAgent = useAgentStore((s) => agentSelectors.currentAgentItem(s));

return (
<DraggablePanel
Expand Down
6 changes: 3 additions & 3 deletions src/features/RoleList/List/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { createStyles } from 'antd-style';
import { memo } from 'react';
import LazyLoad from 'react-lazy-load';

import { agentListSelectors, useAgentStore } from '@/store/agent';
import { agentSelectors, useAgentStore } from '@/store/agent';

import SessionItem from './Item';

Expand All @@ -18,9 +18,9 @@ interface SessionListProps {

const SessionList = memo<SessionListProps>(({ filter }) => {
const [filterAgentListIds, activateAgent, agentListIds] = useAgentStore((s) => [
agentListSelectors.filterAgentListIds(s, filter),
agentSelectors.filterAgentListIds(s, filter),
s.activateAgent,
agentListSelectors.agentListIds(s),
agentSelectors.agentListIds(s),
]);
const { styles } = useStyles();

Expand Down
3 changes: 2 additions & 1 deletion src/features/Settings/common.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import { Monitor, Settings2, User2Icon } from 'lucide-react';
import React from 'react';

import { MAX_NAME_LENGTH } from '@/constants/common';
import AvatarWithUpload from '@/features/AvatarWithUpload';
import ThemeSwatchesPrimary from '@/features/Settings/features/ThemeSwatchesPrimary';
import { useSyncSettings } from '@/features/Settings/useSyncSettings';
import { useAgentStore } from '@/store/agent';
Expand All @@ -16,6 +15,8 @@ import { useSessionStore } from '@/store/session';
import { useThemeStore } from '@/store/theme';
import { BackgroundEffect } from '@/types/config';

import AvatarWithUpload from './features/AvatarWithUpload';

interface CommonConfigProps {
className?: string;
style?: React.CSSProperties;
Expand Down
File renamed without changes.
4 changes: 2 additions & 2 deletions src/panels/MarketPanel/Market/List/index.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, { memo, useEffect } from 'react';

import GridList from '@/components/GridList';
import { agentListSelectors, useAgentStore } from '@/store/agent';
import { agentSelectors, useAgentStore } from '@/store/agent';
import { useMarketStore } from '@/store/market';

const AgentList = () => {
Expand All @@ -12,7 +12,7 @@ const AgentList = () => {
fetchAgentIndex();
}, [fetchAgentIndex]);

const [subscribed] = useAgentStore((s) => [agentListSelectors.subscribed(s)]);
const [subscribed] = useAgentStore((s) => [agentSelectors.subscribed(s)]);

return (
<GridList
Expand Down
73 changes: 73 additions & 0 deletions src/panels/RolePanel/RoleEdit/Info/AvatarWithUpload/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import { Upload } from 'antd';
import { createStyles } from 'antd-style';
import NextImage from 'next/image';
import { CSSProperties, memo, useCallback } from 'react';

import { DEFAULT_AGENT_AVATAR_URL } from '@/constants/common';
import { agentSelectors, useAgentStore } from '@/store/agent';
import { createUploadImageHandler } from '@/utils/common';
import { imageToBase64 } from '@/utils/imageToBase64';

const useStyle = createStyles(
({ css, token }) => css`
cursor: pointer;
overflow: hidden;
border-radius: 50%;
transition:
scale 400ms ${token.motionEaseOut},
box-shadow 100ms ${token.motionEaseOut};
&:hover {
box-shadow: 0 0 0 3px ${token.colorText};
}
&:active {
scale: 0.8;
}
`,
);

interface AvatarWithUploadProps {
compressSize?: number;
id?: string;
size?: number;
style?: CSSProperties;
}

const AvatarWithUpload = memo<AvatarWithUploadProps>(
({ size = 40, compressSize = 256, style, id }) => {
const { styles } = useStyle();
const [meta, updateAgentMeta] = useAgentStore((s) => [
agentSelectors.currentAgentMeta(s),
s.updateAgentMeta,
]);

const handleUploadAvatar = useCallback(
createUploadImageHandler((avatar) => {
const img = new Image();
img.src = avatar;
img.addEventListener('load', () => {
const webpBase64 = imageToBase64({ img, size: compressSize });
updateAgentMeta({ avatar: webpBase64 });
});
}),
[],
);

return (
<div className={styles} id={id} style={{ maxHeight: size, maxWidth: size, ...style }}>
<Upload beforeUpload={handleUploadAvatar} itemRender={() => void 0} maxCount={1}>
<NextImage
alt={meta?.avatar ? 'userAvatar' : 'LobeVidol'}
height={size}
src={!!meta?.avatar ? meta?.avatar : DEFAULT_AGENT_AVATAR_URL}
unoptimized
width={size}
/>
</Upload>
</div>
);
},
);

export default AvatarWithUpload;
5 changes: 5 additions & 0 deletions src/panels/RolePanel/RoleEdit/Info/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { INPUT_WIDTH_L } from '@/constants/token';
import { useAgentStore } from '@/store/agent';

import { useSyncSettings } from '../useSyncSetting';
import AvatarWithUpload from './AvatarWithUpload';

interface InfoProps {
className?: string;
Expand Down Expand Up @@ -61,9 +62,13 @@ const Info = (props: InfoProps) => {
<div className={classNames(className, styles.container)} style={style}>
<div className={styles.form}>
<div className={styles.config}>
<FormItem desc={'自定义头像'} label={'头像'} name={'avatar'}>
<AvatarWithUpload />
</FormItem>
<FormItem
label={'名称'}
desc={'角色名称,与角色聊天时的称呼'}
divider
name={['meta', 'name']}
required
rules={[{ message: '请输入角色名称', required: true }]}
Expand Down
4 changes: 2 additions & 2 deletions src/panels/RolePanel/RoleEdit/SystemRole/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import classNames from 'classnames';
import { isEqual } from 'lodash-es';
import React from 'react';

import { agentListSelectors, useAgentStore } from '@/store/agent';
import { agentSelectors, useAgentStore } from '@/store/agent';

import { useSyncSettings } from '../useSyncSetting';

Expand Down Expand Up @@ -44,7 +44,7 @@ const Info = (props: InfoProps) => {
const { style, className } = props;
const { styles } = useStyles();
const [form] = Form.useForm();
const currentAgent = useAgentStore((s) => agentListSelectors.currentAgentItem(s), isEqual);
const currentAgent = useAgentStore((s) => agentSelectors.currentAgentItem(s), isEqual);
const updateAgentConfig = useAgentStore((s) => s.updateAgentConfig);

useSyncSettings(form);
Expand Down
4 changes: 2 additions & 2 deletions src/panels/RolePanel/RoleEdit/Tachie/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import React from 'react';

import HolographicCard from '@/components/HolographicCard';
import { useSyncSettings } from '@/panels/RolePanel/RoleEdit/useSyncSetting';
import { agentListSelectors, useAgentStore } from '@/store/agent';
import { agentSelectors, useAgentStore } from '@/store/agent';

const FormItem = Form.Item;

Expand Down Expand Up @@ -42,7 +42,7 @@ const Info = (props: InfoProps) => {
const { style, className } = props;
const { styles } = useStyles();
const [form] = Form.useForm();
const currentAgent = useAgentStore((s) => agentListSelectors.currentAgentItem(s), isEqual);
const currentAgent = useAgentStore((s) => agentSelectors.currentAgentItem(s), isEqual);
const updateAgentConfig = useAgentStore((s) => s.updateAgentConfig);

useSyncSettings(form);
Expand Down
6 changes: 3 additions & 3 deletions src/panels/RolePanel/RoleEdit/useSyncSetting.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,16 @@ import { FormInstance } from 'antd/es/form/hooks/useForm';
import { isEqual } from 'lodash-es';
import { useLayoutEffect } from 'react';

import { agentListSelectors, useAgentStore } from '@/store/agent';
import { agentSelectors, useAgentStore } from '@/store/agent';

export const useSyncSettings = (form: FormInstance) => {
useLayoutEffect(() => {
const currentAgent = agentListSelectors.currentAgentItem(useAgentStore.getState());
const currentAgent = agentSelectors.currentAgentItem(useAgentStore.getState());
form.setFieldsValue(currentAgent);

// sync with later updated settings
const unsubscribe = useAgentStore.subscribe(
(s) => agentListSelectors.currentAgentItem(s),
(s) => agentSelectors.currentAgentItem(s),
(agent) => {
form.setFieldsValue(agent);
},
Expand Down
12 changes: 10 additions & 2 deletions src/store/agent/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { createWithEqualityFn } from 'zustand/traditional';
import { StateCreator } from 'zustand/vanilla';

import { DEFAULT_AGENT_CONFIG, LOBE_VIDOL_DEFAULT_AGENT_ID } from '@/constants/agent';
import { Agent } from '@/types/agent';
import { Agent, AgentMeta } from '@/types/agent';

import { initialState } from './initialState';

Expand Down Expand Up @@ -61,6 +61,10 @@ export interface AgentStore {
* 更新角色配置
*/
updateAgentConfig: (agent: DeepPartial<Agent>) => void;
/**
* 更新角色元数据
*/
updateAgentMeta: (meta: DeepPartial<AgentMeta>) => void;
}

const createAgentStore: StateCreator<AgentStore, [['zustand/devtools', never]]> = (set, get) => ({
Expand Down Expand Up @@ -114,6 +118,10 @@ const createAgentStore: StateCreator<AgentStore, [['zustand/devtools', never]]>
});
set({ localAgentList: agents });
},
updateAgentMeta: (meta) => {
const { updateAgentConfig } = get();
updateAgentConfig({ meta });
},
subscribe: (agent) => {
const { localAgentList } = get();

Expand Down Expand Up @@ -153,4 +161,4 @@ export const useAgentStore = createWithEqualityFn<AgentStore>()(
shallow,
);

export { agentListSelectors } from './selectors/agent';
export { agentSelectors } from './selectors/agent';
12 changes: 10 additions & 2 deletions src/store/agent/selectors/agent.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { LOBE_VIDOL_DEFAULT_AGENT_ID } from '@/constants/agent';
import { Agent } from '@/types/agent';
import { Agent, AgentMeta } from '@/types/agent';

import { AgentStore } from '../index';

Expand All @@ -15,6 +15,13 @@ const currentAgentItem = (s: AgentStore): Agent | undefined => {
return currentAgent;
};

const currentAgentMeta = (s: AgentStore): AgentMeta | undefined => {
const currentAgent = currentAgentItem(s);
if (!currentAgent) return undefined;

return currentAgent.meta;
};

const agentListIds = (s: AgentStore): string[] => {
const { localAgentList } = s;
return localAgentList.map((item) => item.agentId);
Expand Down Expand Up @@ -58,8 +65,9 @@ const subscribed = (s: AgentStore) => (agentId: string) => {
return index !== -1;
};

export const agentListSelectors = {
export const agentSelectors = {
currentAgentItem,
currentAgentMeta,
filterAgentListIds,
agentListIds,
isDefaultAgent,
Expand Down

0 comments on commit 472918f

Please sign in to comment.