chore: images create
This commit is contained in:
+1
-1
@@ -14,7 +14,7 @@ const isProduction = env === 'production';
|
|||||||
const t = Date.now();
|
const t = Date.now();
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
proxy: {
|
proxy: {
|
||||||
...proxy()
|
...proxy('http://csvhs44p420c73bdb41g-80.agent.damodel.com')
|
||||||
},
|
},
|
||||||
history: {
|
history: {
|
||||||
type: 'hash'
|
type: 'hash'
|
||||||
|
|||||||
+1
-1
@@ -54,11 +54,11 @@
|
|||||||
"query-string": "^9.0.0",
|
"query-string": "^9.0.0",
|
||||||
"rc-resize-observer": "^1.4.0",
|
"rc-resize-observer": "^1.4.0",
|
||||||
"rc-virtual-list": "^3.14.8",
|
"rc-virtual-list": "^3.14.8",
|
||||||
|
"re-resizable": "^6.10.1",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
"react-hotkeys-hook": "^4.5.0",
|
"react-hotkeys-hook": "^4.5.0",
|
||||||
"simplebar-react": "^3.2.6",
|
"simplebar-react": "^3.2.6",
|
||||||
"umap-js": "^1.4.0",
|
|
||||||
"umi-presets-pro": "^2.0.3",
|
"umi-presets-pro": "^2.0.3",
|
||||||
"wavesurfer.js": "^7.8.8",
|
"wavesurfer.js": "^7.8.8",
|
||||||
"xlsx": "https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz"
|
"xlsx": "https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz"
|
||||||
|
|||||||
Generated
+13
-20
@@ -125,6 +125,9 @@ dependencies:
|
|||||||
rc-virtual-list:
|
rc-virtual-list:
|
||||||
specifier: ^3.14.8
|
specifier: ^3.14.8
|
||||||
version: 3.14.8(react-dom@18.2.0)(react@18.2.0)
|
version: 3.14.8(react-dom@18.2.0)(react@18.2.0)
|
||||||
|
re-resizable:
|
||||||
|
specifier: ^6.10.1
|
||||||
|
version: 6.10.1(react-dom@18.2.0)(react@18.2.0)
|
||||||
react:
|
react:
|
||||||
specifier: ^18.2.0
|
specifier: ^18.2.0
|
||||||
version: 18.2.0
|
version: 18.2.0
|
||||||
@@ -137,9 +140,6 @@ dependencies:
|
|||||||
simplebar-react:
|
simplebar-react:
|
||||||
specifier: ^3.2.6
|
specifier: ^3.2.6
|
||||||
version: 3.2.6(react@18.2.0)
|
version: 3.2.6(react@18.2.0)
|
||||||
umap-js:
|
|
||||||
specifier: ^1.4.0
|
|
||||||
version: 1.4.0
|
|
||||||
umi-presets-pro:
|
umi-presets-pro:
|
||||||
specifier: ^2.0.3
|
specifier: ^2.0.3
|
||||||
version: 2.0.3(@babel/core@7.25.7)(@types/react-dom@18.3.0)(@types/react@18.3.1)(antd@5.21.6)(dva@2.5.0-beta.2)(rc-field-form@2.4.0)(react-dom@18.2.0)(react@18.2.0)(umi@4.3.24)
|
version: 2.0.3(@babel/core@7.25.7)(@types/react-dom@18.3.0)(@types/react@18.3.1)(antd@5.21.6)(dva@2.5.0-beta.2)(rc-field-form@2.4.0)(react-dom@18.2.0)(react@18.2.0)(umi@4.3.24)
|
||||||
@@ -11643,10 +11643,6 @@ packages:
|
|||||||
is-decimal: 1.0.4
|
is-decimal: 1.0.4
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/is-any-array@0.1.1:
|
|
||||||
resolution: {integrity: sha512-qTiELO+kpTKqPgxPYbshMERlzaFu29JDnpB8s3bjg+JkxBpw29/qqSaOdKv2pCdaG92rLGeG/zG2GauX58hfoA==, tarball: https://registry.npmjs.org/is-any-array/-/is-any-array-0.1.1.tgz}
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/is-any-array@2.0.1:
|
/is-any-array@2.0.1:
|
||||||
resolution: {integrity: sha512-UtilS7hLRu++wb/WBAw9bNuP1Eg04Ivn1vERJck8zJthEvXCBEBpGR/33u/xLKWEQf95803oalHrVDptcAvFdQ==, tarball: https://registry.npmjs.org/is-any-array/-/is-any-array-2.0.1.tgz}
|
resolution: {integrity: sha512-UtilS7hLRu++wb/WBAw9bNuP1Eg04Ivn1vERJck8zJthEvXCBEBpGR/33u/xLKWEQf95803oalHrVDptcAvFdQ==, tarball: https://registry.npmjs.org/is-any-array/-/is-any-array-2.0.1.tgz}
|
||||||
dev: false
|
dev: false
|
||||||
@@ -12983,13 +12979,6 @@ packages:
|
|||||||
resolution: {integrity: sha512-7GO+Xk382d+HhVgjebaQnJ4Tcm8+uaL9Mc76UdxhBAU0aFWs6JDjINZLnrlZ0KDiIi9Erc52bD26QOvYsG7Nnw==, tarball: https://registry.npmjs.org/ml-dataset-iris/-/ml-dataset-iris-1.2.1.tgz}
|
resolution: {integrity: sha512-7GO+Xk382d+HhVgjebaQnJ4Tcm8+uaL9Mc76UdxhBAU0aFWs6JDjINZLnrlZ0KDiIi9Erc52bD26QOvYsG7Nnw==, tarball: https://registry.npmjs.org/ml-dataset-iris/-/ml-dataset-iris-1.2.1.tgz}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/ml-levenberg-marquardt@2.1.1:
|
|
||||||
resolution: {integrity: sha512-2+HwUqew4qFFFYujYlQtmFUrxCB4iJAPqnUYro3P831wj70eJZcANwcRaIMGUVaH9NDKzfYuA4N5u67KExmaRA==, tarball: https://registry.npmjs.org/ml-levenberg-marquardt/-/ml-levenberg-marquardt-2.1.1.tgz}
|
|
||||||
dependencies:
|
|
||||||
is-any-array: 0.1.1
|
|
||||||
ml-matrix: 6.12.0
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/ml-matrix@6.12.0:
|
/ml-matrix@6.12.0:
|
||||||
resolution: {integrity: sha512-AGfR+pWaC0GmzjUnB6BfwhndPEUGz0i7QUYdqNuw1zhTov/vSRJ9pP2hs6BoGpaSbtXgrKjZz2zjD1M0xuur6A==, tarball: https://registry.npmjs.org/ml-matrix/-/ml-matrix-6.12.0.tgz}
|
resolution: {integrity: sha512-AGfR+pWaC0GmzjUnB6BfwhndPEUGz0i7QUYdqNuw1zhTov/vSRJ9pP2hs6BoGpaSbtXgrKjZz2zjD1M0xuur6A==, tarball: https://registry.npmjs.org/ml-matrix/-/ml-matrix-6.12.0.tgz}
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -16147,6 +16136,16 @@ packages:
|
|||||||
react-dom: 18.2.0(react@18.2.0)
|
react-dom: 18.2.0(react@18.2.0)
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/re-resizable@6.10.1(react-dom@18.2.0)(react@18.2.0):
|
||||||
|
resolution: {integrity: sha512-m33nSWRH57UZLmep5M/LatkZ2NRqimVD/bOOpvymw5Zf33+eTSEixsUugscOZzAtK0/nx+OSuOf8VbKJx/4ptw==, tarball: https://registry.npmjs.org/re-resizable/-/re-resizable-6.10.1.tgz}
|
||||||
|
peerDependencies:
|
||||||
|
react: ^16.13.1 || ^17.0.0 || ^18.0.0
|
||||||
|
react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0
|
||||||
|
dependencies:
|
||||||
|
react: 18.2.0
|
||||||
|
react-dom: 18.2.0(react@18.2.0)
|
||||||
|
dev: false
|
||||||
|
|
||||||
/react-dom@18.1.0(react@18.1.0):
|
/react-dom@18.1.0(react@18.1.0):
|
||||||
resolution: {integrity: sha512-fU1Txz7Budmvamp7bshe4Zi32d0ll7ect+ccxNu9FlObT605GOEB8BfO4tmRJ39R5Zj831VCpvQ05QPBW5yb+w==, tarball: https://registry.npmjs.org/react-dom/-/react-dom-18.1.0.tgz}
|
resolution: {integrity: sha512-fU1Txz7Budmvamp7bshe4Zi32d0ll7ect+ccxNu9FlObT605GOEB8BfO4tmRJ39R5Zj831VCpvQ05QPBW5yb+w==, tarball: https://registry.npmjs.org/react-dom/-/react-dom-18.1.0.tgz}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@@ -18462,12 +18461,6 @@ packages:
|
|||||||
resolution: {integrity: sha512-fYmIy7fKTSFAhG3fuPlubeGaMoAd6r0rSnfEsO5nEY55i26KSLt9EH7PLQiiqPUhNqYIJvSkTy1oArIcXAbPbA==, tarball: https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.38.tgz}
|
resolution: {integrity: sha512-fYmIy7fKTSFAhG3fuPlubeGaMoAd6r0rSnfEsO5nEY55i26KSLt9EH7PLQiiqPUhNqYIJvSkTy1oArIcXAbPbA==, tarball: https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.38.tgz}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/umap-js@1.4.0:
|
|
||||||
resolution: {integrity: sha512-xxpviF9wUO6Nxrx+C58SoDgea+h2PnVaRPKDelWv0HotmY6BeWeh0kAPJoumfqUkzUvowGsYfMbnsWI0b9do+A==, tarball: https://registry.npmjs.org/umap-js/-/umap-js-1.4.0.tgz}
|
|
||||||
dependencies:
|
|
||||||
ml-levenberg-marquardt: 2.1.1
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/umi-presets-pro@2.0.3(@babel/core@7.25.7)(@types/react-dom@18.3.0)(@types/react@18.3.1)(antd@5.21.6)(dva@2.5.0-beta.2)(rc-field-form@2.4.0)(react-dom@18.2.0)(react@18.2.0)(umi@4.3.24):
|
/umi-presets-pro@2.0.3(@babel/core@7.25.7)(@types/react-dom@18.3.0)(@types/react@18.3.1)(antd@5.21.6)(dva@2.5.0-beta.2)(rc-field-form@2.4.0)(react-dom@18.2.0)(react@18.2.0)(umi@4.3.24):
|
||||||
resolution: {integrity: sha512-sHKynw/fi7UeUftzTRPRsrV5GHV4BWvWYhyvwkg8s+shmt0ROPW/52y4gxBziEvetxl8yWMKUCWk50OUDOcrww==, tarball: https://registry.npmjs.org/umi-presets-pro/-/umi-presets-pro-2.0.3.tgz}
|
resolution: {integrity: sha512-sHKynw/fi7UeUftzTRPRsrV5GHV4BWvWYhyvwkg8s+shmt0ROPW/52y4gxBziEvetxl8yWMKUCWk50OUDOcrww==, tarball: https://registry.npmjs.org/umi-presets-pro/-/umi-presets-pro-2.0.3.tgz}
|
||||||
dependencies:
|
dependencies:
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 2.3 KiB |
@@ -89,6 +89,16 @@
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.justify-start {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.justify-end {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
// align-items: center
|
// align-items: center
|
||||||
.flex-center {
|
.flex-center {
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -170,6 +180,10 @@
|
|||||||
font-size: 24px;
|
font-size: 24px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.font-size-32 {
|
||||||
|
font-size: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
.m-b-0 {
|
.m-b-0 {
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,39 @@
|
|||||||
|
import { WarningOutlined } from '@ant-design/icons';
|
||||||
|
import { Typography } from 'antd';
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
interface AlertInfoProps {
|
||||||
|
type: 'danger' | 'warning';
|
||||||
|
message: string;
|
||||||
|
rows?: number;
|
||||||
|
icon?: React.ReactNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
const AlertInfo: React.FC<AlertInfoProps> = (props) => {
|
||||||
|
const { message, type, rows = 1 } = props;
|
||||||
|
if (!message) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Typography.Paragraph
|
||||||
|
type={type}
|
||||||
|
ellipsis={{
|
||||||
|
rows: rows,
|
||||||
|
tooltip: message
|
||||||
|
}}
|
||||||
|
style={{
|
||||||
|
textAlign: 'center',
|
||||||
|
padding: '2px 5px',
|
||||||
|
borderRadius: 'var(--border-radius-base)',
|
||||||
|
margin: 0,
|
||||||
|
backgroundColor: 'var(--ant-color-error-bg)'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<WarningOutlined className="m-r-8" />
|
||||||
|
{message}
|
||||||
|
</Typography.Paragraph>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default React.memo(AlertInfo);
|
||||||
@@ -61,7 +61,7 @@ const AudioPlayer: React.FC<AudioPlayerProps> = forwardRef((props, ref) => {
|
|||||||
setPlayOn(false);
|
setPlayOn(false);
|
||||||
setAudioState((prestate: any) => {
|
setAudioState((prestate: any) => {
|
||||||
return {
|
return {
|
||||||
currentTime: 0,
|
currentTime: audioRef.current?.ended ? 0 : prestate.currentTime,
|
||||||
duration: prestate.duration
|
duration: prestate.duration
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
@@ -87,6 +87,7 @@ const AudioPlayer: React.FC<AudioPlayerProps> = forwardRef((props, ref) => {
|
|||||||
|
|
||||||
const handleLoadedMetadata = useCallback(
|
const handleLoadedMetadata = useCallback(
|
||||||
(data: any) => {
|
(data: any) => {
|
||||||
|
console.log('loadmetadata++++++++');
|
||||||
const duration = Math.ceil(audioRef.current?.duration || 0);
|
const duration = Math.ceil(audioRef.current?.duration || 0);
|
||||||
setAudioState({
|
setAudioState({
|
||||||
currentTime: 0,
|
currentTime: 0,
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import fallbackImg from '@/assets/images/img_fallback.png';
|
||||||
import {
|
import {
|
||||||
DownloadOutlined,
|
DownloadOutlined,
|
||||||
EyeOutlined,
|
EyeOutlined,
|
||||||
@@ -13,9 +14,16 @@ import { round } from 'lodash';
|
|||||||
import React, { useCallback, useEffect, useState } from 'react';
|
import React, { useCallback, useEffect, useState } from 'react';
|
||||||
import './index.less';
|
import './index.less';
|
||||||
|
|
||||||
const AutoImage: React.FC<ImageProps & { height: number }> = (props) => {
|
const AutoImage: React.FC<
|
||||||
const { height = 100, ...rest } = props;
|
ImageProps & {
|
||||||
const [width, setWidth] = useState(0);
|
height: number | string;
|
||||||
|
width?: number | string;
|
||||||
|
autoSize?: boolean;
|
||||||
|
}
|
||||||
|
> = (props) => {
|
||||||
|
const { height = 100, width: w, autoSize, ...rest } = props;
|
||||||
|
const [width, setWidth] = useState(w || 0);
|
||||||
|
const [isError, setIsError] = useState(false);
|
||||||
|
|
||||||
const getImgRatio = useCallback((url: string): Promise<{ ratio: number }> => {
|
const getImgRatio = useCallback((url: string): Promise<{ ratio: number }> => {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
@@ -31,8 +39,15 @@ const AutoImage: React.FC<ImageProps & { height: number }> = (props) => {
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const handleOnLoad = useCallback(async () => {
|
const handleOnLoad = useCallback(async () => {
|
||||||
|
if (autoSize) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
const { ratio } = await getImgRatio(props.src || '');
|
const { ratio } = await getImgRatio(props.src || '');
|
||||||
setWidth(height * ratio);
|
if (typeof height === 'number') {
|
||||||
|
setWidth(height * ratio);
|
||||||
|
} else {
|
||||||
|
throw new Error('Height must be a number');
|
||||||
|
}
|
||||||
}, [getImgRatio, height, props.src]);
|
}, [getImgRatio, height, props.src]);
|
||||||
|
|
||||||
const onDownload = () => {
|
const onDownload = () => {
|
||||||
@@ -47,6 +62,10 @@ const AutoImage: React.FC<ImageProps & { height: number }> = (props) => {
|
|||||||
link.remove();
|
link.remove();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleOnError = () => {
|
||||||
|
setIsError(true);
|
||||||
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
handleOnLoad();
|
handleOnLoad();
|
||||||
}, [handleOnLoad]);
|
}, [handleOnLoad]);
|
||||||
@@ -54,8 +73,10 @@ const AutoImage: React.FC<ImageProps & { height: number }> = (props) => {
|
|||||||
return (
|
return (
|
||||||
<AntImage
|
<AntImage
|
||||||
{...rest}
|
{...rest}
|
||||||
height={height}
|
height={isError ? 'auto' : height}
|
||||||
width={width}
|
width={isError ? '100%' : width}
|
||||||
|
onError={handleOnError}
|
||||||
|
fallback={fallbackImg}
|
||||||
preview={{
|
preview={{
|
||||||
mask: <EyeOutlined />,
|
mask: <EyeOutlined />,
|
||||||
toolbarRender: (
|
toolbarRender: (
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import type {
|
|||||||
TooltipComponentOption
|
TooltipComponentOption
|
||||||
} from 'echarts/components';
|
} from 'echarts/components';
|
||||||
import {
|
import {
|
||||||
|
DataZoomComponent,
|
||||||
DatasetComponent,
|
DatasetComponent,
|
||||||
GridComponent,
|
GridComponent,
|
||||||
LegendComponent,
|
LegendComponent,
|
||||||
@@ -44,6 +45,7 @@ echarts.use([
|
|||||||
GridComponent,
|
GridComponent,
|
||||||
DatasetComponent,
|
DatasetComponent,
|
||||||
TransformComponent,
|
TransformComponent,
|
||||||
|
DataZoomComponent,
|
||||||
BarChart,
|
BarChart,
|
||||||
LineChart,
|
LineChart,
|
||||||
ScatterChart,
|
ScatterChart,
|
||||||
|
|||||||
@@ -17,35 +17,47 @@ const options: any = {
|
|||||||
borderRadius: 4
|
borderRadius: 4
|
||||||
},
|
},
|
||||||
xAxis: {
|
xAxis: {
|
||||||
|
min: -1,
|
||||||
|
max: 1,
|
||||||
scale: false,
|
scale: false,
|
||||||
slient: true,
|
slient: true,
|
||||||
splitNumber: 15,
|
splitNumber: 15,
|
||||||
splitLine: {
|
splitLine: {
|
||||||
lineStyle: {
|
lineStyle: {
|
||||||
color: 'rgba(5,5,5,0.06)'
|
color: '#F2F2F2'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
axisLine: {
|
axisLine: {
|
||||||
show: false
|
show: false,
|
||||||
|
lineStyle: {
|
||||||
|
color: '#F2F2F2'
|
||||||
|
}
|
||||||
},
|
},
|
||||||
axisTick: {
|
axisTick: {
|
||||||
show: false
|
show: false
|
||||||
},
|
},
|
||||||
axisLabel: {
|
axisLabel: {
|
||||||
show: false
|
show: false
|
||||||
}
|
},
|
||||||
|
boundaryGap: [0.05, 0.05]
|
||||||
},
|
},
|
||||||
yAxis: {
|
yAxis: {
|
||||||
|
min: -1,
|
||||||
|
max: 1,
|
||||||
scale: false,
|
scale: false,
|
||||||
slient: true,
|
slient: true,
|
||||||
splitNumber: 10,
|
splitNumber: 10,
|
||||||
|
boundaryGap: [0.05, 0.05],
|
||||||
splitLine: {
|
splitLine: {
|
||||||
lineStyle: {
|
lineStyle: {
|
||||||
color: 'rgba(5,5,5,0.06)'
|
color: '#F2F2F2'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
axisLine: {
|
axisLine: {
|
||||||
show: false
|
show: false,
|
||||||
|
lineStyle: {
|
||||||
|
color: '#F2F2F2'
|
||||||
|
}
|
||||||
},
|
},
|
||||||
axisTick: {
|
axisTick: {
|
||||||
show: false
|
show: false
|
||||||
@@ -54,6 +66,7 @@ const options: any = {
|
|||||||
show: false
|
show: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
symbol: 'roundRect',
|
symbol: 'roundRect',
|
||||||
label: {
|
label: {
|
||||||
show: true,
|
show: true,
|
||||||
@@ -67,16 +80,7 @@ const options: any = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const Scatter: React.FC<ChartProps> = (props) => {
|
const Scatter: React.FC<ChartProps> = (props) => {
|
||||||
const {
|
const { seriesData, xAxisData, height, width, showEmpty, title } = props;
|
||||||
seriesData,
|
|
||||||
xAxisData,
|
|
||||||
height,
|
|
||||||
width,
|
|
||||||
showEmpty,
|
|
||||||
labelFormatter,
|
|
||||||
legendData,
|
|
||||||
title
|
|
||||||
} = props;
|
|
||||||
|
|
||||||
const chart = useRef<any>(null);
|
const chart = useRef<any>(null);
|
||||||
|
|
||||||
@@ -118,18 +122,21 @@ const Scatter: React.FC<ChartProps> = (props) => {
|
|||||||
[]
|
[]
|
||||||
);
|
);
|
||||||
|
|
||||||
const dataOptions = useMemo((): any => {
|
const renderNameInTooltip = useCallback((dataList: any[]) => {
|
||||||
if (!seriesData.length) {
|
if (!dataList.length || dataList.length < 2) {
|
||||||
options.xAxis.min = 0;
|
return null;
|
||||||
options.xAxis.max = 1;
|
|
||||||
options.yAxis.min = 0;
|
|
||||||
options.yAxis.max = 1;
|
|
||||||
} else {
|
|
||||||
options.xAxis.min = null;
|
|
||||||
options.xAxis.max = null;
|
|
||||||
options.yAxis.min = null;
|
|
||||||
options.yAxis.max = null;
|
|
||||||
}
|
}
|
||||||
|
const renderText = (item: any) => {
|
||||||
|
return `<span class="tooltip-item-name">
|
||||||
|
<span style="display:flex;justify-content:center;align-items: center;color:#fff;
|
||||||
|
margin-right:0;border-radius:4px;width:14px;
|
||||||
|
height:14px;background-color:${item?.itemStyle?.color};"
|
||||||
|
>${item.name}</span>
|
||||||
|
</span>`;
|
||||||
|
};
|
||||||
|
return renderText;
|
||||||
|
}, []);
|
||||||
|
const dataOptions = useMemo((): any => {
|
||||||
const seriseDataList = seriesData.map((item: any, index: number) => {
|
const seriseDataList = seriesData.map((item: any, index: number) => {
|
||||||
return {
|
return {
|
||||||
...item,
|
...item,
|
||||||
@@ -147,15 +154,11 @@ const Scatter: React.FC<ChartProps> = (props) => {
|
|||||||
formatter(params: any, callback?: (val: any) => any) {
|
formatter(params: any, callback?: (val: any) => any) {
|
||||||
const dataList = findOverlappingPoints(seriseDataList, params.data);
|
const dataList = findOverlappingPoints(seriseDataList, params.data);
|
||||||
let result = '';
|
let result = '';
|
||||||
|
const renderText: any = renderNameInTooltip(dataList);
|
||||||
dataList.forEach((item: any) => {
|
dataList.forEach((item: any) => {
|
||||||
result += `
|
result += `
|
||||||
<span class="tooltip-item" style="justify-content: flex-start;">
|
<span class="tooltip-item" style="justify-content: flex-start;">
|
||||||
<span class="tooltip-item-name">
|
${renderText ? renderText(item) : ''}
|
||||||
<span style="display:flex;justify-content:center;align-items: center;color:#fff;
|
|
||||||
margin-right:0;border-radius:4px;width:14px;
|
|
||||||
height:14px;background-color:${item.itemStyle?.color};"
|
|
||||||
>${item.name}</span>
|
|
||||||
</span>
|
|
||||||
<span class="tooltip-value">${item.text}</span>
|
<span class="tooltip-value">${item.text}</span>
|
||||||
</span>`;
|
</span>`;
|
||||||
});
|
});
|
||||||
@@ -168,6 +171,9 @@ const Scatter: React.FC<ChartProps> = (props) => {
|
|||||||
},
|
},
|
||||||
series: {
|
series: {
|
||||||
type: 'scatter',
|
type: 'scatter',
|
||||||
|
labelLayout: {
|
||||||
|
hideOverlap: true
|
||||||
|
},
|
||||||
data: seriseDataList
|
data: seriseDataList
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ interface CodeViewerProps {
|
|||||||
ignoreIllegals?: boolean;
|
ignoreIllegals?: boolean;
|
||||||
copyable?: boolean;
|
copyable?: boolean;
|
||||||
height?: string | number;
|
height?: string | number;
|
||||||
|
style?: React.CSSProperties;
|
||||||
}
|
}
|
||||||
const DarkViewer: React.FC<CodeViewerProps> = (props) => {
|
const DarkViewer: React.FC<CodeViewerProps> = (props) => {
|
||||||
const {
|
const {
|
||||||
@@ -22,6 +23,7 @@ const DarkViewer: React.FC<CodeViewerProps> = (props) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<CodeViewer
|
<CodeViewer
|
||||||
|
style={props.style}
|
||||||
height={height}
|
height={height}
|
||||||
code={code}
|
code={code}
|
||||||
lang={lang}
|
lang={lang}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ interface CodeViewerProps {
|
|||||||
ignoreIllegals?: boolean;
|
ignoreIllegals?: boolean;
|
||||||
copyable?: boolean;
|
copyable?: boolean;
|
||||||
height?: string | number;
|
height?: string | number;
|
||||||
|
style?: React.CSSProperties;
|
||||||
}
|
}
|
||||||
const LightViewer: React.FC<CodeViewerProps> = (props) => {
|
const LightViewer: React.FC<CodeViewerProps> = (props) => {
|
||||||
const {
|
const {
|
||||||
@@ -17,11 +18,13 @@ const LightViewer: React.FC<CodeViewerProps> = (props) => {
|
|||||||
autodetect,
|
autodetect,
|
||||||
ignoreIllegals,
|
ignoreIllegals,
|
||||||
copyable,
|
copyable,
|
||||||
|
style,
|
||||||
height = 'auto'
|
height = 'auto'
|
||||||
} = props || {};
|
} = props || {};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<CodeViewer
|
<CodeViewer
|
||||||
|
style={style}
|
||||||
height={height}
|
height={height}
|
||||||
code={code}
|
code={code}
|
||||||
lang={lang}
|
lang={lang}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ interface CodeViewerProps {
|
|||||||
copyable?: boolean;
|
copyable?: boolean;
|
||||||
height?: string | number;
|
height?: string | number;
|
||||||
theme?: 'light' | 'dark';
|
theme?: 'light' | 'dark';
|
||||||
|
style?: React.CSSProperties;
|
||||||
}
|
}
|
||||||
const CodeViewer: React.FC<CodeViewerProps> = (props) => {
|
const CodeViewer: React.FC<CodeViewerProps> = (props) => {
|
||||||
const {
|
const {
|
||||||
@@ -20,7 +21,8 @@ const CodeViewer: React.FC<CodeViewerProps> = (props) => {
|
|||||||
autodetect = true,
|
autodetect = true,
|
||||||
ignoreIllegals = true,
|
ignoreIllegals = true,
|
||||||
copyable = true,
|
copyable = true,
|
||||||
height = 'auto'
|
height = 'auto',
|
||||||
|
style
|
||||||
} = props || {};
|
} = props || {};
|
||||||
|
|
||||||
const highlightedCode = useMemo(() => {
|
const highlightedCode = useMemo(() => {
|
||||||
@@ -69,7 +71,8 @@ const CodeViewer: React.FC<CodeViewerProps> = (props) => {
|
|||||||
}
|
}
|
||||||
)}
|
)}
|
||||||
style={{
|
style={{
|
||||||
height: height
|
height: height,
|
||||||
|
...style
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<code
|
<code
|
||||||
|
|||||||
@@ -9,8 +9,10 @@ const HighlightCode: React.FC<{
|
|||||||
copyable?: boolean;
|
copyable?: boolean;
|
||||||
theme?: 'light' | 'dark';
|
theme?: 'light' | 'dark';
|
||||||
height?: string | number;
|
height?: string | number;
|
||||||
|
style?: React.CSSProperties;
|
||||||
}> = (props) => {
|
}> = (props) => {
|
||||||
const {
|
const {
|
||||||
|
style,
|
||||||
code,
|
code,
|
||||||
lang = 'bash',
|
lang = 'bash',
|
||||||
copyable = true,
|
copyable = true,
|
||||||
@@ -26,9 +28,11 @@ const HighlightCode: React.FC<{
|
|||||||
code={code}
|
code={code}
|
||||||
copyable={copyable}
|
copyable={copyable}
|
||||||
height={height}
|
height={height}
|
||||||
|
style={style}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<CodeViewerLight
|
<CodeViewerLight
|
||||||
|
style={style}
|
||||||
lang={lang}
|
lang={lang}
|
||||||
code={code}
|
code={code}
|
||||||
copyable={copyable}
|
copyable={copyable}
|
||||||
|
|||||||
@@ -13,6 +13,10 @@
|
|||||||
border-radius: @borderRadius;
|
border-radius: @borderRadius;
|
||||||
background-color: var(--color-white-1);
|
background-color: var(--color-white-1);
|
||||||
|
|
||||||
|
&.seal-input-number {
|
||||||
|
padding-right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
&.borderless {
|
&.borderless {
|
||||||
border: none;
|
border: none;
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
@@ -97,6 +101,12 @@
|
|||||||
padding-block: 20px 0;
|
padding-block: 20px 0;
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
:global(.ant-input-number-handler-wrap) {
|
||||||
|
width: 34px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
&.no-wrapper-style {
|
&.no-wrapper-style {
|
||||||
padding-block: 0;
|
padding-block: 0;
|
||||||
}
|
}
|
||||||
@@ -201,6 +211,7 @@
|
|||||||
height: @inputheight !important;
|
height: @inputheight !important;
|
||||||
}
|
}
|
||||||
// ==================== input ====================
|
// ==================== input ====================
|
||||||
|
|
||||||
:global(.ant-input),
|
:global(.ant-input),
|
||||||
:global(.ant-input-password) {
|
:global(.ant-input-password) {
|
||||||
// width: 100%;
|
// width: 100%;
|
||||||
@@ -221,6 +232,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
:global(.ant-input-number) {
|
:global(.ant-input-number) {
|
||||||
|
position: static;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
border: none;
|
border: none;
|
||||||
@@ -228,6 +240,15 @@
|
|||||||
padding: 0;
|
padding: 0;
|
||||||
height: @inputheight !important;
|
height: @inputheight !important;
|
||||||
background-color: @bgColor;
|
background-color: @bgColor;
|
||||||
|
|
||||||
|
&:hover .ant-input-number-handler-wrap,
|
||||||
|
&-focused .ant-input-number-handler-wrap {
|
||||||
|
width: 34px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
cursor: text;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
:global(.ant-input-outlined) {
|
:global(.ant-input-outlined) {
|
||||||
@@ -293,13 +314,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
:global(.ant-input-number-handler-wrap) {
|
:global(.ant-input-number-handler-wrap) {
|
||||||
top: -20px;
|
top: 0;
|
||||||
height: @wrapheight - 2px;
|
height: @wrapheight - 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
// :global(.ant-input-prefix) {
|
|
||||||
// position: absolute;
|
|
||||||
// top: 1px;
|
|
||||||
// left: -4px;
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,6 +68,7 @@ const SealInputNumber: React.FC<InputNumberProps & SealFormItemProps> = (
|
|||||||
description={description}
|
description={description}
|
||||||
disabled={props.disabled}
|
disabled={props.disabled}
|
||||||
onClick={handleClickWrapper}
|
onClick={handleClickWrapper}
|
||||||
|
className="seal-input-number"
|
||||||
>
|
>
|
||||||
<InputNumber
|
<InputNumber
|
||||||
{...rest}
|
{...rest}
|
||||||
|
|||||||
@@ -10,11 +10,12 @@ interface SystemMessageProps {
|
|||||||
value: string;
|
value: string;
|
||||||
placeholder?: string;
|
placeholder?: string;
|
||||||
label?: React.ReactNode;
|
label?: React.ReactNode;
|
||||||
|
height?: number;
|
||||||
onChange: (e: any) => void;
|
onChange: (e: any) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const RowTextarea: React.FC<SystemMessageProps> = (props) => {
|
const RowTextarea: React.FC<SystemMessageProps> = (props) => {
|
||||||
const { value, onChange, style, label, placeholder } = props;
|
const { value, onChange, style, label, placeholder, height = 46 } = props;
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const rowTextAreaRef = React.useRef<any>(null);
|
const rowTextAreaRef = React.useRef<any>(null);
|
||||||
const [autoSize, setAutoSize] = useState<{
|
const [autoSize, setAutoSize] = useState<{
|
||||||
@@ -64,7 +65,7 @@ const RowTextarea: React.FC<SystemMessageProps> = (props) => {
|
|||||||
style={{ display: autoSize.focus ? 'block' : 'none' }}
|
style={{ display: autoSize.focus ? 'block' : 'none' }}
|
||||||
className="textarea-wrapper"
|
className="textarea-wrapper"
|
||||||
>
|
>
|
||||||
<span className="textarea-label">{label}</span>
|
{label && <span className="textarea-label">{label}</span>}
|
||||||
<Input.TextArea
|
<Input.TextArea
|
||||||
className="custome-scrollbar"
|
className="custome-scrollbar"
|
||||||
ref={rowTextAreaRef}
|
ref={rowTextAreaRef}
|
||||||
@@ -87,8 +88,8 @@ const RowTextarea: React.FC<SystemMessageProps> = (props) => {
|
|||||||
}
|
}
|
||||||
{!autoSize.focus && (
|
{!autoSize.focus && (
|
||||||
<div className="content-wrap" onClick={handleFocus}>
|
<div className="content-wrap" onClick={handleFocus}>
|
||||||
<div className="content">
|
<div className="content" style={{ height: height }}>
|
||||||
<span className="title">{label}</span>
|
{label && <span className="title">{label}</span>}
|
||||||
{value || (
|
{value || (
|
||||||
<span style={{ color: 'var(--ant-color-text-tertiary)' }}>
|
<span style={{ color: 'var(--ant-color-text-tertiary)' }}>
|
||||||
{placeholder}
|
{placeholder}
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
import { isNotEmptyValue } from '@/utils/index';
|
import { isNotEmptyValue } from '@/utils/index';
|
||||||
|
import { useIntl } from '@umijs/max';
|
||||||
import type { SelectProps } from 'antd';
|
import type { SelectProps } from 'antd';
|
||||||
import { Form, Select } from 'antd';
|
import { Form, Select } from 'antd';
|
||||||
import { useEffect, useRef, useState } from 'react';
|
import { cloneDeep } from 'lodash';
|
||||||
|
import { useEffect, useMemo, useRef, useState } from 'react';
|
||||||
import Wrapper from './components/wrapper';
|
import Wrapper from './components/wrapper';
|
||||||
import { SealFormItemProps } from './types';
|
import { SealFormItemProps } from './types';
|
||||||
|
|
||||||
@@ -12,9 +14,11 @@ const SealSelect: React.FC<SelectProps & SealFormItemProps> = (props) => {
|
|||||||
children,
|
children,
|
||||||
required,
|
required,
|
||||||
description,
|
description,
|
||||||
|
options,
|
||||||
isInFormItems = true,
|
isInFormItems = true,
|
||||||
...rest
|
...rest
|
||||||
} = props;
|
} = props;
|
||||||
|
const intl = useIntl();
|
||||||
const [isFocus, setIsFocus] = useState(false);
|
const [isFocus, setIsFocus] = useState(false);
|
||||||
const inputRef = useRef<any>(null);
|
const inputRef = useRef<any>(null);
|
||||||
let status = '';
|
let status = '';
|
||||||
@@ -23,6 +27,19 @@ const SealSelect: React.FC<SelectProps & SealFormItemProps> = (props) => {
|
|||||||
status = statusData?.status || '';
|
status = statusData?.status || '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const _options = useMemo(() => {
|
||||||
|
if (!options?.length) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
const list = cloneDeep(options);
|
||||||
|
return list.map((item: any) => {
|
||||||
|
if (item.locale) {
|
||||||
|
item.label = intl.formatMessage({ id: item.label as string });
|
||||||
|
}
|
||||||
|
return item;
|
||||||
|
});
|
||||||
|
}, [options, intl]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isNotEmptyValue(props.value)) {
|
if (isNotEmptyValue(props.value)) {
|
||||||
setIsFocus(true);
|
setIsFocus(true);
|
||||||
@@ -70,6 +87,7 @@ const SealSelect: React.FC<SelectProps & SealFormItemProps> = (props) => {
|
|||||||
<Select
|
<Select
|
||||||
{...rest}
|
{...rest}
|
||||||
ref={inputRef}
|
ref={inputRef}
|
||||||
|
options={_options}
|
||||||
onFocus={handleOnFocus}
|
onFocus={handleOnFocus}
|
||||||
onBlur={handleOnBlur}
|
onBlur={handleOnBlur}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
&.focus {
|
&.focus {
|
||||||
padding-top: 9px;
|
// padding-top: 9px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.content-wrap {
|
.content-wrap {
|
||||||
@@ -15,7 +15,7 @@
|
|||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
.clear-btn {
|
.clear-btn {
|
||||||
display: block;
|
display: flex;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -29,7 +29,8 @@
|
|||||||
display: none;
|
display: none;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: 6px;
|
right: 6px;
|
||||||
top: 6px;
|
top: 50%;
|
||||||
|
transform: translateY(-50%);
|
||||||
}
|
}
|
||||||
|
|
||||||
.textarea-label {
|
.textarea-label {
|
||||||
@@ -41,8 +42,8 @@
|
|||||||
.content {
|
.content {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
width: 100px;
|
width: 100px;
|
||||||
height: 40px;
|
height: 46px;
|
||||||
line-height: 24px;
|
line-height: 30px;
|
||||||
padding: 8px 14px;
|
padding: 8px 14px;
|
||||||
padding-right: 4px;
|
padding-right: 4px;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
|
|||||||
@@ -9,11 +9,11 @@ interface SpeechContentProps {
|
|||||||
const SpeechContent: React.FC<SpeechContentProps> = (props) => {
|
const SpeechContent: React.FC<SpeechContentProps> = (props) => {
|
||||||
console.log('SpeechContent', props);
|
console.log('SpeechContent', props);
|
||||||
return (
|
return (
|
||||||
<div>
|
<>
|
||||||
{props.dataList.map((item) => (
|
{props.dataList.map((item) => (
|
||||||
<SpeechItem key={item.uid} {...item} />
|
<SpeechItem key={item.uid} {...item} />
|
||||||
))}
|
))}
|
||||||
</div>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Vendored
+2
@@ -24,11 +24,13 @@ declare namespace Global {
|
|||||||
|
|
||||||
interface BaseListItem<T> {
|
interface BaseListItem<T> {
|
||||||
key: string;
|
key: string;
|
||||||
|
locale?: boolean;
|
||||||
value: T;
|
value: T;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface BaseOption<T> {
|
interface BaseOption<T> {
|
||||||
label: string;
|
label: string;
|
||||||
|
locale?: boolean;
|
||||||
value: T;
|
value: T;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -48,5 +48,26 @@ export default {
|
|||||||
'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',
|
||||||
'playground.model.noavailable.tips':
|
'playground.model.noavailable.tips':
|
||||||
'Please deploy a model first, and it should not be an embedding-only model.'
|
'Please deploy a model first, and it should not be an embedding-only model.',
|
||||||
|
'playground.params.counts': 'Counts',
|
||||||
|
'playground.params.quality': 'Quality',
|
||||||
|
'playground.params.style': 'Style',
|
||||||
|
'playground.params.size': 'Size',
|
||||||
|
'playground.params.voice': 'Voice',
|
||||||
|
'playground.params.format': 'Format',
|
||||||
|
'playground.params.speed': 'Speed',
|
||||||
|
'playground.params.language': 'Language',
|
||||||
|
'playground.params.width': 'Width',
|
||||||
|
'playground.params.height': 'Height',
|
||||||
|
'playground.params.custom': 'Custom',
|
||||||
|
'playground.params.empty.tips': 'Generated images will appear here',
|
||||||
|
'playground.embedding.documents': 'Documents',
|
||||||
|
'playground.embedding.addtext': 'Add Text',
|
||||||
|
'playground.embedding.inputyourtext': 'Input your text',
|
||||||
|
'playground.embedding.output': 'Output',
|
||||||
|
'playground.embedding.chart': 'Chart',
|
||||||
|
'playground.rerank.query': 'Query',
|
||||||
|
'playground.rerank.rank': 'Rank',
|
||||||
|
'playground.rerank.score': 'Score',
|
||||||
|
'playground.rerank.query.holder': 'Input your query'
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -48,5 +48,26 @@ export default {
|
|||||||
'playground.compare.applytoall': '应用到所有模型',
|
'playground.compare.applytoall': '应用到所有模型',
|
||||||
'playground.model.noavailable': '无可用模型',
|
'playground.model.noavailable': '无可用模型',
|
||||||
'playground.model.noavailable.tips':
|
'playground.model.noavailable.tips':
|
||||||
'请先部署模型,且不是 Embedding Only 的模型'
|
'请先部署模型,且不是 Embedding Only 的模型',
|
||||||
|
'playground.params.counts': '数量',
|
||||||
|
'playground.params.quality': '质量',
|
||||||
|
'playground.params.style': '风格',
|
||||||
|
'playground.params.size': '尺寸',
|
||||||
|
'playground.params.voice': '声音',
|
||||||
|
'playground.params.format': '格式',
|
||||||
|
'playground.params.speed': '播放速度',
|
||||||
|
'playground.params.language': '语言',
|
||||||
|
'playground.params.width': '宽度',
|
||||||
|
'playground.params.height': '高度',
|
||||||
|
'playground.params.custom': '自定义',
|
||||||
|
'playground.params.empty.tips': '生成的图片将出现在这里',
|
||||||
|
'playground.embedding.documents': '文档',
|
||||||
|
'playground.embedding.addtext': '添加文本',
|
||||||
|
'playground.embedding.inputyourtext': '输入你的文本',
|
||||||
|
'playground.embedding.output': '输出',
|
||||||
|
'playground.embedding.chart': '图表',
|
||||||
|
'playground.rerank.query': '查询',
|
||||||
|
'playground.rerank.rank': '排序',
|
||||||
|
'playground.rerank.score': '分数',
|
||||||
|
'playground.rerank.query.holder': '输入查询'
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -65,9 +65,19 @@ export const createImages = async (
|
|||||||
},
|
},
|
||||||
options?: any
|
options?: any
|
||||||
) => {
|
) => {
|
||||||
return request(`${CREAT_IMAGE_API}`, {
|
const res = await fetch(`${CREAT_IMAGE_API}`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
data: params,
|
body: JSON.stringify(params),
|
||||||
cancelToken: options?.cancelToken
|
signal: options.signal,
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
if (!res.ok) {
|
||||||
|
return {
|
||||||
|
error: true,
|
||||||
|
data: await res.json()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return res.json();
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ interface AudioInputProps {
|
|||||||
onAnalyse?: (analyseData: any, frequencyBinCount: any) => void;
|
onAnalyse?: (analyseData: any, frequencyBinCount: any) => void;
|
||||||
onAudioPermission: (audioPermission: boolean) => void;
|
onAudioPermission: (audioPermission: boolean) => void;
|
||||||
onRecord?: (isRecording: boolean) => void;
|
onRecord?: (isRecording: boolean) => void;
|
||||||
|
onStop?: () => void;
|
||||||
voiceActivity?: boolean;
|
voiceActivity?: boolean;
|
||||||
type?: 'text' | 'primary' | 'default';
|
type?: 'text' | 'primary' | 'default';
|
||||||
}
|
}
|
||||||
@@ -55,7 +56,7 @@ const AudioInput: React.FC<AudioInputProps> = (props) => {
|
|||||||
const handleStopRecording = () => {
|
const handleStopRecording = () => {
|
||||||
setIsRecording(false);
|
setIsRecording(false);
|
||||||
audioRecorder.current?.stop();
|
audioRecorder.current?.stop();
|
||||||
props.onRecord?.(false);
|
// props.onRecord?.(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
// get all audio tracks
|
// get all audio tracks
|
||||||
@@ -136,6 +137,7 @@ const AudioInput: React.FC<AudioInputProps> = (props) => {
|
|||||||
const stopRecording = () => {
|
const stopRecording = () => {
|
||||||
audioRecorder.current?.stop();
|
audioRecorder.current?.stop();
|
||||||
setIsRecording(false);
|
setIsRecording(false);
|
||||||
|
props.onRecord?.(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleAudioData = (audioData: any) => {
|
const handleAudioData = (audioData: any) => {
|
||||||
|
|||||||
@@ -0,0 +1,290 @@
|
|||||||
|
import FieldWrapper from '@/components/seal-form/field-wrapper';
|
||||||
|
import SealInput from '@/components/seal-form/seal-input';
|
||||||
|
import SealSelect from '@/components/seal-form/seal-select';
|
||||||
|
import { INPUT_WIDTH } from '@/constants';
|
||||||
|
import { InfoCircleOutlined } from '@ant-design/icons';
|
||||||
|
import { useIntl } from '@umijs/max';
|
||||||
|
import { Form, InputNumber, Slider, Tooltip } from 'antd';
|
||||||
|
import _ from 'lodash';
|
||||||
|
import {
|
||||||
|
forwardRef,
|
||||||
|
memo,
|
||||||
|
useCallback,
|
||||||
|
useEffect,
|
||||||
|
useId,
|
||||||
|
useImperativeHandle,
|
||||||
|
useMemo
|
||||||
|
} from 'react';
|
||||||
|
import { ParamsSchema } from '../config/types';
|
||||||
|
import CustomLabelStyles from '../style/custom-label.less';
|
||||||
|
|
||||||
|
type ParamsSettingsFormProps = {
|
||||||
|
top_n?: number;
|
||||||
|
model?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
type ParamsSettingsProps = {
|
||||||
|
ref?: any;
|
||||||
|
selectedModel?: string;
|
||||||
|
showModelSelector?: boolean;
|
||||||
|
params?: Record<string, any>;
|
||||||
|
model?: string;
|
||||||
|
modelList: Global.BaseOption<string>[];
|
||||||
|
onValuesChange?: (changeValues: any, value: Record<string, any>) => void;
|
||||||
|
setParams: (params: any) => void;
|
||||||
|
globalParams?: Record<string, any>;
|
||||||
|
paramsConfig?: ParamsSchema[];
|
||||||
|
initialValues?: Record<string, any>;
|
||||||
|
extra?: React.ReactNode[];
|
||||||
|
};
|
||||||
|
|
||||||
|
const ParamsSettings: React.FC<ParamsSettingsProps> = forwardRef(
|
||||||
|
(
|
||||||
|
{
|
||||||
|
setParams,
|
||||||
|
onValuesChange,
|
||||||
|
selectedModel,
|
||||||
|
globalParams,
|
||||||
|
initialValues,
|
||||||
|
paramsConfig,
|
||||||
|
modelList,
|
||||||
|
params,
|
||||||
|
showModelSelector = true,
|
||||||
|
extra
|
||||||
|
},
|
||||||
|
ref
|
||||||
|
) => {
|
||||||
|
const intl = useIntl();
|
||||||
|
const [form] = Form.useForm();
|
||||||
|
const formId = useId();
|
||||||
|
|
||||||
|
useImperativeHandle(ref, () => ({
|
||||||
|
form
|
||||||
|
}));
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (showModelSelector) {
|
||||||
|
form.setFieldsValue({
|
||||||
|
model: selectedModel || _.get(modelList, '[0].value'),
|
||||||
|
...initialValues
|
||||||
|
});
|
||||||
|
setParams({
|
||||||
|
model: selectedModel || _.get(modelList, '[0].value'),
|
||||||
|
...initialValues
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
form.setFieldsValue({
|
||||||
|
model: selectedModel || '',
|
||||||
|
...initialValues
|
||||||
|
});
|
||||||
|
setParams({
|
||||||
|
model: selectedModel || '',
|
||||||
|
...initialValues
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [modelList, showModelSelector, selectedModel, initialValues]);
|
||||||
|
|
||||||
|
const handleOnFinish = (values: any) => {
|
||||||
|
console.log('handleOnFinish', values);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleOnFinishFailed = (errorInfo: any) => {
|
||||||
|
console.log('handleOnFinishFailed', errorInfo);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleValuesChange = useCallback(
|
||||||
|
(changedValues: any, allValues: any) => {
|
||||||
|
setParams?.(allValues);
|
||||||
|
onValuesChange?.(changedValues, allValues);
|
||||||
|
},
|
||||||
|
[onValuesChange, setParams]
|
||||||
|
);
|
||||||
|
const handleFieldValueChange = useCallback(
|
||||||
|
(val: any, field: string) => {
|
||||||
|
const values = form.getFieldsValue();
|
||||||
|
form.setFieldsValue({
|
||||||
|
...values,
|
||||||
|
[field]: val
|
||||||
|
});
|
||||||
|
setParams({
|
||||||
|
...values,
|
||||||
|
[field]: val
|
||||||
|
});
|
||||||
|
onValuesChange?.(
|
||||||
|
{ [field]: val },
|
||||||
|
{
|
||||||
|
...values,
|
||||||
|
[field]: val
|
||||||
|
}
|
||||||
|
);
|
||||||
|
},
|
||||||
|
[form, setParams, onValuesChange]
|
||||||
|
);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
form.setFieldsValue(globalParams);
|
||||||
|
}, [globalParams]);
|
||||||
|
|
||||||
|
const renderLabel = useCallback(
|
||||||
|
(args: { field: string; label: string; description: string }) => {
|
||||||
|
return (
|
||||||
|
<span
|
||||||
|
className={CustomLabelStyles.label}
|
||||||
|
style={{ width: INPUT_WIDTH.mini }}
|
||||||
|
>
|
||||||
|
<span className="text">
|
||||||
|
{args.description ? (
|
||||||
|
<Tooltip title={args.description}>
|
||||||
|
<span> {args.label}</span>
|
||||||
|
<span className="m-l-5">
|
||||||
|
<InfoCircleOutlined />
|
||||||
|
</span>
|
||||||
|
</Tooltip>
|
||||||
|
) : (
|
||||||
|
<span>{args.label}</span>
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<InputNumber
|
||||||
|
className="label-val"
|
||||||
|
variant="outlined"
|
||||||
|
size="small"
|
||||||
|
value={form.getFieldValue(args.field)}
|
||||||
|
controls={false}
|
||||||
|
onChange={(val) => handleFieldValueChange(val, args.field)}
|
||||||
|
></InputNumber>
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
[form, handleFieldValueChange]
|
||||||
|
);
|
||||||
|
|
||||||
|
const renderFields = useMemo(() => {
|
||||||
|
console.log('paramsConfig:', paramsConfig);
|
||||||
|
if (!paramsConfig?.length) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return paramsConfig.map((item: ParamsSchema) => {
|
||||||
|
if (item.type === 'InputNumber') {
|
||||||
|
return (
|
||||||
|
<Form.Item name={item.name} rules={item.rules} key={item.name}>
|
||||||
|
<SealInput.Number
|
||||||
|
{...item.attrs}
|
||||||
|
style={{ width: '100%' }}
|
||||||
|
label={
|
||||||
|
item.label.isLocalized
|
||||||
|
? intl.formatMessage({ id: item.label.text })
|
||||||
|
: item.label.text
|
||||||
|
}
|
||||||
|
></SealInput.Number>
|
||||||
|
</Form.Item>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (item.type === 'TextArea') {
|
||||||
|
return (
|
||||||
|
<Form.Item name={item.name} rules={item.rules} key={item.name}>
|
||||||
|
<SealInput.TextArea
|
||||||
|
{...item.attrs}
|
||||||
|
style={{ width: '100%' }}
|
||||||
|
label={
|
||||||
|
item.label.isLocalized
|
||||||
|
? intl.formatMessage({ id: item.label.text })
|
||||||
|
: item.label.text
|
||||||
|
}
|
||||||
|
></SealInput.TextArea>
|
||||||
|
</Form.Item>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (item.type === 'Select') {
|
||||||
|
return (
|
||||||
|
<Form.Item name={item.name} rules={item.rules} key={item.name}>
|
||||||
|
<SealSelect
|
||||||
|
{...item.attrs}
|
||||||
|
options={item.options}
|
||||||
|
label={
|
||||||
|
item.label.isLocalized
|
||||||
|
? intl.formatMessage({ id: item.label.text })
|
||||||
|
: item.label.text
|
||||||
|
}
|
||||||
|
></SealSelect>
|
||||||
|
</Form.Item>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (item.type === 'Slider') {
|
||||||
|
return (
|
||||||
|
<Form.Item name={item.name} rules={item.rules} key={item.name}>
|
||||||
|
<FieldWrapper
|
||||||
|
label={renderLabel({
|
||||||
|
field: item.name,
|
||||||
|
label: item.label.isLocalized
|
||||||
|
? intl.formatMessage({ id: item.label.text })
|
||||||
|
: item.label.text,
|
||||||
|
description: item.description?.isLocalized
|
||||||
|
? intl.formatMessage({ id: item.description?.text })
|
||||||
|
: item.description?.text || ''
|
||||||
|
})}
|
||||||
|
style={{ padding: '20px 2px 0' }}
|
||||||
|
variant="borderless"
|
||||||
|
>
|
||||||
|
<Slider
|
||||||
|
{...item.attrs}
|
||||||
|
style={{ marginBottom: 0, marginTop: 16, marginInline: 0 }}
|
||||||
|
tooltip={{ open: false }}
|
||||||
|
value={form.getFieldValue(item.name) || undefined}
|
||||||
|
onChange={(val) => handleFieldValueChange(val, item.name)}
|
||||||
|
></Slider>
|
||||||
|
</FieldWrapper>
|
||||||
|
</Form.Item>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
}, [paramsConfig, params]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Form
|
||||||
|
name={formId}
|
||||||
|
form={form}
|
||||||
|
onValuesChange={handleValuesChange}
|
||||||
|
onFinish={handleOnFinish}
|
||||||
|
onFinishFailed={handleOnFinishFailed}
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
{
|
||||||
|
<>
|
||||||
|
<h3 className="m-b-20 m-l-10 font-size-14 line-24">
|
||||||
|
<span>
|
||||||
|
{intl.formatMessage({ id: 'playground.parameters' })}
|
||||||
|
</span>
|
||||||
|
</h3>
|
||||||
|
<Form.Item<ParamsSettingsFormProps>
|
||||||
|
name="model"
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: intl.formatMessage(
|
||||||
|
{
|
||||||
|
id: 'common.form.rule.select'
|
||||||
|
},
|
||||||
|
{ name: intl.formatMessage({ id: 'playground.model' }) }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<SealSelect
|
||||||
|
showSearch={true}
|
||||||
|
options={modelList}
|
||||||
|
label={intl.formatMessage({ id: 'playground.model' })}
|
||||||
|
></SealSelect>
|
||||||
|
</Form.Item>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
{renderFields}
|
||||||
|
{extra}
|
||||||
|
</div>
|
||||||
|
</Form>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
export default memo(ParamsSettings);
|
||||||
@@ -1,18 +1,21 @@
|
|||||||
|
import AlertInfo from '@/components/alert-info';
|
||||||
import ScatterChart from '@/components/echarts/scatter';
|
import ScatterChart from '@/components/echarts/scatter';
|
||||||
|
import HighlightCode from '@/components/highlight-code';
|
||||||
|
import IconFont from '@/components/icon-font';
|
||||||
import useOverlayScroller from '@/hooks/use-overlay-scroller';
|
import useOverlayScroller from '@/hooks/use-overlay-scroller';
|
||||||
import useRequestToken from '@/hooks/use-request-token';
|
import useRequestToken from '@/hooks/use-request-token';
|
||||||
import {
|
import {
|
||||||
ClearOutlined,
|
ClearOutlined,
|
||||||
LoadingOutlined,
|
HolderOutlined,
|
||||||
PlusOutlined,
|
PlusOutlined,
|
||||||
ThunderboltOutlined,
|
SendOutlined
|
||||||
UploadOutlined
|
|
||||||
} from '@ant-design/icons';
|
} from '@ant-design/icons';
|
||||||
import { useIntl, useSearchParams } from '@umijs/max';
|
import { useIntl, useSearchParams } from '@umijs/max';
|
||||||
import { Button, Tooltip } from 'antd';
|
import { Button, Segmented, Tabs } from 'antd';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { PCA } from 'ml-pca';
|
import { PCA } from 'ml-pca';
|
||||||
import 'overlayscrollbars/overlayscrollbars.css';
|
import 'overlayscrollbars/overlayscrollbars.css';
|
||||||
|
import { Resizable } from 're-resizable';
|
||||||
import {
|
import {
|
||||||
forwardRef,
|
forwardRef,
|
||||||
memo,
|
memo,
|
||||||
@@ -23,16 +26,14 @@ import {
|
|||||||
useRef,
|
useRef,
|
||||||
useState
|
useState
|
||||||
} from 'react';
|
} from 'react';
|
||||||
import { UMAP } from 'umap-js';
|
|
||||||
import { handleEmbedding } from '../apis';
|
import { handleEmbedding } from '../apis';
|
||||||
|
import { OpenAIViewCode } from '../config';
|
||||||
import { ParamsSchema } from '../config/types';
|
import { ParamsSchema } from '../config/types';
|
||||||
import '../style/ground-left.less';
|
import '../style/ground-left.less';
|
||||||
import '../style/rerank.less';
|
import '../style/rerank.less';
|
||||||
import '../style/system-message-wrap.less';
|
import DynamicParams from './dynamic-params';
|
||||||
import FileList from './file-list';
|
import FileList from './file-list';
|
||||||
import InputList from './input-list';
|
import InputList from './input-list';
|
||||||
import RerankerParams from './reranker-params';
|
|
||||||
import UploadFile from './upload-file';
|
|
||||||
import ViewCodeModal from './view-code-modal';
|
import ViewCodeModal from './view-code-modal';
|
||||||
|
|
||||||
interface MessageProps {
|
interface MessageProps {
|
||||||
@@ -41,42 +42,11 @@ interface MessageProps {
|
|||||||
ref?: any;
|
ref?: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
const paramsConfig: ParamsSchema[] = [
|
const paramsConfig: ParamsSchema[] = [];
|
||||||
// {
|
|
||||||
// type: 'Select',
|
|
||||||
// name: 'truncate',
|
|
||||||
// label: {
|
|
||||||
// text: 'Truncate',
|
|
||||||
// isLocalized: false
|
|
||||||
// },
|
|
||||||
// options: [
|
|
||||||
// {
|
|
||||||
// label: 'None',
|
|
||||||
// value: 'none'
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// label: 'Start',
|
|
||||||
// value: 'start'
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// label: 'End',
|
|
||||||
// value: 'end'
|
|
||||||
// }
|
|
||||||
// ],
|
|
||||||
// rules: [
|
|
||||||
// {
|
|
||||||
// required: true,
|
|
||||||
// message: 'Please select truncate'
|
|
||||||
// }
|
|
||||||
// ]
|
|
||||||
// }
|
|
||||||
];
|
|
||||||
|
|
||||||
const initialValues = {
|
const initialValues = {};
|
||||||
truncate: 'none'
|
|
||||||
};
|
|
||||||
|
|
||||||
const GroundReranker: React.FC<MessageProps> = forwardRef((props, ref) => {
|
const GroundEmbedding: React.FC<MessageProps> = forwardRef((props, ref) => {
|
||||||
const { modelList } = props;
|
const { modelList } = props;
|
||||||
const acceptType =
|
const acceptType =
|
||||||
'.txt, .doc, .docx, .xls, .xlsx, .csv, .md, .pdf, .eml, .msg, .ppt, .pptx, .xml, .epub, .html';
|
'.txt, .doc, .docx, .xls, .xlsx, .csv, .md, .pdf, .eml, .msg, .ppt, .pptx, .xml, .epub, .html';
|
||||||
@@ -100,6 +70,10 @@ const GroundReranker: React.FC<MessageProps> = forwardRef((props, ref) => {
|
|||||||
const [fileList, setFileList] = useState<
|
const [fileList, setFileList] = useState<
|
||||||
{ text: string; name: string; uid: number | string }[]
|
{ text: string; name: string; uid: number | string }[]
|
||||||
>([]);
|
>([]);
|
||||||
|
const [outputType, setOutputType] = useState<string>('chart');
|
||||||
|
const [outputHeight, setOutputHeight] = useState<number>(180);
|
||||||
|
const [embeddingData, setEmbeddingData] = useState<string>('');
|
||||||
|
const [lessTwoInput, setLessTwoInput] = useState<boolean>(false);
|
||||||
|
|
||||||
const [textList, setTextList] = useState<
|
const [textList, setTextList] = useState<
|
||||||
{ text: string; uid: number | string; name: string }[]
|
{ text: string; uid: number | string; name: string }[]
|
||||||
@@ -136,56 +110,23 @@ const GroundReranker: React.FC<MessageProps> = forwardRef((props, ref) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const inputEmpty = useMemo(() => {
|
const inputEmpty = useMemo(() => {
|
||||||
const list = [...textList, ...fileList].filter((item) => item.text);
|
const list = [...textList, ...fileList];
|
||||||
return list.length < 2;
|
return list.length < 2;
|
||||||
}, [textList, fileList]);
|
}, [textList, fileList]);
|
||||||
|
|
||||||
const cosine = useCallback((x: number[], y: number[]) => {
|
|
||||||
let result = 0;
|
|
||||||
let normX = 0;
|
|
||||||
let normY = 0;
|
|
||||||
|
|
||||||
for (let i = 0; i < x.length; i++) {
|
|
||||||
result += x[i] * y[i];
|
|
||||||
normX += x[i] ** 2;
|
|
||||||
normY += y[i] ** 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (normX === 0 && normY === 0) {
|
|
||||||
return 0;
|
|
||||||
} else if (normX === 0 || normY === 0) {
|
|
||||||
return 1;
|
|
||||||
} else {
|
|
||||||
return 1 - result / Math.sqrt(normX * normY);
|
|
||||||
}
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const generateEmbedding = useCallback(
|
const generateEmbedding = useCallback(
|
||||||
(embeddings: any[]) => {
|
(embeddings: any[]) => {
|
||||||
try {
|
try {
|
||||||
const umap = new UMAP({
|
|
||||||
// random: random,
|
|
||||||
minDist: 0,
|
|
||||||
nComponents: 3,
|
|
||||||
nEpochs: 200,
|
|
||||||
distanceFn: cosine,
|
|
||||||
nNeighbors: embeddings.length - 1
|
|
||||||
});
|
|
||||||
|
|
||||||
const dataList = embeddings.map((item) => {
|
const dataList = embeddings.map((item) => {
|
||||||
return item.embedding;
|
return item.embedding;
|
||||||
});
|
});
|
||||||
|
|
||||||
const embedding = umap.fit([...dataList]);
|
const pca = new PCA(dataList);
|
||||||
console.log('embedding:----------------', embedding);
|
|
||||||
const pca = new PCA(dataList, {});
|
|
||||||
console.log('dataList====', dataList, embeddings);
|
|
||||||
const pcadata = pca.predict(dataList, { nComponents: 2 }).to2DArray();
|
const pcadata = pca.predict(dataList, { nComponents: 2 }).to2DArray();
|
||||||
console.log('pcadata++++++++++++++++', pcadata);
|
|
||||||
|
|
||||||
const input = [
|
const input = [
|
||||||
...textList.map((item) => item.text),
|
...textList.map((item) => item.text).filter((item) => item),
|
||||||
...fileList.map((item) => item.text)
|
...fileList.map((item) => item.text).filter((item) => item)
|
||||||
];
|
];
|
||||||
|
|
||||||
const list = pcadata.map((item: number[], index: number) => {
|
const list = pcadata.map((item: number[], index: number) => {
|
||||||
@@ -195,13 +136,8 @@ const GroundReranker: React.FC<MessageProps> = forwardRef((props, ref) => {
|
|||||||
text: input[index]
|
text: input[index]
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
console.log('embedding____________:', {
|
|
||||||
list,
|
|
||||||
input,
|
|
||||||
textList,
|
|
||||||
fileList
|
|
||||||
});
|
|
||||||
setScatterData(list);
|
setScatterData(list);
|
||||||
|
setEmbeddingData(JSON.stringify(embeddings, null, 2));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log('error:', e);
|
console.log('error:', e);
|
||||||
}
|
}
|
||||||
@@ -220,7 +156,26 @@ const GroundReranker: React.FC<MessageProps> = forwardRef((props, ref) => {
|
|||||||
|
|
||||||
const submitMessage = async (current?: { role: string; content: string }) => {
|
const submitMessage = async (current?: { role: string; content: string }) => {
|
||||||
if (!parameters.model) return;
|
if (!parameters.model) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
const validTextList = textList.filter((item) => item.text);
|
||||||
|
const validFileList = fileList.filter((item) => item.text);
|
||||||
|
|
||||||
|
const inputList = [
|
||||||
|
...validTextList.map((item) => item.text),
|
||||||
|
...validFileList.map((item) => item.text)
|
||||||
|
];
|
||||||
|
|
||||||
|
if (inputList.length < 2) {
|
||||||
|
setLessTwoInput(true);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setTextList(validTextList);
|
||||||
|
setFileList(validFileList);
|
||||||
|
|
||||||
|
setLessTwoInput(false);
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
setMessageId();
|
setMessageId();
|
||||||
setTokenResult(null);
|
setTokenResult(null);
|
||||||
@@ -234,26 +189,19 @@ const GroundReranker: React.FC<MessageProps> = forwardRef((props, ref) => {
|
|||||||
{
|
{
|
||||||
model: parameters.model,
|
model: parameters.model,
|
||||||
encoding_format: 'float',
|
encoding_format: 'float',
|
||||||
input: [
|
input: inputList
|
||||||
...textList.map((item) => item.text),
|
|
||||||
...fileList.map((item) => item.text)
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
token: requestToken.current.token
|
token: requestToken.current.token
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
console.log('result:', result);
|
|
||||||
|
|
||||||
setTokenResult(result.usage);
|
setTokenResult(result.usage);
|
||||||
|
|
||||||
const embeddingsList = result.data || [];
|
const embeddingsList = result.data || [];
|
||||||
|
|
||||||
console.log('embeddings:', embeddingsList);
|
|
||||||
|
|
||||||
generateEmbedding(embeddingsList);
|
generateEmbedding(embeddingsList);
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
console.log('error========', error);
|
|
||||||
setTokenResult({
|
setTokenResult({
|
||||||
error: true,
|
error: true,
|
||||||
errorMessage: error.response?.data?.error?.message
|
errorMessage: error.response?.data?.error?.message
|
||||||
@@ -280,6 +228,18 @@ const GroundReranker: React.FC<MessageProps> = forwardRef((props, ref) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleScaleOutputSize = (
|
||||||
|
e: any,
|
||||||
|
direction: string,
|
||||||
|
ref: any,
|
||||||
|
d: any
|
||||||
|
) => {
|
||||||
|
console.log('handleScaleOutputSize', e, direction, ref, d);
|
||||||
|
if (d.height + outputHeight <= 300 && d.height + outputHeight >= 180) {
|
||||||
|
setOutputHeight(d.height + outputHeight);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const handleDeleteFile = (uid: number | string) => {
|
const handleDeleteFile = (uid: number | string) => {
|
||||||
setFileList((preList) => {
|
setFileList((preList) => {
|
||||||
return preList.filter((item) => item.uid !== uid);
|
return preList.filter((item) => item.uid !== uid);
|
||||||
@@ -310,8 +270,47 @@ const GroundReranker: React.FC<MessageProps> = forwardRef((props, ref) => {
|
|||||||
]);
|
]);
|
||||||
setFileList([]);
|
setFileList([]);
|
||||||
setScatterData([]);
|
setScatterData([]);
|
||||||
|
setTokenResult(null);
|
||||||
|
setLessTwoInput(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleOutputTypeChange = (value: string) => {
|
||||||
|
setOutputType(value);
|
||||||
|
};
|
||||||
|
|
||||||
|
const outputItems = useMemo(() => {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
key: 'chart',
|
||||||
|
label: 'Chart',
|
||||||
|
children: (
|
||||||
|
<ScatterChart
|
||||||
|
seriesData={scatterData}
|
||||||
|
height={outputHeight}
|
||||||
|
width="100%"
|
||||||
|
xAxisData={[]}
|
||||||
|
></ScatterChart>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'json',
|
||||||
|
label: 'JSON',
|
||||||
|
children: (
|
||||||
|
<div style={{ padding: 10, backgroundColor: '#fafafa' }}>
|
||||||
|
<HighlightCode
|
||||||
|
height={outputHeight - 20}
|
||||||
|
theme="light"
|
||||||
|
code={embeddingData}
|
||||||
|
lang="json"
|
||||||
|
copyable={true}
|
||||||
|
style={{ marginBottom: 0 }}
|
||||||
|
></HighlightCode>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}, [outputHeight, scatterData, embeddingData]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setMessageId();
|
setMessageId();
|
||||||
setScatterData([]);
|
setScatterData([]);
|
||||||
@@ -339,7 +338,7 @@ const GroundReranker: React.FC<MessageProps> = forwardRef((props, ref) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="ground-left-wrapper rerank">
|
<div className="ground-left-wrapper rerank">
|
||||||
<div className="ground-left" style={{ justifyContent: 'flex-start' }}>
|
<div className="ground-left">
|
||||||
<div
|
<div
|
||||||
className="center"
|
className="center"
|
||||||
ref={scroller}
|
ref={scroller}
|
||||||
@@ -348,25 +347,18 @@ const GroundReranker: React.FC<MessageProps> = forwardRef((props, ref) => {
|
|||||||
<div className="documents">
|
<div className="documents">
|
||||||
<div className="flex-between m-b-8 doc-header">
|
<div className="flex-between m-b-8 doc-header">
|
||||||
<h3 className="m-l-10 flex-between flex-center font-size-14 line-24 m-b-0">
|
<h3 className="m-l-10 flex-between flex-center font-size-14 line-24 m-b-0">
|
||||||
<span>Documents</span>
|
<div className="flex gap-20">
|
||||||
|
<span>
|
||||||
|
{intl.formatMessage({
|
||||||
|
id: 'playground.embedding.documents'
|
||||||
|
})}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
</h3>
|
</h3>
|
||||||
<div className="flex gap-10">
|
<div className="flex gap-10">
|
||||||
<UploadFile
|
|
||||||
handleUpdateFileList={handleUpdateFileList}
|
|
||||||
accept={acceptType}
|
|
||||||
>
|
|
||||||
<Tooltip title={<span>Support: {acceptType}</span>}>
|
|
||||||
<Button
|
|
||||||
size="middle"
|
|
||||||
icon={<UploadOutlined></UploadOutlined>}
|
|
||||||
>
|
|
||||||
Upload File
|
|
||||||
</Button>
|
|
||||||
</Tooltip>
|
|
||||||
</UploadFile>
|
|
||||||
<Button size="middle" onClick={handleAddText}>
|
<Button size="middle" onClick={handleAddText}>
|
||||||
<PlusOutlined />
|
<PlusOutlined />
|
||||||
Add Text
|
{intl.formatMessage({ id: 'playground.embedding.addtext' })}
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
icon={<ClearOutlined />}
|
icon={<ClearOutlined />}
|
||||||
@@ -375,15 +367,31 @@ const GroundReranker: React.FC<MessageProps> = forwardRef((props, ref) => {
|
|||||||
>
|
>
|
||||||
{intl.formatMessage({ id: 'common.button.clear' })}
|
{intl.formatMessage({ id: 'common.button.clear' })}
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
{!loading ? (
|
||||||
size="middle"
|
<Button
|
||||||
type="primary"
|
size="middle"
|
||||||
disabled={inputEmpty}
|
type="primary"
|
||||||
onClick={handleSendMessage}
|
disabled={inputEmpty}
|
||||||
>
|
onClick={handleSendMessage}
|
||||||
{loading ? <LoadingOutlined /> : <ThunderboltOutlined />}
|
icon={<SendOutlined rotate={0} className="font-size-14" />}
|
||||||
{intl.formatMessage({ id: 'common.button.run' })}
|
style={{ width: 60 }}
|
||||||
</Button>
|
></Button>
|
||||||
|
) : (
|
||||||
|
<Button
|
||||||
|
style={{ width: 80 }}
|
||||||
|
size="middle"
|
||||||
|
type="primary"
|
||||||
|
onClick={handleStopConversation}
|
||||||
|
icon={
|
||||||
|
<IconFont
|
||||||
|
type="icon-stop1"
|
||||||
|
className="font-size-12"
|
||||||
|
></IconFont>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{intl.formatMessage({ id: 'common.button.stop' })}
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="docs-wrapper">
|
<div className="docs-wrapper">
|
||||||
@@ -399,6 +407,12 @@ const GroundReranker: React.FC<MessageProps> = forwardRef((props, ref) => {
|
|||||||
onDelete={handleDeleteFile}
|
onDelete={handleDeleteFile}
|
||||||
></FileList>
|
></FileList>
|
||||||
</div>
|
</div>
|
||||||
|
{lessTwoInput && (
|
||||||
|
<AlertInfo
|
||||||
|
type="danger"
|
||||||
|
message="Please input at least two documents"
|
||||||
|
></AlertInfo>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -411,23 +425,75 @@ const GroundReranker: React.FC<MessageProps> = forwardRef((props, ref) => {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<h3 className="m-l-10 flex-between flex-center font-size-14 line-24 m-b-16">
|
<h3 className="m-l-10 flex-between flex-center font-size-14 line-24 m-b-16">
|
||||||
<span>Output</span>
|
<div className="flex gap-20">
|
||||||
|
<span>
|
||||||
|
{intl.formatMessage({ id: 'playground.embedding.output' })}
|
||||||
|
</span>
|
||||||
|
<AlertInfo
|
||||||
|
type="danger"
|
||||||
|
message={tokenResult?.errorMessage}
|
||||||
|
></AlertInfo>
|
||||||
|
</div>
|
||||||
|
<Segmented
|
||||||
|
onChange={handleOutputTypeChange}
|
||||||
|
value={outputType}
|
||||||
|
options={[
|
||||||
|
{
|
||||||
|
label: intl.formatMessage({
|
||||||
|
id: 'playground.embedding.chart'
|
||||||
|
}),
|
||||||
|
value: 'chart'
|
||||||
|
},
|
||||||
|
{ label: 'JSON', value: 'json' }
|
||||||
|
]}
|
||||||
|
></Segmented>
|
||||||
</h3>
|
</h3>
|
||||||
<div
|
<div className="embed-chart">
|
||||||
style={{
|
<Resizable
|
||||||
border: '1px solid var(--ant-color-border)',
|
enable={{
|
||||||
borderRadius: 'var(--border-radius-base)',
|
top: true
|
||||||
overflow: 'hidden',
|
}}
|
||||||
width: '100%'
|
defaultSize={{
|
||||||
}}
|
height: 180
|
||||||
className="scatter"
|
}}
|
||||||
>
|
handleComponent={{
|
||||||
<ScatterChart
|
top: (
|
||||||
seriesData={scatterData}
|
<Button
|
||||||
height={160}
|
size="small"
|
||||||
width="100%"
|
className="drag-handler"
|
||||||
xAxisData={[]}
|
color="default"
|
||||||
></ScatterChart>
|
variant="filled"
|
||||||
|
icon={
|
||||||
|
<HolderOutlined
|
||||||
|
rotate={90}
|
||||||
|
style={{ fontSize: 'var(--font-size-14)' }}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
></Button>
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
maxHeight={300}
|
||||||
|
minHeight={180}
|
||||||
|
onResizeStop={handleScaleOutputSize}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
border: '1px solid var(--ant-color-border)',
|
||||||
|
borderRadius: 'var(--border-radius-base)',
|
||||||
|
overflow: 'hidden',
|
||||||
|
width: '100%'
|
||||||
|
}}
|
||||||
|
className="scatter "
|
||||||
|
>
|
||||||
|
<Tabs
|
||||||
|
defaultActiveKey={outputType}
|
||||||
|
activeKey={outputType}
|
||||||
|
centered
|
||||||
|
renderTabBar={() => <></>}
|
||||||
|
items={outputItems}
|
||||||
|
></Tabs>
|
||||||
|
</div>
|
||||||
|
</Resizable>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -438,7 +504,7 @@ const GroundReranker: React.FC<MessageProps> = forwardRef((props, ref) => {
|
|||||||
ref={paramsRef}
|
ref={paramsRef}
|
||||||
>
|
>
|
||||||
<div className="box">
|
<div className="box">
|
||||||
<RerankerParams
|
<DynamicParams
|
||||||
setParams={setParams}
|
setParams={setParams}
|
||||||
paramsConfig={paramsConfig}
|
paramsConfig={paramsConfig}
|
||||||
initialValues={initialValues}
|
initialValues={initialValues}
|
||||||
@@ -450,13 +516,13 @@ const GroundReranker: React.FC<MessageProps> = forwardRef((props, ref) => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ViewCodeModal
|
<ViewCodeModal
|
||||||
|
{...OpenAIViewCode.embeddings}
|
||||||
open={show}
|
open={show}
|
||||||
apiType="embedding"
|
|
||||||
payLoad={{
|
payLoad={{
|
||||||
input: [
|
input: [
|
||||||
...textList.map((item) => item.text),
|
...textList.map((item) => item.text).filter((item) => item),
|
||||||
...fileList.map((item) => item.text)
|
...fileList.map((item) => item.text).filter((item) => item)
|
||||||
].filter((text) => text)
|
]
|
||||||
}}
|
}}
|
||||||
parameters={{
|
parameters={{
|
||||||
...parameters
|
...parameters
|
||||||
@@ -468,4 +534,4 @@ const GroundReranker: React.FC<MessageProps> = forwardRef((props, ref) => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
export default memo(GroundReranker);
|
export default memo(GroundEmbedding);
|
||||||
|
|||||||
@@ -1,26 +1,33 @@
|
|||||||
|
import AlertInfo from '@/components/alert-info';
|
||||||
|
import SealInput from '@/components/seal-form/seal-input';
|
||||||
|
import SealSelect from '@/components/seal-form/seal-select';
|
||||||
import useOverlayScroller from '@/hooks/use-overlay-scroller';
|
import useOverlayScroller from '@/hooks/use-overlay-scroller';
|
||||||
import useRequestToken from '@/hooks/use-request-token';
|
|
||||||
import ThumbImg from '@/pages/playground/components/thumb-img';
|
import ThumbImg from '@/pages/playground/components/thumb-img';
|
||||||
|
import { fetchChunkedData, readStreamData } from '@/utils/fetch-chunk-data';
|
||||||
|
import { FileImageOutlined } from '@ant-design/icons';
|
||||||
import { useIntl, useSearchParams } from '@umijs/max';
|
import { useIntl, useSearchParams } from '@umijs/max';
|
||||||
|
import { Form } from 'antd';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import 'overlayscrollbars/overlayscrollbars.css';
|
import 'overlayscrollbars/overlayscrollbars.css';
|
||||||
import React, {
|
import React, {
|
||||||
forwardRef,
|
forwardRef,
|
||||||
memo,
|
memo,
|
||||||
|
useCallback,
|
||||||
useEffect,
|
useEffect,
|
||||||
useImperativeHandle,
|
useImperativeHandle,
|
||||||
|
useMemo,
|
||||||
useRef,
|
useRef,
|
||||||
useState
|
useState
|
||||||
} from 'react';
|
} from 'react';
|
||||||
import { createImages } from '../apis';
|
import { CREAT_IMAGE_API } from '../apis';
|
||||||
|
import { OpenAIViewCode } from '../config';
|
||||||
import { ImageParamsConfig as paramsConfig } from '../config/params-config';
|
import { ImageParamsConfig as paramsConfig } from '../config/params-config';
|
||||||
import { MessageItem } from '../config/types';
|
import { MessageItem, ParamsSchema } from '../config/types';
|
||||||
import '../style/ground-left.less';
|
import '../style/ground-left.less';
|
||||||
import '../style/system-message-wrap.less';
|
import '../style/system-message-wrap.less';
|
||||||
|
import DynamicParams from './dynamic-params';
|
||||||
import MessageInput from './message-input';
|
import MessageInput from './message-input';
|
||||||
import ReferenceParams from './reference-params';
|
|
||||||
import RerankerParams from './reranker-params';
|
|
||||||
import ViewCodeModal from './view-code-modal';
|
import ViewCodeModal from './view-code-modal';
|
||||||
|
|
||||||
interface MessageProps {
|
interface MessageProps {
|
||||||
@@ -33,18 +40,98 @@ const initialValues = {
|
|||||||
n: 1,
|
n: 1,
|
||||||
size: '512x512',
|
size: '512x512',
|
||||||
quality: 'standard',
|
quality: 'standard',
|
||||||
style: 'vivid'
|
style: ''
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const extraConfig: ParamsSchema[] = [
|
||||||
|
{
|
||||||
|
type: 'Select',
|
||||||
|
name: 'quality',
|
||||||
|
options: [
|
||||||
|
{ label: 'standard', value: 'standard' },
|
||||||
|
{ label: 'hd', value: 'hd' }
|
||||||
|
],
|
||||||
|
label: {
|
||||||
|
text: 'playground.params.quality',
|
||||||
|
isLocalized: true
|
||||||
|
},
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
required: false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'Select',
|
||||||
|
name: 'style',
|
||||||
|
options: [
|
||||||
|
{ label: 'vivid', value: 'vivid' },
|
||||||
|
{ label: 'natural', value: 'natural' }
|
||||||
|
],
|
||||||
|
label: {
|
||||||
|
text: 'playground.params.style',
|
||||||
|
isLocalized: true
|
||||||
|
},
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
required: false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
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);
|
||||||
const [messageList, setMessageList] = useState<
|
const [imageList, setImageList] = useState<
|
||||||
{ dataUrl: string; height: number; uid: number }[]
|
{
|
||||||
>([]);
|
dataUrl: string;
|
||||||
|
height: number | string;
|
||||||
|
width: string | number;
|
||||||
|
uid: number;
|
||||||
|
span?: number;
|
||||||
|
progress?: number;
|
||||||
|
}[]
|
||||||
|
>([
|
||||||
|
{
|
||||||
|
dataUrl:
|
||||||
|
'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png',
|
||||||
|
height: 'auto',
|
||||||
|
width: 'auto',
|
||||||
|
uid: 0,
|
||||||
|
span: 12,
|
||||||
|
progress: 10
|
||||||
|
},
|
||||||
|
{
|
||||||
|
dataUrl:
|
||||||
|
'https://gw.alipayobjects.com/zos/antfincdn/LlvErxo8H9/photo-1503185912284-5271ff81b9a8.webp',
|
||||||
|
height: 'auto',
|
||||||
|
width: 'auto',
|
||||||
|
uid: 1,
|
||||||
|
span: 12,
|
||||||
|
progress: 15
|
||||||
|
},
|
||||||
|
{
|
||||||
|
dataUrl:
|
||||||
|
'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png',
|
||||||
|
height: 'auto',
|
||||||
|
width: 'auto',
|
||||||
|
uid: 3,
|
||||||
|
span: 12,
|
||||||
|
progress: 10
|
||||||
|
},
|
||||||
|
{
|
||||||
|
dataUrl:
|
||||||
|
'https://gw.alipayobjects.com/zos/antfincdn/LlvErxo8H9/photo-1503185912284-5271ff81b9a8.webp',
|
||||||
|
height: 'auto',
|
||||||
|
width: 'auto',
|
||||||
|
uid: 4,
|
||||||
|
span: 12,
|
||||||
|
progress: 15
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const requestSource = useRequestToken();
|
|
||||||
const [searchParams] = useSearchParams();
|
const [searchParams] = useSearchParams();
|
||||||
const selectModel = searchParams.get('model') || '';
|
const selectModel = searchParams.get('model') || '';
|
||||||
const [parameters, setParams] = useState<any>({});
|
const [parameters, setParams] = useState<any>({});
|
||||||
@@ -57,6 +144,9 @@ const GroundImages: React.FC<MessageProps> = forwardRef((props, ref) => {
|
|||||||
const messageListLengthCache = useRef<number>(0);
|
const messageListLengthCache = useRef<number>(0);
|
||||||
const requestToken = useRef<any>(null);
|
const requestToken = useRef<any>(null);
|
||||||
const [currentPrompt, setCurrentPrompt] = useState<string>('');
|
const [currentPrompt, setCurrentPrompt] = useState<string>('');
|
||||||
|
const form = useRef<any>(null);
|
||||||
|
|
||||||
|
const size = Form.useWatch('size', form.current?.form);
|
||||||
|
|
||||||
const { initialize, updateScrollerPosition } = useOverlayScroller();
|
const { initialize, updateScrollerPosition } = useOverlayScroller();
|
||||||
const { initialize: innitializeParams } = useOverlayScroller();
|
const { initialize: innitializeParams } = useOverlayScroller();
|
||||||
@@ -73,79 +163,150 @@ const GroundImages: React.FC<MessageProps> = forwardRef((props, ref) => {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const setImageSize = useCallback(() => {
|
||||||
|
let size: Record<string, string | number> = {
|
||||||
|
with: 256,
|
||||||
|
height: 256,
|
||||||
|
span: 12
|
||||||
|
};
|
||||||
|
if (parameters.n === 1) {
|
||||||
|
size.width = '100%';
|
||||||
|
size.height = '100%';
|
||||||
|
size.span = 24;
|
||||||
|
}
|
||||||
|
if (parameters.n === 2) {
|
||||||
|
size.width = '50%';
|
||||||
|
size.height = 256;
|
||||||
|
size.span = 12;
|
||||||
|
}
|
||||||
|
if (parameters.n === 3) {
|
||||||
|
size.width = '33%';
|
||||||
|
size.height = 256;
|
||||||
|
size.span = 12;
|
||||||
|
}
|
||||||
|
if (parameters.n === 4) {
|
||||||
|
size.width = '25%';
|
||||||
|
size.height = 256;
|
||||||
|
size.span = 12;
|
||||||
|
}
|
||||||
|
return size;
|
||||||
|
}, [parameters.n]);
|
||||||
|
|
||||||
|
const finalParameters = useMemo(() => {
|
||||||
|
if (parameters.size === 'custom') {
|
||||||
|
return {
|
||||||
|
..._.omit(parameters, ['width', 'height']),
|
||||||
|
size:
|
||||||
|
parameters.width && parameters.height
|
||||||
|
? `${parameters.width}x${parameters.height}`
|
||||||
|
: ''
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
..._.omit(parameters, ['width', 'height'])
|
||||||
|
};
|
||||||
|
}, [parameters]);
|
||||||
|
|
||||||
const setMessageId = () => {
|
const setMessageId = () => {
|
||||||
messageId.current = messageId.current + 1;
|
messageId.current = messageId.current + 1;
|
||||||
return messageId.current;
|
return messageId.current;
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleStopConversation = () => {
|
const handleStopConversation = () => {
|
||||||
requestToken.current?.cancel?.();
|
requestToken.current?.abort?.();
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
const submitMessage = async (current?: { role: string; content: string }) => {
|
const submitMessage = async (current?: { role: string; content: string }) => {
|
||||||
if (!parameters.model) return;
|
|
||||||
try {
|
try {
|
||||||
|
await form.current?.form?.validateFields();
|
||||||
|
if (!parameters.model) return;
|
||||||
|
const size: any = setImageSize();
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
setMessageId();
|
setMessageId();
|
||||||
setCurrentPrompt(current?.content || '');
|
setCurrentPrompt(current?.content || '');
|
||||||
setMessageList(
|
|
||||||
Array(parameters.n)
|
|
||||||
.fill({})
|
|
||||||
.map((item, index: number) => {
|
|
||||||
return {
|
|
||||||
dataUrl: '',
|
|
||||||
height: 256,
|
|
||||||
width: 256,
|
|
||||||
uid: index
|
|
||||||
};
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
requestToken.current?.cancel?.();
|
let newImageList = Array(parameters.n)
|
||||||
requestToken.current = requestSource();
|
.fill({})
|
||||||
|
.map((item, index: number) => {
|
||||||
|
return {
|
||||||
|
dataUr: '',
|
||||||
|
...size,
|
||||||
|
progress: 0,
|
||||||
|
height: 'auto',
|
||||||
|
width: 'auto',
|
||||||
|
uid: index
|
||||||
|
};
|
||||||
|
});
|
||||||
|
setImageList(newImageList);
|
||||||
|
|
||||||
|
requestToken.current?.abort?.();
|
||||||
|
requestToken.current = new AbortController();
|
||||||
|
|
||||||
const params = {
|
const params = {
|
||||||
|
stream: true,
|
||||||
prompt: current?.content || currentPrompt || '',
|
prompt: current?.content || currentPrompt || '',
|
||||||
...parameters
|
..._.omitBy(finalParameters, (value: string) => !value)
|
||||||
};
|
};
|
||||||
|
|
||||||
const result = await createImages(params, {
|
const result: any = await fetchChunkedData({
|
||||||
cancelToken: requestToken.current.token
|
data: params,
|
||||||
|
url: CREAT_IMAGE_API,
|
||||||
|
signal: requestToken.current.signal
|
||||||
});
|
});
|
||||||
|
|
||||||
const imgList = _.map(result.data, (item: any, index: number) => {
|
if (result?.error) {
|
||||||
return {
|
setTokenResult({
|
||||||
dataUrl: `data:image/png;base64,${item.b64_json}`,
|
error: true,
|
||||||
created: result.created,
|
errorMessage:
|
||||||
height: 256,
|
result?.data?.error?.message || result?.data?.message || ''
|
||||||
width: 256,
|
});
|
||||||
uid: index
|
return;
|
||||||
};
|
}
|
||||||
});
|
|
||||||
setMessageList(imgList);
|
|
||||||
console.log('result:', imgList);
|
|
||||||
|
|
||||||
setMessageId();
|
const { reader, decoder } = result;
|
||||||
|
|
||||||
|
await readStreamData(reader, decoder, (chunk: any) => {
|
||||||
|
if (chunk?.error) {
|
||||||
|
setTokenResult({
|
||||||
|
error: true,
|
||||||
|
errorMessage: chunk?.error?.message || chunk?.message || ''
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const data = chunk?.data || [];
|
||||||
|
data.forEach((item: any) => {
|
||||||
|
const imgItem = newImageList[item.index];
|
||||||
|
newImageList[item.index] = {
|
||||||
|
dataUrl: `data:image/png;base64,${item.b64_json}`,
|
||||||
|
height: '100%',
|
||||||
|
width: '100%',
|
||||||
|
uid: imgItem.uid,
|
||||||
|
span: imgItem.span,
|
||||||
|
progress: _.round(item.progress, 0)
|
||||||
|
};
|
||||||
|
});
|
||||||
|
setImageList([...newImageList]);
|
||||||
|
});
|
||||||
|
console.log('result:', newImageList);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// console.log('error:', error);
|
console.log('error:', error);
|
||||||
requestToken.current?.cancel?.();
|
requestToken.current?.abort?.();
|
||||||
setMessageList([]);
|
setImageList([]);
|
||||||
} finally {
|
} finally {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const handleClear = () => {
|
const handleClear = () => {
|
||||||
if (!messageList.length) {
|
if (!imageList.length) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setMessageId();
|
setMessageId();
|
||||||
setMessageList([]);
|
setImageList([]);
|
||||||
setTokenResult(null);
|
setTokenResult(null);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSendMessage = (message: Omit<MessageItem, 'uid'>) => {
|
const handleSendMessage = (message: Omit<MessageItem, 'uid'>) => {
|
||||||
console.log('message:', message);
|
|
||||||
const currentMessage = message.content ? message : undefined;
|
const currentMessage = message.content ? message : undefined;
|
||||||
submitMessage(currentMessage);
|
submitMessage(currentMessage);
|
||||||
};
|
};
|
||||||
@@ -154,6 +315,78 @@ const GroundImages: React.FC<MessageProps> = forwardRef((props, ref) => {
|
|||||||
setShow(false);
|
setShow(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const renderExtra = useMemo(() => {
|
||||||
|
return extraConfig.map((item: ParamsSchema) => {
|
||||||
|
return (
|
||||||
|
<Form.Item name={item.name} rules={item.rules} key={item.name}>
|
||||||
|
<SealSelect
|
||||||
|
{...item.attrs}
|
||||||
|
options={item.options}
|
||||||
|
label={
|
||||||
|
item.label.isLocalized
|
||||||
|
? intl.formatMessage({ id: item.label.text })
|
||||||
|
: item.label.text
|
||||||
|
}
|
||||||
|
></SealSelect>
|
||||||
|
</Form.Item>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}, [extraConfig, intl]);
|
||||||
|
|
||||||
|
const renderCustomSize = useMemo(() => {
|
||||||
|
if (size === 'custom') {
|
||||||
|
return (
|
||||||
|
<div className="flex gap-10" key="custom">
|
||||||
|
<Form.Item
|
||||||
|
name="width"
|
||||||
|
key="width"
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: intl.formatMessage(
|
||||||
|
{
|
||||||
|
id: 'common.form.rule.input'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: intl.formatMessage({ id: 'playground.params.width' })
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<SealInput.Number
|
||||||
|
style={{ width: '100%' }}
|
||||||
|
label={intl.formatMessage({ id: 'playground.params.width' })}
|
||||||
|
></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' })
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<SealInput.Number
|
||||||
|
style={{ width: '100%' }}
|
||||||
|
label="Height"
|
||||||
|
></SealInput.Number>
|
||||||
|
</Form.Item>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}, [size, intl]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (scroller.current) {
|
if (scroller.current) {
|
||||||
initialize(scroller.current);
|
initialize(scroller.current);
|
||||||
@@ -170,42 +403,70 @@ const GroundImages: React.FC<MessageProps> = forwardRef((props, ref) => {
|
|||||||
if (loading) {
|
if (loading) {
|
||||||
updateScrollerPosition();
|
updateScrollerPosition();
|
||||||
}
|
}
|
||||||
}, [messageList, loading]);
|
}, [imageList, loading]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (messageList.length > messageListLengthCache.current) {
|
if (imageList.length > messageListLengthCache.current) {
|
||||||
updateScrollerPosition();
|
updateScrollerPosition();
|
||||||
}
|
}
|
||||||
messageListLengthCache.current = messageList.length;
|
messageListLengthCache.current = imageList.length;
|
||||||
}, [messageList.length]);
|
console.log('imageList:', imageList);
|
||||||
|
}, [imageList.length]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="ground-left-wrapper">
|
<div className="ground-left-wrapper">
|
||||||
<div className="ground-left">
|
<div className="ground-left">
|
||||||
<div className="message-list-wrap" ref={scroller}>
|
<div
|
||||||
|
className="message-list-wrap"
|
||||||
|
ref={scroller}
|
||||||
|
style={{ paddingBottom: 16 }}
|
||||||
|
>
|
||||||
<>
|
<>
|
||||||
<div className="content">
|
<div className="content" style={{ height: '100%' }}>
|
||||||
<ThumbImg
|
<ThumbImg
|
||||||
style={{ paddingInline: 0 }}
|
style={{
|
||||||
|
padding: 0,
|
||||||
|
height: '100%',
|
||||||
|
justifyContent: 'center',
|
||||||
|
flexDirection: 'column',
|
||||||
|
flexWrap: 'unset',
|
||||||
|
alignItems: 'center'
|
||||||
|
}}
|
||||||
editable={false}
|
editable={false}
|
||||||
dataList={messageList}
|
dataList={imageList}
|
||||||
loading={loading}
|
loading={loading}
|
||||||
|
responseable={true}
|
||||||
|
gutter={[16, 16]}
|
||||||
|
autoSize={true}
|
||||||
></ThumbImg>
|
></ThumbImg>
|
||||||
|
{!imageList.length && (
|
||||||
|
<div className="flex-column font-size-14 flex-center gap-20 justify-center hold-wrapper">
|
||||||
|
<span>
|
||||||
|
<FileImageOutlined className="font-size-32 text-secondary" />
|
||||||
|
</span>
|
||||||
|
<span>
|
||||||
|
{intl.formatMessage({ id: 'playground.params.empty.tips' })}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
</div>
|
</div>
|
||||||
{tokenResult && (
|
{tokenResult && (
|
||||||
<div style={{ height: 40 }}>
|
<div style={{ height: 40 }}>
|
||||||
<ReferenceParams usage={tokenResult}></ReferenceParams>
|
<AlertInfo
|
||||||
|
type="danger"
|
||||||
|
message={tokenResult?.errorMessage}
|
||||||
|
></AlertInfo>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div className="ground-left-footer">
|
<div className="ground-left-footer">
|
||||||
<MessageInput
|
<MessageInput
|
||||||
placeholer="Type <kbd>/</kbd> to input prompt"
|
placeholer="Type <kbd>/</kbd> to input prompt"
|
||||||
actions={['clear']}
|
actions={[]}
|
||||||
loading={loading}
|
loading={loading}
|
||||||
disabled={!parameters.model}
|
disabled={!parameters.model}
|
||||||
isEmpty={!messageList.length}
|
isEmpty={!imageList.length}
|
||||||
handleSubmit={handleSendMessage}
|
handleSubmit={handleSendMessage}
|
||||||
handleAbortFetch={handleStopConversation}
|
handleAbortFetch={handleStopConversation}
|
||||||
shouldResetMessage={false}
|
shouldResetMessage={false}
|
||||||
@@ -220,23 +481,28 @@ const GroundImages: React.FC<MessageProps> = forwardRef((props, ref) => {
|
|||||||
ref={paramsRef}
|
ref={paramsRef}
|
||||||
>
|
>
|
||||||
<div className="box">
|
<div className="box">
|
||||||
<RerankerParams
|
<DynamicParams
|
||||||
|
ref={form}
|
||||||
setParams={setParams}
|
setParams={setParams}
|
||||||
paramsConfig={paramsConfig}
|
paramsConfig={paramsConfig}
|
||||||
initialValues={initialValues}
|
initialValues={initialValues}
|
||||||
params={parameters}
|
params={parameters}
|
||||||
selectedModel={selectModel}
|
selectedModel={selectModel}
|
||||||
modelList={modelList}
|
modelList={modelList}
|
||||||
|
extra={[renderCustomSize, ...renderExtra]}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ViewCodeModal
|
<ViewCodeModal
|
||||||
|
{...OpenAIViewCode.images}
|
||||||
open={show}
|
open={show}
|
||||||
payLoad={{
|
payLoad={{
|
||||||
prompt: currentPrompt
|
prompt: currentPrompt
|
||||||
}}
|
}}
|
||||||
parameters={parameters}
|
parameters={{
|
||||||
|
...finalParameters
|
||||||
|
}}
|
||||||
onCancel={handleCloseViewCode}
|
onCancel={handleCloseViewCode}
|
||||||
title={intl.formatMessage({ id: 'playground.viewcode' })}
|
title={intl.formatMessage({ id: 'playground.viewcode' })}
|
||||||
></ViewCodeModal>
|
></ViewCodeModal>
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import {
|
|||||||
useState
|
useState
|
||||||
} from 'react';
|
} from 'react';
|
||||||
import { CHAT_API } from '../apis';
|
import { CHAT_API } from '../apis';
|
||||||
import { Roles, generateMessages } from '../config';
|
import { OpenAIViewCode, Roles, generateMessages } from '../config';
|
||||||
import { MessageItem } from '../config/types';
|
import { MessageItem } from '../config/types';
|
||||||
import '../style/ground-left.less';
|
import '../style/ground-left.less';
|
||||||
import '../style/system-message-wrap.less';
|
import '../style/system-message-wrap.less';
|
||||||
@@ -274,10 +274,6 @@ const GroundLeft: React.FC<MessageProps> = forwardRef((props, ref) => {
|
|||||||
|
|
||||||
<div className="content">
|
<div className="content">
|
||||||
<MessageContent
|
<MessageContent
|
||||||
spans={{
|
|
||||||
span: 24,
|
|
||||||
count: 1
|
|
||||||
}}
|
|
||||||
messageList={messageList}
|
messageList={messageList}
|
||||||
setMessageList={setMessageList}
|
setMessageList={setMessageList}
|
||||||
editable={true}
|
editable={true}
|
||||||
@@ -298,7 +294,6 @@ const GroundLeft: React.FC<MessageProps> = forwardRef((props, ref) => {
|
|||||||
)}
|
)}
|
||||||
<div className="ground-left-footer">
|
<div className="ground-left-footer">
|
||||||
<MessageInput
|
<MessageInput
|
||||||
scope="chat"
|
|
||||||
loading={loading}
|
loading={loading}
|
||||||
disabled={!parameters.model}
|
disabled={!parameters.model}
|
||||||
isEmpty={!messageList.length}
|
isEmpty={!messageList.length}
|
||||||
@@ -329,6 +324,7 @@ const GroundLeft: React.FC<MessageProps> = forwardRef((props, ref) => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ViewCodeModal
|
<ViewCodeModal
|
||||||
|
{...OpenAIViewCode.chat}
|
||||||
open={show}
|
open={show}
|
||||||
payLoad={{
|
payLoad={{
|
||||||
messages: viewCodeMessage
|
messages: viewCodeMessage
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import useOverlayScroller from '@/hooks/use-overlay-scroller';
|
import useOverlayScroller from '@/hooks/use-overlay-scroller';
|
||||||
import useRequestToken from '@/hooks/use-request-token';
|
import useRequestToken from '@/hooks/use-request-token';
|
||||||
import { ClearOutlined, PlusOutlined, SearchOutlined } from '@ant-design/icons';
|
import { ClearOutlined, PlusOutlined, SendOutlined } from '@ant-design/icons';
|
||||||
import { useIntl, useSearchParams } from '@umijs/max';
|
import { useIntl, useSearchParams } from '@umijs/max';
|
||||||
import { Button, Progress, Spin, Tag } from 'antd';
|
import { Button, Input, Spin, Tag } from 'antd';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import 'overlayscrollbars/overlayscrollbars.css';
|
import 'overlayscrollbars/overlayscrollbars.css';
|
||||||
@@ -20,9 +20,8 @@ import { MessageItem, ParamsSchema } from '../config/types';
|
|||||||
import '../style/ground-left.less';
|
import '../style/ground-left.less';
|
||||||
import '../style/rerank.less';
|
import '../style/rerank.less';
|
||||||
import '../style/system-message-wrap.less';
|
import '../style/system-message-wrap.less';
|
||||||
|
import DynamicParams from './dynamic-params';
|
||||||
import InputList from './input-list';
|
import InputList from './input-list';
|
||||||
import MessageInput from './message-input';
|
|
||||||
import RerankerParams from './reranker-params';
|
|
||||||
import ViewRerankCode from './view-rerank-code';
|
import ViewRerankCode from './view-rerank-code';
|
||||||
|
|
||||||
interface MessageProps {
|
interface MessageProps {
|
||||||
@@ -52,7 +51,7 @@ const paramsConfig: ParamsSchema[] = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
const initialValues = {
|
const initialValues = {
|
||||||
top_n: 1
|
top_n: 3
|
||||||
};
|
};
|
||||||
|
|
||||||
const GroundReranker: React.FC<MessageProps> = forwardRef((props, ref) => {
|
const GroundReranker: React.FC<MessageProps> = forwardRef((props, ref) => {
|
||||||
@@ -111,6 +110,7 @@ const GroundReranker: React.FC<MessageProps> = forwardRef((props, ref) => {
|
|||||||
name: ''
|
name: ''
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
|
const [sortIndexMap, setSortIndexMap] = useState<number[]>([]);
|
||||||
|
|
||||||
const { initialize, updateScrollerPosition: updateDocumentScrollerPosition } =
|
const { initialize, updateScrollerPosition: updateDocumentScrollerPosition } =
|
||||||
useOverlayScroller();
|
useOverlayScroller();
|
||||||
@@ -145,51 +145,33 @@ const GroundReranker: React.FC<MessageProps> = forwardRef((props, ref) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const renderPercent = useCallback((data: any) => {
|
const renderPercent = useCallback((data: any) => {
|
||||||
if (!data.showExtra) {
|
if (!data.showExtra || !data.percent) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
const percent = data.percent;
|
const percent = data.percent;
|
||||||
return (
|
return (
|
||||||
<>
|
<div className="rank-wrapper">
|
||||||
<Progress
|
<div className="percent-wrapper">
|
||||||
size={{
|
<div
|
||||||
height: 4
|
className="pregress-bar"
|
||||||
}}
|
style={{
|
||||||
type="line"
|
backgroundImage: `linear-gradient(90deg, #388bff 0%, #cce1ff 100%)`,
|
||||||
status="normal"
|
width: `${percent}%`,
|
||||||
strokeLinecap={'square'}
|
height: '4px',
|
||||||
showInfo={false}
|
borderRadius: '2px'
|
||||||
percentPosition={{ align: 'end', type: 'outer' }}
|
}}
|
||||||
strokeColor={`linear-gradient(90deg, #388bff 0%, rgba(255,255,255,1) ${percent}%)`}
|
></div>
|
||||||
trailColor="transparent"
|
</div>
|
||||||
percent={percent}
|
<span className="flex-center hover-hidden rank-tag">
|
||||||
style={{
|
<Tag color={'geekblue'} bordered={false}>
|
||||||
position: 'absolute',
|
{intl.formatMessage({ id: 'playground.rerank.rank' })}: {data.rank}
|
||||||
left: 0,
|
</Tag>
|
||||||
bottom: -2,
|
<Tag color={'cyan'} bordered={false}>
|
||||||
width: 'calc(100% - 2px)',
|
{intl.formatMessage({ id: 'playground.rerank.score' })}:{' '}
|
||||||
lineHeight: '12px',
|
{_.round(data.score, 2)}
|
||||||
borderRadius: '0 0 0 6px',
|
|
||||||
overflow: 'hidden'
|
|
||||||
}}
|
|
||||||
></Progress>
|
|
||||||
<span
|
|
||||||
className="flex-center hover-hidden"
|
|
||||||
style={{
|
|
||||||
position: 'absolute',
|
|
||||||
right: 10,
|
|
||||||
top: 8,
|
|
||||||
padding: '0 4px',
|
|
||||||
backgroundColor: 'transparent',
|
|
||||||
opacity: 0.7
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Tag color={'geekblue'}>Rank: {data.rank}</Tag>
|
|
||||||
<Tag style={{ margin: 0 }} color={'cyan'}>
|
|
||||||
Score: {_.round(data.score, 2)}
|
|
||||||
</Tag>
|
</Tag>
|
||||||
</span>
|
</span>
|
||||||
</>
|
</div>
|
||||||
);
|
);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
@@ -203,12 +185,13 @@ const GroundReranker: React.FC<MessageProps> = forwardRef((props, ref) => {
|
|||||||
setLoading(false);
|
setLoading(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
const submitMessage = async (current?: { role: string; content: string }) => {
|
const submitMessage = async (current?: { content: string }) => {
|
||||||
if (!parameters.model) return;
|
if (!parameters.model) return;
|
||||||
try {
|
try {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
setMessageId();
|
setMessageId();
|
||||||
setTokenResult(null);
|
setTokenResult(null);
|
||||||
|
setSortIndexMap([]);
|
||||||
|
|
||||||
requestToken.current?.cancel?.();
|
requestToken.current?.cancel?.();
|
||||||
requestToken.current = requestSource();
|
requestToken.current = requestSource();
|
||||||
@@ -242,11 +225,22 @@ const GroundReranker: React.FC<MessageProps> = forwardRef((props, ref) => {
|
|||||||
const maxValue = sortList[sortList.length - 1].relevance_score;
|
const maxValue = sortList[sortList.length - 1].relevance_score;
|
||||||
const minValue = sortList[0].relevance_score;
|
const minValue = sortList[0].relevance_score;
|
||||||
|
|
||||||
let newTextList = [...textList];
|
// reset state
|
||||||
|
let newTextList = textList.map((item) => {
|
||||||
|
item.percent = undefined;
|
||||||
|
item.score = undefined;
|
||||||
|
item.rank = undefined;
|
||||||
|
return item;
|
||||||
|
});
|
||||||
|
|
||||||
|
let sortMap: number[] = [];
|
||||||
|
|
||||||
result.results?.forEach((item: any, sIndex: number) => {
|
result.results?.forEach((item: any, sIndex: number) => {
|
||||||
|
sortMap.push(item.index);
|
||||||
|
|
||||||
newTextList[item.index] = {
|
newTextList[item.index] = {
|
||||||
...newTextList[item.index],
|
...newTextList[item.index],
|
||||||
|
uid: setMessageId(),
|
||||||
rank: sIndex + 1,
|
rank: sIndex + 1,
|
||||||
score: item.relevance_score,
|
score: item.relevance_score,
|
||||||
showExtra: true,
|
showExtra: true,
|
||||||
@@ -257,6 +251,9 @@ const GroundReranker: React.FC<MessageProps> = forwardRef((props, ref) => {
|
|||||||
})
|
})
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
newTextList = _.sortBy(newTextList, 'rank');
|
||||||
|
setSortIndexMap(sortMap);
|
||||||
setTextList(newTextList);
|
setTextList(newTextList);
|
||||||
|
|
||||||
setMessageList([
|
setMessageList([
|
||||||
@@ -270,7 +267,7 @@ const GroundReranker: React.FC<MessageProps> = forwardRef((props, ref) => {
|
|||||||
value: item.relevance_score
|
value: item.relevance_score
|
||||||
});
|
});
|
||||||
return {
|
return {
|
||||||
uid: item.index,
|
uid: setMessageId(),
|
||||||
text: `${item.document?.text?.slice(0, 500) || ''}`,
|
text: `${item.document?.text?.slice(0, 500) || ''}`,
|
||||||
docIndex: item.index,
|
docIndex: item.index,
|
||||||
title: documentList[item.index]?.name || '',
|
title: documentList[item.index]?.name || '',
|
||||||
@@ -279,7 +276,7 @@ const GroundReranker: React.FC<MessageProps> = forwardRef((props, ref) => {
|
|||||||
normalizValue: percent
|
normalizValue: percent
|
||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
uid: messageId.current
|
uid: setMessageId()
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
@@ -304,6 +301,11 @@ const GroundReranker: React.FC<MessageProps> = forwardRef((props, ref) => {
|
|||||||
submitMessage(message);
|
submitMessage(message);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleSearch = (val: string) => {
|
||||||
|
console.log('val:', val);
|
||||||
|
submitMessage({ content: val });
|
||||||
|
};
|
||||||
|
|
||||||
const handleCloseViewCode = () => {
|
const handleCloseViewCode = () => {
|
||||||
setShow(false);
|
setShow(false);
|
||||||
};
|
};
|
||||||
@@ -326,11 +328,30 @@ const GroundReranker: React.FC<MessageProps> = forwardRef((props, ref) => {
|
|||||||
inputListRef.current?.handleAdd();
|
inputListRef.current?.handleAdd();
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleTextListChange = (
|
const handleTextListChange = useCallback(
|
||||||
list: { text: string; uid: number | string; name: string }[]
|
(list: { text: string; uid: number | string; name: string }[]) => {
|
||||||
) => {
|
const newList = list?.map((item: any) => {
|
||||||
setTextList(list);
|
item.percent = undefined;
|
||||||
};
|
item.score = undefined;
|
||||||
|
item.rank = undefined;
|
||||||
|
return item;
|
||||||
|
});
|
||||||
|
setTextList(newList);
|
||||||
|
},
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
const handleOnSort = useCallback(
|
||||||
|
(list: { text: string; uid: number | string; name: string }[]) => {
|
||||||
|
const newList = list?.map((item) => {
|
||||||
|
return {
|
||||||
|
...item,
|
||||||
|
uid: setMessageId()
|
||||||
|
};
|
||||||
|
});
|
||||||
|
setTextList(newList);
|
||||||
|
},
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
|
||||||
const handleClearDocuments = () => {
|
const handleClearDocuments = () => {
|
||||||
setTextList([
|
setTextList([
|
||||||
@@ -381,50 +402,43 @@ const GroundReranker: React.FC<MessageProps> = forwardRef((props, ref) => {
|
|||||||
<div className="ground-left-wrapper rerank">
|
<div className="ground-left-wrapper rerank">
|
||||||
<div className="ground-left">
|
<div className="ground-left">
|
||||||
<div className="ground-left-footer">
|
<div className="ground-left-footer">
|
||||||
<MessageInput
|
<h3
|
||||||
actions={[]}
|
className="m-l-10 flex-between flex-center font-size-14 line-24 m-b-0"
|
||||||
defaultSize={{
|
style={{ padding: '0 32px', marginTop: 16 }}
|
||||||
minRows: 1,
|
>
|
||||||
maxRows: 2
|
<span>{intl.formatMessage({ id: 'playground.rerank.query' })}</span>
|
||||||
}}
|
</h3>
|
||||||
submitIcon={<SearchOutlined className="font-size-16" />}
|
<div style={{ margin: '16px 32px 10px' }}>
|
||||||
loading={loading}
|
<Input.Search
|
||||||
disabled={!parameters.model}
|
onSearch={handleSearch}
|
||||||
isEmpty={true}
|
enterButton={<SendOutlined rotate={0} className="font-size-14" />}
|
||||||
shouldResetMessage={false}
|
placeholder={intl.formatMessage({
|
||||||
handleSubmit={handleSendMessage}
|
id: 'playground.rerank.query.holder'
|
||||||
handleAbortFetch={handleStopConversation}
|
})}
|
||||||
clearAll={handleClear}
|
></Input.Search>
|
||||||
modelList={[]}
|
</div>
|
||||||
placeholer={intl.formatMessage({
|
|
||||||
id: 'playground.input.keyword.holder'
|
|
||||||
})}
|
|
||||||
tools={
|
|
||||||
<span style={{ paddingLeft: 6, fontSize: 14, fontWeight: 500 }}>
|
|
||||||
Query
|
|
||||||
</span>
|
|
||||||
}
|
|
||||||
style={{
|
|
||||||
borderTop: 'none',
|
|
||||||
width: 'unset',
|
|
||||||
marginInline: 32,
|
|
||||||
marginTop: 16,
|
|
||||||
border: '1px solid var(--ant-color-border)',
|
|
||||||
borderRadius: 'var(--border-radius-base)',
|
|
||||||
paddingInline: 10
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
<div className="center" ref={scroller}>
|
<div className="center" ref={scroller}>
|
||||||
<div className="documents">
|
<div className="documents">
|
||||||
<div className="flex-between m-b-8 doc-header">
|
<div className="flex-between m-b-8 doc-header">
|
||||||
<h3 className="m-l-10 flex-between flex-center font-size-14 line-24 m-b-0">
|
<h3 className="m-l-10 flex-between flex-center font-size-14 line-24 m-b-0">
|
||||||
<span>Documents</span>
|
<span>
|
||||||
|
{intl.formatMessage({ id: 'playground.embedding.documents' })}
|
||||||
|
</span>
|
||||||
</h3>
|
</h3>
|
||||||
|
<span className="m-l-10 font-size-12">
|
||||||
|
{' '}
|
||||||
|
{tokenResult?.total_tokens && (
|
||||||
|
<span style={{ color: 'var(--ant-orange)' }}>
|
||||||
|
{intl.formatMessage({ id: 'playground.tokenusage' })}:{' '}
|
||||||
|
{tokenResult?.total_tokens}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
<div className="flex gap-10">
|
<div className="flex gap-10">
|
||||||
<Button size="middle" onClick={handleAddText}>
|
<Button size="middle" onClick={handleAddText}>
|
||||||
<PlusOutlined />
|
<PlusOutlined />
|
||||||
Add Text
|
{intl.formatMessage({ id: 'playground.embedding.addtext' })}
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
icon={<ClearOutlined />}
|
icon={<ClearOutlined />}
|
||||||
@@ -437,33 +451,25 @@ const GroundReranker: React.FC<MessageProps> = forwardRef((props, ref) => {
|
|||||||
</div>
|
</div>
|
||||||
<div className="docs-wrapper">
|
<div className="docs-wrapper">
|
||||||
<InputList
|
<InputList
|
||||||
|
sortIndex={sortIndexMap}
|
||||||
ref={inputListRef}
|
ref={inputListRef}
|
||||||
textList={textList}
|
textList={textList}
|
||||||
|
showLabel={false}
|
||||||
|
sortable={false}
|
||||||
|
height={46}
|
||||||
onChange={handleTextListChange}
|
onChange={handleTextListChange}
|
||||||
|
onSort={handleOnSort}
|
||||||
extra={renderPercent}
|
extra={renderPercent}
|
||||||
></InputList>
|
></InputList>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div></div>
|
||||||
{messageList.length ? (
|
|
||||||
<div className="result-header flex-center">
|
|
||||||
<h3 className="font-size-14 m-b-0">Results</h3>
|
|
||||||
{tokenResult?.total_tokens && (
|
|
||||||
<span style={{ color: 'var(--ant-orange)' }}>
|
|
||||||
{intl.formatMessage({ id: 'playground.tokenusage' })}:{' '}
|
|
||||||
{tokenResult?.total_tokens}
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
) : null}
|
|
||||||
</div>
|
|
||||||
<div
|
<div
|
||||||
className="message-list-wrap"
|
className="message-list-wrap"
|
||||||
style={{ paddingInline: 0, paddingTop: 0 }}
|
style={{ paddingInline: 0, paddingTop: 0 }}
|
||||||
>
|
>
|
||||||
<>
|
<>
|
||||||
<div className="content">
|
<div className="content">
|
||||||
{/*<RerankMessage dataList={messageList} />*/}
|
|
||||||
{loading && (
|
{loading && (
|
||||||
<Spin size="small">
|
<Spin size="small">
|
||||||
<div style={{ height: '46px' }}></div>
|
<div style={{ height: '46px' }}></div>
|
||||||
@@ -481,7 +487,7 @@ const GroundReranker: React.FC<MessageProps> = forwardRef((props, ref) => {
|
|||||||
ref={paramsRef}
|
ref={paramsRef}
|
||||||
>
|
>
|
||||||
<div className="box">
|
<div className="box">
|
||||||
<RerankerParams
|
<DynamicParams
|
||||||
setParams={setParams}
|
setParams={setParams}
|
||||||
params={parameters}
|
params={parameters}
|
||||||
paramsConfig={paramsConfig}
|
paramsConfig={paramsConfig}
|
||||||
@@ -494,9 +500,11 @@ const GroundReranker: React.FC<MessageProps> = forwardRef((props, ref) => {
|
|||||||
|
|
||||||
<ViewRerankCode
|
<ViewRerankCode
|
||||||
open={show}
|
open={show}
|
||||||
documentList={[...textList, ...fileList]
|
payload={{
|
||||||
.map((item) => item.text)
|
documents: [...textList, ...fileList]
|
||||||
.filter((text) => text)}
|
.map((item) => item.text)
|
||||||
|
.filter((text) => text)
|
||||||
|
}}
|
||||||
parameters={{
|
parameters={{
|
||||||
...parameters,
|
...parameters,
|
||||||
query: contentRef.current
|
query: contentRef.current
|
||||||
|
|||||||
@@ -29,8 +29,8 @@ import '../style/ground-left.less';
|
|||||||
import '../style/speech-to-text.less';
|
import '../style/speech-to-text.less';
|
||||||
import '../style/system-message-wrap.less';
|
import '../style/system-message-wrap.less';
|
||||||
import AudioInput from './audio-input';
|
import AudioInput from './audio-input';
|
||||||
|
import DynamicParams from './dynamic-params';
|
||||||
import MessageContent from './multiple-chat/message-content';
|
import MessageContent from './multiple-chat/message-content';
|
||||||
import RerankerParams from './reranker-params';
|
|
||||||
import ViewCodeModal from './view-code-modal';
|
import ViewCodeModal from './view-code-modal';
|
||||||
|
|
||||||
interface MessageProps {
|
interface MessageProps {
|
||||||
@@ -70,6 +70,7 @@ const GroundLeft: React.FC<MessageProps> = forwardRef((props, ref) => {
|
|||||||
analyser: null
|
analyser: null
|
||||||
});
|
});
|
||||||
const [isRecording, setIsRecording] = useState(false);
|
const [isRecording, setIsRecording] = useState(false);
|
||||||
|
const [recordEnd, setRecordEnd] = useState(false);
|
||||||
|
|
||||||
const { initialize, updateScrollerPosition } = useOverlayScroller();
|
const { initialize, updateScrollerPosition } = useOverlayScroller();
|
||||||
const { initialize: innitializeParams } = useOverlayScroller();
|
const { initialize: innitializeParams } = useOverlayScroller();
|
||||||
@@ -251,6 +252,9 @@ const GroundLeft: React.FC<MessageProps> = forwardRef((props, ref) => {
|
|||||||
duration: data.duration
|
duration: data.duration
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
setTimeout(() => {
|
||||||
|
setRecordEnd(true);
|
||||||
|
}, 200);
|
||||||
},
|
},
|
||||||
[]
|
[]
|
||||||
);
|
);
|
||||||
@@ -264,6 +268,7 @@ const GroundLeft: React.FC<MessageProps> = forwardRef((props, ref) => {
|
|||||||
const res = await readAudioFile(data.file.originFileObj);
|
const res = await readAudioFile(data.file.originFileObj);
|
||||||
console.log('res=======', res);
|
console.log('res=======', res);
|
||||||
setAudioData(res);
|
setAudioData(res);
|
||||||
|
setRecordEnd(true);
|
||||||
},
|
},
|
||||||
[]
|
[]
|
||||||
);
|
);
|
||||||
@@ -281,6 +286,25 @@ const GroundLeft: React.FC<MessageProps> = forwardRef((props, ref) => {
|
|||||||
setAudioData(null);
|
setAudioData(null);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const handleOnGenerate = useCallback(() => {
|
||||||
|
setMessageList([
|
||||||
|
{
|
||||||
|
content: 'Generating text content...',
|
||||||
|
title: '',
|
||||||
|
role: '',
|
||||||
|
uid: messageId.current
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
setRecordEnd(false);
|
||||||
|
setIsRecording(false);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const handleOnDiscard = useCallback(() => {
|
||||||
|
setRecordEnd(false);
|
||||||
|
setAudioData(null);
|
||||||
|
setIsRecording(false);
|
||||||
|
}, []);
|
||||||
|
|
||||||
const renderAniamtion = () => {
|
const renderAniamtion = () => {
|
||||||
if (!audioPermissionOn) {
|
if (!audioPermissionOn) {
|
||||||
return null;
|
return null;
|
||||||
@@ -334,32 +358,62 @@ const GroundLeft: React.FC<MessageProps> = forwardRef((props, ref) => {
|
|||||||
<div className="ground-left-footer" style={{ flex: 1 }}>
|
<div className="ground-left-footer" style={{ flex: 1 }}>
|
||||||
<div className="speech-to-text">
|
<div className="speech-to-text">
|
||||||
<div className="speech-box">
|
<div className="speech-box">
|
||||||
<Tooltip title="Upload an audio file">
|
{isRecording ? (
|
||||||
<UploadAudio
|
<>
|
||||||
type="default"
|
<AudioInput
|
||||||
accept=".mp3,.mp4,.wav"
|
type="default"
|
||||||
onChange={handleUploadChange}
|
voiceActivity={true}
|
||||||
></UploadAudio>
|
onAudioData={handleOnAudioData}
|
||||||
</Tooltip>
|
onAudioPermission={handleOnAudioPermission}
|
||||||
<AudioInput
|
onAnalyse={handleOnAnalyse}
|
||||||
type="default"
|
onRecord={handleOnRecord}
|
||||||
voiceActivity={true}
|
></AudioInput>
|
||||||
onAudioData={handleOnAudioData}
|
</>
|
||||||
onAudioPermission={handleOnAudioPermission}
|
) : (
|
||||||
onAnalyse={handleOnAnalyse}
|
<>
|
||||||
onRecord={handleOnRecord}
|
{/* <Tooltip title="discard">
|
||||||
></AudioInput>
|
<Button
|
||||||
|
onClick={handleOnDiscard}
|
||||||
|
icon={<DeleteRowOutlined />}
|
||||||
|
shape="circle"
|
||||||
|
></Button>
|
||||||
|
</Tooltip>
|
||||||
|
<Tooltip title="generate text content">
|
||||||
|
<Button
|
||||||
|
type="primary"
|
||||||
|
onClick={handleOnGenerate}
|
||||||
|
shape="circle"
|
||||||
|
icon={<ThunderboltOutlined></ThunderboltOutlined>}
|
||||||
|
></Button>
|
||||||
|
</Tooltip> */}
|
||||||
|
<Tooltip title="Upload an audio file">
|
||||||
|
<UploadAudio
|
||||||
|
type="default"
|
||||||
|
accept=".mp3,.mp4,.wav"
|
||||||
|
onChange={handleUploadChange}
|
||||||
|
></UploadAudio>
|
||||||
|
</Tooltip>
|
||||||
|
<AudioInput
|
||||||
|
type="default"
|
||||||
|
voiceActivity={true}
|
||||||
|
onAudioData={handleOnAudioData}
|
||||||
|
onAudioPermission={handleOnAudioPermission}
|
||||||
|
onAnalyse={handleOnAnalyse}
|
||||||
|
onRecord={handleOnRecord}
|
||||||
|
></AudioInput>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{audioData ? (
|
{audioData ? (
|
||||||
<div className="flex-between flex-center">
|
<div className="flex-between flex-center justify-center">
|
||||||
<div style={{ flex: 1 }}>
|
<div style={{ width: 600 }}>
|
||||||
<AudioPlayer
|
<AudioPlayer
|
||||||
url={audioData.url}
|
url={audioData.url}
|
||||||
name={audioData.name}
|
name={audioData.name}
|
||||||
duration={audioData.duration}
|
duration={audioData.duration}
|
||||||
></AudioPlayer>
|
></AudioPlayer>
|
||||||
<div
|
{/* <div
|
||||||
style={{
|
style={{
|
||||||
paddingRight: 5,
|
paddingRight: 5,
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
@@ -376,7 +430,7 @@ const GroundLeft: React.FC<MessageProps> = forwardRef((props, ref) => {
|
|||||||
Generata Text Content
|
Generata Text Content
|
||||||
</Button>
|
</Button>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</div>
|
</div> */}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
@@ -420,15 +474,31 @@ const GroundLeft: React.FC<MessageProps> = forwardRef((props, ref) => {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="message-list-wrap" ref={scroller}>
|
<div
|
||||||
<>
|
style={{
|
||||||
|
flex: 1,
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
justifyContent: 'space-between'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className="message-list-wrap"
|
||||||
|
ref={scroller}
|
||||||
|
style={{
|
||||||
|
borderTop: messageList.length
|
||||||
|
? '1px solid var(--ant-color-split)'
|
||||||
|
: '1px solid var(--ant-color-split)'
|
||||||
|
}}
|
||||||
|
>
|
||||||
<div className="content" style={{ height: '100%' }}>
|
<div className="content" style={{ height: '100%' }}>
|
||||||
<>
|
<>
|
||||||
<MessageContent
|
<MessageContent
|
||||||
actions={['copy']}
|
actions={[]}
|
||||||
messageList={messageList[0] ? [messageList[0]] : []}
|
messageList={messageList[0] ? [messageList[0]] : []}
|
||||||
setMessageList={setMessageList}
|
setMessageList={setMessageList}
|
||||||
editable={false}
|
editable={false}
|
||||||
|
showTitle={false}
|
||||||
loading={loading}
|
loading={loading}
|
||||||
/>
|
/>
|
||||||
{loading && (
|
{loading && (
|
||||||
@@ -438,7 +508,17 @@ const GroundLeft: React.FC<MessageProps> = forwardRef((props, ref) => {
|
|||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</div>
|
||||||
|
<div style={{ padding: '16px 32px', textAlign: 'right' }}>
|
||||||
|
<Tooltip title="generate text content">
|
||||||
|
<Button
|
||||||
|
disabled={!audioData}
|
||||||
|
type="primary"
|
||||||
|
onClick={handleOnGenerate}
|
||||||
|
icon={<ThunderboltOutlined></ThunderboltOutlined>}
|
||||||
|
></Button>
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
@@ -448,7 +528,7 @@ const GroundLeft: React.FC<MessageProps> = forwardRef((props, ref) => {
|
|||||||
ref={paramsRef}
|
ref={paramsRef}
|
||||||
>
|
>
|
||||||
<div className="box">
|
<div className="box">
|
||||||
<RerankerParams
|
<DynamicParams
|
||||||
setParams={setParams}
|
setParams={setParams}
|
||||||
paramsConfig={paramsConfig}
|
paramsConfig={paramsConfig}
|
||||||
initialValues={initialValues}
|
initialValues={initialValues}
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
|
import IconFont from '@/components/icon-font';
|
||||||
import SpeechContent from '@/components/speech-content';
|
import SpeechContent from '@/components/speech-content';
|
||||||
import useOverlayScroller from '@/hooks/use-overlay-scroller';
|
import useOverlayScroller from '@/hooks/use-overlay-scroller';
|
||||||
import { fetchChunkedData, readStreamData } from '@/utils/fetch-chunk-data';
|
import { fetchChunkedData, readStreamData } from '@/utils/fetch-chunk-data';
|
||||||
|
import { ThunderboltOutlined } from '@ant-design/icons';
|
||||||
import { useIntl, useSearchParams } from '@umijs/max';
|
import { useIntl, useSearchParams } from '@umijs/max';
|
||||||
import { Spin } from 'antd';
|
import { Spin } from 'antd';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
@@ -21,9 +23,9 @@ import { TTSParamsConfig as paramsConfig } from '../config/params-config';
|
|||||||
import { MessageItem } from '../config/types';
|
import { MessageItem } from '../config/types';
|
||||||
import '../style/ground-left.less';
|
import '../style/ground-left.less';
|
||||||
import '../style/system-message-wrap.less';
|
import '../style/system-message-wrap.less';
|
||||||
|
import RerankerParams from './dynamic-params';
|
||||||
import MessageInput from './message-input';
|
import MessageInput from './message-input';
|
||||||
import ReferenceParams from './reference-params';
|
import ReferenceParams from './reference-params';
|
||||||
import RerankerParams from './reranker-params';
|
|
||||||
import ViewCodeModal from './view-code-modal';
|
import ViewCodeModal from './view-code-modal';
|
||||||
|
|
||||||
interface MessageProps {
|
interface MessageProps {
|
||||||
@@ -59,6 +61,7 @@ const GroundLeft: React.FC<MessageProps> = forwardRef((props, ref) => {
|
|||||||
const paramsRef = useRef<any>(null);
|
const paramsRef = useRef<any>(null);
|
||||||
const messageListLengthCache = useRef<number>(0);
|
const messageListLengthCache = useRef<number>(0);
|
||||||
const checkvalueRef = useRef<any>(true);
|
const checkvalueRef = useRef<any>(true);
|
||||||
|
const [currentPrompt, setCurrentPrompt] = useState<string>('');
|
||||||
|
|
||||||
const { initialize, updateScrollerPosition } = useOverlayScroller();
|
const { initialize, updateScrollerPosition } = useOverlayScroller();
|
||||||
const { initialize: innitializeParams } = useOverlayScroller();
|
const { initialize: innitializeParams } = useOverlayScroller();
|
||||||
@@ -232,20 +235,6 @@ const GroundLeft: React.FC<MessageProps> = forwardRef((props, ref) => {
|
|||||||
|
|
||||||
const handleSelectModel = () => {};
|
const handleSelectModel = () => {};
|
||||||
|
|
||||||
const handlePresetPrompt = (list: { role: string; content: string }[]) => {
|
|
||||||
const sysMsg = list.filter((item) => item.role === 'system');
|
|
||||||
const userMsg = list
|
|
||||||
.filter((item) => item.role === 'user')
|
|
||||||
.map((item) => {
|
|
||||||
setMessageId();
|
|
||||||
return {
|
|
||||||
...item,
|
|
||||||
uid: messageId.current
|
|
||||||
};
|
|
||||||
});
|
|
||||||
setSystemMessage(sysMsg[0]?.content || '');
|
|
||||||
setMessageList(userMsg);
|
|
||||||
};
|
|
||||||
const handleOnCheckChange = (e: any) => {
|
const handleOnCheckChange = (e: any) => {
|
||||||
console.log('handleOnCheckChange', e);
|
console.log('handleOnCheckChange', e);
|
||||||
checkvalueRef.current = e.target.checked;
|
checkvalueRef.current = e.target.checked;
|
||||||
@@ -279,16 +268,35 @@ const GroundLeft: React.FC<MessageProps> = forwardRef((props, ref) => {
|
|||||||
<div className="ground-left-wrapper">
|
<div className="ground-left-wrapper">
|
||||||
<div className="ground-left">
|
<div className="ground-left">
|
||||||
<div className="message-list-wrap" ref={scroller}>
|
<div className="message-list-wrap" ref={scroller}>
|
||||||
<>
|
<div
|
||||||
|
style={{
|
||||||
|
height: '100%',
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center'
|
||||||
|
}}
|
||||||
|
>
|
||||||
<div className="content">
|
<div className="content">
|
||||||
<SpeechContent dataList={messageList} loading={loading} />
|
{messageList.length ? (
|
||||||
|
<SpeechContent dataList={messageList} loading={loading} />
|
||||||
|
) : (
|
||||||
|
<div className="flex-column font-size-14 flex-center gap-20">
|
||||||
|
<span>
|
||||||
|
<IconFont
|
||||||
|
type="icon-audio "
|
||||||
|
className="font-size-32 text-secondary"
|
||||||
|
></IconFont>
|
||||||
|
</span>
|
||||||
|
<span>Generated speech will appear here</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
{loading && (
|
{loading && (
|
||||||
<Spin size="small">
|
<Spin size="small">
|
||||||
<div style={{ height: '46px' }}></div>
|
<div style={{ height: '46px' }}></div>
|
||||||
</Spin>
|
</Spin>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{tokenResult && (
|
{tokenResult && (
|
||||||
<div style={{ height: 40 }}>
|
<div style={{ height: 40 }}>
|
||||||
@@ -297,8 +305,7 @@ const GroundLeft: React.FC<MessageProps> = forwardRef((props, ref) => {
|
|||||||
)}
|
)}
|
||||||
<div className="ground-left-footer">
|
<div className="ground-left-footer">
|
||||||
<MessageInput
|
<MessageInput
|
||||||
scope="chat"
|
actions={['check']}
|
||||||
actions={['clear', 'check']}
|
|
||||||
checkLabel={intl.formatMessage({
|
checkLabel={intl.formatMessage({
|
||||||
id: 'playground.toolbar.autoplay'
|
id: 'playground.toolbar.autoplay'
|
||||||
})}
|
})}
|
||||||
@@ -311,7 +318,8 @@ const GroundLeft: React.FC<MessageProps> = forwardRef((props, ref) => {
|
|||||||
handleAbortFetch={handleStopConversation}
|
handleAbortFetch={handleStopConversation}
|
||||||
clearAll={handleClear}
|
clearAll={handleClear}
|
||||||
setModelSelections={handleSelectModel}
|
setModelSelections={handleSelectModel}
|
||||||
presetPrompt={handlePresetPrompt}
|
shouldResetMessage={false}
|
||||||
|
submitIcon={<ThunderboltOutlined></ThunderboltOutlined>}
|
||||||
modelList={modelList}
|
modelList={modelList}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -337,7 +345,7 @@ const GroundLeft: React.FC<MessageProps> = forwardRef((props, ref) => {
|
|||||||
<ViewCodeModal
|
<ViewCodeModal
|
||||||
open={show}
|
open={show}
|
||||||
payLoad={{
|
payLoad={{
|
||||||
messages: viewCodeMessage
|
prompt: currentPrompt
|
||||||
}}
|
}}
|
||||||
parameters={parameters}
|
parameters={parameters}
|
||||||
onCancel={handleCloseViewCode}
|
onCancel={handleCloseViewCode}
|
||||||
|
|||||||
@@ -2,26 +2,182 @@ import RowTextarea from '@/components/seal-form/row-textarea';
|
|||||||
import { DeleteOutlined } from '@ant-design/icons';
|
import { DeleteOutlined } from '@ant-design/icons';
|
||||||
import { useIntl } from '@umijs/max';
|
import { useIntl } from '@umijs/max';
|
||||||
import { Button, Tooltip } from 'antd';
|
import { Button, Tooltip } from 'antd';
|
||||||
import React, { forwardRef, useImperativeHandle, useRef } from 'react';
|
import _ from 'lodash';
|
||||||
|
import React, {
|
||||||
|
forwardRef,
|
||||||
|
useCallback,
|
||||||
|
useEffect,
|
||||||
|
useImperativeHandle,
|
||||||
|
useRef
|
||||||
|
} from 'react';
|
||||||
import '../style/input-list.less';
|
import '../style/input-list.less';
|
||||||
|
|
||||||
interface InputListProps {
|
interface InputListProps {
|
||||||
ref?: any;
|
ref?: any;
|
||||||
|
height?: number;
|
||||||
extra?: (data: any) => React.ReactNode;
|
extra?: (data: any) => React.ReactNode;
|
||||||
|
showLabel?: boolean;
|
||||||
|
sortIndex?: number[];
|
||||||
textList: {
|
textList: {
|
||||||
text: string;
|
text: string;
|
||||||
uid: number | string;
|
uid: number | string;
|
||||||
name: string;
|
name: string;
|
||||||
}[];
|
}[];
|
||||||
|
sortable?: boolean;
|
||||||
onChange?: (
|
onChange?: (
|
||||||
textList: { text: string; uid: number | string; name: string }[]
|
textList: { text: string; uid: number | string; name: string }[]
|
||||||
) => void;
|
) => void;
|
||||||
|
onSort?: (
|
||||||
|
textList: { text: string; uid: number | string; name: string }[]
|
||||||
|
) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const InputList: React.FC<InputListProps> = forwardRef(
|
const InputList: React.FC<InputListProps> = forwardRef(
|
||||||
({ textList, onChange, extra }, ref) => {
|
(
|
||||||
|
{
|
||||||
|
textList,
|
||||||
|
showLabel = true,
|
||||||
|
sortIndex = [],
|
||||||
|
sortable,
|
||||||
|
height,
|
||||||
|
onSort,
|
||||||
|
onChange,
|
||||||
|
extra
|
||||||
|
},
|
||||||
|
ref
|
||||||
|
) => {
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const messageId = useRef(0);
|
const messageId = useRef(0);
|
||||||
|
const containerRef = useRef<any>(null);
|
||||||
|
const childListRef = useRef<any[]>([]);
|
||||||
|
|
||||||
|
const getContainerChildList = () => {
|
||||||
|
childListRef.current = Array.from(containerRef.current?.children || []);
|
||||||
|
};
|
||||||
|
|
||||||
|
const getOffsetUsingBoundingClientRect = useCallback(
|
||||||
|
(element: HTMLElement, targetElement: HTMLElement) => {
|
||||||
|
const currentRect = element.getBoundingClientRect();
|
||||||
|
const targetRect = targetElement.getBoundingClientRect();
|
||||||
|
|
||||||
|
return {
|
||||||
|
x: targetRect.left - currentRect.left,
|
||||||
|
y: targetRect.top - currentRect.top
|
||||||
|
};
|
||||||
|
},
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
|
||||||
|
// move item from fromIndex to toIndex
|
||||||
|
const moveItem = useCallback((child: any, toIndex: number) => {
|
||||||
|
const container = containerRef.current;
|
||||||
|
if (!container) return;
|
||||||
|
|
||||||
|
const children = Array.from(container.children);
|
||||||
|
|
||||||
|
if (toIndex >= children.length) {
|
||||||
|
if (container.firstChild) {
|
||||||
|
container.insertBefore(child, container.firstChild);
|
||||||
|
} else {
|
||||||
|
container.appendChild(child);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
container.insertBefore(child, children[toIndex]);
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const moveElement = (arr: any[], fromIndex: number, toIndex: number) => {
|
||||||
|
if (
|
||||||
|
fromIndex === toIndex ||
|
||||||
|
fromIndex < 0 ||
|
||||||
|
toIndex < 0 ||
|
||||||
|
fromIndex >= arr.length ||
|
||||||
|
toIndex > arr.length
|
||||||
|
) {
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
|
||||||
|
const element = arr.splice(fromIndex, 1)[0];
|
||||||
|
arr.splice(toIndex > fromIndex ? toIndex - 1 : toIndex, 0, element);
|
||||||
|
return arr;
|
||||||
|
};
|
||||||
|
|
||||||
|
const sort = useCallback(() => {
|
||||||
|
if (!sortable) return;
|
||||||
|
getContainerChildList();
|
||||||
|
const container = containerRef.current;
|
||||||
|
if (!container) return;
|
||||||
|
|
||||||
|
const newOrder = [...textList];
|
||||||
|
|
||||||
|
const offsets = sortIndex.map((fromIndex, toIndex) => {
|
||||||
|
const currentElement = childListRef.current[fromIndex];
|
||||||
|
const targetElement = childListRef.current[toIndex];
|
||||||
|
if (!currentElement || !targetElement) return null;
|
||||||
|
|
||||||
|
const offset = getOffsetUsingBoundingClientRect(
|
||||||
|
currentElement,
|
||||||
|
targetElement
|
||||||
|
);
|
||||||
|
return {
|
||||||
|
element: currentElement,
|
||||||
|
offset: {
|
||||||
|
x: offset.x,
|
||||||
|
y: offset.y
|
||||||
|
},
|
||||||
|
fromIndex,
|
||||||
|
toIndex
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
const moveSequentially = async () => {
|
||||||
|
for (const [index, data] of offsets.entries()) {
|
||||||
|
if (!data) continue;
|
||||||
|
|
||||||
|
const { element, offset, fromIndex, toIndex } = data;
|
||||||
|
console.log('sort+++++++', {
|
||||||
|
textList,
|
||||||
|
element,
|
||||||
|
offset,
|
||||||
|
fromIndex,
|
||||||
|
toIndex
|
||||||
|
});
|
||||||
|
|
||||||
|
await new Promise((resolve) => {
|
||||||
|
element.style.opacity = 0.5;
|
||||||
|
element.style.transform = `translate(${offset.x}px, ${offset.y}px)`;
|
||||||
|
element.style.transition = 'transform 0.8s,opacity 0.8s';
|
||||||
|
|
||||||
|
element.addEventListener(
|
||||||
|
'transitionend',
|
||||||
|
() => {
|
||||||
|
moveItem(element, toIndex);
|
||||||
|
moveElement(newOrder, fromIndex, toIndex);
|
||||||
|
getContainerChildList();
|
||||||
|
|
||||||
|
element.style.opacity = 1;
|
||||||
|
element.style.transform = '';
|
||||||
|
console.log('sort++++++++++end');
|
||||||
|
|
||||||
|
resolve(null);
|
||||||
|
},
|
||||||
|
{ once: true }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onSort?.(newOrder);
|
||||||
|
};
|
||||||
|
|
||||||
|
moveSequentially();
|
||||||
|
}, [
|
||||||
|
sortable,
|
||||||
|
sortIndex,
|
||||||
|
textList,
|
||||||
|
onSort,
|
||||||
|
getContainerChildList,
|
||||||
|
getOffsetUsingBoundingClientRect
|
||||||
|
]);
|
||||||
|
|
||||||
const setMessageId = () => {
|
const setMessageId = () => {
|
||||||
messageId.current = messageId.current + 1;
|
messageId.current = messageId.current + 1;
|
||||||
@@ -54,6 +210,14 @@ const InputList: React.FC<InputListProps> = forwardRef(
|
|||||||
dataList[index].text = value;
|
dataList[index].text = value;
|
||||||
onChange?.(dataList);
|
onChange?.(dataList);
|
||||||
};
|
};
|
||||||
|
const debounceSort = _.debounce(sort, 100);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (sortIndex?.length) {
|
||||||
|
console.log('sort++++2+++');
|
||||||
|
debounceSort();
|
||||||
|
}
|
||||||
|
}, [sortIndex]);
|
||||||
|
|
||||||
useImperativeHandle(ref, () => ({
|
useImperativeHandle(ref, () => ({
|
||||||
handleAdd,
|
handleAdd,
|
||||||
@@ -62,15 +226,18 @@ const InputList: React.FC<InputListProps> = forwardRef(
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="input-list">
|
<div className="input-list" ref={containerRef}>
|
||||||
{textList.map((text, index) => {
|
{textList.map((text, index) => {
|
||||||
return (
|
return (
|
||||||
<div key={text.uid} className="input-item">
|
<div key={text.uid} className="input-item" data-uid={text.uid}>
|
||||||
<div className="input-wrap">
|
<div className="input-wrap">
|
||||||
<RowTextarea
|
<RowTextarea
|
||||||
label={`${index + 1}.`}
|
height={height}
|
||||||
|
label={showLabel ? `${index + 1}` : null}
|
||||||
value={text.text}
|
value={text.text}
|
||||||
placeholder="Input your text"
|
placeholder={intl.formatMessage({
|
||||||
|
id: 'playground.embedding.inputyourtext'
|
||||||
|
})}
|
||||||
onChange={(e) => handleTextChange(e.target.value, text)}
|
onChange={(e) => handleTextChange(e.target.value, text)}
|
||||||
></RowTextarea>
|
></RowTextarea>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -477,6 +477,7 @@ const MessageInput: React.FC<MessageInputProps> = ({
|
|||||||
<ThumbImg
|
<ThumbImg
|
||||||
dataList={message.imgs || []}
|
dataList={message.imgs || []}
|
||||||
onDelete={handleDeleteImg}
|
onDelete={handleDeleteImg}
|
||||||
|
editable={true}
|
||||||
></ThumbImg>
|
></ThumbImg>
|
||||||
<div className="input-box">
|
<div className="input-box">
|
||||||
{actions.includes('paste') ? (
|
{actions.includes('paste') ? (
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ interface MessageItemProps {
|
|||||||
data: MessageItem;
|
data: MessageItem;
|
||||||
editable?: boolean;
|
editable?: boolean;
|
||||||
loading?: boolean;
|
loading?: boolean;
|
||||||
|
showTitle?: boolean;
|
||||||
actions?: MessageItemAction[];
|
actions?: MessageItemAction[];
|
||||||
updateMessage?: (message: MessageItem) => void;
|
updateMessage?: (message: MessageItem) => void;
|
||||||
onDelete?: () => void;
|
onDelete?: () => void;
|
||||||
@@ -26,6 +27,7 @@ const ContentItem: React.FC<MessageItemProps> = ({
|
|||||||
loading,
|
loading,
|
||||||
data,
|
data,
|
||||||
editable,
|
editable,
|
||||||
|
showTitle = true,
|
||||||
actions = ['upload', 'delete', 'copy']
|
actions = ['upload', 'delete', 'copy']
|
||||||
}) => {
|
}) => {
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
@@ -169,10 +171,16 @@ const ContentItem: React.FC<MessageItemProps> = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="content-item">
|
<div className="content-item">
|
||||||
<div className="content-item-role">
|
<div
|
||||||
<div className="role">
|
className="content-item-role"
|
||||||
{data.title ?? intl.formatMessage({ id: `playground.${data.role}` })}
|
style={{ display: !showTitle && !actions.length ? 'none' : 'flex' }}
|
||||||
</div>
|
>
|
||||||
|
{showTitle && (
|
||||||
|
<div className="role">
|
||||||
|
{data.title ??
|
||||||
|
intl.formatMessage({ id: `playground.${data.role}` })}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
<div className="actions">
|
<div className="actions">
|
||||||
{actions.includes('upload') && data.role === Roles.User && (
|
{actions.includes('upload') && data.role === Roles.User && (
|
||||||
<UploadImg handleUpdateImgList={handleUpdateImgList}></UploadImg>
|
<UploadImg handleUpdateImgList={handleUpdateImgList}></UploadImg>
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ interface MessageContentProps {
|
|||||||
loading?: boolean;
|
loading?: boolean;
|
||||||
actions?: MessageItemAction[];
|
actions?: MessageItemAction[];
|
||||||
editable?: boolean;
|
editable?: boolean;
|
||||||
|
showTitle?: boolean;
|
||||||
messageList: MessageItem[];
|
messageList: MessageItem[];
|
||||||
setMessageList?: (list: any) => void;
|
setMessageList?: (list: any) => void;
|
||||||
}
|
}
|
||||||
@@ -15,6 +16,7 @@ const MessageContent: React.FC<MessageContentProps> = ({
|
|||||||
setMessageList,
|
setMessageList,
|
||||||
messageList,
|
messageList,
|
||||||
editable,
|
editable,
|
||||||
|
showTitle = true,
|
||||||
actions = ['upload', 'delete', 'copy']
|
actions = ['upload', 'delete', 'copy']
|
||||||
}) => {
|
}) => {
|
||||||
const updateMessage = (index: number, message: MessageItem) => {
|
const updateMessage = (index: number, message: MessageItem) => {
|
||||||
@@ -39,6 +41,7 @@ const MessageContent: React.FC<MessageContentProps> = ({
|
|||||||
data={item}
|
data={item}
|
||||||
editable={editable}
|
editable={editable}
|
||||||
actions={actions}
|
actions={actions}
|
||||||
|
showTitle={showTitle}
|
||||||
onDelete={() => handleDelete(index)}
|
onDelete={() => handleDelete(index)}
|
||||||
updateMessage={(data) => updateMessage(index, data)}
|
updateMessage={(data) => updateMessage(index, data)}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ import React, {
|
|||||||
} from 'react';
|
} from 'react';
|
||||||
import 'simplebar-react/dist/simplebar.min.css';
|
import 'simplebar-react/dist/simplebar.min.css';
|
||||||
import { CHAT_API } from '../../apis';
|
import { CHAT_API } from '../../apis';
|
||||||
import { Roles, generateMessages } from '../../config';
|
import { OpenAIViewCode, Roles, generateMessages } from '../../config';
|
||||||
import CompareContext from '../../config/compare-context';
|
import CompareContext from '../../config/compare-context';
|
||||||
import { MessageItem, ModelSelectionItem } from '../../config/types';
|
import { MessageItem, ModelSelectionItem } from '../../config/types';
|
||||||
import '../../style/model-item.less';
|
import '../../style/model-item.less';
|
||||||
@@ -452,7 +452,6 @@ const ModelItem: React.FC<ModelItemProps> = forwardRef(
|
|||||||
<div className="content" ref={modelScrollRef}>
|
<div className="content" ref={modelScrollRef}>
|
||||||
<div>
|
<div>
|
||||||
<MessageContent
|
<MessageContent
|
||||||
spans={spans}
|
|
||||||
messageList={messageList}
|
messageList={messageList}
|
||||||
setMessageList={setMessageList}
|
setMessageList={setMessageList}
|
||||||
editable={true}
|
editable={true}
|
||||||
@@ -465,6 +464,7 @@ const ModelItem: React.FC<ModelItemProps> = forwardRef(
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<ViewCodeModal
|
<ViewCodeModal
|
||||||
|
{...OpenAIViewCode.chat}
|
||||||
open={show}
|
open={show}
|
||||||
payLoad={{
|
payLoad={{
|
||||||
messages: viewCodeMessage
|
messages: viewCodeMessage
|
||||||
|
|||||||
@@ -1,252 +0,0 @@
|
|||||||
import FieldWrapper from '@/components/seal-form/field-wrapper';
|
|
||||||
import SealInput from '@/components/seal-form/seal-input';
|
|
||||||
import SealSelect from '@/components/seal-form/seal-select';
|
|
||||||
import { INPUT_WIDTH } from '@/constants';
|
|
||||||
import { InfoCircleOutlined } from '@ant-design/icons';
|
|
||||||
import { useIntl } from '@umijs/max';
|
|
||||||
import { Form, InputNumber, Slider, Tooltip } from 'antd';
|
|
||||||
import _ from 'lodash';
|
|
||||||
import { memo, useCallback, useEffect, useId, useMemo } from 'react';
|
|
||||||
import { ParamsSchema } from '../config/types';
|
|
||||||
import CustomLabelStyles from '../style/custom-label.less';
|
|
||||||
|
|
||||||
type ParamsSettingsFormProps = {
|
|
||||||
top_n?: number;
|
|
||||||
model?: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
type ParamsSettingsProps = {
|
|
||||||
selectedModel?: string;
|
|
||||||
showModelSelector?: boolean;
|
|
||||||
params?: Record<string, any>;
|
|
||||||
model?: string;
|
|
||||||
modelList: Global.BaseOption<string>[];
|
|
||||||
onValuesChange?: (changeValues: any, value: Record<string, any>) => void;
|
|
||||||
setParams: (params: any) => void;
|
|
||||||
globalParams?: Record<string, any>;
|
|
||||||
paramsConfig?: ParamsSchema[];
|
|
||||||
initialValues?: Record<string, any>;
|
|
||||||
};
|
|
||||||
|
|
||||||
const ParamsSettings: React.FC<ParamsSettingsProps> = ({
|
|
||||||
setParams,
|
|
||||||
onValuesChange,
|
|
||||||
selectedModel,
|
|
||||||
globalParams,
|
|
||||||
initialValues,
|
|
||||||
paramsConfig,
|
|
||||||
modelList,
|
|
||||||
params,
|
|
||||||
showModelSelector = true
|
|
||||||
}) => {
|
|
||||||
const intl = useIntl();
|
|
||||||
const [form] = Form.useForm();
|
|
||||||
const formId = useId();
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (showModelSelector) {
|
|
||||||
form.setFieldsValue({
|
|
||||||
model: selectedModel || _.get(modelList, '[0].value'),
|
|
||||||
...initialValues
|
|
||||||
});
|
|
||||||
setParams({
|
|
||||||
model: selectedModel || _.get(modelList, '[0].value'),
|
|
||||||
...initialValues
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
form.setFieldsValue({
|
|
||||||
model: selectedModel || '',
|
|
||||||
...initialValues
|
|
||||||
});
|
|
||||||
setParams({
|
|
||||||
model: selectedModel || '',
|
|
||||||
...initialValues
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}, [modelList, showModelSelector, selectedModel, initialValues]);
|
|
||||||
|
|
||||||
const handleOnFinish = (values: any) => {
|
|
||||||
console.log('handleOnFinish', values);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleOnFinishFailed = (errorInfo: any) => {
|
|
||||||
console.log('handleOnFinishFailed', errorInfo);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleValuesChange = useCallback(
|
|
||||||
(changedValues: any, allValues: any) => {
|
|
||||||
setParams?.(allValues);
|
|
||||||
onValuesChange?.(changedValues, allValues);
|
|
||||||
},
|
|
||||||
[onValuesChange, setParams]
|
|
||||||
);
|
|
||||||
const handleFieldValueChange = useCallback(
|
|
||||||
(val: any, field: string) => {
|
|
||||||
const values = form.getFieldsValue();
|
|
||||||
form.setFieldsValue({
|
|
||||||
...values,
|
|
||||||
[field]: val
|
|
||||||
});
|
|
||||||
setParams({
|
|
||||||
...values,
|
|
||||||
[field]: val
|
|
||||||
});
|
|
||||||
onValuesChange?.(
|
|
||||||
{ [field]: val },
|
|
||||||
{
|
|
||||||
...values,
|
|
||||||
[field]: val
|
|
||||||
}
|
|
||||||
);
|
|
||||||
},
|
|
||||||
[form, setParams, onValuesChange]
|
|
||||||
);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
form.setFieldsValue(globalParams);
|
|
||||||
}, [globalParams]);
|
|
||||||
|
|
||||||
const renderLabel = useCallback(
|
|
||||||
(args: { field: string; label: string; description: string }) => {
|
|
||||||
return (
|
|
||||||
<span
|
|
||||||
className={CustomLabelStyles.label}
|
|
||||||
style={{ width: INPUT_WIDTH.mini }}
|
|
||||||
>
|
|
||||||
<span className="text">
|
|
||||||
{args.description ? (
|
|
||||||
<Tooltip title={args.description}>
|
|
||||||
<span> {args.label}</span>
|
|
||||||
<span className="m-l-5">
|
|
||||||
<InfoCircleOutlined />
|
|
||||||
</span>
|
|
||||||
</Tooltip>
|
|
||||||
) : (
|
|
||||||
<span>{args.label}</span>
|
|
||||||
)}
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<InputNumber
|
|
||||||
className="label-val"
|
|
||||||
variant="outlined"
|
|
||||||
size="small"
|
|
||||||
value={form.getFieldValue(args.field)}
|
|
||||||
controls={false}
|
|
||||||
onChange={(val) => handleFieldValueChange(val, args.field)}
|
|
||||||
></InputNumber>
|
|
||||||
</span>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
[form, handleFieldValueChange]
|
|
||||||
);
|
|
||||||
|
|
||||||
const renderFields = useMemo(() => {
|
|
||||||
console.log('paramsConfig:', paramsConfig);
|
|
||||||
if (!paramsConfig?.length) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return paramsConfig.map((item: ParamsSchema) => {
|
|
||||||
if (item.type === 'InputNumber') {
|
|
||||||
return (
|
|
||||||
<Form.Item name={item.name} rules={item.rules} key={item.name}>
|
|
||||||
<SealInput.Number
|
|
||||||
{...item.attrs}
|
|
||||||
style={{ width: '100%' }}
|
|
||||||
label={
|
|
||||||
item.label.isLocalized
|
|
||||||
? intl.formatMessage({ id: item.label.text })
|
|
||||||
: item.label.text
|
|
||||||
}
|
|
||||||
></SealInput.Number>
|
|
||||||
</Form.Item>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (item.type === 'Select') {
|
|
||||||
return (
|
|
||||||
<Form.Item name={item.name} rules={item.rules} key={item.name}>
|
|
||||||
<SealSelect
|
|
||||||
{...item.attrs}
|
|
||||||
options={item.options}
|
|
||||||
label={
|
|
||||||
item.label.isLocalized
|
|
||||||
? intl.formatMessage({ id: item.label.text })
|
|
||||||
: item.label.text
|
|
||||||
}
|
|
||||||
></SealSelect>
|
|
||||||
</Form.Item>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (item.type === 'Slider') {
|
|
||||||
return (
|
|
||||||
<Form.Item name={item.name} rules={item.rules} key={item.name}>
|
|
||||||
<FieldWrapper
|
|
||||||
label={renderLabel({
|
|
||||||
field: item.name,
|
|
||||||
label: item.label.isLocalized
|
|
||||||
? intl.formatMessage({ id: item.label.text })
|
|
||||||
: item.label.text,
|
|
||||||
description: item.description?.isLocalized
|
|
||||||
? intl.formatMessage({ id: item.description?.text })
|
|
||||||
: item.description?.text || ''
|
|
||||||
})}
|
|
||||||
style={{ padding: '20px 2px 0' }}
|
|
||||||
variant="borderless"
|
|
||||||
>
|
|
||||||
<Slider
|
|
||||||
{...item.attrs}
|
|
||||||
style={{ marginBottom: 0, marginTop: 16, marginInline: 0 }}
|
|
||||||
tooltip={{ open: false }}
|
|
||||||
value={form.getFieldValue(item.name) || undefined}
|
|
||||||
onChange={(val) => handleFieldValueChange(val, item.name)}
|
|
||||||
></Slider>
|
|
||||||
</FieldWrapper>
|
|
||||||
</Form.Item>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
});
|
|
||||||
}, [paramsConfig, params]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Form
|
|
||||||
name={formId}
|
|
||||||
form={form}
|
|
||||||
onValuesChange={handleValuesChange}
|
|
||||||
onFinish={handleOnFinish}
|
|
||||||
onFinishFailed={handleOnFinishFailed}
|
|
||||||
>
|
|
||||||
<div>
|
|
||||||
{
|
|
||||||
<>
|
|
||||||
<h3 className="m-b-20 m-l-10 font-size-14 line-24">
|
|
||||||
<span>{intl.formatMessage({ id: 'playground.parameters' })}</span>
|
|
||||||
</h3>
|
|
||||||
<Form.Item<ParamsSettingsFormProps>
|
|
||||||
name="model"
|
|
||||||
rules={[
|
|
||||||
{
|
|
||||||
required: true,
|
|
||||||
message: intl.formatMessage(
|
|
||||||
{
|
|
||||||
id: 'common.form.rule.select'
|
|
||||||
},
|
|
||||||
{ name: intl.formatMessage({ id: 'playground.model' }) }
|
|
||||||
)
|
|
||||||
}
|
|
||||||
]}
|
|
||||||
>
|
|
||||||
<SealSelect
|
|
||||||
showSearch={true}
|
|
||||||
options={modelList}
|
|
||||||
label={intl.formatMessage({ id: 'playground.model' })}
|
|
||||||
></SealSelect>
|
|
||||||
</Form.Item>
|
|
||||||
</>
|
|
||||||
}
|
|
||||||
{renderFields}
|
|
||||||
</div>
|
|
||||||
</Form>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default memo(ParamsSettings);
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import AutoImage from '@/components/auto-image';
|
import AutoImage from '@/components/auto-image';
|
||||||
import { CloseCircleOutlined } from '@ant-design/icons';
|
import { CloseCircleOutlined } from '@ant-design/icons';
|
||||||
import { Spin } from 'antd';
|
import { Col, Progress, Row } from 'antd';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import React, { useCallback } from 'react';
|
import React, { useCallback } from 'react';
|
||||||
import '../style/thumb-img.less';
|
import '../style/thumb-img.less';
|
||||||
@@ -11,7 +11,20 @@ const ThumbImg: React.FC<{
|
|||||||
onDelete?: (uid: number) => void;
|
onDelete?: (uid: number) => void;
|
||||||
loading?: boolean;
|
loading?: boolean;
|
||||||
style?: React.CSSProperties;
|
style?: React.CSSProperties;
|
||||||
}> = ({ dataList, editable, onDelete, loading, style }) => {
|
responseable?: boolean;
|
||||||
|
gutter?: number | number[] | object;
|
||||||
|
justify?: any;
|
||||||
|
autoSize?: boolean;
|
||||||
|
}> = ({
|
||||||
|
dataList,
|
||||||
|
editable,
|
||||||
|
responseable,
|
||||||
|
gutter,
|
||||||
|
onDelete,
|
||||||
|
loading,
|
||||||
|
autoSize,
|
||||||
|
style
|
||||||
|
}) => {
|
||||||
const handleOnDelete = useCallback(
|
const handleOnDelete = useCallback(
|
||||||
(uid: number) => {
|
(uid: number) => {
|
||||||
onDelete?.(uid);
|
onDelete?.(uid);
|
||||||
@@ -23,52 +36,119 @@ const ThumbImg: React.FC<{
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const renderImageItem = (item: any) => {
|
||||||
|
return (
|
||||||
|
<span
|
||||||
|
key={item.uid}
|
||||||
|
className="thumb-img"
|
||||||
|
style={{
|
||||||
|
width: item.width,
|
||||||
|
height: item.height
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<>
|
||||||
|
{loading ? (
|
||||||
|
<span
|
||||||
|
className="progress-wrap"
|
||||||
|
style={{
|
||||||
|
width: '100%',
|
||||||
|
height: '100%',
|
||||||
|
display: 'flex',
|
||||||
|
border: '1px solid var(--ant-color-split)',
|
||||||
|
borderRadius: 'var(--border-radius-base)',
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
padding: '10px',
|
||||||
|
overflow: 'hidden'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Progress percent={item.progress} type="circle" />
|
||||||
|
</span>
|
||||||
|
) : (
|
||||||
|
<span className="img">
|
||||||
|
<AutoImage
|
||||||
|
autoSize={autoSize}
|
||||||
|
src={item.dataUrl}
|
||||||
|
width={item.width || 100}
|
||||||
|
height={item.height || 100}
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
|
||||||
|
{editable && (
|
||||||
|
<span className="del" onClick={() => handleOnDelete(item.uid)}>
|
||||||
|
<CloseCircleOutlined />
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{
|
{
|
||||||
<div className="thumb-list-wrap" style={{ ...style }}>
|
<div className="thumb-list-wrap" style={{ ...style }}>
|
||||||
{_.map(dataList, (item: any) => {
|
{responseable ? (
|
||||||
return (
|
<>
|
||||||
<span
|
<Row
|
||||||
key={item.uid}
|
gutter={gutter || []}
|
||||||
className="thumb-img"
|
className="flex-center"
|
||||||
style={{
|
style={{
|
||||||
width: item.width || 100,
|
height: dataList.length > 2 ? '50%' : '100%',
|
||||||
height: item.height || 100
|
flex: 'none',
|
||||||
|
width: '100%',
|
||||||
|
justifyContent:
|
||||||
|
dataList.length === 1 ? 'center' : 'flex-start'
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<span className="img">
|
{_.map(_.slice(dataList, 0, 2), (item: any, index: string) => {
|
||||||
{loading ? (
|
return (
|
||||||
<span
|
<Col
|
||||||
style={{
|
span={item.span}
|
||||||
width: '100%',
|
key={`1-${index}`}
|
||||||
height: '100%',
|
className="flex-center justify-center"
|
||||||
display: 'flex',
|
style={{ height: '100%', width: '100%' }}
|
||||||
border: '1px solid var(--ant-color-split)',
|
|
||||||
borderRadius: 'var(--border-radius-base)'
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<Spin
|
{renderImageItem(item)}
|
||||||
|
</Col>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</Row>
|
||||||
|
{dataList.length > 2 && (
|
||||||
|
<Row
|
||||||
|
gutter={gutter || []}
|
||||||
|
style={{
|
||||||
|
height: '50%',
|
||||||
|
flex: 'none',
|
||||||
|
width: '100%',
|
||||||
|
justifyContent:
|
||||||
|
dataList.length === 1 ? 'center' : 'flex-start'
|
||||||
|
}}
|
||||||
|
className="flex-center"
|
||||||
|
>
|
||||||
|
{_.map(_.slice(dataList, 2), (item: any, index: string) => {
|
||||||
|
return (
|
||||||
|
<Col
|
||||||
|
span={item.span}
|
||||||
|
key={`2-${index}`}
|
||||||
className="flex-center justify-center"
|
className="flex-center justify-center"
|
||||||
style={{ width: '100%', height: '100%' }}
|
style={{ height: '100%', width: '100%' }}
|
||||||
></Spin>
|
>
|
||||||
</span>
|
{renderImageItem(item)}
|
||||||
) : (
|
</Col>
|
||||||
<AutoImage src={item.dataUrl} height={item.height || 100} />
|
);
|
||||||
)}
|
})}
|
||||||
</span>
|
</Row>
|
||||||
|
)}
|
||||||
{editable && (
|
</>
|
||||||
<span
|
) : (
|
||||||
className="del"
|
<>
|
||||||
onClick={() => handleOnDelete(item.uid)}
|
{_.map(dataList, (item: any) => {
|
||||||
>
|
return renderImageItem(item);
|
||||||
<CloseCircleOutlined />
|
})}
|
||||||
</span>
|
</>
|
||||||
)}
|
)}
|
||||||
</span>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -12,8 +12,10 @@ type ViewModalProps = {
|
|||||||
payLoad: Record<string, any>;
|
payLoad: Record<string, any>;
|
||||||
parameters: any;
|
parameters: any;
|
||||||
title: string;
|
title: string;
|
||||||
|
api: string;
|
||||||
|
clientType: string;
|
||||||
|
logcommand?: string;
|
||||||
open: boolean;
|
open: boolean;
|
||||||
apiType?: string;
|
|
||||||
onCancel: () => void;
|
onCancel: () => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -33,21 +35,18 @@ const ViewCodeModal: React.FC<ViewModalProps> = (props) => {
|
|||||||
const {
|
const {
|
||||||
title,
|
title,
|
||||||
open,
|
open,
|
||||||
|
api,
|
||||||
|
clientType,
|
||||||
|
logcommand,
|
||||||
onCancel,
|
onCancel,
|
||||||
messageList,
|
|
||||||
payLoad,
|
payLoad,
|
||||||
parameters = {},
|
parameters = {}
|
||||||
apiType = 'chat'
|
|
||||||
} = props || {};
|
} = props || {};
|
||||||
|
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const [lang, setLang] = useState(langMap.shell);
|
const [lang, setLang] = useState(langMap.shell);
|
||||||
|
|
||||||
const BaseURL = `${window.location.origin}/v1-openai`;
|
const BaseURL = `${window.location.origin}/v1-openai`;
|
||||||
const ClientType = apiType === 'chat' ? 'chat.completions' : 'embeddings';
|
|
||||||
const api = apiType === 'chat' ? 'chat/completions' : 'embeddings';
|
|
||||||
const logcommand =
|
|
||||||
apiType === 'chat' ? 'choices[0].message.content' : 'data[0].embedding';
|
|
||||||
|
|
||||||
const formatPyParams = (params: any) => {
|
const formatPyParams = (params: any) => {
|
||||||
return _.keys(params).reduce((acc: string, key: string) => {
|
return _.keys(params).reduce((acc: string, key: string) => {
|
||||||
@@ -63,8 +62,13 @@ const ViewCodeModal: React.FC<ViewModalProps> = (props) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const codeValue = useMemo(() => {
|
const codeValue = useMemo(() => {
|
||||||
|
const consoleLog = logcommand
|
||||||
|
? `console.log(response.${logcommand});\n`
|
||||||
|
: '';
|
||||||
|
|
||||||
|
const printLog = logcommand ? `print(response.${logcommand})` : '';
|
||||||
|
|
||||||
if (lang === langMap.shell) {
|
if (lang === langMap.shell) {
|
||||||
const messages = messageList;
|
|
||||||
const code = `curl ${window.location.origin}/v1-openai/${api} \\\n-H "Content-Type: application/json" \\\n-H "Authorization: Bearer $\{YOUR_GPUSTACK_API_KEY}" \\\n-d '${JSON.stringify(
|
const code = `curl ${window.location.origin}/v1-openai/${api} \\\n-H "Content-Type: application/json" \\\n-H "Authorization: Bearer $\{YOUR_GPUSTACK_API_KEY}" \\\n-d '${JSON.stringify(
|
||||||
{
|
{
|
||||||
...parameters,
|
...parameters,
|
||||||
@@ -76,7 +80,6 @@ const ViewCodeModal: React.FC<ViewModalProps> = (props) => {
|
|||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
if (lang === langMap.javascript) {
|
if (lang === langMap.javascript) {
|
||||||
const messages = messageList;
|
|
||||||
const code = `const OpenAI = require("openai");\n\nconst openai = new OpenAI({\n "apiKey": "YOUR_GPUSTACK_API_KEY",\n "baseURL": "${BaseURL}"\n});\n\nasync function main(){\n const params = ${JSON.stringify(
|
const code = `const OpenAI = require("openai");\n\nconst openai = new OpenAI({\n "apiKey": "YOUR_GPUSTACK_API_KEY",\n "baseURL": "${BaseURL}"\n});\n\nasync function main(){\n const params = ${JSON.stringify(
|
||||||
{
|
{
|
||||||
...parameters,
|
...parameters,
|
||||||
@@ -84,7 +87,7 @@ const ViewCodeModal: React.FC<ViewModalProps> = (props) => {
|
|||||||
},
|
},
|
||||||
null,
|
null,
|
||||||
4
|
4
|
||||||
)};\nconst response = await openai.${ClientType}.create(params);\n console.log(response.${logcommand});\n}\nmain();`;
|
)};\nconst response = await openai.${clientType}.create(params);\n ${consoleLog}}\nmain();`;
|
||||||
|
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
@@ -102,12 +105,12 @@ const ViewCodeModal: React.FC<ViewModalProps> = (props) => {
|
|||||||
},
|
},
|
||||||
''
|
''
|
||||||
);
|
);
|
||||||
const params = apiType === 'chat' ? formatPyParams(payLoad) : '';
|
const params = formatPyParams(payLoad);
|
||||||
const code = `from openai import OpenAI\n\nclient = OpenAI(\n base_url="${BaseURL}", \n api_key="YOUR_GPUSTACK_API_KEY"\n)\n\nresponse = client.${ClientType}.create(\n${formattedParams} ${params})\nprint(response.${logcommand})`;
|
const code = `from openai import OpenAI\n\nclient = OpenAI(\n base_url="${BaseURL}", \n api_key="YOUR_GPUSTACK_API_KEY"\n)\n\nresponse = client.${clientType}.create(\n${formattedParams}${params})\n${printLog}`;
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
return '';
|
return '';
|
||||||
}, [lang, payLoad, parameters]);
|
}, [lang, payLoad, parameters, api, clientType, logcommand]);
|
||||||
|
|
||||||
const handleOnChangeLang = (value: string) => {
|
const handleOnChangeLang = (value: string) => {
|
||||||
setLang(value);
|
setLang(value);
|
||||||
|
|||||||
@@ -6,11 +6,11 @@ import { Button, Modal } from 'antd';
|
|||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
|
|
||||||
type ViewModalProps = {
|
type ViewModalProps = {
|
||||||
documentList: string[];
|
|
||||||
parameters: any;
|
parameters: any;
|
||||||
title: string;
|
title: string;
|
||||||
open: boolean;
|
open: boolean;
|
||||||
apiType?: string;
|
apiType?: string;
|
||||||
|
payload?: Record<string, any>;
|
||||||
onCancel: () => void;
|
onCancel: () => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -27,13 +27,7 @@ const langOptions = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
const ViewCodeModal: React.FC<ViewModalProps> = (props) => {
|
const ViewCodeModal: React.FC<ViewModalProps> = (props) => {
|
||||||
const {
|
const { title, open, onCancel, payload, parameters = {} } = props || {};
|
||||||
title,
|
|
||||||
open,
|
|
||||||
onCancel,
|
|
||||||
documentList = [],
|
|
||||||
parameters = {}
|
|
||||||
} = props || {};
|
|
||||||
|
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const [codeValue, setCodeValue] = useState('');
|
const [codeValue, setCodeValue] = useState('');
|
||||||
@@ -46,7 +40,7 @@ const ViewCodeModal: React.FC<ViewModalProps> = (props) => {
|
|||||||
const code = `curl ${window.location.origin}/v1/rerank \\\n-H "Content-Type: application/json" \\\n-H "Authorization: Bearer $\{YOUR_GPUSTACK_API_KEY}" \\\n-d '${JSON.stringify(
|
const code = `curl ${window.location.origin}/v1/rerank \\\n-H "Content-Type: application/json" \\\n-H "Authorization: Bearer $\{YOUR_GPUSTACK_API_KEY}" \\\n-d '${JSON.stringify(
|
||||||
{
|
{
|
||||||
...parameters,
|
...parameters,
|
||||||
documents: documentList
|
...payload
|
||||||
},
|
},
|
||||||
null,
|
null,
|
||||||
2
|
2
|
||||||
@@ -55,7 +49,7 @@ const ViewCodeModal: React.FC<ViewModalProps> = (props) => {
|
|||||||
} else if (lang === langMap.javascript) {
|
} else if (lang === langMap.javascript) {
|
||||||
const data = {
|
const data = {
|
||||||
...parameters,
|
...parameters,
|
||||||
documents: documentList
|
...payload
|
||||||
};
|
};
|
||||||
const headers = {
|
const headers = {
|
||||||
'Content-type': 'application/json',
|
'Content-type': 'application/json',
|
||||||
@@ -66,7 +60,7 @@ const ViewCodeModal: React.FC<ViewModalProps> = (props) => {
|
|||||||
} else if (lang === langMap.python) {
|
} else if (lang === langMap.python) {
|
||||||
const data = {
|
const data = {
|
||||||
...parameters,
|
...parameters,
|
||||||
documents: documentList
|
...payload
|
||||||
};
|
};
|
||||||
const headers = {
|
const headers = {
|
||||||
'Content-type': 'application/json',
|
'Content-type': 'application/json',
|
||||||
@@ -88,7 +82,7 @@ const ViewCodeModal: React.FC<ViewModalProps> = (props) => {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
generateCode();
|
generateCode();
|
||||||
}, [lang, parameters, documentList]);
|
}, [lang, parameters, payload]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|||||||
@@ -103,3 +103,20 @@ export const generateMessages = (messageList: Omit<MessageItem, 'uid'>[]) => {
|
|||||||
|
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const OpenAIViewCode = {
|
||||||
|
chat: {
|
||||||
|
api: 'chat/completions',
|
||||||
|
clientType: 'chat.completions',
|
||||||
|
logcommand: 'choices[0].message.content'
|
||||||
|
},
|
||||||
|
embeddings: {
|
||||||
|
api: 'embeddings',
|
||||||
|
clientType: 'embeddings',
|
||||||
|
logcommand: 'data[0].embedding'
|
||||||
|
},
|
||||||
|
images: {
|
||||||
|
api: 'images/generations',
|
||||||
|
clientType: 'images.generate'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|||||||
@@ -13,8 +13,8 @@ export const TTSParamsConfig: ParamsSchema[] = [
|
|||||||
{ label: 'Shimmer', value: 'Shimmer' }
|
{ label: 'Shimmer', value: 'Shimmer' }
|
||||||
],
|
],
|
||||||
label: {
|
label: {
|
||||||
text: 'Voice',
|
text: 'playground.params.voice',
|
||||||
isLocalized: false
|
isLocalized: true
|
||||||
},
|
},
|
||||||
rules: [
|
rules: [
|
||||||
{
|
{
|
||||||
@@ -35,8 +35,8 @@ export const TTSParamsConfig: ParamsSchema[] = [
|
|||||||
{ label: 'pcm', value: 'pcm' }
|
{ label: 'pcm', value: 'pcm' }
|
||||||
],
|
],
|
||||||
label: {
|
label: {
|
||||||
text: 'Response Format',
|
text: 'playground.params.format',
|
||||||
isLocalized: false
|
isLocalized: true
|
||||||
},
|
},
|
||||||
rules: [
|
rules: [
|
||||||
{
|
{
|
||||||
@@ -55,8 +55,8 @@ export const TTSParamsConfig: ParamsSchema[] = [
|
|||||||
{ label: '4x', value: 4 }
|
{ label: '4x', value: 4 }
|
||||||
],
|
],
|
||||||
label: {
|
label: {
|
||||||
text: 'Speed',
|
text: 'playground.params.speed',
|
||||||
isLocalized: false
|
isLocalized: true
|
||||||
},
|
},
|
||||||
rules: [
|
rules: [
|
||||||
{
|
{
|
||||||
@@ -64,6 +64,25 @@ export const TTSParamsConfig: ParamsSchema[] = [
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
// {
|
||||||
|
// type: 'TextArea',
|
||||||
|
// name: 'prompt',
|
||||||
|
// label: {
|
||||||
|
// text: 'Prompt',
|
||||||
|
// isLocalized: false
|
||||||
|
// },
|
||||||
|
// attrs: {
|
||||||
|
// autoSize: {
|
||||||
|
// minRows: 2,
|
||||||
|
// maxRows: 3
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// rules: [
|
||||||
|
// {
|
||||||
|
// required: false
|
||||||
|
// }
|
||||||
|
// ]
|
||||||
|
// }
|
||||||
];
|
];
|
||||||
|
|
||||||
export const RealtimeParamsConfig: ParamsSchema[] = [
|
export const RealtimeParamsConfig: ParamsSchema[] = [
|
||||||
@@ -79,13 +98,12 @@ export const RealtimeParamsConfig: ParamsSchema[] = [
|
|||||||
{ label: 'Deutsch', value: 'de' }
|
{ label: 'Deutsch', value: 'de' }
|
||||||
],
|
],
|
||||||
label: {
|
label: {
|
||||||
text: 'Language',
|
text: 'playground.params.language',
|
||||||
isLocalized: false
|
isLocalized: true
|
||||||
},
|
},
|
||||||
rules: [
|
rules: [
|
||||||
{
|
{
|
||||||
required: true,
|
required: true
|
||||||
message: 'Language is required'
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -96,12 +114,12 @@ export const ImageParamsConfig: ParamsSchema[] = [
|
|||||||
type: 'InputNumber',
|
type: 'InputNumber',
|
||||||
name: 'n',
|
name: 'n',
|
||||||
label: {
|
label: {
|
||||||
text: 'Counts',
|
text: 'playground.params.counts',
|
||||||
isLocalized: false
|
isLocalized: true
|
||||||
},
|
},
|
||||||
attrs: {
|
attrs: {
|
||||||
min: 1,
|
min: 1,
|
||||||
max: 10
|
max: 4
|
||||||
},
|
},
|
||||||
rules: [
|
rules: [
|
||||||
{
|
{
|
||||||
@@ -117,45 +135,12 @@ export const ImageParamsConfig: ParamsSchema[] = [
|
|||||||
{ label: '512x512', value: '512x512' },
|
{ label: '512x512', value: '512x512' },
|
||||||
{ label: '1024x1024', value: '1024x1024' },
|
{ label: '1024x1024', value: '1024x1024' },
|
||||||
{ label: '1792x1024', value: '1792x1024' },
|
{ label: '1792x1024', value: '1792x1024' },
|
||||||
{ label: '1024x1792', value: '1024x1792' }
|
{ label: '1024x1792', value: '1024x1792' },
|
||||||
|
{ label: 'playground.params.custom', value: 'custom', locale: true }
|
||||||
],
|
],
|
||||||
label: {
|
label: {
|
||||||
text: 'Size',
|
text: 'playground.params.size',
|
||||||
isLocalized: false
|
isLocalized: true
|
||||||
},
|
|
||||||
rules: [
|
|
||||||
{
|
|
||||||
required: false
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'Select',
|
|
||||||
name: 'quality',
|
|
||||||
options: [
|
|
||||||
{ label: 'standard', value: 'standard' },
|
|
||||||
{ label: 'hd', value: 'hd' }
|
|
||||||
],
|
|
||||||
label: {
|
|
||||||
text: 'Quality',
|
|
||||||
isLocalized: false
|
|
||||||
},
|
|
||||||
rules: [
|
|
||||||
{
|
|
||||||
required: false
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'Select',
|
|
||||||
name: 'style',
|
|
||||||
options: [
|
|
||||||
{ label: 'vivid', value: 'vivid' },
|
|
||||||
{ label: 'natural', value: 'natural' }
|
|
||||||
],
|
|
||||||
label: {
|
|
||||||
text: 'Style',
|
|
||||||
isLocalized: false
|
|
||||||
},
|
},
|
||||||
rules: [
|
rules: [
|
||||||
{
|
{
|
||||||
@@ -163,4 +148,57 @@ export const ImageParamsConfig: ParamsSchema[] = [
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
// {
|
||||||
|
// type: 'Select',
|
||||||
|
// name: 'quality',
|
||||||
|
// options: [
|
||||||
|
// { label: 'standard', value: 'standard' },
|
||||||
|
// { label: 'hd', value: 'hd' }
|
||||||
|
// ],
|
||||||
|
// label: {
|
||||||
|
// text: 'playground.params.quality',
|
||||||
|
// isLocalized: true
|
||||||
|
// },
|
||||||
|
// rules: [
|
||||||
|
// {
|
||||||
|
// required: false
|
||||||
|
// }
|
||||||
|
// ]
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// type: 'Select',
|
||||||
|
// name: 'style',
|
||||||
|
// options: [
|
||||||
|
// { label: 'vivid', value: 'vivid' },
|
||||||
|
// { label: 'natural', value: 'natural' }
|
||||||
|
// ],
|
||||||
|
// label: {
|
||||||
|
// text: 'playground.params.style',
|
||||||
|
// isLocalized: true
|
||||||
|
// },
|
||||||
|
// rules: [
|
||||||
|
// {
|
||||||
|
// required: false
|
||||||
|
// }
|
||||||
|
// ]
|
||||||
|
// }
|
||||||
|
// {
|
||||||
|
// type: 'TextArea',
|
||||||
|
// name: 'prompt',
|
||||||
|
// label: {
|
||||||
|
// text: 'Prompt',
|
||||||
|
// isLocalized: false
|
||||||
|
// },
|
||||||
|
// attrs: {
|
||||||
|
// autoSize: {
|
||||||
|
// minRows: 2,
|
||||||
|
// maxRows: 3
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// rules: [
|
||||||
|
// {
|
||||||
|
// required: false
|
||||||
|
// }
|
||||||
|
// ]
|
||||||
|
// }
|
||||||
];
|
];
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 26 KiB |
@@ -20,6 +20,7 @@ type SchemaType =
|
|||||||
| 'Textarea'
|
| 'Textarea'
|
||||||
| 'Select'
|
| 'Select'
|
||||||
| 'Slider'
|
| 'Slider'
|
||||||
|
| 'TextArea'
|
||||||
| 'Checkbox';
|
| 'Checkbox';
|
||||||
|
|
||||||
export interface ParamsSchema {
|
export interface ParamsSchema {
|
||||||
|
|||||||
@@ -30,7 +30,8 @@ const PlaygroundEmbedding: React.FC = () => {
|
|||||||
const getModelListByEmbedding = async () => {
|
const getModelListByEmbedding = async () => {
|
||||||
try {
|
try {
|
||||||
const params = {
|
const params = {
|
||||||
embedding_only: true
|
embedding_only: true,
|
||||||
|
reranker: false
|
||||||
};
|
};
|
||||||
const res = await queryModelsList(params);
|
const res = await queryModelsList(params);
|
||||||
const list = _.map(res.data || [], (item: any) => {
|
const list = _.map(res.data || [], (item: any) => {
|
||||||
|
|||||||
@@ -54,6 +54,19 @@
|
|||||||
.content {
|
.content {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.hold-wrapper {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hold-text-icon {
|
||||||
|
display: flex;
|
||||||
|
padding: 4px;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
background-color: var(--ant-color-fill-tertiary);
|
||||||
|
border-radius: var(--border-radius-base);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -63,4 +76,19 @@
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.embed-chart {
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
.drag-handler {
|
||||||
|
position: absolute;
|
||||||
|
padding: 0;
|
||||||
|
height: fit-content;
|
||||||
|
top: -10px;
|
||||||
|
font-size: var(--font-size-middle);
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
transition: background-color 0.3s ease;
|
transition: background-color 0.3s ease;
|
||||||
border-radius: var(--border-radius-base);
|
border-radius: var(--border-radius-base);
|
||||||
border: 1px solid var(--ant-color-border);
|
border: 1px solid var(--ant-color-border);
|
||||||
|
background-color: #fff;
|
||||||
|
|
||||||
.btn-group {
|
.btn-group {
|
||||||
display: none;
|
display: none;
|
||||||
|
|||||||
@@ -43,3 +43,40 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.rank-wrapper {
|
||||||
|
position: absolute;
|
||||||
|
left: 14px;
|
||||||
|
right: 14px;
|
||||||
|
bottom: 0;
|
||||||
|
line-height: 12px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
overflow: hidden;
|
||||||
|
align-items: flex-end;
|
||||||
|
|
||||||
|
.percent-wrapper {
|
||||||
|
flex: 1;
|
||||||
|
padding: 2px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rank-tag {
|
||||||
|
padding: 0 4px;
|
||||||
|
margin-left: 10px;
|
||||||
|
background-color: transparent;
|
||||||
|
opacity: 0.7;
|
||||||
|
width: 160px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
|
.ant-tag {
|
||||||
|
margin: 0;
|
||||||
|
justify-content: center;
|
||||||
|
display: flex;
|
||||||
|
height: 16px;
|
||||||
|
border-radius: 4px;
|
||||||
|
align-items: center;
|
||||||
|
transform: scale(0.85);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,14 +1,21 @@
|
|||||||
.thumb-img {
|
.thumb-img {
|
||||||
position: relative;
|
position: relative;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
max-width: 100%;
|
||||||
|
max-height: 100%;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
.img {
|
.img {
|
||||||
display: flex;
|
display: flex;
|
||||||
width: 100%;
|
width: auto;
|
||||||
height: 100%;
|
height: auto;
|
||||||
|
max-width: 100%;
|
||||||
|
max-height: 100%;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
border-radius: var(--border-radius-base);
|
border-radius: var(--border-radius-base);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.del {
|
.del {
|
||||||
|
|||||||
+25
-112
@@ -1,5 +1,3 @@
|
|||||||
import _ from 'lodash';
|
|
||||||
|
|
||||||
export const isNotEmptyValue = (value: any) => {
|
export const isNotEmptyValue = (value: any) => {
|
||||||
if (Array.isArray(value)) {
|
if (Array.isArray(value)) {
|
||||||
return value.length > 0;
|
return value.length > 0;
|
||||||
@@ -32,116 +30,6 @@ export const convertFileSize = (sizeInBytes: number, prec?: number) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const generateRandomArray = (config?: {
|
|
||||||
min: number;
|
|
||||||
max: number;
|
|
||||||
length: number;
|
|
||||||
offset: number;
|
|
||||||
}) => {
|
|
||||||
const { min, max, length, offset } = config || {
|
|
||||||
min: 10,
|
|
||||||
max: 80,
|
|
||||||
length: 10,
|
|
||||||
offset: 10
|
|
||||||
};
|
|
||||||
|
|
||||||
const data = [];
|
|
||||||
let prevValue = Math.floor(Math.random() * (max - min + 1)) + min;
|
|
||||||
|
|
||||||
for (let i = 0; i < length; i++) {
|
|
||||||
let newValue = prevValue + Math.floor(Math.random() * 21) - offset; // Fluctuation range [-10, 10]
|
|
||||||
newValue = Math.max(min, Math.min(max, newValue)); // Ensure within [10, 100]
|
|
||||||
data.push(newValue);
|
|
||||||
prevValue = newValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
return data;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const generateFluctuatingData2 = ({
|
|
||||||
total = 100,
|
|
||||||
noiseLevel = 10,
|
|
||||||
max = 50,
|
|
||||||
min = 5
|
|
||||||
}) => {
|
|
||||||
const x = [];
|
|
||||||
const y = [];
|
|
||||||
|
|
||||||
for (let i = 0; i < total; i++) {
|
|
||||||
// Generate a basic linear trend using a sine function
|
|
||||||
const phaseShift = Math.random() * 2 * Math.PI;
|
|
||||||
const trend =
|
|
||||||
max * Math.sin((3 * Math.PI * i + phaseShift) / total) + max / 2;
|
|
||||||
|
|
||||||
// Generate noise
|
|
||||||
const noise = (Math.random() * 2 - 1) * noiseLevel;
|
|
||||||
|
|
||||||
// Add trend and noise
|
|
||||||
const value = trend + noise;
|
|
||||||
x.push(i);
|
|
||||||
y.push(Math.max(min, value));
|
|
||||||
}
|
|
||||||
|
|
||||||
return y;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const generateFluctuatingData = ({
|
|
||||||
total = 50,
|
|
||||||
trendType = 'linear',
|
|
||||||
max = 1,
|
|
||||||
f = 1,
|
|
||||||
phase = 0,
|
|
||||||
min = 0
|
|
||||||
}) => {
|
|
||||||
/**
|
|
||||||
* Generate a set of data for a line chart with a natural and aesthetically pleasing trend.
|
|
||||||
*
|
|
||||||
* Parameters:
|
|
||||||
* total (number): Number of data points to generate
|
|
||||||
* trendType (string): Type of data trend, options are 'linear', 'sine', 'exponential'
|
|
||||||
* max (number): Fluctuation amplitude
|
|
||||||
* f (number): Fluctuation frequency
|
|
||||||
* phase (number): Fluctuation phase
|
|
||||||
* min (number): Minimum value of the data
|
|
||||||
*
|
|
||||||
* Returns:
|
|
||||||
* x (number[]): x-axis data
|
|
||||||
* y (number[]): y-axis data
|
|
||||||
*/
|
|
||||||
const x = Array.from({ length: total }, (_, i) => (i * 10) / (total - 1));
|
|
||||||
|
|
||||||
let y;
|
|
||||||
switch (trendType) {
|
|
||||||
case 'linear':
|
|
||||||
y = x.map(
|
|
||||||
(val) => val * (Math.random() * 2 - 1) * 3 + Math.random() * 8 - 4
|
|
||||||
);
|
|
||||||
|
|
||||||
break;
|
|
||||||
case 'sine':
|
|
||||||
y = x.map(
|
|
||||||
(val) =>
|
|
||||||
max * Math.sin(2 * Math.PI * f * val + phase) + Math.random() * 2 - 1
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
case 'exponential':
|
|
||||||
y = x.map(
|
|
||||||
(val) => Math.exp(val * Math.random() * 0.2) + Math.random() * 4 - 2
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new Error(
|
|
||||||
'Invalid trendType parameter. Please choose "linear", "sine", or "exponential".'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Adjust the data to the minimum value
|
|
||||||
const minY = Math.min(...y);
|
|
||||||
y = y.map((val) => _.round(val - minY + min, 2));
|
|
||||||
|
|
||||||
return y;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const platformCall = () => {
|
export const platformCall = () => {
|
||||||
const platform = navigator.userAgent;
|
const platform = navigator.userAgent;
|
||||||
const isMac = () => {
|
const isMac = () => {
|
||||||
@@ -190,6 +78,7 @@ export const formatNumber = (num: number) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export function loadLanguageConfig(language: string) {
|
export function loadLanguageConfig(language: string) {
|
||||||
|
// @ts-ignore
|
||||||
const requireContext = require.context(`./${language}`, false, /\.ts$/);
|
const requireContext = require.context(`./${language}`, false, /\.ts$/);
|
||||||
|
|
||||||
const languageConfig: Record<string, string> = {};
|
const languageConfig: Record<string, string> = {};
|
||||||
@@ -214,3 +103,27 @@ export function readBlob(blob: Blob): Promise<string> {
|
|||||||
reader.readAsText(blob, 'utf-8');
|
reader.readAsText(blob, 'utf-8');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const cosineSimilarity = (vec1: number[], vec2: number[]) => {
|
||||||
|
if (vec1.length !== vec2.length) {
|
||||||
|
throw new Error('both vectors must have the same length');
|
||||||
|
}
|
||||||
|
|
||||||
|
const dotProduct = vec1.reduce(
|
||||||
|
(sum, value, index) => sum + value * vec2[index],
|
||||||
|
0
|
||||||
|
);
|
||||||
|
|
||||||
|
const magnitudeA = Math.sqrt(
|
||||||
|
vec1.reduce((sum, value) => sum + value * value, 0)
|
||||||
|
);
|
||||||
|
const magnitudeB = Math.sqrt(
|
||||||
|
vec2.reduce((sum, value) => sum + value * value, 0)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (magnitudeA === 0 || magnitudeB === 0) {
|
||||||
|
throw new Error('both vectors must have a length greater than 0');
|
||||||
|
}
|
||||||
|
|
||||||
|
return dotProduct / (magnitudeA * magnitudeB);
|
||||||
|
};
|
||||||
|
|||||||
Vendored
+1
@@ -20,5 +20,6 @@ declare module 'has-ansi';
|
|||||||
declare module 'terminal-kit';
|
declare module 'terminal-kit';
|
||||||
declare module 'monaco-vim';
|
declare module 'monaco-vim';
|
||||||
declare module '@orcid/bibtex-parse-js';
|
declare module '@orcid/bibtex-parse-js';
|
||||||
|
declare module 'sortablejs';
|
||||||
|
|
||||||
declare const REACT_APP_ENV: 'test' | 'dev' | 'pre' | false;
|
declare const REACT_APP_ENV: 'test' | 'dev' | 'pre' | false;
|
||||||
|
|||||||
Reference in New Issue
Block a user