chore: slider to change width and height in image
This commit is contained in:
@@ -6,5 +6,6 @@
|
|||||||
|
|
||||||
canvas {
|
canvas {
|
||||||
display: block;
|
display: block;
|
||||||
|
image-rendering: crisp-edges;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,19 +4,40 @@ import './index.less';
|
|||||||
interface AudioAnimationProps {
|
interface AudioAnimationProps {
|
||||||
width: number;
|
width: number;
|
||||||
height: number;
|
height: number;
|
||||||
|
scaleFactor?: number;
|
||||||
analyserData: {
|
analyserData: {
|
||||||
data: Uint8Array;
|
data: Uint8Array;
|
||||||
analyser: any;
|
analyser: any;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const AudioAnimation: React.FC<AudioAnimationProps> = (props) => {
|
const AudioAnimation: React.FC<AudioAnimationProps> = ({
|
||||||
const { width, height, analyserData } = props;
|
width,
|
||||||
|
height,
|
||||||
|
scaleFactor = 1.2,
|
||||||
|
analyserData
|
||||||
|
}) => {
|
||||||
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 maxBarCount = 128;
|
||||||
|
|
||||||
|
const calculateJitter = (
|
||||||
|
i: number,
|
||||||
|
timestamp: number,
|
||||||
|
baseHeight: number,
|
||||||
|
minJitter: number,
|
||||||
|
jitterAmplitude: number
|
||||||
|
) => {
|
||||||
|
//
|
||||||
|
const jitterFactor = Math.sin(timestamp / 200 + i) * 0.5 + 0.5;
|
||||||
|
const jitter =
|
||||||
|
minJitter +
|
||||||
|
jitterFactor * (jitterAmplitude - minJitter) * (baseHeight / maxBarCount);
|
||||||
|
return jitter;
|
||||||
|
};
|
||||||
|
|
||||||
const startAudioVisualization = () => {
|
const startAudioVisualization = () => {
|
||||||
if (!canvasRef.current || !analyserData.data?.length) return;
|
if (!canvasRef.current || !analyserData.data?.length) return;
|
||||||
@@ -33,42 +54,51 @@ const AudioAnimation: React.FC<AudioAnimationProps> = (props) => {
|
|||||||
isScaled.current = true;
|
isScaled.current = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const barWidth = 3;
|
const barWidth = 4;
|
||||||
const barSpacing = 2;
|
const barSpacing = 6;
|
||||||
const centerX = HEIGHT / 2;
|
|
||||||
const centerLine = Math.floor(HEIGHT / 2);
|
const centerLine = Math.floor(HEIGHT / 2);
|
||||||
const jitterAmplitude = 60; // 最大抖动幅度
|
|
||||||
const minJitter = 15; // 最小抖动幅度
|
|
||||||
|
|
||||||
const frameInterval = 2;
|
const jitterAmplitude = 40;
|
||||||
let frameCount = 0;
|
const minJitter = 10;
|
||||||
|
|
||||||
canvasCtx.fillStyle = '#0073EF';
|
let lastFrameTime = 0;
|
||||||
|
|
||||||
const draw = () => {
|
const gradient = canvasCtx.createLinearGradient(0, 0, 0, HEIGHT);
|
||||||
frameCount++;
|
gradient.addColorStop(0, '#007BFF');
|
||||||
if (frameCount % frameInterval !== 0) {
|
gradient.addColorStop(1, '#0069DA');
|
||||||
|
canvasCtx.fillStyle = gradient;
|
||||||
|
|
||||||
|
const draw = (timestamp: number) => {
|
||||||
|
const elapsed = timestamp - lastFrameTime;
|
||||||
|
if (elapsed < 16) {
|
||||||
animationId.current = requestAnimationFrame(draw);
|
animationId.current = requestAnimationFrame(draw);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
lastFrameTime = timestamp;
|
||||||
|
|
||||||
analyserData.analyser?.current?.getByteFrequencyData(analyserData.data);
|
analyserData.analyser?.current?.getByteFrequencyData(analyserData.data);
|
||||||
canvasCtx.clearRect(0, 0, WIDTH, HEIGHT);
|
canvasCtx.clearRect(0, 0, WIDTH, HEIGHT);
|
||||||
|
|
||||||
const barCount = analyserData.data.length;
|
const barCount = Math.min(maxBarCount, analyserData.data.length);
|
||||||
const totalWidth = barCount * (barWidth + barSpacing) - barSpacing;
|
const totalWidth = barCount * (barWidth + barSpacing) - barSpacing;
|
||||||
let x = centerX - totalWidth / 2 + oscillationOffset.current;
|
let x = WIDTH / 2 - totalWidth / 2 + oscillationOffset.current;
|
||||||
oscillationOffset.current += direction.current * 0.5;
|
|
||||||
|
|
||||||
if (oscillationOffset.current > 20 || oscillationOffset.current < -20) {
|
oscillationOffset.current += direction.current;
|
||||||
|
if (Math.abs(oscillationOffset.current) > 20) {
|
||||||
direction.current *= -1;
|
direction.current *= -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let i = 0; i < barCount; i++) {
|
for (let i = 0; i < barCount; i++) {
|
||||||
const baseHeight = Math.floor(analyserData.data[i] / 2);
|
const baseHeight = Math.floor(analyserData.data[i] / 2) * scaleFactor;
|
||||||
const jitter =
|
|
||||||
minJitter +
|
const jitter = calculateJitter(
|
||||||
Math.round((Math.random() - 0.5) * (jitterAmplitude - minJitter));
|
i,
|
||||||
const barHeight = baseHeight + jitter;
|
timestamp,
|
||||||
|
baseHeight,
|
||||||
|
minJitter,
|
||||||
|
jitterAmplitude
|
||||||
|
);
|
||||||
|
const barHeight = baseHeight + Math.round(jitter);
|
||||||
|
|
||||||
const topY = Math.round(centerLine - barHeight / 2);
|
const topY = Math.round(centerLine - barHeight / 2);
|
||||||
const bottomY = Math.round(centerLine + barHeight / 2);
|
const bottomY = Math.round(centerLine + barHeight / 2);
|
||||||
@@ -87,21 +117,29 @@ const AudioAnimation: React.FC<AudioAnimationProps> = (props) => {
|
|||||||
animationId.current = requestAnimationFrame(draw);
|
animationId.current = requestAnimationFrame(draw);
|
||||||
};
|
};
|
||||||
|
|
||||||
draw();
|
draw(performance.now());
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!analyserData.data?.length || !analyserData.analyser.current) {
|
const clearCanvas = () => {
|
||||||
canvasRef.current
|
if (canvasRef.current) {
|
||||||
?.getContext('2d')
|
const ctx = canvasRef.current.getContext('2d');
|
||||||
?.clearRect(0, 0, width * 2, height * 2);
|
if (ctx) ctx.clearRect(0, 0, width * 2, height * 2);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!analyserData.data?.length || !analyserData.analyser?.current) {
|
||||||
|
clearCanvas();
|
||||||
cancelAnimationFrame(animationId.current);
|
cancelAnimationFrame(animationId.current);
|
||||||
animationId.current = 0;
|
animationId.current = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
startAudioVisualization();
|
startAudioVisualization();
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
if (animationId.current) cancelAnimationFrame(animationId.current);
|
cancelAnimationFrame(animationId.current);
|
||||||
|
clearCanvas();
|
||||||
};
|
};
|
||||||
}, [analyserData, width, height]);
|
}, [analyserData, width, height]);
|
||||||
|
|
||||||
|
|||||||
@@ -75,6 +75,12 @@
|
|||||||
.file-name {
|
.file-name {
|
||||||
line-height: 20px;
|
line-height: 20px;
|
||||||
height: 20px;
|
height: 20px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ant-slider-horizontal {
|
.ant-slider-horizontal {
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ const AudioPlayer: React.FC<AudioPlayerProps> = forwardRef((props, ref) => {
|
|||||||
});
|
});
|
||||||
const [playOn, setPlayOn] = React.useState<boolean>(false);
|
const [playOn, setPlayOn] = React.useState<boolean>(false);
|
||||||
const [speakerOn, setSpeakerOn] = React.useState<boolean>(false);
|
const [speakerOn, setSpeakerOn] = React.useState<boolean>(false);
|
||||||
const [volume, setVolume] = React.useState<number>(0.5);
|
const [volume, setVolume] = React.useState<number>(1);
|
||||||
const [speed, setSpeed] = React.useState<number>(defaultSpeed);
|
const [speed, setSpeed] = React.useState<number>(defaultSpeed);
|
||||||
const timer = React.useRef<any>(null);
|
const timer = React.useRef<any>(null);
|
||||||
|
|
||||||
@@ -98,12 +98,12 @@ const AudioPlayer: React.FC<AudioPlayerProps> = forwardRef((props, ref) => {
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const handlePlay = useCallback(() => {
|
const handlePlay = useCallback(() => {
|
||||||
|
setPlayOn(!playOn);
|
||||||
if (playOn) {
|
if (playOn) {
|
||||||
audioRef.current?.pause();
|
audioRef.current?.pause();
|
||||||
} else {
|
} else {
|
||||||
audioRef.current?.play();
|
audioRef.current?.play();
|
||||||
}
|
}
|
||||||
setPlayOn(!playOn);
|
|
||||||
}, [playOn]);
|
}, [playOn]);
|
||||||
|
|
||||||
const handleFormatVolume = (val?: number) => {
|
const handleFormatVolume = (val?: number) => {
|
||||||
@@ -118,10 +118,12 @@ const AudioPlayer: React.FC<AudioPlayerProps> = forwardRef((props, ref) => {
|
|||||||
setVolume(round(value, 2));
|
setVolume(round(value, 2));
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const initPlayerConfig = useCallback(() => {
|
const initPlayerConfig = () => {
|
||||||
audioRef.current!.volume = volume;
|
if (audioRef.current) {
|
||||||
audioRef.current!.playbackRate = speed;
|
audioRef.current!.volume = volume;
|
||||||
}, []);
|
audioRef.current!.playbackRate = speed;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const handleLoadedMetadata = useCallback(
|
const handleLoadedMetadata = useCallback(
|
||||||
(data: any) => {
|
(data: any) => {
|
||||||
@@ -168,6 +170,10 @@ const AudioPlayer: React.FC<AudioPlayerProps> = forwardRef((props, ref) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleOnLoad = (e: any) => {
|
||||||
|
console.log('onload', e);
|
||||||
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (audioRef.current) {
|
if (audioRef.current) {
|
||||||
initPlayerConfig();
|
initPlayerConfig();
|
||||||
@@ -195,6 +201,7 @@ const AudioPlayer: React.FC<AudioPlayerProps> = forwardRef((props, ref) => {
|
|||||||
<Slider
|
<Slider
|
||||||
tooltip={{ open: false }}
|
tooltip={{ open: false }}
|
||||||
min={0}
|
min={0}
|
||||||
|
step={1}
|
||||||
max={audioState.duration}
|
max={audioState.duration}
|
||||||
value={audioState.currentTime}
|
value={audioState.currentTime}
|
||||||
onChange={handleCurrentChange}
|
onChange={handleCurrentChange}
|
||||||
@@ -203,23 +210,6 @@ const AudioPlayer: React.FC<AudioPlayerProps> = forwardRef((props, ref) => {
|
|||||||
<span className="time">{formatTime(audioState.duration)}</span>
|
<span className="time">{formatTime(audioState.duration)}</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="controls">
|
<div className="controls">
|
||||||
{/* <Tooltip
|
|
||||||
overlayInnerStyle={{
|
|
||||||
backgroundColor: 'var(--color-white-1)'
|
|
||||||
}}
|
|
||||||
arrow={false}
|
|
||||||
title={
|
|
||||||
<CheckButtons
|
|
||||||
options={speedOptions}
|
|
||||||
onChange={handleSeepdChange}
|
|
||||||
size="small"
|
|
||||||
></CheckButtons>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<span style={{ cursor: 'pointer' }}>
|
|
||||||
{speed ? `${speed}x` : '1x'}
|
|
||||||
</span>
|
|
||||||
</Tooltip> */}
|
|
||||||
<Tooltip
|
<Tooltip
|
||||||
title={intl.formatMessage({
|
title={intl.formatMessage({
|
||||||
id: 'playground.audio.button.slow'
|
id: 'playground.audio.button.slow'
|
||||||
@@ -276,38 +266,6 @@ const AudioPlayer: React.FC<AudioPlayerProps> = forwardRef((props, ref) => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/* <span className="speaker">
|
|
||||||
<Button
|
|
||||||
size="middle"
|
|
||||||
type="text"
|
|
||||||
icon={
|
|
||||||
volume > 0 ? (
|
|
||||||
<IconFont
|
|
||||||
type="icon-SpeakerHigh"
|
|
||||||
style={{ fontSize: '22px' }}
|
|
||||||
></IconFont>
|
|
||||||
) : (
|
|
||||||
<IconFont
|
|
||||||
type="icon-speaker-slash"
|
|
||||||
style={{ fontSize: '22px' }}
|
|
||||||
></IconFont>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
></Button>
|
|
||||||
{speakerOn && (
|
|
||||||
<Slider
|
|
||||||
tooltip={{ formatter: handleFormatVolume }}
|
|
||||||
style={{ height: '100px' }}
|
|
||||||
className="volume-slider"
|
|
||||||
min={0}
|
|
||||||
max={1}
|
|
||||||
step={0.01}
|
|
||||||
value={volume}
|
|
||||||
vertical
|
|
||||||
onChange={handleVolumeChange}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</span> */}
|
|
||||||
</div>
|
</div>
|
||||||
<audio
|
<audio
|
||||||
controls
|
controls
|
||||||
|
|||||||
@@ -69,7 +69,7 @@
|
|||||||
left: 0;
|
left: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
backdrop-filter: blur(100px);
|
filter: blur(100px);
|
||||||
backdrop-filter: blur(100px);
|
backdrop-filter: blur(100px);
|
||||||
z-index: 5;
|
z-index: 5;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -109,7 +109,13 @@ const SingleImage: React.FC<SingleImageProps> = (props) => {
|
|||||||
overflow: 'hidden'
|
overflow: 'hidden'
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Progress percent={progress} type="circle" />
|
<Progress
|
||||||
|
percent={progress}
|
||||||
|
type="dashboard"
|
||||||
|
steps={{ count: 50, gap: 2 }}
|
||||||
|
format={() => <span className="font-size-20">{progress}%</span>}
|
||||||
|
trailColor="var(--ant-color-fill-secondary)"
|
||||||
|
/>
|
||||||
</span>
|
</span>
|
||||||
) : (
|
) : (
|
||||||
<span
|
<span
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { Checkbox, Slider } from 'antd';
|
import { Checkbox } from 'antd';
|
||||||
import SealInput from '../seal-input';
|
import SealInput from '../seal-input';
|
||||||
import SealSelect from '../seal-select';
|
import SealSelect from '../seal-select';
|
||||||
|
import Slider from '../seal-slider';
|
||||||
|
|
||||||
const components: {
|
const components: {
|
||||||
InputNumber: typeof SealInput.Number;
|
InputNumber: typeof SealInput.Number;
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { useIntl } from '@umijs/max';
|
|||||||
import React, { useCallback, useMemo } from 'react';
|
import React, { useCallback, useMemo } from 'react';
|
||||||
import LabelInfo from './components/label-info';
|
import LabelInfo from './components/label-info';
|
||||||
import componentsMap from './config/components';
|
import componentsMap from './config/components';
|
||||||
|
|
||||||
const FieldComponent: React.FC<ParamsSchema> = (props) => {
|
const FieldComponent: React.FC<ParamsSchema> = (props) => {
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const { type, label, attrs, style, value, ...rest } = props;
|
const { type, label, attrs, style, value, ...rest } = props;
|
||||||
|
|||||||
@@ -0,0 +1,114 @@
|
|||||||
|
import { INPUT_WIDTH } from '@/constants';
|
||||||
|
import { InfoCircleOutlined } from '@ant-design/icons';
|
||||||
|
import {
|
||||||
|
Form,
|
||||||
|
InputNumber,
|
||||||
|
Slider,
|
||||||
|
Tooltip,
|
||||||
|
type SliderSingleProps
|
||||||
|
} from 'antd';
|
||||||
|
import React from 'react';
|
||||||
|
import FieldWrapper from './field-wrapper';
|
||||||
|
import SliderStyles from './styles/slider.less';
|
||||||
|
|
||||||
|
interface SealSliderProps extends SliderSingleProps {
|
||||||
|
required?: boolean;
|
||||||
|
label?: React.ReactNode;
|
||||||
|
labelWidth?: number | string;
|
||||||
|
description?: string;
|
||||||
|
isInFormItems?: boolean;
|
||||||
|
inputnumber?: boolean;
|
||||||
|
checkStatus?: 'success' | 'error' | 'warning' | '';
|
||||||
|
}
|
||||||
|
|
||||||
|
const SealSlider: React.FC<SealSliderProps> = (props) => {
|
||||||
|
const {
|
||||||
|
label,
|
||||||
|
value,
|
||||||
|
required,
|
||||||
|
description,
|
||||||
|
isInFormItems = true,
|
||||||
|
max,
|
||||||
|
min,
|
||||||
|
step,
|
||||||
|
defaultValue,
|
||||||
|
checkStatus,
|
||||||
|
inputnumber = false,
|
||||||
|
labelWidth,
|
||||||
|
tooltip = { open: false },
|
||||||
|
...rest
|
||||||
|
} = props;
|
||||||
|
|
||||||
|
let status = '';
|
||||||
|
if (isInFormItems) {
|
||||||
|
const statusData = Form?.Item?.useStatus?.();
|
||||||
|
status = statusData?.status || '';
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleChange = (value: number) => {
|
||||||
|
props.onChange?.(value);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleInput = (value: number | null) => {
|
||||||
|
const newValue = value || 0;
|
||||||
|
props.onChange?.(newValue);
|
||||||
|
};
|
||||||
|
|
||||||
|
const renderLabel = React.useMemo(() => {
|
||||||
|
return (
|
||||||
|
<span
|
||||||
|
className={SliderStyles['slider-label']}
|
||||||
|
style={{ width: labelWidth || INPUT_WIDTH.mini }}
|
||||||
|
>
|
||||||
|
<span className="text">
|
||||||
|
{description ? (
|
||||||
|
<Tooltip title={description}>
|
||||||
|
<span> {label}</span>
|
||||||
|
<span className="m-l-5">
|
||||||
|
<InfoCircleOutlined />
|
||||||
|
</span>
|
||||||
|
</Tooltip>
|
||||||
|
) : (
|
||||||
|
<span>{label}</span>
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
{inputnumber ? (
|
||||||
|
<InputNumber
|
||||||
|
className="label-val"
|
||||||
|
variant="outlined"
|
||||||
|
size="small"
|
||||||
|
value={value}
|
||||||
|
controls={false}
|
||||||
|
onChange={handleInput}
|
||||||
|
></InputNumber>
|
||||||
|
) : (
|
||||||
|
<span className="val">{value}</span>
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
}, [label, labelWidth, description, value, max, min, step, defaultValue]);
|
||||||
|
return (
|
||||||
|
<FieldWrapper
|
||||||
|
required={required}
|
||||||
|
status={checkStatus || status}
|
||||||
|
label={renderLabel}
|
||||||
|
style={{ padding: '20px 2px 0' }}
|
||||||
|
variant="borderless"
|
||||||
|
>
|
||||||
|
<Slider
|
||||||
|
{...rest}
|
||||||
|
defaultValue={defaultValue}
|
||||||
|
max={max}
|
||||||
|
min={min}
|
||||||
|
step={step}
|
||||||
|
style={{ marginBottom: 0, marginTop: 16, marginInline: 0 }}
|
||||||
|
tooltip={tooltip}
|
||||||
|
value={value}
|
||||||
|
onChange={handleChange}
|
||||||
|
></Slider>
|
||||||
|
</FieldWrapper>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default SealSlider;
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
:local(.slider-label) {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: flex-start;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
:global(.val) {
|
||||||
|
color: var(--ant-color-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
:global(.label-val) {
|
||||||
|
position: absolute !important;
|
||||||
|
top: -14px;
|
||||||
|
right: -14px;
|
||||||
|
width: 80px;
|
||||||
|
border-radius: var(--border-radius-base);
|
||||||
|
text-align: center;
|
||||||
|
border: 1px solid var(--ant-color-border) !important;
|
||||||
|
|
||||||
|
:global(.ant-input-number-input) {
|
||||||
|
text-align: center !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,10 +1,11 @@
|
|||||||
import React, {
|
import React, {
|
||||||
forwardRef,
|
forwardRef,
|
||||||
|
useCallback,
|
||||||
useEffect,
|
useEffect,
|
||||||
useImperativeHandle,
|
useImperativeHandle,
|
||||||
useRef
|
useRef
|
||||||
} from 'react';
|
} from 'react';
|
||||||
import useWavesurfer from './hooks/use-wavesurfer';
|
import WaveSurfer, { WaveSurferOptions } from 'wavesurfer.js';
|
||||||
|
|
||||||
interface AudioPlayerProps {
|
interface AudioPlayerProps {
|
||||||
autoplay: boolean;
|
autoplay: boolean;
|
||||||
@@ -15,27 +16,104 @@ interface AudioPlayerProps {
|
|||||||
width?: number;
|
width?: number;
|
||||||
onReady?: () => void;
|
onReady?: () => void;
|
||||||
onClick?: (value: number) => void;
|
onClick?: (value: number) => void;
|
||||||
|
onFinish?: () => void;
|
||||||
|
onAnalyse?: (analyseData: any, frequencyBinCount: any) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const AudioPlayer: React.FC<AudioPlayerProps> = forwardRef((props, ref) => {
|
const AudioPlayer: React.FC<
|
||||||
|
AudioPlayerProps & Omit<WaveSurferOptions, 'container'>
|
||||||
|
> = forwardRef((props, ref) => {
|
||||||
const { autoplay, audioUrl, speed = 1, ...rest } = props;
|
const { autoplay, audioUrl, speed = 1, ...rest } = props;
|
||||||
const container = useRef<HTMLDivElement>(null);
|
const wavesurfer = useRef<WaveSurfer | null>(null);
|
||||||
const {
|
const container = useRef<any>(null);
|
||||||
createWavesurfer,
|
const audioContext = useRef<any>(null);
|
||||||
play,
|
const analyser = useRef<any>(null);
|
||||||
pause,
|
const dataArray = useRef<any>(null);
|
||||||
duration,
|
const audioStream = useRef<any>(null);
|
||||||
destroyWavesurfer,
|
const mediaElement = useRef<any>(null);
|
||||||
wavesurfer
|
|
||||||
} = useWavesurfer({
|
const initAudioContext = useCallback(() => {
|
||||||
container,
|
audioContext.current = new (window.AudioContext ||
|
||||||
autoplay: autoplay,
|
window.webkitAudioContext)();
|
||||||
url: audioUrl,
|
|
||||||
audioRate: speed,
|
analyser.current = audioContext.current.createAnalyser();
|
||||||
onReady: props.onReady,
|
analyser.current.fftSize = 512;
|
||||||
onClick: props.onClick,
|
dataArray.current = new Uint8Array(analyser.current.frequencyBinCount);
|
||||||
...rest
|
}, []);
|
||||||
});
|
|
||||||
|
const generateVisualData = useCallback(() => {
|
||||||
|
const source = audioContext.current.createMediaElementSource(
|
||||||
|
mediaElement.current
|
||||||
|
);
|
||||||
|
source.connect(analyser.current);
|
||||||
|
analyser.current.connect(audioContext.current.destination);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const listenEvents = () => {
|
||||||
|
wavesurfer.current?.on('ready', () => {
|
||||||
|
props.onReady?.();
|
||||||
|
});
|
||||||
|
|
||||||
|
wavesurfer.current?.on('click', (value) => {
|
||||||
|
props.onClick?.(value);
|
||||||
|
});
|
||||||
|
wavesurfer.current?.on('finish', () => {
|
||||||
|
props.onFinish?.();
|
||||||
|
});
|
||||||
|
wavesurfer.current?.on('play', () => {
|
||||||
|
// analyser.current?.getByteFrequencyData(dataArray.current);
|
||||||
|
// props.onAnalyse?.(dataArray.current, analyser);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const createWavesurfer = () => {
|
||||||
|
wavesurfer.current = WaveSurfer.create({
|
||||||
|
container: container.current,
|
||||||
|
url: audioUrl,
|
||||||
|
autoplay: autoplay,
|
||||||
|
audioRate: speed,
|
||||||
|
waveColor: '#4096ff',
|
||||||
|
progressColor: 'rgb(100, 0, 100)',
|
||||||
|
height: 60,
|
||||||
|
barWidth: 2,
|
||||||
|
barGap: 1,
|
||||||
|
barRadius: 2,
|
||||||
|
interact: true,
|
||||||
|
cursorWidth: 0,
|
||||||
|
...rest
|
||||||
|
});
|
||||||
|
|
||||||
|
mediaElement.current = wavesurfer.current?.getMediaElement();
|
||||||
|
|
||||||
|
initAudioContext();
|
||||||
|
generateVisualData();
|
||||||
|
listenEvents();
|
||||||
|
};
|
||||||
|
|
||||||
|
const destroyWavesurfer = () => {
|
||||||
|
if (wavesurfer.current) {
|
||||||
|
wavesurfer.current.destroy();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const play = () => {
|
||||||
|
if (wavesurfer.current) {
|
||||||
|
wavesurfer.current.play();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const duration = () => {
|
||||||
|
if (wavesurfer.current) {
|
||||||
|
return wavesurfer.current.getDuration();
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
const pause = () => {
|
||||||
|
if (wavesurfer.current) {
|
||||||
|
wavesurfer.current.pause();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
useImperativeHandle(ref, () => {
|
useImperativeHandle(ref, () => {
|
||||||
return {
|
return {
|
||||||
@@ -46,13 +124,13 @@ const AudioPlayer: React.FC<AudioPlayerProps> = forwardRef((props, ref) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (container.current) {
|
if (container.current && audioUrl) {
|
||||||
createWavesurfer();
|
createWavesurfer();
|
||||||
}
|
}
|
||||||
return () => {
|
return () => {
|
||||||
destroyWavesurfer();
|
destroyWavesurfer();
|
||||||
};
|
};
|
||||||
}, [container.current]);
|
}, [audioUrl, container.current]);
|
||||||
return <div ref={container} className="audio-container"></div>;
|
return <div ref={container} className="audio-container"></div>;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,86 +0,0 @@
|
|||||||
import { useRef } from 'react';
|
|
||||||
import WaveSurfer from 'wavesurfer.js';
|
|
||||||
|
|
||||||
interface Options {
|
|
||||||
container: React.RefObject<HTMLDivElement>;
|
|
||||||
waveColor?: string;
|
|
||||||
progressColor?: string;
|
|
||||||
url: string;
|
|
||||||
barWidth?: number;
|
|
||||||
barGap?: number;
|
|
||||||
barRadius?: number;
|
|
||||||
autoplay?: boolean;
|
|
||||||
audioRate?: number;
|
|
||||||
onReady?: () => void;
|
|
||||||
onClick: (value: number) => void;
|
|
||||||
}
|
|
||||||
const useWavesurfer = (options: Options) => {
|
|
||||||
const wavesurfer = useRef<WaveSurfer | null>(null);
|
|
||||||
|
|
||||||
const { container, url, ...rest } = options;
|
|
||||||
|
|
||||||
const createWavesurfer = () => {
|
|
||||||
if (!container.current) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (wavesurfer.current) {
|
|
||||||
wavesurfer.current.destroy();
|
|
||||||
}
|
|
||||||
wavesurfer.current = WaveSurfer.create({
|
|
||||||
container: container.current,
|
|
||||||
waveColor: '#4096ff',
|
|
||||||
progressColor: 'rgb(100, 0, 100)',
|
|
||||||
url: url,
|
|
||||||
height: 60,
|
|
||||||
barWidth: 2,
|
|
||||||
barGap: 1,
|
|
||||||
barRadius: 2,
|
|
||||||
interact: true,
|
|
||||||
cursorWidth: 0,
|
|
||||||
...rest
|
|
||||||
});
|
|
||||||
wavesurfer.current?.on('ready', () => {
|
|
||||||
options.onReady?.();
|
|
||||||
});
|
|
||||||
|
|
||||||
wavesurfer.current?.on('click', (value) => {
|
|
||||||
options.onClick?.(value);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const destroyWavesurfer = () => {
|
|
||||||
if (wavesurfer.current) {
|
|
||||||
wavesurfer.current.destroy();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const play = () => {
|
|
||||||
if (wavesurfer.current) {
|
|
||||||
wavesurfer.current.play();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const duration = () => {
|
|
||||||
if (wavesurfer.current) {
|
|
||||||
return wavesurfer.current.getDuration();
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
const pause = () => {
|
|
||||||
if (wavesurfer.current) {
|
|
||||||
wavesurfer.current.pause();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
|
||||||
createWavesurfer,
|
|
||||||
play,
|
|
||||||
pause,
|
|
||||||
wavesurfer,
|
|
||||||
duration,
|
|
||||||
destroyWavesurfer
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export default useWavesurfer;
|
|
||||||
@@ -37,9 +37,13 @@ interface SpeechContentProps {
|
|||||||
const SpeechItem: React.FC<SpeechContentProps> = (props) => {
|
const SpeechItem: React.FC<SpeechContentProps> = (props) => {
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const [collapsed, setCollapsed] = useState(false);
|
const [collapsed, setCollapsed] = useState(false);
|
||||||
const [isPlay, setIsPlay] = useState(false);
|
const [isPlay, setIsPlay] = useState(props.autoplay);
|
||||||
const [duration, setDuration] = useState(0);
|
const [duration, setDuration] = useState(0);
|
||||||
const [currentTime, setCurrentTime] = useState(0);
|
const [currentTime, setCurrentTime] = useState(0);
|
||||||
|
const [audioChunks, setAudioChunks] = useState<any>({
|
||||||
|
data: [],
|
||||||
|
analyser: null
|
||||||
|
});
|
||||||
const ref = useRef<any>(null);
|
const ref = useRef<any>(null);
|
||||||
|
|
||||||
const handlePlay = () => {
|
const handlePlay = () => {
|
||||||
@@ -52,8 +56,13 @@ const SpeechItem: React.FC<SpeechContentProps> = (props) => {
|
|||||||
setIsPlay(true);
|
setIsPlay(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleCollapse = () => {
|
const handleOnAnalyse = (data: any, analyser: any) => {
|
||||||
setCollapsed(!collapsed);
|
setAudioChunks((pre: any) => {
|
||||||
|
return {
|
||||||
|
data: data,
|
||||||
|
analyser: analyser
|
||||||
|
};
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleReay = () => {
|
const handleReay = () => {
|
||||||
@@ -80,6 +89,13 @@ const SpeechItem: React.FC<SpeechContentProps> = (props) => {
|
|||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div className="speech-item">
|
<div className="speech-item">
|
||||||
|
{/* {isPlay && (
|
||||||
|
<AudioAnimation
|
||||||
|
height={82}
|
||||||
|
width={500}
|
||||||
|
analyserData={audioChunks}
|
||||||
|
></AudioAnimation>
|
||||||
|
)} */}
|
||||||
<div className="voice">
|
<div className="voice">
|
||||||
<IconFont type="icon-user_voice" className="font-size-16" />
|
<IconFont type="icon-user_voice" className="font-size-16" />
|
||||||
</div>
|
</div>
|
||||||
@@ -89,6 +105,8 @@ const SpeechItem: React.FC<SpeechContentProps> = (props) => {
|
|||||||
audioUrl={props.audioUrl}
|
audioUrl={props.audioUrl}
|
||||||
onReady={handleReay}
|
onReady={handleReay}
|
||||||
onClick={handleOnClick}
|
onClick={handleOnClick}
|
||||||
|
onFinish={() => setIsPlay(false)}
|
||||||
|
onAnalyse={handleOnAnalyse}
|
||||||
ref={ref}
|
ref={ref}
|
||||||
></AudioPlayer>
|
></AudioPlayer>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -270,6 +270,7 @@ export default (props: any) => {
|
|||||||
title={userConfig.title}
|
title={userConfig.title}
|
||||||
navTheme="light"
|
navTheme="light"
|
||||||
layout="side"
|
layout="side"
|
||||||
|
openKeys={false}
|
||||||
disableMobile={true}
|
disableMobile={true}
|
||||||
siderWidth={220}
|
siderWidth={220}
|
||||||
onCollapse={(collapsed) => {
|
onCollapse={(collapsed) => {
|
||||||
@@ -284,6 +285,7 @@ export default (props: any) => {
|
|||||||
collapsed={collapsed}
|
collapsed={collapsed}
|
||||||
onPageChange={(route) => {
|
onPageChange={(route) => {
|
||||||
const { location } = history;
|
const { location } = history;
|
||||||
|
const { pathname } = location;
|
||||||
|
|
||||||
// if user is not change password, redirect to change password page
|
// if user is not change password, redirect to change password page
|
||||||
if (
|
if (
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ export default {
|
|||||||
'playground.input.holder': 'Type <kbd>/</kbd> to input message',
|
'playground.input.holder': 'Type <kbd>/</kbd> to input message',
|
||||||
'playground.input.prompt.holder': 'Type <kbd>/</kbd> to input prompt',
|
'playground.input.prompt.holder': 'Type <kbd>/</kbd> to input prompt',
|
||||||
'playground.input.keyword.holder': 'Type <kbd>/</kbd> to input your query',
|
'playground.input.keyword.holder': 'Type <kbd>/</kbd> to input your query',
|
||||||
|
'playground.input.text.holder': 'Type <kbd>/</kbd> to input text',
|
||||||
'playground.compare.apply': 'Apply',
|
'playground.compare.apply': 'Apply',
|
||||||
'playground.compare.applytoall': 'Apply to all models',
|
'playground.compare.applytoall': 'Apply to all models',
|
||||||
'playground.model.noavailable': 'No available models',
|
'playground.model.noavailable': 'No available models',
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ export default {
|
|||||||
'playground.input.holder': '按 <kbd>/</kbd> 开始输入',
|
'playground.input.holder': '按 <kbd>/</kbd> 开始输入',
|
||||||
'playground.input.keyword.holder': '按 <kbd>/</kbd> 输入你的查询',
|
'playground.input.keyword.holder': '按 <kbd>/</kbd> 输入你的查询',
|
||||||
'playground.input.prompt.holder': '按 <kbd>/</kbd> 输入提示',
|
'playground.input.prompt.holder': '按 <kbd>/</kbd> 输入提示',
|
||||||
|
'playground.input.text.holder': '按 <kbd>/</kbd> 输入文本',
|
||||||
'playground.compare.apply': '应用',
|
'playground.compare.apply': '应用',
|
||||||
'playground.compare.applytoall': '应用到所有模型',
|
'playground.compare.applytoall': '应用到所有模型',
|
||||||
'playground.model.noavailable': '无可用模型',
|
'playground.model.noavailable': '无可用模型',
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { AudioOutlined } from '@ant-design/icons';
|
import { AudioOutlined } from '@ant-design/icons';
|
||||||
import { useIntl } from '@umijs/max';
|
import { useIntl } from '@umijs/max';
|
||||||
import { Button, Space, Tooltip } from 'antd';
|
import { Button, Space, Tooltip } from 'antd';
|
||||||
|
import dayjs from 'dayjs';
|
||||||
import React, {
|
import React, {
|
||||||
useCallback,
|
useCallback,
|
||||||
useEffect,
|
useEffect,
|
||||||
@@ -8,7 +9,6 @@ import React, {
|
|||||||
useRef,
|
useRef,
|
||||||
useState
|
useState
|
||||||
} from 'react';
|
} from 'react';
|
||||||
// import '../style/audio-input.less';
|
|
||||||
|
|
||||||
interface AudioInputProps {
|
interface AudioInputProps {
|
||||||
onAudioData: (audioData: {
|
onAudioData: (audioData: {
|
||||||
@@ -49,7 +49,7 @@ const AudioInput: React.FC<AudioInputProps> = (props) => {
|
|||||||
window.webkitAudioContext)();
|
window.webkitAudioContext)();
|
||||||
|
|
||||||
analyser.current = audioContext.current.createAnalyser();
|
analyser.current = audioContext.current.createAnalyser();
|
||||||
analyser.current.fftSize = 256;
|
analyser.current.fftSize = 512;
|
||||||
dataArray.current = new Uint8Array(analyser.current.frequencyBinCount);
|
dataArray.current = new Uint8Array(analyser.current.frequencyBinCount);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
@@ -136,7 +136,7 @@ const AudioInput: React.FC<AudioInputProps> = (props) => {
|
|||||||
setAudioPermission(true);
|
setAudioPermission(true);
|
||||||
initAudioContext();
|
initAudioContext();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// console.log(error);
|
console.log('enable+++++++++', error);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -158,6 +158,10 @@ const AudioInput: React.FC<AudioInputProps> = (props) => {
|
|||||||
props.onAudioData?.(audioData);
|
props.onAudioData?.(audioData);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const generateFileNameByTime = () => {
|
||||||
|
// format: recording-YYYY-MM-DD-HH_mm_ss.wav
|
||||||
|
return `recording-${dayjs().format('YYYY-MM-DD-HH_mm_ss')}${recordingFormat.suffix}`;
|
||||||
|
};
|
||||||
// start recording
|
// start recording
|
||||||
const StartRecording = async () => {
|
const StartRecording = async () => {
|
||||||
if (isRecording) {
|
if (isRecording) {
|
||||||
@@ -167,7 +171,6 @@ const AudioInput: React.FC<AudioInputProps> = (props) => {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
await EnableAudio();
|
await EnableAudio();
|
||||||
console.log('audioStream:', audioStream.current);
|
|
||||||
|
|
||||||
audioRecorder.current = new MediaRecorder(audioStream.current);
|
audioRecorder.current = new MediaRecorder(audioStream.current);
|
||||||
|
|
||||||
@@ -186,13 +189,14 @@ const AudioInput: React.FC<AudioInputProps> = (props) => {
|
|||||||
audioRecorder.current.onstop = () => {
|
audioRecorder.current.onstop = () => {
|
||||||
const audioBlob = new Blob(audioChunks, { type: recordingFormat.type });
|
const audioBlob = new Blob(audioChunks, { type: recordingFormat.type });
|
||||||
const audioUrl = URL.createObjectURL(audioBlob);
|
const audioUrl = URL.createObjectURL(audioBlob);
|
||||||
|
|
||||||
handleAudioData({
|
handleAudioData({
|
||||||
chunks: audioBlob,
|
chunks: audioBlob,
|
||||||
size: audioBlob.size,
|
size: audioBlob.size,
|
||||||
type: audioBlob.type,
|
type: audioBlob.type,
|
||||||
url: audioUrl,
|
url: audioUrl,
|
||||||
name: `recording-${new Date().toISOString()}${recordingFormat.suffix}`,
|
name: generateFileNameByTime(),
|
||||||
duration: Math.ceil((Date.now() - startTime.current) / 1000)
|
duration: Math.floor((Date.now() - startTime.current) / 1000)
|
||||||
});
|
});
|
||||||
|
|
||||||
props.onAnalyse?.([], null);
|
props.onAnalyse?.([], null);
|
||||||
@@ -201,7 +205,7 @@ const AudioInput: React.FC<AudioInputProps> = (props) => {
|
|||||||
setIsRecording(true);
|
setIsRecording(true);
|
||||||
props.onRecord?.(true);
|
props.onRecord?.(true);
|
||||||
startTime.current = Date.now();
|
startTime.current = Date.now();
|
||||||
audioRecorder.current.start(1000);
|
audioRecorder.current.start(100);
|
||||||
generateVisualData();
|
generateVisualData();
|
||||||
console.log('start recording');
|
console.log('start recording');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -226,6 +230,7 @@ const AudioInput: React.FC<AudioInputProps> = (props) => {
|
|||||||
border: 'none'
|
border: 'none'
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
return {};
|
||||||
}, [audioPermission]);
|
}, [audioPermission]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import AlertInfo from '@/components/alert-info';
|
import AlertInfo from '@/components/alert-info';
|
||||||
import IconFont from '@/components/icon-font';
|
import IconFont from '@/components/icon-font';
|
||||||
import FieldComponent from '@/components/seal-form/field-component';
|
import FieldComponent from '@/components/seal-form/field-component';
|
||||||
import SealInput from '@/components/seal-form/seal-input';
|
|
||||||
import SealSelect from '@/components/seal-form/seal-select';
|
import SealSelect from '@/components/seal-form/seal-select';
|
||||||
import useOverlayScroller from '@/hooks/use-overlay-scroller';
|
import useOverlayScroller from '@/hooks/use-overlay-scroller';
|
||||||
import ThumbImg from '@/pages/playground/components/thumb-img';
|
import ThumbImg from '@/pages/playground/components/thumb-img';
|
||||||
@@ -30,6 +29,7 @@ import { CREAT_IMAGE_API } from '../apis';
|
|||||||
import { OpenAIViewCode, promptList } from '../config';
|
import { OpenAIViewCode, promptList } from '../config';
|
||||||
import {
|
import {
|
||||||
ImageAdvancedParamsConfig,
|
ImageAdvancedParamsConfig,
|
||||||
|
ImageCustomSizeConfig,
|
||||||
ImageconstExtraConfig,
|
ImageconstExtraConfig,
|
||||||
ImageParamsConfig as paramsConfig
|
ImageParamsConfig as paramsConfig
|
||||||
} from '../config/params-config';
|
} from '../config/params-config';
|
||||||
@@ -46,10 +46,7 @@ interface MessageProps {
|
|||||||
loaded?: boolean;
|
loaded?: boolean;
|
||||||
ref?: any;
|
ref?: any;
|
||||||
}
|
}
|
||||||
|
const advancedFieldsDefaultValus = {
|
||||||
const initialValues = {
|
|
||||||
n: 1,
|
|
||||||
size: '512x512',
|
|
||||||
seed: null,
|
seed: null,
|
||||||
sampler: 'euler_a',
|
sampler: 'euler_a',
|
||||||
cfg_scale: 4.5,
|
cfg_scale: 4.5,
|
||||||
@@ -58,6 +55,17 @@ const initialValues = {
|
|||||||
schedule: 'discrete'
|
schedule: 'discrete'
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const openaiCompatibleFieldsDefaultValus = {
|
||||||
|
quality: 'standard',
|
||||||
|
style: null
|
||||||
|
};
|
||||||
|
|
||||||
|
const initialValues = {
|
||||||
|
n: 1,
|
||||||
|
size: '512x512',
|
||||||
|
...advancedFieldsDefaultValus
|
||||||
|
};
|
||||||
|
|
||||||
const GroundImages: React.FC<MessageProps> = forwardRef((props, ref) => {
|
const GroundImages: React.FC<MessageProps> = forwardRef((props, ref) => {
|
||||||
const { modelList } = props;
|
const { modelList } = props;
|
||||||
const messageId = useRef<number>(0);
|
const messageId = useRef<number>(0);
|
||||||
@@ -293,37 +301,22 @@ const GroundImages: React.FC<MessageProps> = forwardRef((props, ref) => {
|
|||||||
const handleToggleParamsStyle = () => {
|
const handleToggleParamsStyle = () => {
|
||||||
if (isOpenaiCompatible) {
|
if (isOpenaiCompatible) {
|
||||||
form.current?.form?.setFieldsValue({
|
form.current?.form?.setFieldsValue({
|
||||||
seed: null,
|
...advancedFieldsDefaultValus
|
||||||
sampler: 'euler_a',
|
|
||||||
cfg_scale: 4.5,
|
|
||||||
sample_steps: 10,
|
|
||||||
negative_prompt: null,
|
|
||||||
schedule: 'discrete'
|
|
||||||
});
|
});
|
||||||
setParams((pre: object) => {
|
setParams((pre: object) => {
|
||||||
return {
|
return {
|
||||||
..._.omit(pre, ['quality', 'style']),
|
..._.omit(pre, _.keys(openaiCompatibleFieldsDefaultValus)),
|
||||||
seed: null,
|
...advancedFieldsDefaultValus
|
||||||
sampler: 'euler_a',
|
|
||||||
cfg_scale: 4.5,
|
|
||||||
sample_steps: 10,
|
|
||||||
negative_prompt: null,
|
|
||||||
schedule: 'discrete'
|
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
form.current?.form?.setFieldsValue({
|
||||||
|
...openaiCompatibleFieldsDefaultValus
|
||||||
|
});
|
||||||
setParams((pre: object) => {
|
setParams((pre: object) => {
|
||||||
return {
|
return {
|
||||||
quality: 'standard',
|
...openaiCompatibleFieldsDefaultValus,
|
||||||
style: null,
|
..._.omit(pre, _.keys(advancedFieldsDefaultValus))
|
||||||
..._.omit(pre, [
|
|
||||||
'seed',
|
|
||||||
'sampler',
|
|
||||||
'cfg_scale',
|
|
||||||
'sample_steps',
|
|
||||||
'negative_prompt',
|
|
||||||
'schedule'
|
|
||||||
])
|
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -370,6 +363,7 @@ const GroundImages: React.FC<MessageProps> = forwardRef((props, ref) => {
|
|||||||
noStyle={item.name === 'random_seed'}
|
noStyle={item.name === 'random_seed'}
|
||||||
>
|
>
|
||||||
<FieldComponent
|
<FieldComponent
|
||||||
|
style={item.name === 'random_seed' ? { marginBottom: 20 } : {}}
|
||||||
disabled={
|
disabled={
|
||||||
item.disabledConfig
|
item.disabledConfig
|
||||||
? item.disabledConfig?.when?.(formValues)
|
? item.disabledConfig?.when?.(formValues)
|
||||||
@@ -385,58 +379,63 @@ const GroundImages: React.FC<MessageProps> = forwardRef((props, ref) => {
|
|||||||
|
|
||||||
const renderCustomSize = useMemo(() => {
|
const renderCustomSize = useMemo(() => {
|
||||||
if (size === 'custom') {
|
if (size === 'custom') {
|
||||||
return (
|
return ImageCustomSizeConfig.map((item: ParamsSchema) => {
|
||||||
<div className="flex gap-10" key="custom">
|
return (
|
||||||
<Form.Item
|
<Form.Item
|
||||||
name="width"
|
name={item.name}
|
||||||
key="width"
|
|
||||||
rules={[
|
rules={[
|
||||||
{
|
{
|
||||||
required: true,
|
|
||||||
message: intl.formatMessage(
|
message: intl.formatMessage(
|
||||||
{
|
{ id: 'common.form.rule.input' },
|
||||||
id: 'common.form.rule.input'
|
{ name: intl.formatMessage({ id: item.label.text }) }
|
||||||
},
|
),
|
||||||
{
|
required: true
|
||||||
name: intl.formatMessage({ id: 'playground.params.width' })
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
]}
|
]}
|
||||||
|
key={item.name}
|
||||||
>
|
>
|
||||||
<SealInput.Number
|
<FieldComponent
|
||||||
style={{ width: '100%' }}
|
label={
|
||||||
label={`${intl.formatMessage({ id: 'playground.params.width' })}(px)`}
|
item.label.isLocalized
|
||||||
></SealInput.Number>
|
? intl.formatMessage({ id: item.label.text })
|
||||||
</Form.Item>
|
: item.label.text
|
||||||
<Form.Item
|
|
||||||
name="height"
|
|
||||||
key="height"
|
|
||||||
rules={[
|
|
||||||
{
|
|
||||||
required: true,
|
|
||||||
message: intl.formatMessage(
|
|
||||||
{
|
|
||||||
id: 'common.form.rule.input'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: intl.formatMessage({ id: 'playground.params.height' })
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
]}
|
description={
|
||||||
>
|
item.description?.isLocalized
|
||||||
<SealInput.Number
|
? intl.formatMessage({ id: item.description.text })
|
||||||
style={{ width: '100%' }}
|
: item.description?.text
|
||||||
label={`${intl.formatMessage({ id: 'playground.params.height' })}(px)`}
|
}
|
||||||
></SealInput.Number>
|
{...item.attrs}
|
||||||
|
{..._.omit(item, [
|
||||||
|
'name',
|
||||||
|
'description',
|
||||||
|
'rules',
|
||||||
|
'disabledConfig'
|
||||||
|
])}
|
||||||
|
></FieldComponent>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</div>
|
);
|
||||||
);
|
});
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}, [size, intl]);
|
}, [size, intl]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (size === 'custom') {
|
||||||
|
form.current?.form?.setFieldsValue({
|
||||||
|
width: 256,
|
||||||
|
height: 256
|
||||||
|
});
|
||||||
|
setParams((pre: object) => {
|
||||||
|
return {
|
||||||
|
...pre,
|
||||||
|
width: 256,
|
||||||
|
height: 256
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [size]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (scroller.current) {
|
if (scroller.current) {
|
||||||
initialize(scroller.current);
|
initialize(scroller.current);
|
||||||
|
|||||||
@@ -134,7 +134,7 @@ const GroundLeft: React.FC<MessageProps> = forwardRef((props, ref) => {
|
|||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
console.log('error:', error);
|
console.log('error:', error);
|
||||||
const res = error?.response?.data;
|
const res = error?.response?.data;
|
||||||
if (res.error) {
|
if (res?.error) {
|
||||||
setTokenResult({
|
setTokenResult({
|
||||||
error: true,
|
error: true,
|
||||||
errorMessage:
|
errorMessage:
|
||||||
@@ -226,8 +226,8 @@ const GroundLeft: React.FC<MessageProps> = forwardRef((props, ref) => {
|
|||||||
if (isRecording) {
|
if (isRecording) {
|
||||||
return (
|
return (
|
||||||
<AudioAnimation
|
<AudioAnimation
|
||||||
height={66}
|
height={82}
|
||||||
width={200}
|
width={500}
|
||||||
analyserData={audioChunks}
|
analyserData={audioChunks}
|
||||||
></AudioAnimation>
|
></AudioAnimation>
|
||||||
);
|
);
|
||||||
@@ -235,7 +235,7 @@ const GroundLeft: React.FC<MessageProps> = forwardRef((props, ref) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="tips-text">
|
<div className="tips-text">
|
||||||
<IconFont type={'icon-audio'} style={{ fontSize: 20 }}></IconFont>
|
<IconFont type={'icon-audio'} style={{ fontSize: 18 }}></IconFont>
|
||||||
<span>
|
<span>
|
||||||
{intl.formatMessage({ id: 'playground.audio.speechtotext.tips' })}
|
{intl.formatMessage({ id: 'playground.audio.speechtotext.tips' })}
|
||||||
</span>
|
</span>
|
||||||
@@ -320,10 +320,9 @@ const GroundLeft: React.FC<MessageProps> = forwardRef((props, ref) => {
|
|||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<Button
|
<Button
|
||||||
style={{ width: 46 }}
|
|
||||||
size="middle"
|
|
||||||
disabled={!audioData}
|
disabled={!audioData}
|
||||||
type="primary"
|
type="primary"
|
||||||
|
shape="circle"
|
||||||
onClick={handleOnGenerate}
|
onClick={handleOnGenerate}
|
||||||
icon={<SendOutlined></SendOutlined>}
|
icon={<SendOutlined></SendOutlined>}
|
||||||
></Button>
|
></Button>
|
||||||
|
|||||||
@@ -124,7 +124,7 @@ const GroundLeft: React.FC<MessageProps> = forwardRef((props, ref) => {
|
|||||||
|
|
||||||
console.log('result:', res);
|
console.log('result:', res);
|
||||||
|
|
||||||
if (res.error) {
|
if (res?.error) {
|
||||||
setTokenResult({
|
setTokenResult({
|
||||||
error: true,
|
error: true,
|
||||||
errorMessage:
|
errorMessage:
|
||||||
@@ -147,7 +147,7 @@ const GroundLeft: React.FC<MessageProps> = forwardRef((props, ref) => {
|
|||||||
]);
|
]);
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
const res = error?.response?.data;
|
const res = error?.response?.data;
|
||||||
if (res.error) {
|
if (res?.error) {
|
||||||
setTokenResult({
|
setTokenResult({
|
||||||
error: true,
|
error: true,
|
||||||
errorMessage:
|
errorMessage:
|
||||||
@@ -180,7 +180,7 @@ const GroundLeft: React.FC<MessageProps> = forwardRef((props, ref) => {
|
|||||||
model: value
|
model: value
|
||||||
});
|
});
|
||||||
console.log('res:', res);
|
console.log('res:', res);
|
||||||
if (res.error) {
|
if (res?.error) {
|
||||||
setVoiceError({
|
setVoiceError({
|
||||||
error: true,
|
error: true,
|
||||||
errorMessage:
|
errorMessage:
|
||||||
@@ -209,7 +209,7 @@ const GroundLeft: React.FC<MessageProps> = forwardRef((props, ref) => {
|
|||||||
formRef.current?.form.setFieldValue('voice', voiceList[0]?.value);
|
formRef.current?.form.setFieldValue('voice', voiceList[0]?.value);
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
const res = error?.response?.data;
|
const res = error?.response?.data;
|
||||||
if (res.error) {
|
if (res?.error) {
|
||||||
setVoiceError({
|
setVoiceError({
|
||||||
error: true,
|
error: true,
|
||||||
errorMessage:
|
errorMessage:
|
||||||
@@ -353,6 +353,9 @@ const GroundLeft: React.FC<MessageProps> = forwardRef((props, ref) => {
|
|||||||
checkLabel={intl.formatMessage({
|
checkLabel={intl.formatMessage({
|
||||||
id: 'playground.toolbar.autoplay'
|
id: 'playground.toolbar.autoplay'
|
||||||
})}
|
})}
|
||||||
|
placeholer={intl.formatMessage({
|
||||||
|
id: 'playground.input.text.holder'
|
||||||
|
})}
|
||||||
defaultSize={{
|
defaultSize={{
|
||||||
minRows: 5,
|
minRows: 5,
|
||||||
maxRows: 5
|
maxRows: 5
|
||||||
|
|||||||
@@ -356,3 +356,46 @@ export const ImageAdvancedParamsConfig: ParamsSchema[] = [
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
export const ImageCustomSizeConfig: ParamsSchema[] = [
|
||||||
|
{
|
||||||
|
type: 'Slider',
|
||||||
|
name: 'width',
|
||||||
|
label: {
|
||||||
|
text: 'playground.params.width',
|
||||||
|
isLocalized: true
|
||||||
|
},
|
||||||
|
attrs: {
|
||||||
|
min: 256,
|
||||||
|
max: 1792,
|
||||||
|
step: 64,
|
||||||
|
inputnumber: false
|
||||||
|
},
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: 'playground.params.width'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'Slider',
|
||||||
|
name: 'height',
|
||||||
|
label: {
|
||||||
|
text: 'playground.params.height',
|
||||||
|
isLocalized: true
|
||||||
|
},
|
||||||
|
attrs: {
|
||||||
|
min: 256,
|
||||||
|
max: 1792,
|
||||||
|
step: 64,
|
||||||
|
inputnumber: false
|
||||||
|
},
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: 'playground.params.height'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ export default [
|
|||||||
width: 'auto',
|
width: 'auto',
|
||||||
uid: 0,
|
uid: 0,
|
||||||
span: 12,
|
span: 12,
|
||||||
loading: false,
|
loading: true,
|
||||||
progress: 60
|
progress: 30
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
dataUrl:
|
dataUrl:
|
||||||
|
|||||||
@@ -46,7 +46,11 @@ export interface ParamsSchema {
|
|||||||
};
|
};
|
||||||
defaultValue?: string | number | boolean;
|
defaultValue?: string | number | boolean;
|
||||||
required?: boolean;
|
required?: boolean;
|
||||||
rules: { required: boolean; message?: string }[];
|
rules: {
|
||||||
|
required: boolean;
|
||||||
|
message?: string;
|
||||||
|
formatter?: (value: any) => any;
|
||||||
|
}[];
|
||||||
placeholder?: React.ReactNode;
|
placeholder?: React.ReactNode;
|
||||||
attrs?: Record<string, any>;
|
attrs?: Record<string, any>;
|
||||||
description?: {
|
description?: {
|
||||||
|
|||||||
@@ -137,5 +137,6 @@ export const isHTMLDocumentString = (str: string) => {
|
|||||||
// generate a random number between 0 and 64 bit
|
// generate a random number between 0 and 64 bit
|
||||||
|
|
||||||
export const generateRandomNumber = () => {
|
export const generateRandomNumber = () => {
|
||||||
|
// 0x100000000
|
||||||
return Math.floor(Math.random() * Number.MAX_SAFE_INTEGER);
|
return Math.floor(Math.random() * Number.MAX_SAFE_INTEGER);
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user