refactor: playground params container

This commit is contained in:
jialin
2026-03-17 16:35:55 +08:00
committed by jialin
parent 68519223fa
commit 64955c26a7
16 changed files with 199 additions and 434 deletions
@@ -0,0 +1,6 @@
.wrapper {
overflow-y: auto;
width: 100%;
padding-inline-start: 8px;
padding-inline-end: 8px;
}
+6 -14
View File
@@ -2,15 +2,9 @@ import useOverlayScroller, {
OverlayScrollerOptions
} from '@/hooks/use-overlay-scroller';
import { Tooltip, TooltipProps } from 'antd';
import classNames from 'classnames';
import React from 'react';
import styled from 'styled-components';
const Wrapper = styled.div<{ $maxHeight?: number }>`
max-height: ${({ $maxHeight }) =>
typeof $maxHeight === 'number' ? `${$maxHeight}px` : $maxHeight};
overflow-y: auto;
width: 100%;
`;
import s from './index.module.less';
// export OverlayScrollerOptions
export type { OverlayScrollerOptions };
@@ -49,22 +43,20 @@ export const OverlayScroller: React.FC<
}, []);
return (
<Wrapper
<div
ref={scroller}
data-overlayscrollbars-initialize
className="overlay-scroller-wrapper"
$maxHeight={maxHeight || 200}
className={classNames(s.wrapper, 'overlay-scroller-wrapper')}
hidden={false}
onWheel={onScroll}
style={{
paddingInlineStart: 8,
paddingInlineEnd: 8,
maxHeight: maxHeight || 200,
...style,
...styles?.wrapper
}}
>
{children}
</Wrapper>
</div>
);
};
+1 -1
View File
@@ -171,7 +171,7 @@ const InputWrapper = styled.div`
}
.seal-textarea-wrapper {
height: auto;
padding-right: 10px;
padding-right: 4px;
textarea {
overflow-y: auto !important;
}
@@ -14,7 +14,6 @@ import {
} from '@ant-design/icons';
import { useIntl } from '@umijs/max';
import { Button, Checkbox, Form, Segmented, Spin, Tabs, Tooltip } from 'antd';
import classNames from 'classnames';
import _ from 'lodash';
import 'overlayscrollbars/overlayscrollbars.css';
import React, {
@@ -38,6 +37,7 @@ import { generateEmbeddingCode } from '../view-code/embedding';
import DynamicParams from './dynamic-params';
import FileList from './file-list';
import InputList from './input-list';
import RightContainer from './right-container';
import TokenUsage from './token-usage';
import ViewCommonCode from './view-common-code';
@@ -710,23 +710,16 @@ const GroundEmbedding: React.FC<MessageProps> = forwardRef((props, ref) => {
</div>
</div>
</div>
<div
className={classNames('params-wrapper', {
collapsed: collapse
})}
ref={paramsRef}
>
<div className="box">
<DynamicParams
ref={formRef}
onValuesChange={onValuesChange}
paramsConfig={paramsConfig}
initialValues={initialValues}
modelList={modelList}
extra={renderExtra}
/>
</div>
</div>
<RightContainer collapsed={collapse}>
<DynamicParams
ref={formRef}
onValuesChange={onValuesChange}
paramsConfig={paramsConfig}
initialValues={initialValues}
modelList={modelList}
extra={renderExtra}
/>
</RightContainer>
<ViewCommonCode
open={show}
viewCodeContent={viewCodeContent}
@@ -7,7 +7,6 @@ import { generateRandomNumber } from '@/utils';
import { FileImageOutlined } from '@ant-design/icons';
import { useIntl } from '@umijs/max';
import { Button, Tooltip } from 'antd';
import classNames from 'classnames';
import _ from 'lodash';
import 'overlayscrollbars/overlayscrollbars.css';
import React, {
@@ -26,6 +25,7 @@ import '../style/system-message-wrap.less';
import { generateImageCode, generateOpenaiImageCode } from '../view-code/image';
import DynamicParams from './dynamic-params';
import MessageInput from './message-input';
import RightContainer from './right-container';
import ViewCommonCode from './view-common-code';
interface MessageProps {
@@ -265,23 +265,16 @@ const GroundImages: React.FC<MessageProps> = forwardRef((props, ref) => {
/>
</div>
</div>
<div
className={classNames('params-wrapper', {
collapsed: collapse
})}
ref={paramsRef}
>
<div className="box">
<DynamicParams
ref={form}
formFields={formFields}
onValuesChange={handleOnValuesChange}
paramsConfig={paramsConfig}
initialValues={initialValues}
modelList={modelList}
/>
</div>
</div>
<RightContainer collapsed={collapse}>
<DynamicParams
ref={form}
formFields={formFields}
onValuesChange={handleOnValuesChange}
paramsConfig={paramsConfig}
initialValues={initialValues}
modelList={modelList}
/>
</RightContainer>
<ViewCommonCode
open={show}
viewCodeContent={viewCodeContent}
+11 -18
View File
@@ -1,5 +1,4 @@
import { Spin } from 'antd';
import classNames from 'classnames';
import 'overlayscrollbars/overlayscrollbars.css';
import React, {
forwardRef,
@@ -23,6 +22,7 @@ import MessageInput from './message-input';
import MessageContent from './multiple-chat/message-content';
import SystemMessage from './multiple-chat/system-message';
import ReferenceParams from './reference-params';
import RightContainer from './right-container';
import ViewCommonCode from './view-common-code';
interface MessageProps {
@@ -180,23 +180,16 @@ const GroundLeft: React.FC<MessageProps> = forwardRef((props, ref) => {
/>
</div>
</div>
<div
className={classNames('params-wrapper', {
collapsed: collapse
})}
ref={paramsRef}
>
<div className="box">
<DynamicParams
ref={formRef}
onValuesChange={handleOnValuesChange}
paramsConfig={paramsConfig}
initialValues={initialValues}
modelList={modelList}
showModelSelector={true}
/>
</div>
</div>
<RightContainer collapsed={collapse}>
<DynamicParams
ref={formRef}
onValuesChange={handleOnValuesChange}
paramsConfig={paramsConfig}
initialValues={initialValues}
modelList={modelList}
showModelSelector={true}
/>
</RightContainer>
<ViewCommonCode
open={show}
viewCodeContent={viewCodeContent}
@@ -19,7 +19,6 @@ import {
Tooltip,
Typography
} from 'antd';
import classNames from 'classnames';
import _ from 'lodash';
import 'overlayscrollbars/overlayscrollbars.css';
import React, {
@@ -45,6 +44,7 @@ import '../style/system-message-wrap.less';
import { generateRerankCode } from '../view-code/rerank';
import DynamicParams from './dynamic-params';
import InputList from './input-list';
import RightContainer from './right-container';
import TokenUsage from './token-usage';
import ViewCommonCode from './view-common-code';
@@ -637,23 +637,16 @@ const GroundReranker: React.FC<MessageProps> = forwardRef((props, ref) => {
</div>
</div>
</div>
<div
className={classNames('params-wrapper', {
collapsed: collapse
})}
ref={paramsRef}
>
<div className="box">
<DynamicParams
ref={formRef}
onValuesChange={onValuesChange}
paramsConfig={paramsConfig}
initialValues={initialValues}
modelList={modelList}
extra={renderExtra}
/>
</div>
</div>
<RightContainer collapsed={collapse}>
<DynamicParams
ref={formRef}
onValuesChange={onValuesChange}
paramsConfig={paramsConfig}
initialValues={initialValues}
modelList={modelList}
extra={renderExtra}
/>
</RightContainer>
<ViewCommonCode
open={show}
viewCodeContent={viewCodeContent}
+10 -17
View File
@@ -13,7 +13,6 @@ import { readAudioFile } from '@/utils/load-audio-file';
import { SendOutlined } from '@ant-design/icons';
import { useIntl, useSearchParams } from '@umijs/max';
import { Button, Spin, Tooltip } from 'antd';
import classNames from 'classnames';
import _ from 'lodash';
import React, {
forwardRef,
@@ -39,6 +38,7 @@ import '../style/system-message-wrap.less';
import { speechToTextCode } from '../view-code/audio';
import AudioInput from './audio-input';
import DynamicParams from './dynamic-params';
import RightContainer from './right-container';
import ViewCommonCode from './view-common-code';
interface MessageProps {
@@ -499,22 +499,15 @@ const GroundSTT: React.FC<MessageProps> = forwardRef((props, ref) => {
</div>
</div>
</div>
<div
className={classNames('params-wrapper', {
collapsed: collapse
})}
ref={paramsRef}
>
<div className="box">
<DynamicParams
ref={formRef}
onValuesChange={handleOnValuesChange}
paramsConfig={fieldsConfig}
initialValues={parameters}
modelList={modelList}
/>
</div>
</div>
<RightContainer collapsed={collapse}>
<DynamicParams
ref={formRef}
onValuesChange={handleOnValuesChange}
paramsConfig={fieldsConfig}
initialValues={parameters}
modelList={modelList}
/>
</RightContainer>
<ViewCommonCode
open={show}
viewCodeContent={viewCodeContent}
+16 -23
View File
@@ -10,7 +10,6 @@ import useOverlayScroller from '@/hooks/use-overlay-scroller';
import CollapsePanel from '@/pages/_components/collapse-panel';
import { getLocale, useIntl, useSearchParams } from '@umijs/max';
import { Form, Spin } from 'antd';
import classNames from 'classnames';
import _ from 'lodash';
import 'overlayscrollbars/overlayscrollbars.css';
import React, {
@@ -35,6 +34,7 @@ import '../style/system-message-wrap.less';
import { TextToSpeechCode } from '../view-code/audio';
import DynamicParams from './dynamic-params';
import MessageInput from './message-input';
import RightContainer from './right-container';
import ViewCommonCode from './view-common-code';
const MetaFields = [
@@ -487,28 +487,21 @@ const GroundTTS: React.FC<MessageProps> = forwardRef((props, ref) => {
/>
</div>
</div>
<div
className={classNames('params-wrapper', {
collapsed: collapse
})}
ref={paramsRef}
>
<div className="box">
<DynamicParams
ref={formRef}
meta={modelMeta}
onValuesChange={handleOnValuesChange}
initialValues={parameters}
modelList={modelList}
extra={[
<>
{renderExtra()}
{renderAdvancedFields()}
</>
]}
/>
</div>
</div>
<RightContainer collapsed={collapse}>
<DynamicParams
ref={formRef}
meta={modelMeta}
onValuesChange={handleOnValuesChange}
initialValues={parameters}
modelList={modelList}
extra={[
<>
{renderExtra()}
{renderAdvancedFields()}
</>
]}
/>
</RightContainer>
<ViewCommonCode
open={show}
viewCodeContent={viewCodeContent}
@@ -4,7 +4,6 @@ import routeCachekey from '@/config/route-cachekey';
import { VideoCameraOutlined } from '@ant-design/icons';
import { useIntl } from '@umijs/max';
import { Spin } from 'antd';
import classNames from 'classnames';
import _ from 'lodash';
import 'overlayscrollbars/overlayscrollbars.css';
import React, {
@@ -23,6 +22,7 @@ import '../style/system-message-wrap.less';
import { generateCode } from '../view-code/video';
import DynamicParams from './dynamic-params';
import MessageInput from './message-input';
import RightContainer from './right-container';
import ViewCommonCode from './view-common-code';
interface MessageProps {
@@ -241,22 +241,15 @@ const GroundVideo: React.FC<MessageProps> = forwardRef((props, ref) => {
/>
</div>
</div>
<div
className={classNames('params-wrapper', {
collapsed: collapse
})}
ref={paramsRef}
>
<div className="box">
<DynamicParams
ref={form}
onValuesChange={handleOnValuesChange}
paramsConfig={paramsConfig}
initialValues={initialValues}
modelList={modelList}
/>
</div>
</div>
<RightContainer collapsed={collapse}>
<DynamicParams
ref={form}
onValuesChange={handleOnValuesChange}
paramsConfig={paramsConfig}
initialValues={initialValues}
modelList={modelList}
/>
</RightContainer>
<ViewCommonCode
open={show}
viewCodeContent={viewCodeContent}
+39 -52
View File
@@ -9,7 +9,6 @@ import UploadImg from '@/pages/playground/components/upload-img';
import { base64ToFile, generateRandomNumber } from '@/utils';
import { useIntl } from '@umijs/max';
import { Divider } from 'antd';
import classNames from 'classnames';
import _ from 'lodash';
import 'overlayscrollbars/overlayscrollbars.css';
import React, {
@@ -30,6 +29,7 @@ import '../style/system-message-wrap.less';
import { generateImageCode, generateOpenaiImageCode } from '../view-code/image';
import DynamicParams from './dynamic-params';
import MessageInput from './message-input';
import RightContainer from './right-container';
import ViewCommonCode from './view-common-code';
interface MessageProps {
@@ -500,59 +500,46 @@ const GroundImages: React.FC<MessageProps> = forwardRef((props, ref) => {
</div>
</div>
</div>
<div
className={classNames('params-wrapper', {
collapsed: collapse
})}
style={{
display: 'flex',
flexDirection: 'column',
overflow: 'hidden'
}}
>
<div
style={{ flex: 1, overflow: 'auto' }}
ref={paramsRef}
data-overlayscrollbars-initialize
>
<div className="box">
<DynamicParams
ref={form}
formFields={formFields}
onValuesChange={handleOnValuesChange}
paramsConfig={paramsConfig}
initialValues={initialValues}
modelList={modelList}
<RightContainer
collapsed={collapse}
footer={
<div style={{ width: 389 }}>
<MessageInput
actions={[]}
defaultSize={{
minRows: 5,
maxRows: 5
}}
ref={inputRef}
placeholer={intl.formatMessage({
id: 'playground.input.prompt.holder'
})}
title={
<span className="font-600">
{intl.formatMessage({ id: 'playground.image.prompt' })}
</span>
}
loading={loading}
disabled={!parameters.model}
isEmpty={!imageList.length}
handleSubmit={handleSendMessage}
handleAbortFetch={handleStopConversation}
onInputChange={handleInputChange}
shouldResetMessage={false}
clearAll={handleClear}
/>
</div>
</div>
<div style={{ width: 389 }}>
<MessageInput
actions={[]}
defaultSize={{
minRows: 5,
maxRows: 5
}}
ref={inputRef}
placeholer={intl.formatMessage({
id: 'playground.input.prompt.holder'
})}
title={
<span className="font-600">
{intl.formatMessage({ id: 'playground.image.prompt' })}
</span>
}
loading={loading}
disabled={!parameters.model}
isEmpty={!imageList.length}
handleSubmit={handleSendMessage}
handleAbortFetch={handleStopConversation}
onInputChange={handleInputChange}
shouldResetMessage={false}
clearAll={handleClear}
/>
</div>
</div>
}
>
<DynamicParams
ref={form}
formFields={formFields}
onValuesChange={handleOnValuesChange}
paramsConfig={paramsConfig}
initialValues={initialValues}
modelList={modelList}
/>
</RightContainer>
<ViewCommonCode
open={show}
viewCodeContent={viewCodeContent}
@@ -1,105 +0,0 @@
import FieldComponent from '@/components/seal-form/field-component';
import { useIntl } from '@umijs/max';
import { Form } from 'antd';
import _ from 'lodash';
import React, {
forwardRef,
useCallback,
useEffect,
useId,
useImperativeHandle,
useMemo
} from 'react';
import { ParamsSchema } from '../config/types';
type ParamsSettingsProps = {
ref?: any;
style?: React.CSSProperties;
onValuesChange?: (changeValues: any, value: Record<string, any>) => void;
paramsConfig?: ParamsSchema[];
initialValues?: Record<string, any>;
extra?: React.ReactNode;
};
const ParamsSettings: React.FC<ParamsSettingsProps> = forwardRef(
({ onValuesChange, style, paramsConfig, initialValues, extra }, ref) => {
const intl = useIntl();
const [form] = Form.useForm();
const formId = useId();
useImperativeHandle(ref, () => ({
form
}));
useEffect(() => {
form.setFieldsValue({
...initialValues
});
}, [initialValues]);
const handleOnFinish = (values: any) => {
console.log('handleOnFinish', values);
};
const handleOnFinishFailed = (errorInfo: any) => {
console.log('handleOnFinishFailed', errorInfo);
};
const handleValuesChange = useCallback(
(changedValues: any, allValues: any) => {
onValuesChange?.(changedValues, allValues);
},
[onValuesChange]
);
const renderFields = useMemo(() => {
if (!paramsConfig) {
return null;
}
const formValues = form?.getFieldsValue();
return paramsConfig?.map((item: ParamsSchema) => {
return (
<Form.Item name={item.name} rules={item.rules} key={item.name}>
<FieldComponent
disabled={
item.disabledConfig
? item.disabledConfig?.when?.(formValues)
: item.disabled
}
description={
item.description?.isLocalized
? intl.formatMessage({ id: item.description.text })
: item.description?.text
}
onChange={null}
{..._.omit(item, [
'name',
'rules',
'disabledConfig',
'description'
])}
></FieldComponent>
</Form.Item>
);
});
}, [paramsConfig, intl]);
return (
<Form
style={{ ...style }}
name={formId}
form={form}
onValuesChange={handleValuesChange}
onFinish={handleOnFinish}
onFinishFailed={handleOnFinishFailed}
>
<div>
{renderFields}
{extra}
</div>
</Form>
);
}
);
export default ParamsSettings;
@@ -1,100 +0,0 @@
import useOverlayScroller from '@/hooks/use-overlay-scroller';
import { useIntl } from '@umijs/max';
import { Button, Modal, Typography } from 'antd';
import React from 'react';
import 'simplebar-react/dist/simplebar.min.css';
import promptList from '../config/prompt';
import '../style/prompt-modal.less';
type ViewModalProps = {
open: boolean;
onCancel: () => void;
onSelect: (list: { role: string; content: string }[]) => void;
};
const AddWorker: React.FC<ViewModalProps> = (props) => {
const { open, onCancel } = props || {};
const intl = useIntl();
const { initialize } = useOverlayScroller();
const scrollerRef = React.useRef<any>(null);
React.useEffect(() => {
if (scrollerRef.current) {
initialize(scrollerRef.current);
}
}, [scrollerRef.current, initialize]);
const handleSelect = (item: {
title: string;
data: { role: string; content: string }[];
}) => {
props.onSelect(item.data);
onCancel();
};
return (
<Modal
title="Prompts"
open={open}
centered={true}
onCancel={onCancel}
destroyOnHidden={true}
closeIcon={true}
maskClosable={false}
keyboard={false}
width={660}
styles={{
content: {
padding: '0'
},
header: {
padding: 'var(--ant-modal-content-padding)',
marginBottom: '0'
}
}}
footer={null}
>
<div ref={scrollerRef} style={{ maxHeight: '550px', overflow: 'auto' }}>
<div className="prompt-wrapper">
{promptList.map((item, index) => {
return (
<div key={index} className="prompt-item">
<h3 className="title">
<span className="text">{item.title}</span>
<Button
size="middle"
type="default"
onClick={() => handleSelect(item)}
>
{intl.formatMessage({ id: 'playground.compare.apply' })}
</Button>
</h3>
{item.data.map((data, i) => {
return (
<div key={i} className="data-item">
<span className="role">{data.role}</span>
<span className="prompt">
<Typography.Paragraph
style={{ margin: 0 }}
ellipsis={{
rows: 2,
expandable: true,
symbol: 'more'
}}
>
{data.content}
</Typography.Paragraph>
</span>
</div>
);
})}
</div>
);
})}
</div>
</div>
</Modal>
);
};
export default React.memo(AddWorker);
@@ -0,0 +1,30 @@
import useOverlayScroller from '@/hooks/use-overlay-scroller';
import classNames from 'classnames';
import React, { useEffect } from 'react';
import s from '../style/params-container.module.less';
const RightContainer: React.FC<{
collapsed: boolean;
children: React.ReactNode;
footer?: React.ReactNode;
}> = ({ children, footer, collapsed }) => {
const { initialize } = useOverlayScroller();
const paramsRef = React.useRef<HTMLDivElement>(null);
useEffect(() => {
if (paramsRef.current) {
initialize(paramsRef.current);
}
}, [initialize]);
return (
<div className={classNames(s.wrapper, { [s.collapsed]: collapsed })}>
<div className={s.box} ref={paramsRef}>
{children}
</div>
{footer}
</div>
);
};
export default RightContainer;
@@ -3,39 +3,6 @@
.ground-left-wrapper {
display: flex;
.params-wrapper {
position: relative;
overflow-x: hidden;
width: 390px;
border-left: 1px solid var(--ant-color-split);
transition: width 0.3s ease;
height: calc(100vh - @HEADER_HEIGHT);
padding-top: 16px;
overflow-y: auto;
&::-webkit-scrollbar {
width: 0;
}
.box {
width: 390px;
padding-inline: 24px;
}
&.collapsed {
width: 0;
overflow: hidden;
transition: width 0.3s ease;
border-left: none;
.box {
width: 0;
padding: 0;
overflow: hidden;
}
}
}
.ground-left {
flex: 1;
display: flex;
@@ -0,0 +1,37 @@
@HEADER_HEIGHT: 56px;
.wrapper {
position: relative;
width: 390px;
border-left: 1px solid var(--ant-color-split);
transition: width 0.3s ease;
height: calc(100vh - @HEADER_HEIGHT);
padding-top: 16px;
display: flex;
flex-direction: column;
overflow: hidden;
&::-webkit-scrollbar {
width: 0;
}
.box {
width: 390px;
padding-inline: 24px;
flex: 1;
overflow-y: auto;
}
&.collapsed {
width: 0;
overflow: hidden;
transition: width 0.3s ease;
border-left: none;
.box {
width: 0;
padding: 0;
overflow: hidden;
}
}
}