fix(style): image size cache'

This commit is contained in:
jialin
2024-12-02 22:15:43 +08:00
parent 50c740d219
commit b1d13f5a71
15 changed files with 195 additions and 79 deletions
+1 -1
View File
@@ -14,7 +14,7 @@ const isProduction = env === 'production';
const t = Date.now(); const t = Date.now();
export default defineConfig({ export default defineConfig({
proxy: { proxy: {
...proxy('http://192.168.50.4') ...proxy('http://192.168.50.5')
}, },
history: { history: {
type: 'hash' type: 'hash'
@@ -11,3 +11,9 @@
image-rendering: crisp-edges; image-rendering: crisp-edges;
} }
} }
.scroller-wrapper {
width: 100%;
height: 100%;
overflow: hidden;
}
+25 -31
View File
@@ -1,5 +1,5 @@
import useResizeObserver from '@/components/logs-viewer/use-size'; import useResizeObserver from '@/components/logs-viewer/use-size';
import React, { useEffect } from 'react'; import React, { useEffect, useState } from 'react';
import './index.less'; import './index.less';
interface AudioAnimationProps { interface AudioAnimationProps {
@@ -7,6 +7,7 @@ interface AudioAnimationProps {
height: number; height: number;
scaleFactor?: number; scaleFactor?: number;
maxBarCount?: number; maxBarCount?: number;
fixedHeight?: boolean;
analyserData: { analyserData: {
data: Uint8Array; data: Uint8Array;
analyser: any; analyser: any;
@@ -17,20 +18,22 @@ const AudioAnimation: React.FC<AudioAnimationProps> = (props) => {
const { const {
scaleFactor = 1.2, scaleFactor = 1.2,
maxBarCount = 128, maxBarCount = 128,
fixedHeight = true,
analyserData, analyserData,
width, width: initialWidth,
height height: initialHeight
} = props; } = props;
const canvasRef = React.useRef<HTMLCanvasElement>(null); const canvasRef = React.useRef<HTMLCanvasElement>(null);
const animationId = React.useRef<number>(0); const animationId = React.useRef<number>(0);
const isScaled = React.useRef<boolean>(false); const isScaled = React.useRef<boolean>(false);
const oscillationOffset = React.useRef(0); const oscillationOffset = React.useRef(0);
const direction = React.useRef(1); const direction = React.useRef(1);
// const [width, setWidth] = useState(props.width); const scrollerRef = React.useRef<HTMLDivElement>(null);
// const [height, setHeight] = useState(props.height); const [width, setWidth] = useState(initialWidth);
const [height, setHeight] = useState(initialHeight);
const containerRef = React.useRef<any>(null); const containerRef = React.useRef<any>(null);
const size = useResizeObserver(containerRef); const size = useResizeObserver(scrollerRef);
const calculateJitter = ( const calculateJitter = (
i: number, i: number,
@@ -128,26 +131,14 @@ const AudioAnimation: React.FC<AudioAnimationProps> = (props) => {
draw(performance.now()); draw(performance.now());
}; };
// const handleResizeThrottle = React.useCallback( React.useEffect(() => {
// throttle(() => { if (size) {
// console.log('size:', size); setWidth(size?.width || 0);
// if (size.width && size.width !== width) { if (!fixedHeight) {
// setWidth(size.width); setHeight(size?.height || 0);
// } }
// if (size.height && size.height !== height) { }
// setHeight(size.height); }, [size]);
// }
// }, 100),
// [size, width, height]
// );
// useEffect(() => {
// handleResizeThrottle();
// window.addEventListener('resize', handleResizeThrottle);
// return () => {
// handleResizeThrottle.cancel();
// };
// }, [size, width, height]);
useEffect(() => { useEffect(() => {
if (!canvasRef.current) return; if (!canvasRef.current) return;
@@ -174,15 +165,18 @@ const AudioAnimation: React.FC<AudioAnimationProps> = (props) => {
}, [analyserData, width, height]); }, [analyserData, width, height]);
return ( return (
<div
className="scroller-wrapper"
ref={scrollerRef}
style={{ width: '100%', height: '100%' }}
>
<div <div
ref={containerRef} ref={containerRef}
className="canvas-wrap" className="canvas-wrap"
style={{ style={{ width: '100%', height: '100%' }}
width: '100%',
height: height
}}
> >
<canvas ref={canvasRef} style={{ width, height }}></canvas> <canvas ref={canvasRef} style={{ display: 'block' }}></canvas>
</div>
</div> </div>
); );
}; };
+14 -18
View File
@@ -3,7 +3,7 @@ import { Progress } from 'antd';
import classNames from 'classnames'; import classNames from 'classnames';
import * as Vibrant from 'node-vibrant'; import * as Vibrant from 'node-vibrant';
import ResizeObserver from 'rc-resize-observer'; import ResizeObserver from 'rc-resize-observer';
import React from 'react'; import React, { useCallback } from 'react';
import AutoImage from './index'; import AutoImage from './index';
import './single-image.less'; import './single-image.less';
@@ -20,6 +20,7 @@ interface SingleImageProps {
onDelete: (uid: number) => void; onDelete: (uid: number) => void;
autoBgColor?: boolean; autoBgColor?: boolean;
editable?: boolean; editable?: boolean;
style?: React.CSSProperties;
} }
const SingleImage: React.FC<SingleImageProps> = (props) => { const SingleImage: React.FC<SingleImageProps> = (props) => {
@@ -35,6 +36,7 @@ const SingleImage: React.FC<SingleImageProps> = (props) => {
maxHeight, maxHeight,
maxWidth, maxWidth,
dataUrl, dataUrl,
style,
autoBgColor autoBgColor
} = props; } = props;
@@ -49,36 +51,29 @@ const SingleImage: React.FC<SingleImageProps> = (props) => {
return loading ? { width: '100%', height: '100%' } : {}; return loading ? { width: '100%', height: '100%' } : {};
}, [loading, imgSize]); }, [loading, imgSize]);
const handleResize = React.useCallback( const handleResize = useCallback(
async (size: { width: number; height: number }) => { (size: { width: number; height: number }) => {
if (!autoSize || !dataUrl) return; if (!autoSize) return;
const { width: containerWidth, height: containerHeight } = size; const { width: containerWidth, height: containerHeight } = size;
const { width: originalWidth, height: originalHeight } = props; const { width: originalWidth, height: originalHeight } = props;
console.log('size:', size, originalWidth, originalHeight);
if (!originalWidth || !originalHeight) return; if (!originalWidth || !originalHeight) return;
const imageAspectRatio = originalWidth / originalHeight; const widthRatio = containerWidth / originalWidth;
const containerAspectRatio = containerWidth / containerHeight; const heightRatio = containerHeight / originalHeight;
let newWidth, newHeight; const scale = Math.min(widthRatio, heightRatio, 1);
const newWidth = originalWidth * scale;
const newHeight = originalHeight * scale;
if (containerAspectRatio > imageAspectRatio) {
newHeight = containerHeight;
newWidth = containerHeight * imageAspectRatio;
} else {
newWidth = containerWidth;
newHeight = containerWidth / imageAspectRatio;
}
console.log('size++++++++=', size, newWidth, newHeight);
setImgSize({ setImgSize({
width: newWidth, width: newWidth,
height: newHeight height: newHeight
}); });
}, },
[autoSize, dataUrl, props] [autoSize, props.width, props.height]
); );
const handleOnLoad = React.useCallback(async () => { const handleOnLoad = React.useCallback(async () => {
@@ -129,6 +124,7 @@ const SingleImage: React.FC<SingleImageProps> = (props) => {
return ( return (
<ResizeObserver onResize={handleResize}> <ResizeObserver onResize={handleResize}>
<div <div
style={{ ...style }}
key={uid} key={uid}
className={classNames('single-image', { className={classNames('single-image', {
'auto-bg-color': autoBgColor, 'auto-bg-color': autoBgColor,
+15 -2
View File
@@ -106,6 +106,12 @@ const AudioPlayer: React.FC<
} }
}; };
const seekTo = (value: number) => {
if (wavesurfer.current) {
wavesurfer.current.seekTo(value);
}
};
const duration = () => { const duration = () => {
if (wavesurfer.current) { if (wavesurfer.current) {
return wavesurfer.current.getDuration(); return wavesurfer.current.getDuration();
@@ -123,7 +129,8 @@ const AudioPlayer: React.FC<
return { return {
play, play,
pause, pause,
duration duration,
seekTo
}; };
}); });
@@ -135,7 +142,13 @@ const AudioPlayer: React.FC<
destroyWavesurfer(); destroyWavesurfer();
}; };
}, [audioUrl, container.current]); }, [audioUrl, container.current]);
return <div ref={container} className="audio-container"></div>; return (
<div
ref={container}
className="audio-container"
style={{ display: 'none' }}
></div>
);
}); });
export default React.memo(AudioPlayer); export default React.memo(AudioPlayer);
+34 -12
View File
@@ -1,3 +1,4 @@
import AudioAnimation from '@/components/audio-animation';
import useResizeObserver from '@/components/logs-viewer/use-size'; import useResizeObserver from '@/components/logs-viewer/use-size';
import { import {
DownloadOutlined, DownloadOutlined,
@@ -5,12 +6,13 @@ import {
PlayCircleOutlined PlayCircleOutlined
} from '@ant-design/icons'; } from '@ant-design/icons';
import { useIntl } from '@umijs/max'; import { useIntl } from '@umijs/max';
import { Button, Tooltip } from 'antd'; import { Button, Slider, Tooltip } from 'antd';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import _ from 'lodash'; import _, { throttle } from 'lodash';
import React, { useCallback, useEffect, useRef, useState } from 'react'; import React, { useCallback, useEffect, useRef, useState } from 'react';
import AudioPlayer from './audio-player'; import AudioPlayer from './audio-player';
import './styles/index.less'; import './styles/index.less';
import './styles/slider-progress.less';
const audioFormat = { const audioFormat = {
'audio/mpeg': 'mp3', 'audio/mpeg': 'mp3',
@@ -72,10 +74,18 @@ const SpeechItem: React.FC<SpeechContentProps> = (props) => {
setIsPlay(false); setIsPlay(false);
}, []); }, []);
const handleOnAudioprocess = useCallback((current: number) => { const throttleUpdateCurrentTime = throttle((current: number) => {
setCurrentTime(() => current); setCurrentTime(current);
console.log('current:', current, duration); }, 100);
}, []);
const handleOnAudioprocess = useCallback(
(current: number) => {
console.log('current:', current);
// setCurrentTime(() => current);
throttleUpdateCurrentTime(current);
},
[throttleUpdateCurrentTime]
);
const handleReay = useCallback((duration: number) => { const handleReay = useCallback((duration: number) => {
setIsPlay(props.autoplay); setIsPlay(props.autoplay);
@@ -87,13 +97,17 @@ const SpeechItem: React.FC<SpeechContentProps> = (props) => {
}, []); }, []);
const handleAnimationResize = useCallback((size: any) => { const handleAnimationResize = useCallback((size: any) => {
console.log('size:=======', size);
setAnimationSize({ setAnimationSize({
width: size.width, width: size.width,
height: size.height height: size.height
}); });
}, []); }, []);
const handleSliderChange = (value: number) => {
ref.current?.seekTo(value);
setCurrentTime(value);
};
useEffect(() => { useEffect(() => {
console.log('width:', size); console.log('width:', size);
}, [size]); }, [size]);
@@ -112,7 +126,6 @@ const SpeechItem: React.FC<SpeechContentProps> = (props) => {
return ( return (
<div> <div>
<div className="speech-item"> <div className="speech-item">
<div style={{}}></div>
<div <div
className="wrapper" className="wrapper"
style={{ height: 82, width: '100%' }} style={{ height: 82, width: '100%' }}
@@ -128,22 +141,31 @@ const SpeechItem: React.FC<SpeechContentProps> = (props) => {
onAudioprocess={handleOnAudioprocess} onAudioprocess={handleOnAudioprocess}
ref={ref} ref={ref}
></AudioPlayer> ></AudioPlayer>
{/* {!isPlay && ( {isPlay && (
<AudioAnimation <AudioAnimation
maxBarCount={180} maxBarCount={180}
fixedHeight={true}
height={82} height={82}
width={800} width={800}
analyserData={audioChunks} analyserData={audioChunks}
></AudioAnimation> ></AudioAnimation>
)} */} )}
</div> </div>
</div> </div>
{/* <Slider value={currentTime} max={duration} step={0.01}></Slider> */} <Slider
className="slider-progress"
value={currentTime}
max={duration}
step={0.01}
onChange={handleSliderChange}
></Slider>
<div className="speech-actions"> <div className="speech-actions">
<span className="tags"> <span className="tags">
<span className="item">{props.format}</span> <span className="item">{props.format}</span>
</span> </span>
<span className="duration">{_.round(duration, 2)}</span> <span className="duration">
{_.round(currentTime, 2) || _.round(duration, 2)}
</span>
<div className="actions"> <div className="actions">
<Tooltip <Tooltip
title={ title={
@@ -69,6 +69,12 @@
} }
} }
.duration {
display: flex;
justify-content: center;
width: 100px;
}
.tags { .tags {
display: flex; display: flex;
justify-content: flex-start; justify-content: flex-start;
@@ -0,0 +1,21 @@
.slider-progress {
&:hover {
.ant-slider-track {
background-color: var(--ant-blue-5);
}
}
.ant-slider-rail {
border-radius: var(--border-radius-base);
height: 2px;
}
.ant-slider-track {
background-color: var(--ant-blue-5);
height: 2px;
}
.ant-slider-handle {
display: none;
}
}
+1 -1
View File
@@ -58,7 +58,7 @@ export default {
'models.table.layers': 'Layers', 'models.table.layers': 'Layers',
'models.form.backend': 'Backend', 'models.form.backend': 'Backend',
'models.form.backend_parameters': 'Backend Parameters', 'models.form.backend_parameters': 'Backend Parameters',
'models.search.gguf.tips': '1. GGUF model backend is llama-box(llama.cpp).', 'models.search.gguf.tips': '1. GGUF model backend is llama-box.',
'models.search.vllm.tips': '2. Non-GGUF model backend is vLLM.', 'models.search.vllm.tips': '2. Non-GGUF model backend is vLLM.',
'models.form.ollamalink': 'Find More in Ollama Library', 'models.form.ollamalink': 'Find More in Ollama Library',
'models.form.backend_parameters.llamabox.placeholder': 'models.form.backend_parameters.llamabox.placeholder':
+1 -1
View File
@@ -57,7 +57,7 @@ export default {
'models.table.layers': '层', 'models.table.layers': '层',
'models.form.backend': '后端', 'models.form.backend': '后端',
'models.form.backend_parameters': '后端参数', 'models.form.backend_parameters': '后端参数',
'models.search.gguf.tips': '1. GGUF 模型后端为 llama-box(llama.cpp)', 'models.search.gguf.tips': '1. GGUF 模型后端为 llama-box',
'models.search.vllm.tips': '2. 非 GGUF 模型后端为 vLLM', 'models.search.vllm.tips': '2. 非 GGUF 模型后端为 vLLM',
'models.form.ollamalink': '在 Ollama Library 中查找', 'models.form.ollamalink': '在 Ollama Library 中查找',
'models.form.backend_parameters.llamabox.placeholder': 'models.form.backend_parameters.llamabox.placeholder':
@@ -255,7 +255,7 @@ const AdvanceConfig: React.FC<AdvanceConfigProps> = (props) => {
label={intl.formatMessage({ id: 'models.form.backend' })} label={intl.formatMessage({ id: 'models.form.backend' })}
options={[ options={[
{ {
label: `llama-box(llama.cpp)`, label: `llama-box`,
value: backendOptionsMap.llamaBox, value: backendOptionsMap.llamaBox,
disabled: disabled:
source === modelSourceMap.local_path_value ? false : !isGGUF source === modelSourceMap.local_path_value ? false : !isGGUF
@@ -196,7 +196,7 @@ const GroundImages: React.FC<MessageProps> = forwardRef((props, ref) => {
height: imgSize[1], height: imgSize[1],
width: imgSize[0], width: imgSize[0],
loading: true, loading: true,
uid: index uid: setMessageId()
}; };
}); });
setImageList(newImageList); setImageList(newImageList);
@@ -232,6 +232,7 @@ const GroundLeft: React.FC<MessageProps> = forwardRef((props, ref) => {
if (isRecording) { if (isRecording) {
return ( return (
<AudioAnimation <AudioAnimation
fixedHeight={true}
height={82} height={82}
width={500} width={500}
analyserData={audioChunks} analyserData={audioChunks}
@@ -338,7 +338,7 @@ const GroundLeft: React.FC<MessageProps> = forwardRef((props, ref) => {
return ( return (
<div className="ground-left-wrapper"> <div className="ground-left-wrapper">
<div className="ground-left"> <div className="ground-left">
<div className="message-list-wrap" ref={scroller}> <div className="message-list-wrap">
<div <div
style={{ style={{
height: '100%', height: '100%',
+64 -7
View File
@@ -1,7 +1,7 @@
import SingleImage from '@/components/auto-image/single-image'; import SingleImage from '@/components/auto-image/single-image';
import { Col, Row } from 'antd'; import { Col, Row } from 'antd';
import _ from 'lodash'; import _ from 'lodash';
import React, { useCallback } from 'react'; import React, { useCallback, useMemo } from 'react';
import '../style/thumb-img.less'; import '../style/thumb-img.less';
const ThumbImg: React.FC<{ const ThumbImg: React.FC<{
@@ -32,13 +32,67 @@ const ThumbImg: React.FC<{
[onDelete] [onDelete]
); );
if (!dataList?.length) { const responseableStyle: Record<number, any> = useMemo(() => {
return null; if (!responseable) return {};
if (dataList.length === 1) {
return {
0: {
justifyContent: 'center',
alignItems: 'center'
} }
};
}
if (dataList.length === 2) {
return {
0: {
justifyContent: 'flex-end',
alignItems: 'center'
},
1: {
justifyContent: 'flex-start',
alignItems: 'center'
}
};
}
if (dataList.length === 3) {
return {
0: {
justifyContent: 'flex-end',
alignItems: 'flex-end'
},
1: {
justifyContent: 'flex-start',
alignItems: 'flex-end'
},
2: {
justifyContent: 'flex-end',
alignItems: 'flex-start'
}
};
}
return {
0: {
justifyContent: 'flex-end',
alignItems: 'flex-end'
},
1: {
justifyContent: 'flex-start',
alignItems: 'flex-end'
},
2: {
justifyContent: 'flex-end',
alignItems: 'flex-start'
},
3: {
justifyContent: 'flex-start',
alignItems: 'flex-start'
}
};
}, [dataList, responseable]);
return ( return (
<> <>
{ {dataList?.length ? (
<div className="thumb-list-wrap" style={{ ...style }}> <div className="thumb-list-wrap" style={{ ...style }}>
{responseable ? ( {responseable ? (
<> <>
@@ -53,7 +107,7 @@ const ThumbImg: React.FC<{
dataList.length === 1 ? 'center' : 'flex-start' dataList.length === 1 ? 'center' : 'flex-start'
}} }}
> >
{_.map(_.slice(dataList, 0, 2), (item: any, index: string) => { {_.map(_.slice(dataList, 0, 2), (item: any, index: number) => {
return ( return (
<Col <Col
span={item.span} span={item.span}
@@ -63,6 +117,7 @@ const ThumbImg: React.FC<{
> >
<SingleImage <SingleImage
{...item} {...item}
style={{ ...(responseableStyle[index] || {}) }}
autoSize={autoSize} autoSize={autoSize}
editable={editable} editable={editable}
autoBgColor={autoBgColor} autoBgColor={autoBgColor}
@@ -84,7 +139,8 @@ const ThumbImg: React.FC<{
}} }}
className="flex-center" className="flex-center"
> >
{_.map(_.slice(dataList, 2), (item: any, index: string) => { {_.map(_.slice(dataList, 2), (item: any, index: number) => {
console.log('index=======', index);
return ( return (
<Col <Col
span={item.span} span={item.span}
@@ -94,6 +150,7 @@ const ThumbImg: React.FC<{
> >
<SingleImage <SingleImage
{...item} {...item}
style={{ ...(responseableStyle[index + 2] || {}) }}
loading={item.loading} loading={item.loading}
autoSize={autoSize} autoSize={autoSize}
editable={editable} editable={editable}
@@ -122,7 +179,7 @@ const ThumbImg: React.FC<{
</> </>
)} )}
</div> </div>
} ) : null}
</> </>
); );
}; };