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