Skip to content

Commit

Permalink
✨ feat: 优化模型上传提示
Browse files Browse the repository at this point in the history
  • Loading branch information
rdmclin2 committed May 20, 2024
1 parent c4be31f commit 75fba52
Show file tree
Hide file tree
Showing 12 changed files with 94 additions and 131 deletions.
10 changes: 8 additions & 2 deletions src/app/chat/ViewerMode/index.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
'use client';

import classNames from 'classnames';
import { isEqual } from 'lodash-es';
import React, { memo } from 'react';
import { Flexbox } from 'react-layout-kit';

import { HEADER_HEIGHT } from '@/constants/token';
import AgentViewer from '@/features/AgentViewer/Chat';
import AgentViewer from '@/features/AgentViewer';
import Alert from '@/features/Alert';
import ChatDialog from '@/features/ChatDialog';
import MessageInput from '@/features/ChatInput/MessageInput';
import { useGlobalStore } from '@/store/global';
import { sessionSelectors, useSessionStore } from '@/store/session';

import { useStyles } from './style';

Expand All @@ -19,11 +21,15 @@ export default memo(() => {
s.setChatDialog,
]);
const { styles } = useStyles();
const [currentAgent] = useSessionStore((s) => [sessionSelectors.currentAgent(s), isEqual]);

return (
<Flexbox flex={1} style={{ position: 'relative' }}>
<div className={styles.viewer}>
<AgentViewer height={`calc(100vh - ${HEADER_HEIGHT}px);`} />
<AgentViewer
height={`calc(100vh - ${HEADER_HEIGHT}px);`}
modelUrl={currentAgent?.meta.model}
/>
</div>
{showChatDialog ? (
<ChatDialog className={classNames(styles.dialog, styles.content)} setOpen={setChatDialog} />
Expand Down
2 changes: 2 additions & 0 deletions src/constants/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,5 @@ export const DEFAULT_USER_AVATAR_URL =

export const DEFAULT_AGENT_AVATAR_URL =
'https://registry.npmmirror.com/@lobehub/assets-logo/1.2.0/files/assets/logo-3d.webp';
export const ROLE_VIEWER_HEIGHT = 640;
export const ROLE_VIEWER_WIDTH = 400;
2 changes: 0 additions & 2 deletions src/constants/token.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,3 @@ export const INPUT_WIDTH_S = 240;
export const INPUT_WIDTH_M = 320;
export const INPUT_WIDTH_L = 480;
export const INPUT_WIDTH_XL = 640;

export const ROLE_VIEWER_HEIGHT = 640;
85 changes: 0 additions & 85 deletions src/features/AgentViewer/Role/index.tsx

This file was deleted.

30 changes: 0 additions & 30 deletions src/features/AgentViewer/Role/style.ts

This file was deleted.

File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,42 +1,48 @@
import classNames from 'classnames';
import { isEqual } from 'lodash-es';
import React, { memo, useCallback, useRef } from 'react';
import React, { memo, useCallback, useEffect, useRef } from 'react';

import PageLoading from '@/components/PageLoading';
import { useLoadVrm } from '@/hooks/useLoadVrm';
import { sessionSelectors, useSessionStore } from '@/store/session';
import { useViewerStore } from '@/store/viewer';

import ToolBar from '../components/ToolBar';
import ToolBar from './ToolBar';
import { useStyles } from './style';

interface Props {
className?: string;
height?: number | string;
modelUrl?: string;
style?: React.CSSProperties;
width?: number | string;
}

function AgentViewer(props: Props) {
const { className, style, height } = props;
const { className, style, height, modelUrl, width } = props;
const { styles } = useStyles();
const ref = useRef<HTMLDivElement>(null);
const viewer = useViewerStore((s) => s.viewer);
const [currentAgent] = useSessionStore((s) => [sessionSelectors.currentAgent(s), isEqual]);

const { loading, loadVrm } = useLoadVrm(viewer);

useEffect(() => {
loadVrm(modelUrl);
}, [modelUrl]);

const canvasRef = useCallback(
(canvas: HTMLCanvasElement) => {
if (canvas) {
viewer.setup(canvas);
loadVrm(currentAgent?.meta.model);
}
},
[viewer, currentAgent?.meta.model],
[viewer],
);

return (
<div ref={ref} className={classNames(styles.viewer, className)} style={{ height, ...style }}>
<div
ref={ref}
className={classNames(styles.viewer, className)}
style={{ height, width, ...style }}
>
<ToolBar className={styles.toolbar} viewer={viewer} />
{loading ? <PageLoading title={'模型加载中,请稍后...'} className={styles.loading} /> : null}
<canvas ref={canvasRef} className={styles.canvas}></canvas>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { createStyles } from 'antd-style';
export const useStyles = createStyles(({ css, token }) => ({
viewer: css`
position: relative;
width: 100%;
height: 100%;
min-height: 0;
`,
Expand Down
3 changes: 2 additions & 1 deletion src/hooks/useLoadVrm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@ import localforage from 'localforage';
import { useState } from 'react';

import { Viewer } from '@/features/vrmViewer/viewer';
import { isModelKey } from '@/utils/model';

export const useLoadVrm = (viewer: Viewer) => {
const [loading, setLoading] = useState(false);

const loadVrm = async (url?: string) => {
let vrmUrl = url;
if (url && url.startsWith('model:')) {
if (url && isModelKey(url)) {
const blob = await localforage.getItem(url);
if (blob) {
vrmUrl = window.URL.createObjectURL(blob as Blob);
Expand Down
55 changes: 55 additions & 0 deletions src/panels/RolePanel/RoleEdit/Model/ViewerWithUpload/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { Upload } from 'antd';
import localforage from 'localforage';
import React, { CSSProperties, memo } from 'react';

import EmptyGuide from '@/components/EmptyGuide';
import { ROLE_VIEWER_HEIGHT, ROLE_VIEWER_WIDTH } from '@/constants/common';
import AgentViewer from '@/features/AgentViewer';
import { agentSelectors, useAgentStore } from '@/store/agent';
import { generateModelKey } from '@/utils/model';

interface ViewerWithUploadProps {
style?: CSSProperties;
}

const ViewerWithUpload = memo<ViewerWithUploadProps>(({ style }) => {
const [currentAgentModel, updateAgentConfig] = useAgentStore((s) => [
agentSelectors.currentAgentModel(s),
s.updateAgentConfig,
]);

const handleUploadAvatar = (file: any) => {
const { name, size } = file;
const blob = new Blob([file], { type: 'application/octet-stream' });
const modelKey = generateModelKey(name, size);
localforage.setItem(modelKey, blob).then(() => {
updateAgentConfig({ meta: { model: modelKey } });
});
};

return (
<Upload
beforeUpload={handleUploadAvatar}
itemRender={() => void 0}
accept={'.vrm'}
maxCount={1}
style={style}
openFileDialogOnClick={!currentAgentModel}
>
{currentAgentModel ? (
<AgentViewer
height={ROLE_VIEWER_HEIGHT}
modelUrl={currentAgentModel}
width={ROLE_VIEWER_WIDTH}
/>
) : (
<EmptyGuide
size={{ height: ROLE_VIEWER_HEIGHT, width: ROLE_VIEWER_WIDTH }}
extra={`支持单个文件上传,当前仅支持 .vrm 格式文件`}
/>
)}
</Upload>
);
});

export default ViewerWithUpload;
4 changes: 2 additions & 2 deletions src/panels/RolePanel/RoleEdit/Model/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { createStyles } from 'antd-style';
import classNames from 'classnames';
import React from 'react';

import AgentViewer from '@/features/AgentViewer/Role';
import ViewerWithUpload from '@/panels/RolePanel/RoleEdit/Model/ViewerWithUpload';

import Touch from './Touch';

Expand Down Expand Up @@ -45,7 +45,7 @@ const Model = (props: ModelProps) => {
</div>
<div className={styles.right}>
<FormItem label={'模型预览'} name={'model'} desc="模型预览,可拖动模型文件以替换" />
<AgentViewer />
<ViewerWithUpload />
</div>
</div>
</Form>
Expand Down
9 changes: 9 additions & 0 deletions src/utils/model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
const MODEL_SCHEMA = 'model';

export const generateModelKey = (name: string, size: number) => {
return `${MODEL_SCHEMA}://${name}-${size}`;
};

export const isModelKey = (key: string) => {
return key.startsWith(MODEL_SCHEMA);
};

0 comments on commit 75fba52

Please sign in to comment.