diff --git a/packages/lb-components/src/components/LLMMultiWheelView/sidebar/index.tsx b/packages/lb-components/src/components/LLMMultiWheelView/sidebar/index.tsx index df55aa4f..e511bbc4 100644 --- a/packages/lb-components/src/components/LLMMultiWheelView/sidebar/index.tsx +++ b/packages/lb-components/src/components/LLMMultiWheelView/sidebar/index.tsx @@ -4,8 +4,8 @@ * @createdate 2024-9-24 */ -import React, { useState, useEffect, useContext, useMemo } from 'react'; -import { LabelBeeContext, LLMContext } from '@/store/ctx'; +import React, { useState, useEffect, useMemo, useRef } from 'react'; +import { LabelBeeContext } from '@/store/ctx'; import { connect } from 'react-redux'; import { AppState } from '@/store'; @@ -14,11 +14,14 @@ import { ILLMMultiWheelToolConfig, IAnswerList, IConfigUpdate, + IAnswerSort, + IWaitAnswerSort, } from '@/components/LLMToolView/types'; import { getStepConfig } from '@/store/annotation/reducer'; import { jsonParser } from '@/utils'; -import ModelSort from '@/components/LLMToolView/sidebar/components/modelSort'; -import ModelAnswerSort from '@/components/LLMToolView/sidebar/components/modelAnswerSort'; +import ModelAnswerSort, { + getSorts, +} from '@/components/LLMToolView/sidebar/components/modelAnswerSort'; import { useTranslation } from 'react-i18next'; import { useCustomToolInstance } from '@/hooks/annotation'; import { isArray, isBoolean, isNumber, isObject, isString } from 'lodash'; @@ -35,6 +38,8 @@ import { getRenderDataByResult, } from '@/components/LLMToolView/utils/data'; import { useMemoizedFn } from 'ahooks'; +import { ITextList } from '../types'; +import AnswerSort from '@/components/LLMToolView/sidebar/components/answerSort'; const EKeyCode = cKeyCode.default; @@ -53,6 +58,18 @@ interface ILLMAnnotationResultMap { }; } +interface IGlobalResult { + sort: Array; + answerSort: { [key: string]: number[] }; + textAttribute: ITextList[]; +} + +const initGlobalResult = { + sort: [], + answerSort: {}, + textAttribute: [], +}; + const LLMMultiWheelToolSidebar = (props: IProps) => { const { annotation, dispatch, checkMode } = props; const { imgIndex, imgList, stepList, step, skipBeforePageTurning } = annotation; @@ -64,6 +81,13 @@ const LLMMultiWheelToolSidebar = (props: IProps) => { const [valid, setValid] = useState(true); const [annotationResultMap, setAnnotationResultMap] = useState({}); const { selectedID } = useLLMMultiWheelStore(); + const [globalResult, setGlobalResult] = useState(initGlobalResult); + const answerSortRef = useRef(); + const sortRef = useRef(); + const [sortData, setSortData] = useState<{ + newSort?: IAnswerSort[][]; + waitSorts?: IWaitAnswerSort[]; + }>({}); const currentLLMAnnotationResult = useMemo(() => { return annotationResultMap[selectedID]; @@ -90,6 +114,15 @@ const LLMMultiWheelToolSidebar = (props: IProps) => { const clearResult = () => { initResult(currentData?.questionList?.textList); + if (answerSortRef.current?.clearValue) { + answerSortRef.current?.clearValue(); + } + const { waitSorts } = getSorts({ + selectedSort: getCurrentResult()?.sort ?? [], + initSelected: [], + modelList: dialogSort ? modelList ?? [] : [], + }); + setSortData({ ...sortData, waitSorts, newSort: [] }); }; const onSetValid = (newValid?: boolean) => { @@ -101,9 +134,13 @@ const LLMMultiWheelToolSidebar = (props: IProps) => { } }; - const initResult = (initData?: any) => { + const getCurrentResult = () => { const currentStepInfo = StepUtils.getCurrentStepInfo(step, stepList); - const result: any = getCurrentResultFromResultList(currentData?.result, currentStepInfo.step); + return getCurrentResultFromResultList(currentData?.result, currentStepInfo.step); + }; + + const initResult = (initData?: any) => { + const result: any = getCurrentResult(); let sourceData = currentData?.questionList?.textList; @@ -113,9 +150,11 @@ const LLMMultiWheelToolSidebar = (props: IProps) => { if (initData) { sourceData = initData; result.sort = []; + result.textAttribute = []; + result.answerSort = []; } - let tmpMap: ILLMAnnotationResultMap = {}; + let tmpMap: ILLMAnnotationResultMap = {}; sourceData?.forEach((item: any, modelIndex: number) => { const data = getRenderDataByResult(LLMConfig, { ...item, @@ -132,13 +171,23 @@ const LLMMultiWheelToolSidebar = (props: IProps) => { id: item.id, }; }); + const { waitSorts, newSort } = getSorts({ + selectedSort: getCurrentResult()?.sort ?? [], + modelList: dialogSort ? modelList ?? [] : [], + }); + setSortData({ waitSorts, newSort }); + setGlobalResult({ + sort: result?.sort ?? [], + textAttribute: result?.textAttribute ?? [], + answerSort: result?.answerSort ?? [], + }); setAnnotationResultMap(tmpMap); }; useEffect(() => { setExportData(); - }, [annotationResultMap, valid]); + }, [annotationResultMap, valid, globalResult]); useEffect(() => { window.addEventListener('keydown', onKeyDown); @@ -156,7 +205,7 @@ const LLMMultiWheelToolSidebar = (props: IProps) => { }; }); - const result = { modelData }; + const result = { ...globalResult, modelData }; toolInstanceRef.current.exportData = () => { return [[result], { valid }]; }; @@ -209,6 +258,14 @@ const LLMMultiWheelToolSidebar = (props: IProps) => { }); }); + // Used to update global results + const updateGlobalValue = (key: string, value: any) => { + setGlobalResult((prevState) => ({ + ...prevState, + [key]: value, + })); + }; + const { indicatorScore = [], indicatorDetermine = [], @@ -244,65 +301,45 @@ const LLMMultiWheelToolSidebar = (props: IProps) => { const hasTagList = tagInputListConfigurable && inputList.filter((i) => !i.isOverall)?.length > 0; const showAnwerList = indicatorDetermine?.length > 0 || indicatorScore?.length > 0 || isTextEdit || hasTagList; + return (
{t('GlobalAnnotation')}
+ {/* Global Model sort */} + { + const sort = value.map((i) => i.map((item) => item.id)); + updateGlobalValue('sort', sort); + setSortData({ ...sortData, newSort: value }); + }} + disabeledAll={disabeledAll} + title={t('SortConversationQuality')} + prefixId='model' + /> - {/* 全局模型排序 */} - {dialogSort && ( - {}} - modelList={dialogSort ? modelList ?? [] : []} - title={t('SortConversationQuality')} - prefixId='model' - /> - )} - - {/* 文本输入 */} + {/* Global text input */} {LLMConfig?.text && (
{}} + setText={(v) => updateGlobalValue('textAttribute', v)} disabeledAll={disabeledAll} />
)} - {/* 答案模型排序 */} + {/* Answer Model sort */} updateGlobalValue('answerSort', v)} + selectedSort={getCurrentResult()?.answerSort ?? []} + ref={answerSortRef} + disabeledAll={disabeledAll} /> {currentLLMAnnotationResult && ( <> diff --git a/packages/lb-components/src/components/LLMMultiWheelView/types.ts b/packages/lb-components/src/components/LLMMultiWheelView/types.ts new file mode 100644 index 00000000..00f50643 --- /dev/null +++ b/packages/lb-components/src/components/LLMMultiWheelView/types.ts @@ -0,0 +1,64 @@ + +export interface ITextList { + textId?: string; + title?: string | number; + tip?: string; + min?: number; + max?: number; + value?: string; + isFillAnswer?: boolean; + textControl?: boolean; + isLaText?: boolean; +} +export interface IAnswerList { + id: string; + answer: string; + newAnswer: string; + indicatorScore: { + [key: string]: number; + }; + indicatorDetermine: { + [key: string]: boolean; + }; + tagList: { [key: string]: string[] }; +} + +export interface IModelData { + id: number; + sort: Array; + answerList: IAnswerList[]; +} + +export interface IModelResult { + sort: Array; + answerSort: { [key: string]: number[] }; + textAttribute: ITextList[]; + modelData: IModelData[]; +} + +export interface ISortData { + newSort?: IAnswerSort[][]; + waitSorts?: IWaitAnswerSort[]; +} + +export interface IWaitAnswerSort { + title: string; + id: string; +} + +export interface IPoint { + x: number; + y: number; +} +export interface ITagVertexPoint { + bl: IPoint; + br: IPoint; + tl: IPoint; + tr: IPoint; +} +export interface IAnswerSort { + title: string; + id: string; + tagCenterPoint?: IPoint; + tagVertexPoint?: ITagVertexPoint; +} diff --git a/packages/lb-components/src/components/LLMToolView/sidebar/components/answerSort/index.tsx b/packages/lb-components/src/components/LLMToolView/sidebar/components/answerSort/index.tsx index 55accfaf..50a8c0de 100644 --- a/packages/lb-components/src/components/LLMToolView/sidebar/components/answerSort/index.tsx +++ b/packages/lb-components/src/components/LLMToolView/sidebar/components/answerSort/index.tsx @@ -182,7 +182,6 @@ const AnswerSort = (props: IProps) => { const formatSortList = () => { const sortBox = document.getElementById(sortBoxId); - if (sortBox?.childNodes) { let newSortList: IAnswerSort[][] = []; sortBox.childNodes.forEach((item: any, nodeIndex: number) => { @@ -245,6 +244,7 @@ const AnswerSort = (props: IProps) => { if (!sourceTagCenterPoint.x || !sourceTagCenterPoint.y) { return; } + // 不以拖动的tag做参照 if (getAttributeIndex(e.target.id) === tagNearest[0]?.id) { setTargetTagKey(undefined); @@ -340,7 +340,7 @@ const AnswerSort = (props: IProps) => { answers.map((i: IWaitAnswerSort) => singleAnswerItem({ item: i, - id: `waitBoxItem${SEGMENTATION_OF_KEY}${i?.id}`, + id: `${waitBoxId}-waitBoxItem${SEGMENTATION_OF_KEY}${i?.id}`, operation: { onDrag: onDrag, onDragEnd: onDragEnd, @@ -362,7 +362,7 @@ const AnswerSort = (props: IProps) => { {i.map((item: IAnswerSort) => singleAnswerItem({ item, - id: `sortBoxItem${SEGMENTATION_OF_KEY}${item?.id}`, + id: `${sortBoxId}-sortBoxItem${SEGMENTATION_OF_KEY}${item?.id}`, operation: { onDrag: onDrag, onDragEnd: onDragEnd, diff --git a/packages/lb-components/src/components/LLMToolView/sidebar/components/modelAnswerSort/index.tsx b/packages/lb-components/src/components/LLMToolView/sidebar/components/modelAnswerSort/index.tsx index 80fd9a1e..b796c217 100644 --- a/packages/lb-components/src/components/LLMToolView/sidebar/components/modelAnswerSort/index.tsx +++ b/packages/lb-components/src/components/LLMToolView/sidebar/components/modelAnswerSort/index.tsx @@ -1,20 +1,17 @@ -import React, { useState, useEffect, useContext, useMemo } from 'react'; -import { prefix } from '@/constant'; -import { Button, Empty, Tag } from 'antd'; -import AnswerSort from '../answerSort'; -import { IWaitAnswerSort } from '@/components/LLMToolView/types'; -import { getWaitSortList } from '@/components/LLMToolView/utils/data'; -import { isArray } from 'lodash'; -import ModelSort from '../modelSort'; +import React, { useState, useMemo, forwardRef, useImperativeHandle, useEffect } from 'react'; import { useTranslation } from 'react-i18next'; +import { useDebounceFn } from 'ahooks'; +import AnswerSort from '../answerSort'; +import { IAnswerSort } from '@/components/LLMToolView/types'; -interface IAnswerSort { +interface ISelectAnswerSort { [key: string]: number[][]; } interface IModelList { id: number; answerList: IAnswerList[]; + title: string; } interface IAnswerList { @@ -22,35 +19,120 @@ interface IAnswerList { answer: string; } +interface IMaxAnswerList { + id: string; + title: string; +} + interface IProps { - selectedSort?: IAnswerSort; - maxAnswerList: IAnswerList[]; + selectedSort?: ISelectAnswerSort; modelData: IModelList[]; + selectedAnswerSort: (sorts: ISelectAnswerSort) => void; + disabeledAll?: boolean; } -const ModelAnswerSort = (props: IProps) => { - const { selectedSort, maxAnswerList, modelData } = props; - const [answerSortData, setAnswerSortData] = useState({ waitSorts: [], selecteds: selectedSort }); +export const getSorts = ({ + selectedSort, + initSelected, + modelList, +}: { + selectedSort?: number[][]; + modelList: any[]; + initSelected?: number[][]; +}) => { + const selecteds = initSelected ?? selectedSort; + let newSort: any[] = []; + const waitSorts = modelList.filter((i) => { + const selectedIds = selecteds && selecteds?.length > 0 ? selecteds.flat() : []; + if (selectedIds.includes(i.id)) { + return false; + } + return true; + }); + if (selecteds && selecteds?.length > 0) { + newSort = selecteds.map((i) => i.map((item) => modelList.find((j) => j.id === item))); + } + return { waitSorts, newSort }; +}; + +const ModelAnswerSort = (props: IProps, ref: any) => { + const { selectedSort, modelData, selectedAnswerSort, disabeledAll } = props; + const [answerSortData, setAnswerSortData] = useState({ + waitSorts: {}, + selecteds: selectedSort, + }); + const { t } = useTranslation(); - const modelDatas = useMemo( - () => - modelData.map((i, itemIndex) => ({ - ...i, - title: itemIndex + 1, - })), - [modelData], - ); + const modelDatas = useMemo(() => { + return modelData.map((i, itemIndex) => ({ + ...i, + title: itemIndex + 1, + })); + }, [modelData]); + + const maxAnswerList: IMaxAnswerList[] = useMemo(() => { + const maxList = modelData.reduce((longest: any[], current: any) => { + return current.answerList.length > longest.length ? current.answerList : longest; + }, []); + const renderValue = maxList.map((i: { id: string; answer: string }, index: number) => ({ + id: i.id, + title: `${index + 1}`, + })); + return renderValue || []; + }, [modelData]); + + useEffect(() => { + if (selectedSort) { + setRenderAnswerSortData(); + } + }, [modelData]); const getModelList = (id: string) => { const values = modelDatas.filter((i) => i.answerList.some((item) => item.id === id)) || []; - return values.map((i) => ({ id: i.id, title: i.title })); + return values.map((i) => ({ ...i, id: i.id, title: i.title })); }; - const exportSort = (id: string, value: number[][]) => { - // TODO 当拖动一个答案的时,多次调用 - // 因为answerSort组件useEffect(() => {formatSortList();}, [JSON.stringify(sortList)]) + const setRenderAnswerSortData = (initSelecteds?: ISelectAnswerSort) => { + const newValue = answerSortData; + const selects = initSelecteds ?? selectedSort; + maxAnswerList.forEach((i) => { + const modelList = getModelList(i.id); + const selecteds = selects?.[i.id]; + const { waitSorts, newSort } = getSorts({ selectedSort: selecteds, modelList }); + newValue.waitSorts[i.id] = waitSorts; + newValue.selecteds[i.id] = newSort; + }); + setAnswerSortData(newValue); + }; + + useImperativeHandle( + ref, + () => { + return { + clearValue: () => setRenderAnswerSortData({}), + }; + }, + [modelData], + ); + + const exportData = (id: string, value: IAnswerSort[][]) => { + const isDragTag = value.some((innerArray) => innerArray.some((item) => item?.id)); + + if (isDragTag) { + const newSelecteds = { ...answerSortData.selecteds, [id]: value }; + + const formatValue: any = {}; + Object.keys(newSelecteds).forEach((key) => { + formatValue[key] = newSelecteds[key].map((innerArray: IAnswerSort[]) => + innerArray.map((item: IAnswerSort) => item.id), + ); + }); + selectedAnswerSort(formatValue); + setAnswerSortData({ ...answerSortData, selecteds: newSelecteds }); + } }; + const { run: exportSort } = useDebounceFn(exportData, { wait: 10 }); return (
@@ -64,13 +146,13 @@ const ModelAnswerSort = (props: IProps) => { }} > {t('RankingQualityOfAnswers')} - {answerSortData?.waitSorts?.length > 0 && ( + {/* {answerSortData?.waitSorts?.length > 0 && ( {t('Unfinished')} - )} + )} */}
- {maxAnswerList.map((i: IAnswerList, index: number) => { + {maxAnswerList.map((i: IMaxAnswerList, index: number) => { return (
{ textAlign: 'center', }} >{`${t('Answer')}${index + 1}`}
- { + { exportSort(i.id, value); }} - modelList={getModelList(i.id)} - selectedSort={answerSortData.selecteds?.[i.id] ?? []} + disabeledAll={disabeledAll} header={''} prefixId={`modelAnswer${index}`} /> @@ -97,4 +180,4 @@ const ModelAnswerSort = (props: IProps) => {
); }; -export default ModelAnswerSort; +export default forwardRef(ModelAnswerSort); diff --git a/packages/lb-components/src/components/LLMToolView/sidebar/components/modelSort/index.tsx b/packages/lb-components/src/components/LLMToolView/sidebar/components/modelSort/index.tsx deleted file mode 100644 index e3d7135a..00000000 --- a/packages/lb-components/src/components/LLMToolView/sidebar/components/modelSort/index.tsx +++ /dev/null @@ -1,75 +0,0 @@ -import React, { useState, useEffect, useContext, useMemo } from 'react'; -import { prefix } from '@/constant'; -import { Button, Empty } from 'antd'; -import AnswerSort from '../answerSort'; -import { IAnswerSort, IWaitAnswerSort } from '@/components/LLMToolView/types'; -import { getWaitSortList } from '@/components/LLMToolView/utils/data'; -import { isArray } from 'lodash'; - -interface IModelList { - id: number; - title: number; -} - -interface ISortData { - newSort?: IAnswerSort[][]; - waitSorts?: IWaitAnswerSort[]; -} - -interface IProps { - modelList: IModelList[]; - selectedSort?: number[][]; - disabeledAll?: boolean; - setSort: (sort: number[][]) => void; - header?: HTMLElement | string; - title?: string; - prefixId?: string; -} - -const ModelSort = (props: IProps) => { - const { disabeledAll, modelList, selectedSort, setSort, header, title,prefixId } = props; - const [sortData, setSortData] = useState({}); - - useEffect(() => { - initSortData(); - }, []); - - const initSortData = () => { - let newSort: any[] = []; - const waitSorts = modelList.filter((i) => { - const selectedIds = selectedSort && selectedSort?.length > 0 ? selectedSort.flat() : []; - if (selectedIds.includes(i.id)) { - return false; - } - return true; - }); - if (selectedSort && selectedSort?.length > 0) { - newSort = selectedSort.map((i: number[]) => - i.map((item) => modelList.find((j) => j.id === item)), - ); - } - setSortData({ waitSorts, newSort }); - }; - - const exportSort = (list: IAnswerSort[][]) => { - const sort = list.map((i) => i.map((item) => item.id)); - setSort(sort); - }; - - return ( - { - setSortData({ ...sortData, newSort: value }); - exportSort(value); - }} - disabeledAll={disabeledAll} - header={header} - title={title} - prefixId={prefixId} - /> - ); -}; - -export default ModelSort; diff --git a/packages/lb-components/src/components/LLMToolView/sidebar/index.tsx b/packages/lb-components/src/components/LLMToolView/sidebar/index.tsx index 86de81ea..1b556404 100644 --- a/packages/lb-components/src/components/LLMToolView/sidebar/index.tsx +++ b/packages/lb-components/src/components/LLMToolView/sidebar/index.tsx @@ -31,8 +31,6 @@ import emptySvg from '@/assets/annotation/LLMTool/empty.svg'; import TextInputBox from './components/textInputBox'; import OverallTagList from '@/components/tagList/components/overall'; import StepUtils from '@/utils/StepUtils'; -import ModelSort from './components/modelSort'; -import ModelAnswerSort from './components/modelAnswerSort'; interface IProps { annotation?: any; diff --git a/packages/lb-components/src/components/LLMToolView/types.ts b/packages/lb-components/src/components/LLMToolView/types.ts index b345c575..48cbcf52 100644 --- a/packages/lb-components/src/components/LLMToolView/types.ts +++ b/packages/lb-components/src/components/LLMToolView/types.ts @@ -82,7 +82,7 @@ export interface ITextList { // 单个答案 export interface IWaitAnswerSort { - title: number; + title: number | string; id: number; } @@ -98,7 +98,7 @@ export interface ITagVertexPoint { tr: IPoint; } export interface IAnswerSort { - title: number; + title: number | string; id: number; tagCenterPoint?: IPoint; tagVertexPoint?: ITagVertexPoint;