fix: the max embedding value exceeds the limit.

This commit is contained in:
jialin
2026-01-13 20:57:50 +08:00
parent f0bfbfe693
commit c813344c7c
9 changed files with 89 additions and 29 deletions
+27 -10
View File
@@ -2,12 +2,26 @@ import Chart from '@/components/echarts/chart';
import useChartConfig from '@/components/echarts/config';
import EmptyData from '@/components/empty-data';
import _ from 'lodash';
import React, { memo, useCallback, useMemo, useRef } from 'react';
import React, { useCallback, useMemo, useRef } from 'react';
import { ChartProps } from './types';
const Scatter: React.FC<ChartProps> = (props) => {
const Scatter: React.FC<
ChartProps & {
xMax?: number;
yMax?: number;
}
> = (props) => {
const { grid, title: titleConfig, isDark, chartColorMap } = useChartConfig();
const { seriesData, xAxisData, height, width, showEmpty, title } = props;
const {
seriesData,
xAxisData,
height,
width,
showEmpty,
title,
xMax = 1,
yMax = 1
} = props;
const chart = useRef<any>(null);
@@ -36,8 +50,8 @@ const Scatter: React.FC<ChartProps> = (props) => {
borderRadius: 4
},
xAxis: {
min: -1,
max: 1,
min: -xMax,
max: xMax,
scale: false,
slient: true,
splitNumber: 15,
@@ -62,8 +76,8 @@ const Scatter: React.FC<ChartProps> = (props) => {
boundaryGap: [0.05, 0.05]
},
yAxis: {
min: -1,
max: 1,
min: -yMax,
max: yMax,
scale: false,
slient: true,
splitNumber: 10,
@@ -99,7 +113,7 @@ const Scatter: React.FC<ChartProps> = (props) => {
},
series: []
};
}, [isDark]);
}, [isDark, xMax, yMax]);
const findOverlappingPoints = useCallback(
(data: any[], currentPoint: any) => {
@@ -201,7 +215,10 @@ const Scatter: React.FC<ChartProps> = (props) => {
return (
<>
{!seriesData.length && showEmpty ? (
<EmptyData height={height} title={title}></EmptyData>
<EmptyData
height={height}
title={_.get(title, 'text', title || '')}
></EmptyData>
) : (
<Chart
ref={chart}
@@ -214,4 +231,4 @@ const Scatter: React.FC<ChartProps> = (props) => {
);
};
export default memo(Scatter);
export default Scatter;
+1 -6
View File
@@ -212,16 +212,11 @@ body {
// set for the non-form item
.ant-input-outlined,
.ant-input-affix-wrapper,
.ant-select,
.ant-select-lg,
.ant-picker {
height: 40px;
}
// form item help
.ant-form-item-with-help .ant-form-item-explain {
// padding-left: 16px;
}
// icon
.anticon {
&.size-16 {
+2 -1
View File
@@ -162,5 +162,6 @@ export default {
'Please enter a direct image URL (e.g. https://.../image.png). Press ESC to cancel.',
'playground.uploadImage.url.holder': 'Enter an image URL',
'playground.uploadImage.url.button': 'Add Image from URL',
'playground.params.duration': 'Duration (seconds)'
'playground.params.duration': 'Duration (seconds)',
'playground.params.resolution': 'Resolution'
};
+4 -2
View File
@@ -165,7 +165,8 @@ export default {
'Please enter a direct image URL (e.g. https://.../image.png). Press ESC to cancel.',
'playground.uploadImage.url.holder': 'Enter an image URL',
'playground.uploadImage.url.button': 'Add Image from URL',
'playground.params.duration': 'Duration (seconds)'
'playground.params.duration': 'Duration (seconds)',
'playground.params.resolution': 'Resolution'
};
// ========== To-Do: Translate Keys (Remove After Translation) ==========
@@ -175,5 +176,6 @@ export default {
// 4. 'playground.uploadImage.url.invalid': 'Please enter a direct image URL(e.g. https://.../image.png). Press ESC to cancel.',
// 5. 'playground.uploadImage.url.holder': 'Enter an image URL'
// 6. 'playground.uploadImage.url.button': 'Add Image from URL',
// 7. 'playground.params.duration': 'Duration (seconds)'
// 7. 'playground.params.duration': 'Duration (seconds)',
// 8. 'playground.params.resolution': 'Resolution'
// ========== End of To-Do List ==========
+4 -2
View File
@@ -159,12 +159,14 @@ export default {
'Please enter a direct image URL (e.g. https://.../image.png). Press ESC to cancel.',
'playground.uploadImage.url.holder': 'Enter an image URL',
'playground.uploadImage.url.button': 'Add Image from URL',
'playground.params.duration': 'Duration (seconds)'
'playground.params.duration': 'Duration (seconds)',
'playground.params.resolution': 'Resolution'
};
// ========== To-Do: Translate Keys (Remove After Translation) ==========
// 1. 'playground.uploadImage.url.invalid': 'Please enter a direct image URL(e.g. https://.../image.png). Press ESC to cancel.',
// 2. 'playground.uploadImage.url.holder': 'Enter an image URL',
// 3. 'playground.uploadImage.url.button': 'Add Image from URL',
// 4. 'playground.params.duration': 'Duration (seconds)'
// 4. 'playground.params.duration': 'Duration (seconds)',
// 5. 'playground.params.resolution': 'Resolution'
// ========== End of To-Do List ==========
+2 -1
View File
@@ -155,5 +155,6 @@ export default {
'请输入直接的图片链接(例如:https://…/image.png)。按 ESC 可取消。',
'playground.uploadImage.url.holder': '请输入图片链接',
'playground.uploadImage.url.button': '从链接添加图片',
'playground.params.duration': '时长 (秒)'
'playground.params.duration': '时长 (秒)',
'playground.params.resolution': '分辨率'
};
@@ -215,6 +215,7 @@ const GroundEmbedding: React.FC<MessageProps> = forwardRef((props, ref) => {
workerRef.current!.onmessage = (event: MessageEvent) => {
const { scatterData, embeddingData } = event.data;
setScatterData(scatterData);
setEmbeddingData(embeddingData);
setLoading(false);
@@ -1,6 +1,52 @@
import _ from 'lodash';
import { PCA } from 'ml-pca';
type Point = {
value: [number, number];
[key: string]: any;
};
const normalizeEmbeddingToCanvas = (
data: Point[],
padding = 0.9 // 90% fill the canvas
) => {
let minX = Infinity,
maxX = -Infinity;
let minY = Infinity,
maxY = -Infinity;
data.forEach((p) => {
const [x, y] = p.value;
minX = Math.min(minX, x);
maxX = Math.max(maxX, x);
minY = Math.min(minY, y);
maxY = Math.max(maxY, y);
});
// 2. center point
const cx = (minX + maxX) / 2;
const cy = (minY + maxY) / 2;
// 3. max radius
let maxRadius = 0;
data.forEach((p) => {
const dx = Math.abs(p.value[0] - cx);
const dy = Math.abs(p.value[1] - cy);
maxRadius = Math.max(maxRadius, dx, dy);
});
if (maxRadius === 0) maxRadius = 1;
// 4. scale factor
const scale = padding / maxRadius;
// 5. normalization
return data.map((p) => ({
...p,
value: [(p.value[0] - cx) * scale, (p.value[1] - cy) * scale]
}));
};
self.onmessage = (
event: MessageEvent<{
embeddings: any[];
@@ -49,7 +95,7 @@ self.onmessage = (
};
self.postMessage({
scatterData: list,
scatterData: normalizeEmbeddingToCanvas(list),
embeddingData: embeddingData
});
} catch (e) {
@@ -36,13 +36,8 @@ export const videoParamsConfig: ParamsSchema[] = [
type: 'Select',
name: 'size',
options: videoSizeOptions,
description: {
text: 'playground.params.size.description',
html: true,
isLocalized: true
},
label: {
text: 'playground.params.size',
text: 'playground.params.resolution',
isLocalized: true
},
rules: [