diff --git a/packages/lb-annotation/src/constant/tool.ts b/packages/lb-annotation/src/constant/tool.ts index 48dab6014..f0c89818c 100644 --- a/packages/lb-annotation/src/constant/tool.ts +++ b/packages/lb-annotation/src/constant/tool.ts @@ -71,6 +71,7 @@ export enum EToolName { LLM = 'LLMTool', /** NLP标注工具-大模型 */ NLP = 'NLPTool', + LLMMultiWheel = 'LLMMultiWheelTool', } export enum ECheckModel { @@ -110,6 +111,7 @@ export const TOOL_NAME: { [a: string]: string } = { [EToolName.Cuboid]: '立体框', [EToolName.LLM]: '大模型', [EToolName.NLP]: 'NLP标注', + [EToolName.LLMMultiWheel]: '大模型(多轮对话)', }; export const TOOL_NAME_EN: { [a: string]: string } = { @@ -136,6 +138,7 @@ export const TOOL_NAME_EN: { [a: string]: string } = { [EToolName.Cuboid]: 'Cuboid', [EToolName.LLM]: 'LLM', [EToolName.NLP]: 'NLP', + [EToolName.LLMMultiWheel]: 'LLMMultiWheelTool', }; export enum EDependPattern { diff --git a/packages/lb-components/src/components/LLMMultiWheelView/dialogView/index.tsx b/packages/lb-components/src/components/LLMMultiWheelView/dialogView/index.tsx new file mode 100644 index 000000000..9d203dcba --- /dev/null +++ b/packages/lb-components/src/components/LLMMultiWheelView/dialogView/index.tsx @@ -0,0 +1,88 @@ +import { getTextControlByConfig, RenderAnswer } from '@/components/LLMToolView/questionView'; +import { RenderQuestion } from '@/components/LLMToolView/questionView/components/header'; +import ImgView from '@/components/LLMToolView/questionView/components/imgView'; +import { ILLMMultiWheelToolConfig } from '@/components/LLMToolView/types'; +import useLLMMultiWheelStore from '@/store/LLMMultiWheel'; +import { classnames } from '@/utils'; +import { LLMMultiWheelViewCls } from '@/views/MainView/LLMMultiWheelLayout'; +import { Button } from 'antd'; +import React, { useContext, useEffect, useState } from 'react'; +// import { LLMMultiWheelViewCls } from '..'; + +interface IDialogViewProps { + id: number | string; + answerList: any; + question: any; + name?: string; + index: number; + isSelected: boolean; + answerIsImg: boolean; + questionIsImg: boolean; + LLMConfig?: ILLMMultiWheelToolConfig; +} + +const DialogView = (props: IDialogViewProps) => { + const { + id, + answerList, + question, + index, + name = '', + answerIsImg, + questionIsImg, + LLMConfig, + } = props; + const { dataFormatType, selectedID, setSelectedID } = useLLMMultiWheelStore(); + const order = index + 1; + const showName = name || `对话${order}`; + + return ( +
setSelectedID(id)} + className={classnames({ + dialog: true, + selected: id === selectedID, + })} + > +
+ {order} +
+
{showName}
+
(选中标注)
+
+
+
+ +
+ +
+
+
+ {answerList.map((item: any, index: number) => { + const isTextControl = getTextControlByConfig(item, LLMConfig); + return ( +
+ + {answerIsImg ? ( + + ) : ( + + )} +
+ ); + })} +
+
+ ); +}; + +export default DialogView; diff --git a/packages/lb-components/src/components/LLMMultiWheelView/index.tsx b/packages/lb-components/src/components/LLMMultiWheelView/index.tsx new file mode 100644 index 000000000..64ebb6c0d --- /dev/null +++ b/packages/lb-components/src/components/LLMMultiWheelView/index.tsx @@ -0,0 +1,74 @@ +import React, { useContext, useEffect, useState } from 'react'; + +import { connect } from 'react-redux'; +import { AppState } from '@/store'; +import { getStepConfig } from '@/store/annotation/reducer'; +import { getCurrentResultFromResultList } from '../LLMToolView/utils/data'; +import { jsonParser } from '@/utils'; +import { ILLMMultiWheelToolConfig } from '../LLMToolView/types'; +import { ELLMDataType, prefix } from '@/constant'; +import { Layout } from 'antd/es'; +import { LabelBeeContext } from '@/store/ctx'; +import QuestionView from '../LLMToolView/questionView'; +import DialogView from './dialogView'; +import { LLMMultiWheelViewCls } from '@/views/MainView/LLMMultiWheelLayout'; +import useLLMMultiWheelStore from '@/store/LLMMultiWheel'; + +interface IProps { + annotation?: any; +} + +const LLMMultiWheelView: React.FC = (props) => { + const { annotation } = props; + const { imgIndex, imgList, stepList, step, toolInstance } = annotation; + const [LLMConfig, setLLMConfig] = useState(); + const { setSelectedID } = useLLMMultiWheelStore(); + const [dialogList, setDialogList] = useState([]); + const questionIsImg = LLMConfig?.dataType?.prompt === ELLMDataType.Picture; + const answerIsImg = LLMConfig?.dataType?.response === ELLMDataType.Picture; + useEffect(() => { + if (!imgList[imgIndex]) { + return; + } + const currentData = imgList[imgIndex] ?? {}; + const dialogList = currentData?.questionList?.textList ?? []; + + setDialogList(dialogList); + if (dialogList?.length) { + setSelectedID(dialogList[0].id); + } + }, [imgIndex]); + + useEffect(() => { + if (stepList && step) { + const LLMStepConfig = getStepConfig(stepList, step)?.config; + setLLMConfig(jsonParser(LLMStepConfig)); + } + }, [stepList, step]); + + return ( +
+ {dialogList?.map((item: any, index) => ( + + ))} +
+ ); +}; + +const mapStateToProps = (state: AppState) => { + return { + annotation: state.annotation, + }; +}; + +export default connect(mapStateToProps, null, null, { context: LabelBeeContext })( + LLMMultiWheelView, +); diff --git a/packages/lb-components/src/components/LLMMultiWheelView/sidebar/index.tsx b/packages/lb-components/src/components/LLMMultiWheelView/sidebar/index.tsx new file mode 100644 index 000000000..df55aa4fb --- /dev/null +++ b/packages/lb-components/src/components/LLMMultiWheelView/sidebar/index.tsx @@ -0,0 +1,375 @@ +/* + * @file LLMMultiWheelView sidebar + * @author lihuaqi + * @createdate 2024-9-24 + */ + +import React, { useState, useEffect, useContext, useMemo } from 'react'; +import { LabelBeeContext, LLMContext } from '@/store/ctx'; +import { connect } from 'react-redux'; + +import { AppState } from '@/store'; +import { prefix } from '@/constant'; +import { + ILLMMultiWheelToolConfig, + IAnswerList, + IConfigUpdate, +} 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 { useTranslation } from 'react-i18next'; +import { useCustomToolInstance } from '@/hooks/annotation'; +import { isArray, isBoolean, isNumber, isObject, isString } from 'lodash'; +import { PageForward } from '@/store/annotation/actionCreators'; +import { cKeyCode, EToolName } from '@labelbee/lb-annotation'; +import { EmptyConfig, getLLMIsNoConfig, IAnnotationResult } from '@/components/LLMToolView/sidebar'; +import TextInputBox from '@/components/LLMToolView/sidebar/components/textInputBox'; +import { Button } from 'antd'; +import AnswerList from '@/components/LLMToolView/sidebar/components/answerList'; +import useLLMMultiWheelStore from '@/store/LLMMultiWheel'; +import StepUtils from '@/utils/StepUtils'; +import { + getCurrentResultFromResultList, + getRenderDataByResult, +} from '@/components/LLMToolView/utils/data'; +import { useMemoizedFn } from 'ahooks'; + +const EKeyCode = cKeyCode.default; + +const sidebarCls = `${prefix}-sidebar`; + +interface IProps { + annotation?: any; + dispatch: any; + checkMode?: boolean; +} + +interface ILLMAnnotationResultMap { + [id: string | number]: IAnnotationResult & { + id: string | number; + order: string; + }; +} + +const LLMMultiWheelToolSidebar = (props: IProps) => { + const { annotation, dispatch, checkMode } = props; + const { imgIndex, imgList, stepList, step, skipBeforePageTurning } = annotation; + const [LLMConfig, setLLMConfig] = useState(); + const { t } = useTranslation(); + const currentData = imgList[imgIndex] ?? {}; + const basicInfo = jsonParser(currentData?.result); + const { toolInstanceRef } = useCustomToolInstance({ basicInfo }); + const [valid, setValid] = useState(true); + const [annotationResultMap, setAnnotationResultMap] = useState({}); + const { selectedID } = useLLMMultiWheelStore(); + + const currentLLMAnnotationResult = useMemo(() => { + return annotationResultMap[selectedID]; + }, [selectedID, annotationResultMap]); + + const disabeledAll = !toolInstanceRef.current.valid || checkMode; + + useEffect(() => { + if (stepList && step) { + const LLMStepConfig = getStepConfig(stepList, step)?.config; + setLLMConfig(jsonParser(LLMStepConfig)); + } + }, [step, JSON.stringify(stepList)]); + + useEffect(() => { + if (!currentData || imgIndex === -1) { + return; + } + toolInstanceRef.current.setValid = onSetValid; + toolInstanceRef.current.clearResult = clearResult; + onSetValid(); + initResult(); + }, [imgIndex, LLMConfig, currentData?.id]); + + const clearResult = () => { + initResult(currentData?.questionList?.textList); + }; + + const onSetValid = (newValid?: boolean) => { + const valid = newValid ?? basicInfo.valid; + if (isBoolean(valid)) { + setValid(valid); + toolInstanceRef.current.valid = valid; + toolInstanceRef.current?.emit('validUpdated'); + } + }; + + const initResult = (initData?: any) => { + const currentStepInfo = StepUtils.getCurrentStepInfo(step, stepList); + const result: any = getCurrentResultFromResultList(currentData?.result, currentStepInfo.step); + + let sourceData = currentData?.questionList?.textList; + + if (result?.modelData?.length && toolInstanceRef.current.valid) { + sourceData = result?.modelData; + } + if (initData) { + sourceData = initData; + result.sort = []; + } + let tmpMap: ILLMAnnotationResultMap = {}; + + sourceData?.forEach((item: any, modelIndex: number) => { + const data = getRenderDataByResult(LLMConfig, { + ...item, + answerList: item?.answerList?.map((answer: any, index: number) => { + return { + ...answer, + order: `${index + 1}`, + }; + }), + }); + tmpMap[item.id] = { + ...data, + order: `${modelIndex + 1}`, + id: item.id, + }; + }); + + setAnnotationResultMap(tmpMap); + }; + + useEffect(() => { + setExportData(); + }, [annotationResultMap, valid]); + + useEffect(() => { + window.addEventListener('keydown', onKeyDown); + return () => { + window.removeEventListener('keydown', onKeyDown); + }; + }, []); + + const setExportData = useMemoizedFn(() => { + const modelData = currentData?.questionList?.textList?.map((item: any) => { + const nextValue = annotationResultMap[item.id] ?? {}; + return { + id: item.id, + answerList: nextValue.answerList, + }; + }); + + const result = { modelData }; + toolInstanceRef.current.exportData = () => { + return [[result], { valid }]; + }; + toolInstanceRef.current.currentPageResult = { + ...result, + toolName: EToolName.LLMMultiWheel, + valid, + }; + }); + + const onKeyDown = (e: KeyboardEvent) => { + if (e.ctrlKey && e.keyCode === EKeyCode.Enter) { + if (skipBeforePageTurning) { + skipBeforePageTurning(() => dispatch(PageForward())); + return; + } + dispatch(PageForward()); + } + }; + + const updateValue = useMemoizedFn(({ order, value, key }: IConfigUpdate) => { + const { answerList } = currentLLMAnnotationResult; + const newList = answerList?.map((i: IAnswerList) => { + if (i?.order === order) { + // text edit + if (key === 'textEdit' && isString(value)) { + return { ...i, newAnswer: value }; + } + if (isNumber(value)) { + return { ...i, score: value }; + } + if (isObject(value) && key) { + const obj = { [value?.key]: value.value }; + // @ts-ignore + const originData = i[key] ?? {}; + return { ...i, [key]: { ...originData, ...obj } }; + } + } + return i; + }); + + setAnnotationResultMap((prev) => { + return { + ...prev, + [selectedID]: { + ...currentLLMAnnotationResult, + answerList: newList, + }, + }; + }); + }); + + const { + indicatorScore = [], + indicatorDetermine = [], + isTextEdit, + dialogSort = false, + inputList = [], + tagInputListConfigurable, + } = LLMConfig || {}; + + const modelList = useMemo(() => { + if (!dialogSort) { + return []; + } + + return ( + currentData?.questionList?.textList?.map((item: any, index: number) => { + return { + ...item, + title: `${index + 1}`, + }; + }) ?? [] + ); + }, [currentData, dialogSort]); + + const isNoConfig = useMemo(() => { + return getLLMIsNoConfig(LLMConfig); + }, [LLMConfig]); + + if (isNoConfig) { + return ; + } + + const hasTagList = tagInputListConfigurable && inputList.filter((i) => !i.isOverall)?.length > 0; + const showAnwerList = + indicatorDetermine?.length > 0 || indicatorScore?.length > 0 || isTextEdit || hasTagList; + return ( +
+
+
+ {t('GlobalAnnotation')} +
+ + {/* 全局模型排序 */} + {dialogSort && ( + {}} + modelList={dialogSort ? modelList ?? [] : []} + title={t('SortConversationQuality')} + prefixId='model' + /> + )} + + {/* 文本输入 */} + {LLMConfig?.text && ( +
+ {}} + disabeledAll={disabeledAll} + /> +
+ )} + {/* 答案模型排序 */} + + {currentLLMAnnotationResult && ( + <> +
+ {t('QualifiedAnnotation')} +
+
+ +
+ 组:{currentLLMAnnotationResult.order} +
+
+
+ {showAnwerList && ( + + )} +
+ + )} +
+
+ {imgList?.length - 1 !== imgIndex && ( + + )} +
+
+ ); +}; + +const mapStateToProps = (state: AppState) => { + return { + annotation: state.annotation, + }; +}; + +export default connect(mapStateToProps, null, null, { context: LabelBeeContext })( + LLMMultiWheelToolSidebar, +); diff --git a/packages/lb-components/src/components/LLMToolView/questionView/components/header/index.tsx b/packages/lb-components/src/components/LLMToolView/questionView/components/header/index.tsx index 3dd65ac5f..0e21b7e44 100644 --- a/packages/lb-components/src/components/LLMToolView/questionView/components/header/index.tsx +++ b/packages/lb-components/src/components/LLMToolView/questionView/components/header/index.tsx @@ -32,7 +32,7 @@ interface IProps { const LLMViewCls = `${prefix}-LLMView`; -const Content = ({ +export const RenderQuestion = ({ question, dataFormatType, isImg, @@ -85,32 +85,45 @@ const Header = (props: IProps) => { }} > {t('Title')} - - { - setDataFormatType(e.target.value); - }} - > - {``} - - - - - - +
- +
); }; +export const ToggleDataFormatType = (props: { + dataFormatType: EDataFormatType; + setDataFormatType: (v: EDataFormatType) => void; +}) => { + const { dataFormatType, setDataFormatType } = props; + return ( + + { + setDataFormatType(e.target.value); + }} + > + {``} + + + + + + + ); +}; + export default Header; diff --git a/packages/lb-components/src/components/LLMToolView/questionView/index.tsx b/packages/lb-components/src/components/LLMToolView/questionView/index.tsx index 11516bdc9..b39d057e5 100644 --- a/packages/lb-components/src/components/LLMToolView/questionView/index.tsx +++ b/packages/lb-components/src/components/LLMToolView/questionView/index.tsx @@ -46,7 +46,7 @@ interface IProps { export const LLMViewCls = `${prefix}-LLMView`; -const RenderAnswer = ({ +export const RenderAnswer = ({ i, dataFormatType, isTextControl, @@ -68,6 +68,14 @@ const RenderAnswer = ({ return
{i?.newAnswer || i?.answer}
; }; +export const getTextControlByConfig = (result: IAnswerList, LLMConfig: any) => { + if (LLMConfig?.isTextEdit) { + const textEdit = LLMConfig?.textEdit || []; + return !!textEdit.filter((v: ITextList) => v?.title === result.order)[0]?.textControl; + } + return false; +}; + const QuestionView: React.FC = (props) => { const { hoverKey, @@ -91,18 +99,10 @@ const QuestionView: React.FC = (props) => { } }, []); - const getTextControlByConfig = (result: IAnswerList) => { - if (LLMConfig?.isTextEdit) { - const textEdit = LLMConfig?.textEdit || []; - return !!textEdit.filter((v: ITextList) => v?.title === result.order)[0]?.textControl; - } - return false; - }; - const textAnswer = (
{answerList.map((i: IAnswerList, index: number) => { - const isTextControl = getTextControlByConfig(i); + const isTextControl = getTextControlByConfig(i, LLMConfig); return (
{ const { t } = useTranslation(); return (
{t('Best')} -
+
-
+
{t('Worst')}
@@ -57,7 +62,18 @@ const Navigation = () => { const AnswerSort = (props: IProps) => { const [, forceUpdate] = useReducer((x) => x + 1, 0); - const { sortList, setSortList, waitSortList, disabeledAll } = props; + const { + sortList, + setSortList, + waitSortList, + disabeledAll, + header, + title, + prefixId = 'answer', + } = props; + + const waitBoxId = `${prefixId}-waitBox`; + const sortBoxId = `${prefixId}-sortBox`; const { setHoverKey } = useContext(LLMContext); const [activateDirection, setActivateDirection] = useState(undefined); const [targetTagKey, setTargetTagKey] = useState(undefined); @@ -165,7 +181,7 @@ const AnswerSort = (props: IProps) => { }; const formatSortList = () => { - const sortBox = document.getElementById('sortBox'); + const sortBox = document.getElementById(sortBoxId); if (sortBox?.childNodes) { let newSortList: IAnswerSort[][] = []; @@ -250,14 +266,14 @@ const AnswerSort = (props: IProps) => { let formatList = cloneDeep(sortList); tagIndex = formatList.findIndex((i: IAnswerSort[]) => i[0].id === Number(targetTagKey)); - if (target?.parentNode?.parentNode.id === 'sortBox') { + if (target?.parentNode?.parentNode.id === sortBoxId) { key = getAttributeIndex(target.parentNode.id); // 父级 const curKey = getAttributeIndex(target.id); // 拖动tag newList = formatList[~~key].filter((i: IAnswerSort) => i.id === ~~curKey); const removeIndex = formatList[~~key].findIndex((i: IAnswerSort) => i.id === ~~curKey); formatList[~~key].splice(removeIndex, 1); } - if (target?.parentNode.id === 'sortBox') { + if (target?.parentNode.id === sortBoxId) { if (!targetTagKey) { return; } @@ -270,7 +286,7 @@ const AnswerSort = (props: IProps) => { formatList.splice(oldIndex, 1); tagIndex = formatList.findIndex((i: IAnswerSort[]) => i[0].id === ~~targetTagKey); } - if (target.parentNode.id === 'waitBox') { + if (target.parentNode.id === waitBoxId) { key = getAttributeIndex(target.id); oldIndex = answers.findIndex((i: IWaitAnswerSort) => i.id === key); newList = [answers[oldIndex]]; @@ -298,29 +314,33 @@ const AnswerSort = (props: IProps) => { }; const getAttributeIndex = (str: string) => { - const index = str.indexOf('-'); + const index = str.indexOf(SEGMENTATION_OF_KEY); return Number(str.substring(index + 1, str.length)); }; + const headerContainer = header ?? ( +
+ {title ?? t('RankingQualityOfAnswers')} + {answers.length > 0 && ( + + {t('Unfinished')} + + )} +
+ ); + return ( -
-
- {t('RankingQualityOfAnswers')} - {answers.length > 0 && ( - - {t('Unfinished')} - - )} -
+
+ {headerContainer}
{t('ToBeSorted')} -
+
{answers.length > 0 && answers.map((i: IWaitAnswerSort) => singleAnswerItem({ item: i, - id: `waitBoxItem-${i?.id}`, + id: `waitBoxItem${SEGMENTATION_OF_KEY}${i?.id}`, operation: { onDrag: onDrag, onDragEnd: onDragEnd, @@ -330,15 +350,19 @@ const AnswerSort = (props: IProps) => {
-
+
{sortList.map((i: IAnswerSort[], index: number) => { if (i.length > 1) { return ( -
+
{i.map((item: IAnswerSort) => singleAnswerItem({ item, - id: `sortBoxItem-${item?.id}`, + id: `sortBoxItem${SEGMENTATION_OF_KEY}${item?.id}`, operation: { onDrag: onDrag, onDragEnd: onDragEnd, @@ -350,7 +374,7 @@ const AnswerSort = (props: IProps) => { } return singleAnswerItem({ item: i[0], - id: `sortBox-${i[0]?.id}`, + id: `${sortBoxId}${SEGMENTATION_OF_KEY}${i[0]?.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 new file mode 100644 index 000000000..80fd9a1ef --- /dev/null +++ b/packages/lb-components/src/components/LLMToolView/sidebar/components/modelAnswerSort/index.tsx @@ -0,0 +1,100 @@ +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 { useTranslation } from 'react-i18next'; + +interface IAnswerSort { + [key: string]: number[][]; +} + +interface IModelList { + id: number; + answerList: IAnswerList[]; +} + +interface IAnswerList { + id: string; + answer: string; +} + +interface IProps { + selectedSort?: IAnswerSort; + maxAnswerList: IAnswerList[]; + modelData: IModelList[]; +} + +const ModelAnswerSort = (props: IProps) => { + const { selectedSort, maxAnswerList, modelData } = props; + const [answerSortData, setAnswerSortData] = useState({ waitSorts: [], selecteds: selectedSort }); + const { t } = useTranslation(); + + const modelDatas = useMemo( + () => + modelData.map((i, itemIndex) => ({ + ...i, + title: itemIndex + 1, + })), + [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 })); + }; + + const exportSort = (id: string, value: number[][]) => { + // TODO 当拖动一个答案的时,多次调用 + // 因为answerSort组件useEffect(() => {formatSortList();}, [JSON.stringify(sortList)]) + }; + + return ( +
+
+ {t('RankingQualityOfAnswers')} + {answerSortData?.waitSorts?.length > 0 && ( + + {t('Unfinished')} + + )} +
+ {maxAnswerList.map((i: IAnswerList, index: number) => { + return ( +
+
{`${t('Answer')}${index + 1}`}
+ { + exportSort(i.id, value); + }} + modelList={getModelList(i.id)} + selectedSort={answerSortData.selecteds?.[i.id] ?? []} + header={''} + prefixId={`modelAnswer${index}`} + /> +
+ ); + })} +
+ ); +}; +export default 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 new file mode 100644 index 000000000..e3d7135a2 --- /dev/null +++ b/packages/lb-components/src/components/LLMToolView/sidebar/components/modelSort/index.tsx @@ -0,0 +1,75 @@ +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/components/textInputBox/index.tsx b/packages/lb-components/src/components/LLMToolView/sidebar/components/textInputBox/index.tsx index d91bdb2e0..ce6b97380 100644 --- a/packages/lb-components/src/components/LLMToolView/sidebar/components/textInputBox/index.tsx +++ b/packages/lb-components/src/components/LLMToolView/sidebar/components/textInputBox/index.tsx @@ -12,13 +12,12 @@ import LongText from '@/components/longText'; interface IProps { textAttribute: ITextList[]; disabeledAll?: boolean; - LLMConfig?: ILLMToolConfig; setText: (value: ITextList[]) => void; + textConfig: ITextList[]; } const TextInputBox = (props: IProps) => { - const { disabeledAll, LLMConfig, textAttribute, setText } = props; - const textConfig = LLMConfig?.text && isArray(LLMConfig.text) ? LLMConfig?.text : []; + const { disabeledAll, textConfig, textAttribute, setText } = props; const { TextArea } = Input; const [form] = Form.useForm(); const { t } = useTranslation(); diff --git a/packages/lb-components/src/components/LLMToolView/sidebar/index.tsx b/packages/lb-components/src/components/LLMToolView/sidebar/index.tsx index 1800a06f0..86de81ea8 100644 --- a/packages/lb-components/src/components/LLMToolView/sidebar/index.tsx +++ b/packages/lb-components/src/components/LLMToolView/sidebar/index.tsx @@ -4,7 +4,7 @@ import { Button, Empty } from 'antd'; import AnswerSort from './components/answerSort'; import { AppState } from '@/store'; import { connect } from 'react-redux'; -import { isBoolean, isNumber, isObject, isString } from 'lodash'; +import { isArray, isBoolean, isNumber, isObject, isString } from 'lodash'; import AnswerList from './components/answerList'; import { LabelBeeContext, LLMContext } from '@/store/ctx'; import { jsonParser } from '@/utils'; @@ -23,6 +23,7 @@ import { ITextList, ISelectedTags, IConfigUpdate, + ILLMMultiWheelToolConfig, } from '@/components/LLMToolView/types'; import { useTranslation } from 'react-i18next'; import { formatSort, getCurrentResultFromResultList, getRenderDataByResult } from '../utils/data'; @@ -30,13 +31,15 @@ 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; dispatch: any; checkMode?: boolean; } -interface IAnnotationResult { +export interface IAnnotationResult { newSort?: IAnswerSort[][]; waitSorts?: IWaitAnswerSort[]; answerList?: IAnswerList[]; @@ -47,6 +50,57 @@ interface IAnnotationResult { const EKeyCode = cKeyCode.default; const sidebarCls = `${prefix}-sidebar`; +export const EmptyConfig = () => { + const { t } = useTranslation(); + return ( +
+
+ {t('NoScoringScale')}} + imageStyle={{ + width: 200, + height: 200, + }} + image={} + /> +
+
+ ); +}; + +export const getLLMIsNoConfig = (LLMConfig?: ILLMMultiWheelToolConfig | ILLMToolConfig) => { + const { + indicatorScore = [], + indicatorDetermine = [], + text = [], + enableSort, + isTextEdit, + tagInputListConfigurable, + // @ts-ignore + dialogSort = false, + } = LLMConfig || {}; + + const hasIndicatorScore = + indicatorScore?.filter((i: IndicatorScore) => i.label && i.value && i.score)?.length > 0; + + const hasIndicatorDetermine = + indicatorDetermine?.filter((i: IndicatorDetermine) => i.label && i.value)?.length > 0; + const hasText = text?.length > 0; + const noConfig = !( + hasIndicatorScore || + hasIndicatorDetermine || + hasText || + enableSort || + isTextEdit || + tagInputListConfigurable || + dialogSort + ); + return noConfig; +}; + const LLMToolSidebar = (props: IProps) => { const { annotation, dispatch, checkMode } = props; const { imgIndex, imgList, stepList, step, skipBeforePageTurning } = annotation; @@ -181,52 +235,14 @@ const LLMToolSidebar = (props: IProps) => { setAnnotationResult({ ...annotationResult, answerList: newList || [] }); }; - const isNoConfig = () => { - const { - indicatorScore = [], - indicatorDetermine = [], - text = [], - enableSort, - isTextEdit, - tagInputListConfigurable, - } = LLMConfig || {}; - - const hasIndicatorScore = - indicatorScore?.filter((i: IndicatorScore) => i.label && i.value && i.score)?.length > 0; - - const hasIndicatorDetermine = - indicatorDetermine?.filter((i: IndicatorDetermine) => i.label && i.value)?.length > 0; - const hasText = text?.length > 0; - const noConfig = !( - hasIndicatorScore || - hasIndicatorDetermine || - hasText || - enableSort || - isTextEdit || - tagInputListConfigurable - ); - return noConfig; - }; + const isNoConfig = useMemo(() => { + return getLLMIsNoConfig(LLMConfig); + }, [LLMConfig]); - if (isNoConfig()) { - return ( -
-
- {t('NoScoringScale')}} - imageStyle={{ - width: 200, - height: 200, - }} - image={} - /> -
-
- ); + if (isNoConfig) { + return ; } + const { indicatorScore = [], indicatorDetermine = [], @@ -245,6 +261,7 @@ const LLMToolSidebar = (props: IProps) => {
{t('GlobalAnnotation')}
+ {enableSort && ( {
setAnnotationResult({ ...annotationResult, textAttribute: v })} disabeledAll={disabeledAll} /> diff --git a/packages/lb-components/src/components/LLMToolView/types.ts b/packages/lb-components/src/components/LLMToolView/types.ts index abb9069d7..b345c5755 100644 --- a/packages/lb-components/src/components/LLMToolView/types.ts +++ b/packages/lb-components/src/components/LLMToolView/types.ts @@ -62,6 +62,11 @@ export interface ILLMToolConfig { inputList?: IInputList[]; } +export interface ILLMMultiWheelToolConfig + extends Omit { + dialogSort?: boolean; // 对话排序 +} + // LLM文本 export interface ITextList { textId?: string; @@ -104,8 +109,8 @@ export interface ILLMBoxResult { id: number; sort?: number[][]; textAttribute?: ITextList[]; - valid:boolean; - tagList?:ISelectedTags + valid: boolean; + tagList?: ISelectedTags; } export interface IInputList { diff --git a/packages/lb-components/src/data/enums/ToolType.ts b/packages/lb-components/src/data/enums/ToolType.ts index 17c6d906b..7de7dab0f 100644 --- a/packages/lb-components/src/data/enums/ToolType.ts +++ b/packages/lb-components/src/data/enums/ToolType.ts @@ -46,6 +46,7 @@ export enum EToolName { PointCloudPolygon = 'pointCloudPolygon', LLM = 'LLMTool', NLP = 'NLPTool', + LLMMultiWheel = "LLMMultiWheelTool" } // 文本标注类型 diff --git a/packages/lb-components/src/index.scss b/packages/lb-components/src/index.scss index 3bfba5c05..b05c71f8e 100644 --- a/packages/lb-components/src/index.scss +++ b/packages/lb-components/src/index.scss @@ -829,7 +829,7 @@ $hotkey-container-padding: 7px; -ms-user-select: none; user-select: none; - .generalOperation-col{ + .generalOperation-col { display: flex; justify-content: center; } @@ -1280,7 +1280,6 @@ $hotkey-container-padding: 7px; .ant-popover-inner-content .ant-popover-message { align-items: initial; } - } .#{$prefix}-annotated-attribute { @@ -2204,18 +2203,18 @@ $ptToolHeight: 40px; .#{$prefix}-NLPView-question { flex: 1; overflow: hidden; - &-title{ + &-title { font-weight: 500; font-size: 18px; margin-bottom: 24px; } - &-content{ + &-content { font-size: 14px; font-weight: 400; background-color: #f5f5f5; border-radius: 4px; padding: 8px; - &-mask{ + &-mask { position: absolute; left: 0px; top: 0px; @@ -2227,26 +2226,26 @@ $ptToolHeight: 40px; } } -.#{$prefix}-sidebar__content__NLPList{ - display:flex; - flex-direction:column; - &__item{ +.#{$prefix}-sidebar__content__NLPList { + display: flex; + flex-direction: column; + &__item { display: flex; align-items: center; - cursor:pointer; + cursor: pointer; - .#{$prefix}-sidebar-pop-remove{ + .#{$prefix}-sidebar-pop-remove { margin: 0px 16px; display: none; } - &:hover{ - .#{$prefix}-sidebar-pop-remove{ + &:hover { + .#{$prefix}-sidebar-pop-remove { display: block; } } - &__text{ + &__text { font-weight: 400; font-size: 12px; line-height: 20px; @@ -2254,9 +2253,9 @@ $ptToolHeight: 40px; padding: 16px; width: 100%; } - &__active{ + &__active { background-color: #eeefff; - &__text{ + &__text { color: #666fff; } } @@ -2391,3 +2390,54 @@ $predictTrackingPrefix: #{$prefix}-point-cloud-predict-tracking; .bee-audio-combined { cursor: url('./assets/annotation/audio/combine.svg') 10 12, default; } + +/** LLMMultiWheel style */ + +.#{$prefix}-LLMMultiWheelView { + display: flex; + flex: auto; + flex-direction: column; + overflow: hidden; + background-color: #fff; +} + +.#{$prefix}-LLMMultiWheelView-container { + flex: auto; + display: flex; + overflow: hidden; + .dialog { + min-width: 50%; + padding: 8px; + border: 1px solid transparent; + overflow: auto; + &.selected { + border-color: #69b1ff; + } + .header { + position: relative; + .order { + position: absolute; + left: 0; + top: 0; + width: 32px; + height: 32px; + line-height: 32px; + text-align: center; + background: #d4cbcb; + border-radius: 4px; + } + .name { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + .show-name { + font-size: 16px; + } + .tips { + color: #d4cbcb; + } + } + } + } +} diff --git a/packages/lb-components/src/store/LLMMultiWheel/index.ts b/packages/lb-components/src/store/LLMMultiWheel/index.ts new file mode 100644 index 000000000..8e5fd3f5d --- /dev/null +++ b/packages/lb-components/src/store/LLMMultiWheel/index.ts @@ -0,0 +1,34 @@ +import { EDataFormatType } from '@/constant'; +import { create } from 'zustand'; +import React from 'react'; +interface Store { + dataFormatType: EDataFormatType; + setDataFormatType: (dataFormatType: EDataFormatType) => void; + selectedID: React.Key; + setSelectedID: (selectedID: React.Key) => void; + highlightIDs: number[]; + setHighlightIDs: (highlightIDs: number[]) => void; + selectedIDs: string[]; + setSelectedIDs: (selectedIDs: string[]) => void; + rectRotateSensitivity: number; + setRectRotateSensitivity: (sensitivity: number) => void; +} + +const useLLMMultiWheelStore = create((set) => ({ + dataFormatType: EDataFormatType.Default, + setDataFormatType: (dataFormatType) => set((state) => ({ dataFormatType })), + selectedID: '', + setSelectedID: (selectedID) => set((state) => ({ selectedID })), + highlightIDs: [], + setHighlightIDs: (highlightIDs) => set((state) => ({ highlightIDs })), + selectedIDs: [], + setSelectedIDs: (selectedIDs) => + set((state) => { + return { selectedIDs }; + }), + rectRotateSensitivity: 2, + setRectRotateSensitivity: (sensitivity) => + set((state) => ({ rectRotateSensitivity: sensitivity })), +})); + +export default useLLMMultiWheelStore; diff --git a/packages/lb-components/src/store/annotation/reducer.ts b/packages/lb-components/src/store/annotation/reducer.ts index dde491d96..4b1197a56 100644 --- a/packages/lb-components/src/store/annotation/reducer.ts +++ b/packages/lb-components/src/store/annotation/reducer.ts @@ -83,7 +83,11 @@ const updateToolInstance = (annotation: AnnotationState, imgNode: HTMLImageEleme return; } - if ([EToolName.LLM as string, EToolName.NLP as string].includes(stepConfig?.tool)) { + if ( + [EToolName.LLM as string, EToolName.NLP as string, EToolName.LLMMultiWheel].includes( + stepConfig?.tool, + ) + ) { return; } @@ -117,7 +121,10 @@ export const LoadFileAndFileData = const { stepList, step } = getState().annotation; const currentIsVideo = StepUtils.currentToolIsVideo(step, stepList); const currentIsPointCloud = StepUtils.currentToolIsPointCloud(step, stepList); - const currentIsLLM = StepUtils.getCurrentStepInfo(step, stepList)?.tool === EToolName.LLM; + const currentIsLLM = [EToolName.LLM, EToolName.LLMMultiWheel].includes( + // @ts-ignore + StepUtils.getCurrentStepInfo(step, stepList)?.tool, + ); const currentIsNLP = StepUtils.getCurrentStepInfo(step, stepList)?.tool === EToolName.NLP; const currentIsAudio = StepUtils.currentToolIsAudio(step, stepList); diff --git a/packages/lb-components/src/store/ctx.ts b/packages/lb-components/src/store/ctx.ts index 39f77a68b..c01ccdff8 100644 --- a/packages/lb-components/src/store/ctx.ts +++ b/packages/lb-components/src/store/ctx.ts @@ -10,6 +10,14 @@ interface ILLMContext { setModelAPIResponse: React.Dispatch>; setNewAnswerList: (value: IAnswerList[]) => void; } + +interface ILLMMultiWheelContext { + hoverKey: number; + setHoverKey: (value: number) => void; + selectKey: number; + setSelectKey: (value: number) => void; +} + interface INLPContext { highlightKey: string; setHighlightKey: (value: string) => void; @@ -30,3 +38,10 @@ export const NLPContext = React.createContext({ highlightKey: '', setHighlightKey: () => {}, }); + +export const LLMMultiWheelContext = React.createContext({ + hoverKey: -1, + setHoverKey: () => {}, + selectKey: 1, + setSelectKey: () => {}, +}); diff --git a/packages/lb-components/src/types/main.d.ts b/packages/lb-components/src/types/main.d.ts index 4abe29f2d..561049cb0 100644 --- a/packages/lb-components/src/types/main.d.ts +++ b/packages/lb-components/src/types/main.d.ts @@ -45,6 +45,7 @@ export type Sider = ({ horizontal: React.ReactNode; scribbleSidebar: React.ReactNode; LLMSidebar: React.ReactNode; + LLMMultiWheelSidebar: React.ReactNode; NLPSidebar: React.ReactNode; videoClipSidebar: React.ReactNode; NLPSidebar: React.ReactNode; diff --git a/packages/lb-components/src/views/MainView/LLMMultiWheelLayout/index.tsx b/packages/lb-components/src/views/MainView/LLMMultiWheelLayout/index.tsx new file mode 100644 index 000000000..a12fcad69 --- /dev/null +++ b/packages/lb-components/src/views/MainView/LLMMultiWheelLayout/index.tsx @@ -0,0 +1,65 @@ +import { AppProps } from '@/App'; +import { prefix } from '@/constant'; +import { Layout } from 'antd/es'; +import _ from 'lodash'; +import React, { useState, useMemo } from 'react'; +import Sidebar from '../sidebar'; +import ToolFooter from '../toolFooter'; +import { getClassName } from '@/utils/dom'; +import { classnames } from '@/utils'; +import { LLMContext, LLMMultiWheelContext } from '@/store/ctx'; +import LLMToolView from '@/components/LLMToolView'; +import { IModelAPIAnswer, IAnswerList } from '@/components/LLMToolView/types'; +import useLLMMultiWheelStore from '@/store/LLMMultiWheel'; +import { ToggleDataFormatType } from '@/components/LLMToolView/questionView/components/header'; +import LLMMultiWheelView from '@/components/LLMMultiWheelView'; + +export const LLMMultiWheelViewCls = `${prefix}-LLMMultiWheelView`; + +interface IProps { + path: string; + loading: boolean; +} + +const { Sider, Content } = Layout; +const layoutCls = `${prefix}-layout`; + +const LLMMultiWheelLayout: React.FC = (props) => { + const { dataFormatType, setDataFormatType } = useLLMMultiWheelStore(); + + return ( + + {props?.leftSider} + +
+
+ +
+ + +
+ + +
+ + + {props.drawLayerSlot?.({})} + +
+ ); +}; + +export default LLMMultiWheelLayout; diff --git a/packages/lb-components/src/views/MainView/index.tsx b/packages/lb-components/src/views/MainView/index.tsx index 46ffce8ac..2462bbb20 100644 --- a/packages/lb-components/src/views/MainView/index.tsx +++ b/packages/lb-components/src/views/MainView/index.tsx @@ -28,6 +28,7 @@ import AudioAnnotate from '@/components/audioAnnotate'; import { LoadingOutlined } from '@ant-design/icons'; import { useTranslation } from 'react-i18next'; import { EPointCloudName } from '@labelbee/lb-annotation'; +import LLMMultiWheelLayout from './LLMMultiWheelLayout'; interface IProps { path: string; @@ -91,8 +92,12 @@ const ViewportProviderLayout = (props: AppProps & IProps & { children: any }) => const { t } = useTranslation(); const { stepList, step } = props; const currentToolName = getStepConfig(stepList, step)?.tool; - const hasLangNode = ![EToolName.LLM, EToolName.NLP].includes(currentToolName); - const hasHeaderOption = ![EToolName.LLM, EToolName.NLP].includes(currentToolName); + const hasLangNode = ![EToolName.LLM, EToolName.NLP, EToolName.LLMMultiWheel].includes( + currentToolName, + ); + const hasHeaderOption = ![EToolName.LLM, EToolName.NLP, EToolName.LLMMultiWheel].includes( + currentToolName, + ); const hasPredictTrackingIcon = [EPointCloudName.PointCloud].includes(currentToolName); return ( @@ -128,8 +133,16 @@ const MainView: React.FC = (props) => { const currentToolName = getStepConfig(stepList, step)?.tool; const isLLMTool = EToolName.LLM === currentToolName; const isNLPTool = EToolName.NLP === currentToolName; + const isLLMMultiWheelTool = EToolName.LLMMultiWheel === currentToolName; const isAudioTool = ToolUtils.isAudioTool(currentToolName); + if (isLLMMultiWheelTool) { + return ( + + + + ); + } if (isLLMTool) { return ( diff --git a/packages/lb-components/src/views/MainView/sidebar/index.tsx b/packages/lb-components/src/views/MainView/sidebar/index.tsx index cd4ef4be2..0e8451e5f 100644 --- a/packages/lb-components/src/views/MainView/sidebar/index.tsx +++ b/packages/lb-components/src/views/MainView/sidebar/index.tsx @@ -23,6 +23,7 @@ import { Tabs } from 'antd'; import { classnames } from '@/utils'; import menuFoldSvg from '@/assets/annotation/common/icon_menu_fold.svg'; import LLMToolSidebar from '@/components/LLMToolView/sidebar'; +import LLMMultiWheelToolSidebar from '@/components/LLMMultiWheelView/sidebar'; import NLPToolSidebar from './NLPSidebar'; import VideoClipAnnotatedList from '@/components/videoAnnotate/videoClipTool/components/annotatedList'; import { IOperationConfig } from './GeneralOperation/ActionsConfirm'; @@ -130,6 +131,7 @@ const Sidebar: React.FC = ({ const videoClipSidebar = ; const LLMSidebar = ; + const LLMMultiWheelSidebar = ; const NLPSidebar = ; const horizontal =
; @@ -157,6 +159,7 @@ const Sidebar: React.FC = ({ pointCloudOperation, scribbleSidebar, LLMSidebar, + LLMMultiWheelSidebar, videoClipSidebar, NLPSidebar, })} diff --git a/packages/lb-demo/src/App.js b/packages/lb-demo/src/App.js index 889b36320..bf7417077 100644 --- a/packages/lb-demo/src/App.js +++ b/packages/lb-demo/src/App.js @@ -25,6 +25,7 @@ import car1 from './mock/cuboidImages/1.png'; import { EToolName } from '@labelbee/lb-annotation'; import { LLMToolQa, LLMToolResult } from './mock/LLMTool'; import { textData, NLPToolResult } from './mock/NLPTool'; +import { LLMMultiWheelToolQa, LLMMultiWheelToolResult } from './mock/LLMMultiWheelTool'; const App = () => { const tool = qs.parse(window.location.search, { @@ -73,9 +74,18 @@ const App = () => { }, })); } + if (EToolName.LLMMultiWheelTool === tool) { + return srcList.map((url, i) => ({ + ...extraData, + id: i + 1, + url, + result: JSON.stringify(LLMMultiWheelToolResult.step_1.result), + modelList: LLMMultiWheelToolQa, + })); + } if (EToolName.NLP === tool) { - return srcList.map((url, i) => ({ + return srcList.map((url, i) => ({ ...extraData, id: i + 1, url, diff --git a/packages/lb-demo/src/mock/LLMMultiWheelTool.js b/packages/lb-demo/src/mock/LLMMultiWheelTool.js new file mode 100644 index 000000000..8b40c6409 --- /dev/null +++ b/packages/lb-demo/src/mock/LLMMultiWheelTool.js @@ -0,0 +1,93 @@ +export const LLMMultiWheelToolResult = { + step_1: { + dataSourceStep: 0, + result: + { + sort: [ + [1], [2] + ], + answerSort: { + A1: [ + [2], [1] + ], + + A2: [ + [1], [2] + ] + }, + textAttribute: [{ + isLaText: true, + max: 22, + min: 1, + textId: "Ok", + tip: "提示语", + title: "标题", + value: " $$\\frac{a}{b}$$ " + }], + modelData: [ + { + id: 1, + sort: [], + answerList: [ + { + id: 'A1', + answer: '金百味1', + }, + { + id: 'A2', + answer: '全刀手1', + }, + ], + }, + { + id: 2, + sort: [], + answerList: [ + { + id: 'A1', + answer: '金百味', + }, + { + id: 'A2', + answer: '全刀手', + }, + ], + }, + ], + }, + toolName: 'LLMMultiWheelTool', + }, +}; + +export const LLMMultiWheelToolQa = [ + { + id: 1, + question: '今天晚上吃什么?', + name: 'Orl_answer', + answerList: [ + { + id: 'A1', + answer: '金百味1', + }, + { + id: 'A2', + answer: '全刀手1', + }, + ], + }, + { + id: 2, + question: '明天中午吃什么?', + name: 'GPT_answer', + answerList: [ + { + id: 'A1', + answer: '金百味', + }, + { + id: 'A2', + answer: '全刀手', + }, + ], + }, +]; diff --git a/packages/lb-demo/src/mock/index.js b/packages/lb-demo/src/mock/index.js index ff893d1e8..89bc6137b 100644 --- a/packages/lb-demo/src/mock/index.js +++ b/packages/lb-demo/src/mock/index.js @@ -4,6 +4,7 @@ import img3 from './images/20.jpg'; import img4 from './images/66.jpg'; import { pointCloudResult1 } from './pointCloud'; import { LLMToolResult } from './LLMTool'; +import { LLMMultiWheelToolResult } from './LLMMultiWheelTool'; import { NLPToolResult } from './NLPTool'; // audios @@ -134,6 +135,10 @@ export const getMockResult = (tool) => { return LLMToolResult; } + if (tool === 'LLMMultiWheelTool') { + return LLMMultiWheelToolResult; + } + if (tool === 'NLPTool') { return NLPToolResult; } diff --git a/packages/lb-demo/src/mock/taskConfig.js b/packages/lb-demo/src/mock/taskConfig.js index 55e5b8d1c..347900bde 100644 --- a/packages/lb-demo/src/mock/taskConfig.js +++ b/packages/lb-demo/src/mock/taskConfig.js @@ -312,6 +312,52 @@ const LLMToolConfig = { ], }; +const LLMMultiWheelToolConfig = { + enableSort: true, // 开启答案排序 + enableTextAttribute: true, // 文本标注 + score: 7, // 答案评分 + indicatorScore: [ + { label: '可读性', value: 'readability', text: '阅读起来是否顺畅', score: 10 }, + { label: '不可读性', value: 'unReadability', text: '偶是基督教精神', score: 10 }, + ], // 指标评分 + indicatorDetermine: [ + { label: '包含敏感信息', value: 'sensitiveInfo' }, + { label: '包含敏感信息2', value: 'sensitiveInfo2' }, + ], // 指标判断 + dataType: { + prompt: 'picture', + response: 'text', + }, + isTextEdit: true, // 是否打开文本编辑 + textEdit: [ + { + title: 1, + min: 11, + max: 1000, + isFillAnswer: true, // 是否填充答案 + isLaText: true, // 是否打开LaTex编辑 + textControl: true, // 文本对照 + }, + { + title: 2, + min: 10, + isFillAnswer: false, // 是否填充答案 + textControl: true, // 文本对照 + }, + { + title: 3, + max: 100, + isFillAnswer: true, // 是否填充答案 + textControl: false, // 文本对照 + }, + { + title: 4, + isFillAnswer: false, // 是否填充答案 + textControl: false, // 文本对照 + }, + ], +}; + const NLPToolConfig = { indicatorDetermine: [ { @@ -482,6 +528,10 @@ export const getConfig = (tool) => { return LLMToolConfig; } + if (tool === EToolName.LLMMultiWheel) { + return LLMMultiWheelToolConfig; + } + if (tool === EToolName.NLP) { return NLPToolConfig; } diff --git a/packages/lb-utils/src/i18n/resources.json b/packages/lb-utils/src/i18n/resources.json index a1571974f..dfb16741f 100644 --- a/packages/lb-utils/src/i18n/resources.json +++ b/packages/lb-utils/src/i18n/resources.json @@ -375,7 +375,8 @@ "SelectedRect": "Selected Rect", "OnlyLoadTheFirstFramePreAnnotation": "Only load the first frame pre annotation", "SelectBoxToDisplayIndependently": "Select box to display independently", - "SelectBoxSwitchTips": "After turning on the switch, select the box in the top view, and the image view will only display the corresponding 2D box, making it easier to view the corresponding relationship in the top view" + "SelectBoxSwitchTips": "After turning on the switch, select the box in the top view, and the image view will only display the corresponding 2D box, making it easier to view the corresponding relationship in the top view", + "SortConversationQuality": "Please rank the quality of each conversation" }, "cn": { "TextInput": "文本输入", @@ -753,6 +754,7 @@ "SelectedRect": "选中框体", "OnlyLoadTheFirstFramePreAnnotation": "仅载入第一帧预标注", "SelectBoxToDisplayIndependently": "选中框独立显示", - "SelectBoxSwitchTips": "开启开关后,选中俯视图的框体,图片视图仅显示对应的2D框体,便于查看俯视图的对应关系" + "SelectBoxSwitchTips": "开启开关后,选中俯视图的框体,图片视图仅显示对应的2D框体,便于查看俯视图的对应关系", + "SortConversationQuality": "请对每组对话的质量进行排序" } }