chore: slider to change width and height in image

main
jialin 1 year ago
parent 412c6dadca
commit ec2cd29096

@ -6,5 +6,6 @@
canvas {
display: block;
image-rendering: crisp-edges;
}
}

@ -4,19 +4,40 @@ import './index.less';
interface AudioAnimationProps {
width: number;
height: number;
scaleFactor?: number;
analyserData: {
data: Uint8Array;
analyser: any;
};
}
const AudioAnimation: React.FC<AudioAnimationProps> = (props) => {
const { width, height, analyserData } = props;
const AudioAnimation: React.FC<AudioAnimationProps> = ({
width,
height,
scaleFactor = 1.2,
analyserData
}) => {
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 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 = () => {
if (!canvasRef.current || !analyserData.data?.length) return;
@ -33,42 +54,51 @@ const AudioAnimation: React.FC<AudioAnimationProps> = (props) => {
isScaled.current = true;
}
const barWidth = 3;
const barSpacing = 2;
const centerX = HEIGHT / 2;
const barWidth = 4;
const barSpacing = 6;
const centerLine = Math.floor(HEIGHT / 2);
const jitterAmplitude = 60; // 最大抖动幅度
const minJitter = 15; // 最小抖动幅度
const frameInterval = 2;
let frameCount = 0;
const jitterAmplitude = 40;
const minJitter = 10;
let lastFrameTime = 0;
canvasCtx.fillStyle = '#0073EF';
const gradient = canvasCtx.createLinearGradient(0, 0, 0, HEIGHT);
gradient.addColorStop(0, '#007BFF');
gradient.addColorStop(1, '#0069DA');
canvasCtx.fillStyle = gradient;
const draw = () => {
frameCount++;
if (frameCount % frameInterval !== 0) {
const draw = (timestamp: number) => {
const elapsed = timestamp - lastFrameTime;
if (elapsed < 16) {
animationId.current = requestAnimationFrame(draw);
return;
}
lastFrameTime = timestamp;
analyserData.analyser?.current?.getByteFrequencyData(analyserData.data);
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;
let x = centerX - totalWidth / 2 + oscillationOffset.current;
oscillationOffset.current += direction.current * 0.5;
let x = WIDTH / 2 - totalWidth / 2 + oscillationOffset.current;
if (oscillationOffset.current > 20 || oscillationOffset.current < -20) {
oscillationOffset.current += direction.current;
if (Math.abs(oscillationOffset.current) > 20) {
direction.current *= -1;
}
for (let i = 0; i < barCount; i++) {
const baseHeight = Math.floor(analyserData.data[i] / 2);
const jitter =
minJitter +
Math.round((Math.random() - 0.5) * (jitterAmplitude - minJitter));
const barHeight = baseHeight + jitter;
const baseHeight = Math.floor(analyserData.data[i] / 2) * scaleFactor;
const jitter = calculateJitter(
i,
timestamp,
baseHeight,
minJitter,
jitterAmplitude
);
const barHeight = baseHeight + Math.round(jitter);
const topY = 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);
};
draw();
draw(performance.now());
};
useEffect(() => {
if (!analyserData.data?.length || !analyserData.analyser.current) {
canvasRef.current
?.getContext('2d')
?.clearRect(0, 0, width * 2, height * 2);
const clearCanvas = () => {
if (canvasRef.current) {
const ctx = canvasRef.current.getContext('2d');
if (ctx) ctx.clearRect(0, 0, width * 2, height * 2);
}
};
if (!analyserData.data?.length || !analyserData.analyser?.current) {
clearCanvas();
cancelAnimationFrame(animationId.current);
animationId.current = 0;
return;
}
startAudioVisualization();
return () => {
if (animationId.current) cancelAnimationFrame(animationId.current);
cancelAnimationFrame(animationId.current);
clearCanvas();
};
}, [analyserData, width, height]);

@ -75,6 +75,12 @@
.file-name {
line-height: 20px;
height: 20px;
display: flex;
align-items: center;
justify-content: center;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
.ant-slider-horizontal {

@ -53,7 +53,7 @@ const AudioPlayer: React.FC<AudioPlayerProps> = forwardRef((props, ref) => {
});
const [playOn, setPlayOn] = 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 timer = React.useRef<any>(null);
@ -98,12 +98,12 @@ const AudioPlayer: React.FC<AudioPlayerProps> = forwardRef((props, ref) => {
}, []);
const handlePlay = useCallback(() => {
setPlayOn(!playOn);
if (playOn) {
audioRef.current?.pause();
} else {
audioRef.current?.play();
}
setPlayOn(!playOn);
}, [playOn]);
const handleFormatVolume = (val?: number) => {
@ -118,10 +118,12 @@ const AudioPlayer: React.FC<AudioPlayerProps> = forwardRef((props, ref) => {
setVolume(round(value, 2));
}, []);
const initPlayerConfig = useCallback(() => {
audioRef.current!.volume = volume;
audioRef.current!.playbackRate = speed;
}, []);
const initPlayerConfig = () => {
if (audioRef.current) {
audioRef.current!.volume = volume;
audioRef.current!.playbackRate = speed;
}
};
const handleLoadedMetadata = useCallback(
(data: any) => {
@ -168,6 +170,10 @@ const AudioPlayer: React.FC<AudioPlayerProps> = forwardRef((props, ref) => {
});
};
const handleOnLoad = (e: any) => {
console.log('onload', e);
};
useEffect(() => {
if (audioRef.current) {
initPlayerConfig();
@ -195,6 +201,7 @@ const AudioPlayer: React.FC<AudioPlayerProps> = forwardRef((props, ref) => {
<Slider
tooltip={{ open: false }}
min={0}
step={1}
max={audioState.duration}
value={audioState.currentTime}
onChange={handleCurrentChange}
@ -203,23 +210,6 @@ const AudioPlayer: React.FC<AudioPlayerProps> = forwardRef((props, ref) => {
<span className="time">{formatTime(audioState.duration)}</span>
</div>
<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
title={intl.formatMessage({
id: 'playground.audio.button.slow'
@ -276,38 +266,6 @@ const AudioPlayer: React.FC<AudioPlayerProps> = forwardRef((props, ref) => {
</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>
<audio
controls

@ -69,7 +69,7 @@
left: 0;
bottom: 0;
right: 0;
backdrop-filter: blur(100px);
filter: blur(100px);
backdrop-filter: blur(100px);
z-index: 5;
}

@ -109,7 +109,13 @@ const SingleImage: React.FC<SingleImageProps> = (props) => {
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

@ -1,6 +1,7 @@
import { Checkbox, Slider } from 'antd';
import { Checkbox } from 'antd';
import SealInput from '../seal-input';
import SealSelect from '../seal-select';
import Slider from '../seal-slider';
const components: {
InputNumber: typeof SealInput.Number;

@ -3,6 +3,7 @@ import { useIntl } from '@umijs/max';
import React, { useCallback, useMemo } from 'react';
import LabelInfo from './components/label-info';
import componentsMap from './config/components';
const FieldComponent: React.FC<ParamsSchema> = (props) => {
const intl = useIntl();
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, {
forwardRef,
useCallback,
useEffect,
useImperativeHandle,
useRef
} from 'react';
import useWavesurfer from './hooks/use-wavesurfer';
import WaveSurfer, { WaveSurferOptions } from 'wavesurfer.js';
interface AudioPlayerProps {
autoplay: boolean;
@ -15,27 +16,104 @@ interface AudioPlayerProps {
width?: number;
onReady?: () => 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 container = useRef<HTMLDivElement>(null);
const {
createWavesurfer,
play,
pause,
duration,
destroyWavesurfer,
wavesurfer
} = useWavesurfer({
container,
autoplay: autoplay,
url: audioUrl,
audioRate: speed,
onReady: props.onReady,
onClick: props.onClick,
...rest
});
const wavesurfer = useRef<WaveSurfer | null>(null);
const container = useRef<any>(null);
const audioContext = useRef<any>(null);
const analyser = useRef<any>(null);
const dataArray = useRef<any>(null);
const audioStream = useRef<any>(null);
const mediaElement = useRef<any>(null);
const initAudioContext = useCallback(() => {
audioContext.current = new (window.AudioContext ||
window.webkitAudioContext)();
analyser.current = audioContext.current.createAnalyser();
analyser.current.fftSize = 512;
dataArray.current = new Uint8Array(analyser.current.frequencyBinCount);
}, []);
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, () => {
return {
@ -46,13 +124,13 @@ const AudioPlayer: React.FC<AudioPlayerProps> = forwardRef((props, ref) => {
});
useEffect(() => {
if (container.current) {
if (container.current && audioUrl) {
createWavesurfer();
}
return () => {
destroyWavesurfer();
};
}, [container.current]);
}, [audioUrl, container.current]);
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 intl = useIntl();
const [collapsed, setCollapsed] = useState(false);
const [isPlay, setIsPlay] = useState(false);
const [isPlay, setIsPlay] = useState(props.autoplay);
const [duration, setDuration] = useState(0);
const [currentTime, setCurrentTime] = useState(0);
const [audioChunks, setAudioChunks] = useState<any>({
data: [],
analyser: null
});
const ref = useRef<any>(null);
const handlePlay = () => {
@ -52,8 +56,13 @@ const SpeechItem: React.FC<SpeechContentProps> = (props) => {
setIsPlay(true);
};
const handleCollapse = () => {
setCollapsed(!collapsed);
const handleOnAnalyse = (data: any, analyser: any) => {
setAudioChunks((pre: any) => {
return {
data: data,
analyser: analyser
};
});
};
const handleReay = () => {
@ -80,6 +89,13 @@ const SpeechItem: React.FC<SpeechContentProps> = (props) => {
return (
<div>
<div className="speech-item">
{/* {isPlay && (
<AudioAnimation
height={82}
width={500}
analyserData={audioChunks}
></AudioAnimation>
)} */}
<div className="voice">
<IconFont type="icon-user_voice" className="font-size-16" />
</div>
@ -89,6 +105,8 @@ const SpeechItem: React.FC<SpeechContentProps> = (props) => {
audioUrl={props.audioUrl}
onReady={handleReay}
onClick={handleOnClick}
onFinish={() => setIsPlay(false)}
onAnalyse={handleOnAnalyse}
ref={ref}
></AudioPlayer>
</div>

@ -270,6 +270,7 @@ export default (props: any) => {
title={userConfig.title}
navTheme="light"
layout="side"
openKeys={false}
disableMobile={true}
siderWidth={220}
onCollapse={(collapsed) => {
@ -284,6 +285,7 @@ export default (props: any) => {
collapsed={collapsed}
onPageChange={(route) => {
const { location } = history;
const { pathname } = location;
// if user is not change password, redirect to change password page
if (

@ -45,6 +45,7 @@ export default {
'playground.input.holder': 'Type <kbd>/</kbd> to input message',
'playground.input.prompt.holder': 'Type <kbd>/</kbd> to input prompt',
'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.applytoall': 'Apply to all models',
'playground.model.noavailable': 'No available models',

@ -45,6 +45,7 @@ export default {
'playground.input.holder': '按 <kbd>/</kbd> 开始输入',
'playground.input.keyword.holder': '按 <kbd>/</kbd> 输入你的查询',
'playground.input.prompt.holder': '按 <kbd>/</kbd> 输入提示',
'playground.input.text.holder': '按 <kbd>/</kbd> 输入文本',
'playground.compare.apply': '应用',
'playground.compare.applytoall': '应用到所有模型',
'playground.model.noavailable': '无可用模型',

@ -1,6 +1,7 @@
import { AudioOutlined } from '@ant-design/icons';
import { useIntl } from '@umijs/max';
import { Button, Space, Tooltip } from 'antd';
import dayjs from 'dayjs';
import React, {
useCallback,
useEffect,
@ -8,7 +9,6 @@ import React, {
useRef,
useState
} from 'react';
// import '../style/audio-input.less';
interface AudioInputProps {
onAudioData: (audioData: {
@ -49,7 +49,7 @@ const AudioInput: React.FC<AudioInputProps> = (props) => {
window.webkitAudioContext)();
analyser.current = audioContext.current.createAnalyser();
analyser.current.fftSize = 256;
analyser.current.fftSize = 512;
dataArray.current = new Uint8Array(analyser.current.frequencyBinCount);
}, []);
@ -136,7 +136,7 @@ const AudioInput: React.FC<AudioInputProps> = (props) => {
setAudioPermission(true);
initAudioContext();
} catch (error) {
// console.log(error);
console.log('enable+++++++++', error);
}
};
@ -158,6 +158,10 @@ const AudioInput: React.FC<AudioInputProps> = (props) => {
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
const StartRecording = async () => {
if (isRecording) {
@ -167,7 +171,6 @@ const AudioInput: React.FC<AudioInputProps> = (props) => {
try {
await EnableAudio();
console.log('audioStream:', audioStream.current);
audioRecorder.current = new MediaRecorder(audioStream.current);
@ -186,13 +189,14 @@ const AudioInput: React.FC<AudioInputProps> = (props) => {
audioRecorder.current.onstop = () => {
const audioBlob = new Blob(audioChunks, { type: recordingFormat.type });
const audioUrl = URL.createObjectURL(audioBlob);
handleAudioData({
chunks: audioBlob,
size: audioBlob.size,
type: audioBlob.type,
url: audioUrl,
name: `recording-${new Date().toISOString()}${recordingFormat.suffix}`,
duration: Math.ceil((Date.now() - startTime.current) / 1000)
name: generateFileNameByTime(),
duration: Math.floor((Date.now() - startTime.current) / 1000)
});
props.onAnalyse?.([], null);
@ -201,7 +205,7 @@ const AudioInput: React.FC<AudioInputProps> = (props) => {
setIsRecording(true);
props.onRecord?.(true);
startTime.current = Date.now();
audioRecorder.current.start(1000);
audioRecorder.current.start(100);
generateVisualData();
console.log('start recording');
} catch (error) {
@ -226,6 +230,7 @@ const AudioInput: React.FC<AudioInputProps> = (props) => {
border: 'none'
};
}
return {};
}, [audioPermission]);
useEffect(() => {

@ -1,7 +1,6 @@
import AlertInfo from '@/components/alert-info';
import IconFont from '@/components/icon-font';
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 useOverlayScroller from '@/hooks/use-overlay-scroller';
import ThumbImg from '@/pages/playground/components/thumb-img';
@ -30,6 +29,7 @@ import { CREAT_IMAGE_API } from '../apis';
import { OpenAIViewCode, promptList } from '../config';
import {
ImageAdvancedParamsConfig,
ImageCustomSizeConfig,
ImageconstExtraConfig,
ImageParamsConfig as paramsConfig
} from '../config/params-config';
@ -46,10 +46,7 @@ interface MessageProps {
loaded?: boolean;
ref?: any;
}
const initialValues = {
n: 1,
size: '512x512',
const advancedFieldsDefaultValus = {
seed: null,
sampler: 'euler_a',
cfg_scale: 4.5,
@ -58,6 +55,17 @@ const initialValues = {
schedule: 'discrete'
};
const openaiCompatibleFieldsDefaultValus = {
quality: 'standard',
style: null
};
const initialValues = {
n: 1,
size: '512x512',
...advancedFieldsDefaultValus
};
const GroundImages: React.FC<MessageProps> = forwardRef((props, ref) => {
const { modelList } = props;
const messageId = useRef<number>(0);
@ -293,37 +301,22 @@ const GroundImages: React.FC<MessageProps> = forwardRef((props, ref) => {
const handleToggleParamsStyle = () => {
if (isOpenaiCompatible) {
form.current?.form?.setFieldsValue({
seed: null,
sampler: 'euler_a',
cfg_scale: 4.5,
sample_steps: 10,
negative_prompt: null,
schedule: 'discrete'
...advancedFieldsDefaultValus
});
setParams((pre: object) => {
return {
..._.omit(pre, ['quality', 'style']),
seed: null,
sampler: 'euler_a',
cfg_scale: 4.5,
sample_steps: 10,
negative_prompt: null,
schedule: 'discrete'
..._.omit(pre, _.keys(openaiCompatibleFieldsDefaultValus)),
...advancedFieldsDefaultValus
};
});
} else {
form.current?.form?.setFieldsValue({
...openaiCompatibleFieldsDefaultValus
});
setParams((pre: object) => {
return {
quality: 'standard',
style: null,
..._.omit(pre, [
'seed',
'sampler',
'cfg_scale',
'sample_steps',
'negative_prompt',
'schedule'
])
...openaiCompatibleFieldsDefaultValus,
..._.omit(pre, _.keys(advancedFieldsDefaultValus))
};
});
}
@ -370,6 +363,7 @@ const GroundImages: React.FC<MessageProps> = forwardRef((props, ref) => {
noStyle={item.name === 'random_seed'}
>
<FieldComponent
style={item.name === 'random_seed' ? { marginBottom: 20 } : {}}
disabled={
item.disabledConfig
? item.disabledConfig?.when?.(formValues)
@ -385,58 +379,63 @@ const GroundImages: React.FC<MessageProps> = forwardRef((props, ref) => {
const renderCustomSize = useMemo(() => {
if (size === 'custom') {
return (
<div className="flex gap-10" key="custom">
return ImageCustomSizeConfig.map((item: ParamsSchema) => {
return (
<Form.Item
name="width"
key="width"
name={item.name}
rules={[
{
required: true,
message: intl.formatMessage(
{
id: 'common.form.rule.input'
},
{
name: intl.formatMessage({ id: 'playground.params.width' })
}
)
{ id: 'common.form.rule.input' },
{ name: intl.formatMessage({ id: item.label.text }) }
),
required: true
}
]}
key={item.name}
>
<SealInput.Number
style={{ width: '100%' }}
label={`${intl.formatMessage({ id: 'playground.params.width' })}(px)`}
></SealInput.Number>
</Form.Item>
<Form.Item
name="height"
key="height"
rules={[
{
required: true,
message: intl.formatMessage(
{
id: 'common.form.rule.input'
},
{
name: intl.formatMessage({ id: 'playground.params.height' })
}
)
<FieldComponent
label={
item.label.isLocalized
? intl.formatMessage({ id: item.label.text })
: item.label.text
}
]}
>
<SealInput.Number
style={{ width: '100%' }}
label={`${intl.formatMessage({ id: 'playground.params.height' })}(px)`}
></SealInput.Number>
description={
item.description?.isLocalized
? intl.formatMessage({ id: item.description.text })
: item.description?.text
}
{...item.attrs}
{..._.omit(item, [
'name',
'description',
'rules',
'disabledConfig'
])}
></FieldComponent>
</Form.Item>
</div>
);
);
});
}
return null;
}, [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(() => {
if (scroller.current) {
initialize(scroller.current);

@ -134,7 +134,7 @@ const GroundLeft: React.FC<MessageProps> = forwardRef((props, ref) => {
} catch (error: any) {
console.log('error:', error);
const res = error?.response?.data;
if (res.error) {
if (res?.error) {
setTokenResult({
error: true,
errorMessage:
@ -226,8 +226,8 @@ const GroundLeft: React.FC<MessageProps> = forwardRef((props, ref) => {
if (isRecording) {
return (
<AudioAnimation
height={66}
width={200}
height={82}
width={500}
analyserData={audioChunks}
></AudioAnimation>
);
@ -235,7 +235,7 @@ const GroundLeft: React.FC<MessageProps> = forwardRef((props, ref) => {
return (
<div className="tips-text">
<IconFont type={'icon-audio'} style={{ fontSize: 20 }}></IconFont>
<IconFont type={'icon-audio'} style={{ fontSize: 18 }}></IconFont>
<span>
{intl.formatMessage({ id: 'playground.audio.speechtotext.tips' })}
</span>
@ -320,10 +320,9 @@ const GroundLeft: React.FC<MessageProps> = forwardRef((props, ref) => {
})}
>
<Button
style={{ width: 46 }}
size="middle"
disabled={!audioData}
type="primary"
shape="circle"
onClick={handleOnGenerate}
icon={<SendOutlined></SendOutlined>}
></Button>

@ -124,7 +124,7 @@ const GroundLeft: React.FC<MessageProps> = forwardRef((props, ref) => {
console.log('result:', res);
if (res.error) {
if (res?.error) {
setTokenResult({
error: true,
errorMessage:
@ -147,7 +147,7 @@ const GroundLeft: React.FC<MessageProps> = forwardRef((props, ref) => {
]);
} catch (error: any) {
const res = error?.response?.data;
if (res.error) {
if (res?.error) {
setTokenResult({
error: true,
errorMessage:
@ -180,7 +180,7 @@ const GroundLeft: React.FC<MessageProps> = forwardRef((props, ref) => {
model: value
});
console.log('res:', res);
if (res.error) {
if (res?.error) {
setVoiceError({
error: true,
errorMessage:
@ -209,7 +209,7 @@ const GroundLeft: React.FC<MessageProps> = forwardRef((props, ref) => {
formRef.current?.form.setFieldValue('voice', voiceList[0]?.value);
} catch (error: any) {
const res = error?.response?.data;
if (res.error) {
if (res?.error) {
setVoiceError({
error: true,
errorMessage:
@ -353,6 +353,9 @@ const GroundLeft: React.FC<MessageProps> = forwardRef((props, ref) => {
checkLabel={intl.formatMessage({
id: 'playground.toolbar.autoplay'
})}
placeholer={intl.formatMessage({
id: 'playground.input.text.holder'
})}
defaultSize={{
minRows: 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',
uid: 0,
span: 12,
loading: false,
progress: 60
loading: true,
progress: 30
},
{
dataUrl:

@ -46,7 +46,11 @@ export interface ParamsSchema {
};
defaultValue?: string | number | boolean;
required?: boolean;
rules: { required: boolean; message?: string }[];
rules: {
required: boolean;
message?: string;
formatter?: (value: any) => any;
}[];
placeholder?: React.ReactNode;
attrs?: Record<string, any>;
description?: {

@ -137,5 +137,6 @@ export const isHTMLDocumentString = (str: string) => {
// generate a random number between 0 and 64 bit
export const generateRandomNumber = () => {
// 0x100000000
return Math.floor(Math.random() * Number.MAX_SAFE_INTEGER);
};

Loading…
Cancel
Save