perf: embedding calc in worker process
This commit is contained in:
+4
-1
@@ -28,6 +28,9 @@ export default defineConfig({
|
|||||||
logLevel: 'info',
|
logLevel: 'info',
|
||||||
defaultSizes: 'parsed' // stat // gzip
|
defaultSizes: 'parsed' // stat // gzip
|
||||||
},
|
},
|
||||||
|
mfsu: {
|
||||||
|
exclude: ['lodash', 'ml-pca']
|
||||||
|
},
|
||||||
base: process.env.npm_config_base || '/',
|
base: process.env.npm_config_base || '/',
|
||||||
...(isProduction
|
...(isProduction
|
||||||
? {
|
? {
|
||||||
@@ -52,7 +55,7 @@ export default defineConfig({
|
|||||||
]);
|
]);
|
||||||
config.module
|
config.module
|
||||||
.rule('worker')
|
.rule('worker')
|
||||||
.test(/\.worker\.js$/)
|
.test(/\.worker\.(js|ts)$/)
|
||||||
.use('worker-loader')
|
.use('worker-loader')
|
||||||
.loader('worker-loader');
|
.loader('worker-loader');
|
||||||
config.output
|
config.output
|
||||||
|
|||||||
@@ -78,6 +78,7 @@
|
|||||||
"@types/react": "^18.3.1",
|
"@types/react": "^18.3.1",
|
||||||
"@types/react-dom": "^18.3.0",
|
"@types/react-dom": "^18.3.0",
|
||||||
"@umijs/case-sensitive-paths-webpack-plugin": "^1.0.1",
|
"@umijs/case-sensitive-paths-webpack-plugin": "^1.0.1",
|
||||||
|
"@umijs/plugins": "^4.4.11",
|
||||||
"babel-plugin-named-asset-import": "^0.3.8",
|
"babel-plugin-named-asset-import": "^0.3.8",
|
||||||
"case-sensitive-paths-webpack-plugin": "^2.4.0",
|
"case-sensitive-paths-webpack-plugin": "^2.4.0",
|
||||||
"compression-webpack-plugin": "^11.1.0",
|
"compression-webpack-plugin": "^11.1.0",
|
||||||
|
|||||||
Generated
+121
-659
File diff suppressed because it is too large
Load Diff
@@ -148,4 +148,4 @@ const RowTextarea: React.FC<SystemMessageProps> = (props) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default React.memo(RowTextarea);
|
export default RowTextarea;
|
||||||
|
|||||||
@@ -16,7 +16,10 @@ interface ErrorResultProps {
|
|||||||
|
|
||||||
function isChunkLoadError(msg?: string): boolean {
|
function isChunkLoadError(msg?: string): boolean {
|
||||||
if (typeof msg !== 'string') return false;
|
if (typeof msg !== 'string') return false;
|
||||||
return msg.includes('Loading chunk') && msg.includes('failed');
|
const jsChunkFailed = msg.includes('Loading chunk');
|
||||||
|
const cssChunkFailed = msg.includes('Loading CSS chunk');
|
||||||
|
|
||||||
|
return (jsChunkFailed || cssChunkFailed) && msg.includes('failed');
|
||||||
}
|
}
|
||||||
|
|
||||||
const ErrorResult: React.FC<ErrorResultProps> = ({ extra }) => {
|
const ErrorResult: React.FC<ErrorResultProps> = ({ extra }) => {
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ export default {
|
|||||||
'playground.params.temperature.tips':
|
'playground.params.temperature.tips':
|
||||||
'Controls randomness: Lowering results in less random completions. As the temperature approaches zero, the model will become deterministic and repetitive.',
|
'Controls randomness: Lowering results in less random completions. As the temperature approaches zero, the model will become deterministic and repetitive.',
|
||||||
'playground.params.maxtokens.tips':
|
'playground.params.maxtokens.tips':
|
||||||
"The maximum number of tokens to generated. The total length of input tokens and generated tokens is limited by the model's context length.",
|
"The maximum number of tokens to generate. The total length of input tokens and generated tokens is limited by the model's context length.",
|
||||||
'playground.params.topp.tips':
|
'playground.params.topp.tips':
|
||||||
'Controls diversity via nucleus sampling: 0.5 means half of all likelihood-weighted options are considered.',
|
'Controls diversity via nucleus sampling: 0.5 means half of all likelihood-weighted options are considered.',
|
||||||
'playground.params.seed.tips':
|
'playground.params.seed.tips':
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ import { useIntl } from '@umijs/max';
|
|||||||
import { Button, Checkbox, Form, Segmented, Spin, Tabs, Tooltip } from 'antd';
|
import { Button, Checkbox, Form, Segmented, Spin, Tabs, Tooltip } from 'antd';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import { PCA } from 'ml-pca';
|
|
||||||
import 'overlayscrollbars/overlayscrollbars.css';
|
import 'overlayscrollbars/overlayscrollbars.css';
|
||||||
import { Resizable } from 're-resizable';
|
import { Resizable } from 're-resizable';
|
||||||
import React, {
|
import React, {
|
||||||
@@ -31,6 +30,7 @@ import React, {
|
|||||||
import { EMBEDDING_API, handleEmbedding } from '../apis';
|
import { EMBEDDING_API, handleEmbedding } from '../apis';
|
||||||
import { extractErrorMessage } from '../config';
|
import { extractErrorMessage } from '../config';
|
||||||
import { LLM_METAKEYS } from '../hooks/config';
|
import { LLM_METAKEYS } from '../hooks/config';
|
||||||
|
import useEmbeddingWorker from '../hooks/use-embedding-worker';
|
||||||
import { useInitLLmMeta } from '../hooks/use-init-meta';
|
import { useInitLLmMeta } from '../hooks/use-init-meta';
|
||||||
import '../style/ground-left.less';
|
import '../style/ground-left.less';
|
||||||
import '../style/rerank.less';
|
import '../style/rerank.less';
|
||||||
@@ -51,6 +51,8 @@ const GroundEmbedding: React.FC<MessageProps> = forwardRef((props, ref) => {
|
|||||||
const messageId = useRef<number>(0);
|
const messageId = useRef<number>(0);
|
||||||
|
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
const { workerRef, createWorker, postMessage, terminateWorker } =
|
||||||
|
useEmbeddingWorker();
|
||||||
const requestSource = useRequestToken();
|
const requestSource = useRequestToken();
|
||||||
const [show, setShow] = useState(false);
|
const [show, setShow] = useState(false);
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
@@ -154,46 +156,6 @@ const GroundEmbedding: React.FC<MessageProps> = forwardRef((props, ref) => {
|
|||||||
return list.length < 2;
|
return list.length < 2;
|
||||||
}, [textList, fileList]);
|
}, [textList, fileList]);
|
||||||
|
|
||||||
const generateEmbedding = useCallback(
|
|
||||||
(embeddings: any[]) => {
|
|
||||||
try {
|
|
||||||
const dataList = embeddings.map((item) => {
|
|
||||||
return item.embedding;
|
|
||||||
});
|
|
||||||
|
|
||||||
const pca = new PCA(dataList);
|
|
||||||
const pcadata = pca.predict(dataList, { nComponents: 2 }).to2DArray();
|
|
||||||
|
|
||||||
const input = [
|
|
||||||
...textList.map((item) => item.text).filter((item) => item),
|
|
||||||
...fileList.map((item) => item.text).filter((item) => item)
|
|
||||||
];
|
|
||||||
|
|
||||||
const list = pcadata.map((item: number[], index: number) => {
|
|
||||||
return {
|
|
||||||
value: item,
|
|
||||||
name: index + 1,
|
|
||||||
text: input[index]
|
|
||||||
};
|
|
||||||
});
|
|
||||||
setScatterData(list);
|
|
||||||
const embeddingJson = embeddings.map((o, index) => {
|
|
||||||
const item = _.cloneDeep(o);
|
|
||||||
item.embedding = item.embedding.slice(0, 5);
|
|
||||||
item.embedding.push(null);
|
|
||||||
return item;
|
|
||||||
});
|
|
||||||
setEmbeddingData({
|
|
||||||
code: JSON.stringify(embeddingJson, null, 2).replace(/null/g, '...'),
|
|
||||||
copyValue: JSON.stringify(embeddings, null, 2)
|
|
||||||
});
|
|
||||||
} catch (e) {
|
|
||||||
console.log('error:', e);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[textList, fileList]
|
|
||||||
);
|
|
||||||
|
|
||||||
const setMessageId = () => {
|
const setMessageId = () => {
|
||||||
messageId.current = messageId.current + 1;
|
messageId.current = messageId.current + 1;
|
||||||
};
|
};
|
||||||
@@ -245,12 +207,29 @@ const GroundEmbedding: React.FC<MessageProps> = forwardRef((props, ref) => {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
console.log('result=========', result);
|
||||||
setTokenResult(result.usage);
|
setTokenResult(result.usage);
|
||||||
|
|
||||||
const embeddingsList = result.data || [];
|
const embeddingsList = result.data || [];
|
||||||
|
|
||||||
generateEmbedding(embeddingsList);
|
createWorker();
|
||||||
|
|
||||||
|
workerRef.current!.onmessage = (event: MessageEvent) => {
|
||||||
|
const { scatterData, embeddingData } = event.data;
|
||||||
|
console.log('worker result:', scatterData, embeddingData);
|
||||||
|
setScatterData(scatterData);
|
||||||
|
setEmbeddingData(embeddingData);
|
||||||
|
};
|
||||||
|
|
||||||
|
postMessage({
|
||||||
|
embeddings: embeddingsList,
|
||||||
|
textList: textList,
|
||||||
|
fileList: fileList
|
||||||
|
});
|
||||||
|
|
||||||
|
// generateEmbedding(embeddingsList);
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
|
console.log('result=========error', error);
|
||||||
setTokenResult({
|
setTokenResult({
|
||||||
error: true,
|
error: true,
|
||||||
errorMessage: extractErrorMessage(error.response)
|
errorMessage: extractErrorMessage(error.response)
|
||||||
@@ -324,12 +303,11 @@ const GroundEmbedding: React.FC<MessageProps> = forwardRef((props, ref) => {
|
|||||||
if (!multiplePasteEnable.current) return;
|
if (!multiplePasteEnable.current) return;
|
||||||
const text = e.clipboardData.getData('text');
|
const text = e.clipboardData.getData('text');
|
||||||
if (text) {
|
if (text) {
|
||||||
const currentContent = textList[index].text;
|
|
||||||
const dataLlist = text.split('\n').map((item: string) => {
|
const dataLlist = text.split('\n').map((item: string) => {
|
||||||
return {
|
return {
|
||||||
text: item?.trim(),
|
text: item?.trim(),
|
||||||
uid: inputListRef.current?.setMessageId(),
|
name: '',
|
||||||
name: ''
|
uid: setMessageId()
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
dataLlist[0].text = `${selectionTextRef.current?.beforeText || ''}${dataLlist[0].text}${selectionTextRef.current?.afterText || ''}`;
|
dataLlist[0].text = `${selectionTextRef.current?.beforeText || ''}${dataLlist[0].text}${selectionTextRef.current?.afterText || ''}`;
|
||||||
@@ -337,14 +315,8 @@ const GroundEmbedding: React.FC<MessageProps> = forwardRef((props, ref) => {
|
|||||||
...textList.slice(0, index),
|
...textList.slice(0, index),
|
||||||
...dataLlist,
|
...dataLlist,
|
||||||
...textList.slice(index + 1)
|
...textList.slice(index + 1)
|
||||||
]
|
].filter((item) => item.text);
|
||||||
.filter((item) => item.text)
|
|
||||||
.map((item, index) => {
|
|
||||||
return {
|
|
||||||
...item,
|
|
||||||
uid: inputListRef.current?.setMessageId()
|
|
||||||
};
|
|
||||||
});
|
|
||||||
setTextList(result);
|
setTextList(result);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -111,7 +111,6 @@ const GroundReranker: React.FC<MessageProps> = forwardRef((props, ref) => {
|
|||||||
name: ''
|
name: ''
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
const [sortIndexMap, setSortIndexMap] = useState<number[]>([]);
|
|
||||||
const [queryValue, setQueryValue] = useState<string>('');
|
const [queryValue, setQueryValue] = useState<string>('');
|
||||||
const selectionTextRef = useRef<any>(null);
|
const selectionTextRef = useRef<any>(null);
|
||||||
|
|
||||||
@@ -237,8 +236,6 @@ const GroundReranker: React.FC<MessageProps> = forwardRef((props, ref) => {
|
|||||||
setLoading(true);
|
setLoading(true);
|
||||||
setMessageId();
|
setMessageId();
|
||||||
setTokenResult(null);
|
setTokenResult(null);
|
||||||
setSortIndexMap([]);
|
|
||||||
|
|
||||||
requestToken.current?.cancel?.();
|
requestToken.current?.cancel?.();
|
||||||
requestToken.current = requestSource();
|
requestToken.current = requestSource();
|
||||||
|
|
||||||
@@ -278,8 +275,6 @@ const GroundReranker: React.FC<MessageProps> = forwardRef((props, ref) => {
|
|||||||
let sortMap: number[] = [];
|
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(),
|
uid: setMessageId(),
|
||||||
@@ -295,7 +290,6 @@ const GroundReranker: React.FC<MessageProps> = forwardRef((props, ref) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
newTextList = _.sortBy(newTextList, 'rank');
|
newTextList = _.sortBy(newTextList, 'rank');
|
||||||
setSortIndexMap(sortMap);
|
|
||||||
setTextList(newTextList);
|
setTextList(newTextList);
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
setTokenResult({
|
setTokenResult({
|
||||||
@@ -360,8 +354,11 @@ const GroundReranker: React.FC<MessageProps> = forwardRef((props, ref) => {
|
|||||||
const dataLlist = text.split('\n').map((item: string) => {
|
const dataLlist = text.split('\n').map((item: string) => {
|
||||||
return {
|
return {
|
||||||
text: item?.trim(),
|
text: item?.trim(),
|
||||||
|
name: '',
|
||||||
uid: setMessageId(),
|
uid: setMessageId(),
|
||||||
name: ''
|
percent: undefined,
|
||||||
|
score: undefined,
|
||||||
|
rank: undefined
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
dataLlist[0].text = `${selectionTextRef.current?.beforeText || ''}${dataLlist[0].text}${selectionTextRef.current?.afterText || ''}`;
|
dataLlist[0].text = `${selectionTextRef.current?.beforeText || ''}${dataLlist[0].text}${selectionTextRef.current?.afterText || ''}`;
|
||||||
@@ -369,36 +366,14 @@ const GroundReranker: React.FC<MessageProps> = forwardRef((props, ref) => {
|
|||||||
...textList.slice(0, index),
|
...textList.slice(0, index),
|
||||||
...dataLlist,
|
...dataLlist,
|
||||||
...textList.slice(index + 1)
|
...textList.slice(index + 1)
|
||||||
]
|
].filter((item) => item.text);
|
||||||
.filter((item) => item.text)
|
|
||||||
.map((item, index) => {
|
|
||||||
item.percent = undefined;
|
|
||||||
item.score = undefined;
|
|
||||||
item.rank = undefined;
|
|
||||||
return {
|
|
||||||
...item,
|
|
||||||
uid: setMessageId()
|
|
||||||
};
|
|
||||||
});
|
|
||||||
setTextList(result);
|
setTextList(result);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[textList]
|
[textList]
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleOnSort = useCallback(
|
|
||||||
(list: { text: string; uid: number | string; name: string }[]) => {
|
|
||||||
const newList = list?.map((item) => {
|
|
||||||
return {
|
|
||||||
...item,
|
|
||||||
uid: setMessageId()
|
|
||||||
};
|
|
||||||
});
|
|
||||||
setTextList(newList);
|
|
||||||
},
|
|
||||||
[]
|
|
||||||
);
|
|
||||||
|
|
||||||
const renderExtra = useMemo(() => {
|
const renderExtra = useMemo(() => {
|
||||||
if (modelMeta?.n_ctx && modelMeta?.n_slot) {
|
if (modelMeta?.n_ctx && modelMeta?.n_slot) {
|
||||||
return (
|
return (
|
||||||
@@ -538,14 +513,11 @@ const GroundReranker: React.FC<MessageProps> = forwardRef((props, ref) => {
|
|||||||
<div className="docs-wrapper">
|
<div className="docs-wrapper">
|
||||||
<InputList
|
<InputList
|
||||||
key={messageId.current}
|
key={messageId.current}
|
||||||
sortIndex={sortIndexMap}
|
|
||||||
ref={inputListRef}
|
ref={inputListRef}
|
||||||
textList={textList}
|
textList={textList}
|
||||||
showLabel={false}
|
showLabel={false}
|
||||||
sortable={false}
|
|
||||||
height={46}
|
height={46}
|
||||||
onChange={handleTextListChange}
|
onChange={handleTextListChange}
|
||||||
onSort={handleOnSort}
|
|
||||||
extra={renderPercent}
|
extra={renderPercent}
|
||||||
onSelect={handleonSelect}
|
onSelect={handleonSelect}
|
||||||
onPaste={handleOnPaste}
|
onPaste={handleOnPaste}
|
||||||
|
|||||||
@@ -2,14 +2,7 @@ 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 _ from 'lodash';
|
import React, { forwardRef, useImperativeHandle, useRef } from 'react';
|
||||||
import React, {
|
|
||||||
forwardRef,
|
|
||||||
useCallback,
|
|
||||||
useEffect,
|
|
||||||
useImperativeHandle,
|
|
||||||
useRef
|
|
||||||
} from 'react';
|
|
||||||
import '../style/input-list.less';
|
import '../style/input-list.less';
|
||||||
|
|
||||||
interface InputListProps {
|
interface InputListProps {
|
||||||
@@ -17,20 +10,15 @@ interface InputListProps {
|
|||||||
height?: number;
|
height?: number;
|
||||||
extra?: (data: any) => React.ReactNode;
|
extra?: (data: any) => React.ReactNode;
|
||||||
showLabel?: boolean;
|
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;
|
||||||
onPaste?: (e: any, index: number) => void;
|
onPaste?: (e: any, index: number) => void;
|
||||||
onSort?: (
|
|
||||||
textList: { text: string; uid: number | string; name: string }[]
|
|
||||||
) => void;
|
|
||||||
onSelect?: (data: {
|
onSelect?: (data: {
|
||||||
start: number;
|
start: number;
|
||||||
end: number;
|
end: number;
|
||||||
@@ -42,152 +30,12 @@ interface InputListProps {
|
|||||||
|
|
||||||
const InputList: React.FC<InputListProps> = forwardRef(
|
const InputList: React.FC<InputListProps> = forwardRef(
|
||||||
(
|
(
|
||||||
{
|
{ textList, showLabel = true, height, onChange, extra, onPaste, onSelect },
|
||||||
textList,
|
|
||||||
showLabel = true,
|
|
||||||
sortIndex = [],
|
|
||||||
sortable,
|
|
||||||
height,
|
|
||||||
onSort,
|
|
||||||
onChange,
|
|
||||||
extra,
|
|
||||||
onPaste,
|
|
||||||
onSelect
|
|
||||||
},
|
|
||||||
ref
|
ref
|
||||||
) => {
|
) => {
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const messageId = useRef(0);
|
const messageId = useRef(0);
|
||||||
const containerRef = useRef<any>(null);
|
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;
|
||||||
@@ -221,14 +69,6 @@ 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,
|
||||||
@@ -277,4 +117,4 @@ const InputList: React.FC<InputListProps> = forwardRef(
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
export default React.memo(InputList);
|
export default InputList;
|
||||||
|
|||||||
@@ -0,0 +1,69 @@
|
|||||||
|
import _ from 'lodash';
|
||||||
|
import { PCA } from 'ml-pca';
|
||||||
|
|
||||||
|
self.onmessage = (
|
||||||
|
event: MessageEvent<{
|
||||||
|
embeddings: any[];
|
||||||
|
fileList: { text: string; name: string; uid: number | string }[];
|
||||||
|
textList: { text: string; name: string; uid: number | string }[];
|
||||||
|
}>
|
||||||
|
) => {
|
||||||
|
const { embeddings, fileList, textList } = event.data;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const dataList = embeddings.map((item) => {
|
||||||
|
return item.embedding;
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log('list:', dataList);
|
||||||
|
const pca = new PCA(dataList);
|
||||||
|
console.log('list:', pca);
|
||||||
|
const pcadata = pca.predict(dataList, { nComponents: 2 }).to2DArray();
|
||||||
|
|
||||||
|
const input = [
|
||||||
|
...textList.map((item) => item.text).filter((item) => item),
|
||||||
|
...fileList.map((item) => item.text).filter((item) => item)
|
||||||
|
];
|
||||||
|
|
||||||
|
const list = pcadata.map((item: number[], index: number) => {
|
||||||
|
return {
|
||||||
|
value: item,
|
||||||
|
name: index + 1,
|
||||||
|
text: input[index]
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
const embeddingJson = embeddings.map((o, index) => {
|
||||||
|
const item = _.cloneDeep(o);
|
||||||
|
item.embedding = item.embedding.slice(0, 5);
|
||||||
|
item.embedding.push(null);
|
||||||
|
return item;
|
||||||
|
});
|
||||||
|
const embeddingData = {
|
||||||
|
code: JSON.stringify(embeddingJson, null, 2).replace(/null/g, '...'),
|
||||||
|
copyValue: JSON.stringify(embeddings, null, 2)
|
||||||
|
};
|
||||||
|
|
||||||
|
self.postMessage({
|
||||||
|
scatterData: list,
|
||||||
|
embeddingData: embeddingData
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
console.log('error:', e);
|
||||||
|
self.postMessage({
|
||||||
|
scatterData: [],
|
||||||
|
embeddingData: {
|
||||||
|
code: '',
|
||||||
|
copyValue: ''
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
self.onerror = (e) => {
|
||||||
|
console.log('error:', e);
|
||||||
|
};
|
||||||
|
|
||||||
|
self.onmessageerror = (e) => {
|
||||||
|
console.log('message error:', e);
|
||||||
|
};
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
import { useEffect, useRef } from 'react';
|
||||||
|
|
||||||
|
export default function useEmbeddingWorker() {
|
||||||
|
const workerRef = useRef<Worker | null>(null);
|
||||||
|
|
||||||
|
const createWorker = () => {
|
||||||
|
if (workerRef.current) {
|
||||||
|
workerRef.current.terminate();
|
||||||
|
}
|
||||||
|
workerRef.current = new Worker(
|
||||||
|
new URL('../config/embedding-worker.worker.ts', import.meta.url),
|
||||||
|
{
|
||||||
|
type: 'module'
|
||||||
|
}
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const postMessage = (params: {
|
||||||
|
embeddings: any[];
|
||||||
|
textList: { text: string; name: string; uid: number | string }[];
|
||||||
|
fileList: { text: string; name: string; uid: number | string }[];
|
||||||
|
}) => {
|
||||||
|
if (workerRef.current) {
|
||||||
|
workerRef.current.postMessage(params);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const terminateWorker = () => {
|
||||||
|
if (workerRef.current) {
|
||||||
|
workerRef.current.terminate();
|
||||||
|
workerRef.current = null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
return () => {
|
||||||
|
terminateWorker();
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return { workerRef, createWorker, postMessage, terminateWorker };
|
||||||
|
}
|
||||||
@@ -27,5 +27,6 @@
|
|||||||
"src/components/logs-viewer/parse-worker.ts",
|
"src/components/logs-viewer/parse-worker.ts",
|
||||||
"src/components/image-editor/invert-worker.ts",
|
"src/components/image-editor/invert-worker.ts",
|
||||||
"src/components/image-editor/offscreen-worker.ts"
|
"src/components/image-editor/offscreen-worker.ts"
|
||||||
|
// "src/pages/playground/config/embedding-worker.ts"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user