From 5a51756bfade9fd42fa9a6e0a79990b77b0f271a Mon Sep 17 00:00:00 2001 From: Sara H Date: Wed, 10 Jul 2024 09:34:37 -0500 Subject: [PATCH 01/11] Create SelectMultipleTextMultipleTags --- .../SelectMultipleTextMultipleTags.tsx | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 frontends/web/src/new_front/components/CreateSamples/CreateSamples/AnnotationInterfaces/Contexts/SelectMultipleTextMultipleTags.tsx diff --git a/frontends/web/src/new_front/components/CreateSamples/CreateSamples/AnnotationInterfaces/Contexts/SelectMultipleTextMultipleTags.tsx b/frontends/web/src/new_front/components/CreateSamples/CreateSamples/AnnotationInterfaces/Contexts/SelectMultipleTextMultipleTags.tsx new file mode 100644 index 00000000..d0d89f77 --- /dev/null +++ b/frontends/web/src/new_front/components/CreateSamples/CreateSamples/AnnotationInterfaces/Contexts/SelectMultipleTextMultipleTags.tsx @@ -0,0 +1,54 @@ +import AnnotationInstruction from "new_front/components/OverlayInstructions/Annotation"; +import { CreateInterfaceContext } from "new_front/context/CreateInterface/Context"; +import { ContextConfigType } from "new_front/types/createSamples/createSamples/annotationContext"; +import { ContextAnnotationFactoryType } from "new_front/types/createSamples/createSamples/annotationFactory"; +import React, { FC, useEffect, useState, useContext } from "react"; +import { TokenAnnotator } from "react-text-annotate"; + +const SelectMultipleTextMultipleTags: FC< + ContextAnnotationFactoryType & ContextConfigType +> = ({ field_names_for_the_model, context, instruction, metadata }) => { + const { updateModelInputs } = useContext(CreateInterfaceContext); + + useEffect(() => { + updateModelInputs( + { + [field_names_for_the_model.context]: context.context, + }, + metadata.context + ); + }, []); + + const [selectionInfo, setSelectionInfo] = useState([] as any); + + const handleChange = (value: any) => { + setSelectionInfo(value); + updateModelInputs( + { + [field_names_for_the_model.answer ?? "selectable_text"]: context.context + .split(" ") + .slice(value[0].start, value[0].end) + .join(" "), + }, + metadata.answer + ); + }; + + return ( + +
+

Esto si se estΓ‘ mostrando

+ handleChange(value)} + /> +
+
+ ); +}; + +export default SelectMultipleTextMultipleTags; From e02a49d19170b6e9a935ffba2d709209b1a41adc Mon Sep 17 00:00:00 2001 From: Sara H Date: Fri, 12 Jul 2024 18:21:41 -0500 Subject: [PATCH 02/11] Multiple colors and tags working allong with dropdown search --- .../SelectMultipleTextMultipleTags.tsx | 154 ++++++++++++++++-- .../components/Inputs/DropdownSearch.tsx | 92 +++++++++++ 2 files changed, 231 insertions(+), 15 deletions(-) create mode 100644 frontends/web/src/new_front/components/Inputs/DropdownSearch.tsx diff --git a/frontends/web/src/new_front/components/CreateSamples/CreateSamples/AnnotationInterfaces/Contexts/SelectMultipleTextMultipleTags.tsx b/frontends/web/src/new_front/components/CreateSamples/CreateSamples/AnnotationInterfaces/Contexts/SelectMultipleTextMultipleTags.tsx index d0d89f77..45107aef 100644 --- a/frontends/web/src/new_front/components/CreateSamples/CreateSamples/AnnotationInterfaces/Contexts/SelectMultipleTextMultipleTags.tsx +++ b/frontends/web/src/new_front/components/CreateSamples/CreateSamples/AnnotationInterfaces/Contexts/SelectMultipleTextMultipleTags.tsx @@ -4,11 +4,61 @@ import { ContextConfigType } from "new_front/types/createSamples/createSamples/a import { ContextAnnotationFactoryType } from "new_front/types/createSamples/createSamples/annotationFactory"; import React, { FC, useEffect, useState, useContext } from "react"; import { TokenAnnotator } from "react-text-annotate"; +import DropdownSearch from "new_front/components/Inputs/DropdownSearch"; + +import languages from "./BCP47Temp"; + +type MultipleTagsTypes = { + preselectedTag?: string; +}; + +const text = + 'On 31 January 2014, it was reported that Neesonwould workwith director Martin Scorsese again in an adaptation of the novel "Silence". Neeson had a supporting role as the henchman Bad Cop/Good Cop in the animated film "The Lego Movie", which was a critical and commercial success. Neeson later played Bill Marks in the 2014 action film Non-Stop. The film was releasedon 28 February 2014. He also appeared, uncredited, as God in the BBC2 series "Rev.". Neeson stars in the 2014 film "A Walk Among the Tombstones", an adaption of the best-selling novel of the same name, in which he plays former cop Matthew Scudder, a detective hired to hunt the killers of a drug dealer\'s wife.'; const SelectMultipleTextMultipleTags: FC< - ContextAnnotationFactoryType & ContextConfigType -> = ({ field_names_for_the_model, context, instruction, metadata }) => { + ContextAnnotationFactoryType & ContextConfigType & MultipleTagsTypes +> = ({ + field_names_for_the_model, + context, + instruction, + metadata, + preselectedTag, +}) => { const { updateModelInputs } = useContext(CreateInterfaceContext); + const [selectionInfo, setSelectionInfo] = useState([]); + const [tags, setTags] = useState([]); + const [tagSelection, setTagSelection] = useState(preselectedTag || null); + const [tagColors, setTagColors] = useState(undefined); + + const generateRandomColor = (): string => { + const getRelativeLuminance = (r: number, g: number, b: number): number => { + const rs = r / 255; + const gs = g / 255; + const bs = b / 255; + + const rL = + rs <= 0.03928 ? rs / 12.92 : Math.pow((rs + 0.055) / 1.055, 2.4); + const gL = + gs <= 0.03928 ? gs / 12.92 : Math.pow((gs + 0.055) / 1.055, 2.4); + const bL = + bs <= 0.03928 ? bs / 12.92 : Math.pow((bs + 0.055) / 1.055, 2.4); + + return 0.2126 * rL + 0.7152 * gL + 0.0722 * bL; + }; + let color; + let luminance; + + do { + const r = Math.floor(Math.random() * 256); + const g = Math.floor(Math.random() * 256); + const b = Math.floor(Math.random() * 256); + + color = `rgb(${r}, ${g}, ${b})`; + luminance = getRelativeLuminance(r, g, b); + } while (luminance < 0.7); // Adjust the threshold as needed + + return color; + }; useEffect(() => { updateModelInputs( @@ -17,13 +67,28 @@ const SelectMultipleTextMultipleTags: FC< }, metadata.context ); - }, []); - const [selectionInfo, setSelectionInfo] = useState([] as any); + const tempTags: any[] = []; + const colors: string[] = []; + const tempTagColors: any = {}; + languages.forEach((tag: string) => { + let color = generateRandomColor(); + while (colors.includes(color)) { + color = generateRandomColor(); + } + colors.push(color); + tempTags.push({ value: tag, color: color }); + tempTagColors[tag] = color; + }); + setTagSelection(tempTags.find((tag) => tag.value === preselectedTag)); + setTags(tempTags); + setTagColors(tempTagColors); + }, []); const handleChange = (value: any) => { setSelectionInfo(value); - updateModelInputs( + console.log("seleccion", value); + /* updateModelInputs( { [field_names_for_the_model.answer ?? "selectable_text"]: context.context .split(" ") @@ -31,22 +96,81 @@ const SelectMultipleTextMultipleTags: FC< .join(" "), }, metadata.answer - ); + ); */ }; return ( -
-

Esto si se estΓ‘ mostrando

- handleChange(value)} - /> -
+ <> +
+ handleChange(value)} + getSpan={(span) => ({ + ...span, + tag: tagSelection, + color: tagColors[tagSelection], + })} + renderMark={(props) => ( + + props.onClick({ + start: props.start, + end: props.end, + tag: props.tag, + color: props.color, + content: props.content, + }) + } + style={{ + padding: ".2em .3em", + margin: "0 .25em", + lineHeight: "1", + display: "inline-block", + borderRadius: ".25em", + background: tagColors[props.tag], + }} + > + {props.content}{" "} + + {" "} + {props.tag} + + + )} + /> +
+
+ +
+
); }; diff --git a/frontends/web/src/new_front/components/Inputs/DropdownSearch.tsx b/frontends/web/src/new_front/components/Inputs/DropdownSearch.tsx new file mode 100644 index 00000000..adba5e73 --- /dev/null +++ b/frontends/web/src/new_front/components/Inputs/DropdownSearch.tsx @@ -0,0 +1,92 @@ +import React, { FC, useState } from "react"; + +type DropdownSearchProps = { + options: any[]; + value: string; + onChange: (prompt: any) => void; + disabled?: boolean; +}; + +const DropdownSearch: FC = ({ + options, + value, + onChange, + disabled = false, +}) => { + const [open, setOpen] = useState(false); + const [searchTerm, setSearchTerm] = useState(""); + + const filteredOptions = options.filter((option) => + option.value.toLowerCase().includes(searchTerm.toLowerCase()) + ); + + const handleOnClick = (option: any) => { + setOpen(false); + setSearchTerm(""); + onChange(option.value); + }; + + return ( +
+
+ +
+ +
+
+ setSearchTerm(e.target.value)} + /> + {filteredOptions.map((option, key) => ( + + ))} +
+
+
+ ); +}; + +export default DropdownSearch; From 87bd3f8e56358066fbbbf64f178a71e90db78aa2 Mon Sep 17 00:00:00 2001 From: Sara H Date: Mon, 22 Jul 2024 18:32:12 -0500 Subject: [PATCH 03/11] Extract random color function from component --- .../SelectMultipleTextMultipleTags.tsx | 288 +++++++++++------- .../createSamples/annotationContext.ts | 1 + .../createSamples/configurationTask.ts | 2 +- .../functions/GenerateRandomLightColor.tsx | 26 ++ 4 files changed, 206 insertions(+), 111 deletions(-) create mode 100644 frontends/web/src/new_front/utils/helpers/functions/GenerateRandomLightColor.tsx diff --git a/frontends/web/src/new_front/components/CreateSamples/CreateSamples/AnnotationInterfaces/Contexts/SelectMultipleTextMultipleTags.tsx b/frontends/web/src/new_front/components/CreateSamples/CreateSamples/AnnotationInterfaces/Contexts/SelectMultipleTextMultipleTags.tsx index 45107aef..cd008268 100644 --- a/frontends/web/src/new_front/components/CreateSamples/CreateSamples/AnnotationInterfaces/Contexts/SelectMultipleTextMultipleTags.tsx +++ b/frontends/web/src/new_front/components/CreateSamples/CreateSamples/AnnotationInterfaces/Contexts/SelectMultipleTextMultipleTags.tsx @@ -1,64 +1,36 @@ -import AnnotationInstruction from "new_front/components/OverlayInstructions/Annotation"; -import { CreateInterfaceContext } from "new_front/context/CreateInterface/Context"; -import { ContextConfigType } from "new_front/types/createSamples/createSamples/annotationContext"; -import { ContextAnnotationFactoryType } from "new_front/types/createSamples/createSamples/annotationFactory"; import React, { FC, useEffect, useState, useContext } from "react"; +import { Button } from "react-bootstrap"; import { TokenAnnotator } from "react-text-annotate"; +import useFetch from "use-http"; +import { PacmanLoader } from "react-spinners"; + +import { ContextConfigType } from "new_front/types/createSamples/createSamples/annotationContext"; +import { CreateInterfaceContext } from "new_front/context/CreateInterface/Context"; +import { ContextAnnotationFactoryType } from "new_front/types/createSamples/createSamples/annotationFactory"; + +import AnnotationInstruction from "new_front/components/OverlayInstructions/Annotation"; import DropdownSearch from "new_front/components/Inputs/DropdownSearch"; -import languages from "./BCP47Temp"; +import generateLightRandomColor from "new_front/utils/helpers/functions/GenerateRandomLightColor"; type MultipleTagsTypes = { preselectedTag?: string; }; -const text = - 'On 31 January 2014, it was reported that Neesonwould workwith director Martin Scorsese again in an adaptation of the novel "Silence". Neeson had a supporting role as the henchman Bad Cop/Good Cop in the animated film "The Lego Movie", which was a critical and commercial success. Neeson later played Bill Marks in the 2014 action film Non-Stop. The film was releasedon 28 February 2014. He also appeared, uncredited, as God in the BBC2 series "Rev.". Neeson stars in the 2014 film "A Walk Among the Tombstones", an adaption of the best-selling novel of the same name, in which he plays former cop Matthew Scudder, a detective hired to hunt the killers of a drug dealer\'s wife.'; - const SelectMultipleTextMultipleTags: FC< ContextAnnotationFactoryType & ContextConfigType & MultipleTagsTypes -> = ({ - field_names_for_the_model, - context, - instruction, - metadata, - preselectedTag, -}) => { +> = ({ field_names_for_the_model, context, instruction, metadata, tags }) => { + const { post, loading, response } = useFetch(); + const { updateModelInputs } = useContext(CreateInterfaceContext); const [selectionInfo, setSelectionInfo] = useState([]); - const [tags, setTags] = useState([]); - const [tagSelection, setTagSelection] = useState(preselectedTag || null); + const [localTags, setLocalTags] = useState([]); + const [tagSelection, setTagSelection] = useState(null); const [tagColors, setTagColors] = useState(undefined); + const [preferedTag, setPreferedTag] = useState(null); + const [text, setText] = useState(context); - const generateRandomColor = (): string => { - const getRelativeLuminance = (r: number, g: number, b: number): number => { - const rs = r / 255; - const gs = g / 255; - const bs = b / 255; - - const rL = - rs <= 0.03928 ? rs / 12.92 : Math.pow((rs + 0.055) / 1.055, 2.4); - const gL = - gs <= 0.03928 ? gs / 12.92 : Math.pow((gs + 0.055) / 1.055, 2.4); - const bL = - bs <= 0.03928 ? bs / 12.92 : Math.pow((bs + 0.055) / 1.055, 2.4); - - return 0.2126 * rL + 0.7152 * gL + 0.0722 * bL; - }; - let color; - let luminance; - - do { - const r = Math.floor(Math.random() * 256); - const g = Math.floor(Math.random() * 256); - const b = Math.floor(Math.random() * 256); - - color = `rgb(${r}, ${g}, ${b})`; - luminance = getRelativeLuminance(r, g, b); - } while (luminance < 0.7); // Adjust the threshold as needed - - return color; - }; + const submitButton: HTMLElement | null = document.getElementById("submit"); useEffect(() => { updateModelInputs( @@ -68,26 +40,81 @@ const SelectMultipleTextMultipleTags: FC< metadata.context ); + if (submitButton) { + submitButton.hidden = true; + (submitButton as any).disabled = true; + } const tempTags: any[] = []; const colors: string[] = []; const tempTagColors: any = {}; - languages.forEach((tag: string) => { - let color = generateRandomColor(); + tags?.forEach((tag: string) => { + let color = generateLightRandomColor(); while (colors.includes(color)) { - color = generateRandomColor(); + color = generateLightRandomColor(); } colors.push(color); tempTags.push({ value: tag, color: color }); tempTagColors[tag] = color; }); - setTagSelection(tempTags.find((tag) => tag.value === preselectedTag)); - setTags(tempTags); + setLocalTags(tempTags); setTagColors(tempTagColors); + if (field_names_for_the_model?.preselected_tag) { + setPreferedTag(field_names_for_the_model.preselected_tag); + } }, []); + useEffect(() => { + if (preferedTag) { + setTagSelection(localTags.find((tag: any) => tag.value === preferedTag)); + handleSubmit(localTags.find((tag: any) => tag.value === preferedTag)); + submitButton && (submitButton.hidden = false); + } + }, [preferedTag]); + + useEffect(() => { + text && + text.length > 0 && + submitButton && + ((submitButton as any).disabled = false); + }, [text]); + + const handleSubmit = async (value: string | null) => { + console.log("in handle submit"); + !value && (value = tagSelection.value); + submitButton && (submitButton.hidden = false); + /* const payload = { + key_name: field_names_for_the_model?.tag_name_search, + key_value: value, + }; */ + const bringContext = await post( + `/context/get_random_context_from_key_value`, + { + key_name: field_names_for_the_model?.tag_name_search, + key_value: "ace-Arab", + } + ); + console.log(bringContext); + if (response.ok) { + setText(bringContext.text); + } + }; + + const handleSelectAll = async () => { + const tokens = text?.split(" "); + setSelectionInfo([ + { + start: 0, + end: tokens?.length, + tag: tagSelection, + tokens: tokens, + color: tagColors[tagSelection], + }, + ]); + }; + const handleChange = (value: any) => { setSelectionInfo(value); - console.log("seleccion", value); + console.log("selection", value); /* updateModelInputs( { [field_names_for_the_model.answer ?? "selectable_text"]: context.context @@ -107,70 +134,111 @@ const SelectMultipleTextMultipleTags: FC< "Select the tag and the text according to the tag" } > - <> -
- handleChange(value)} - getSpan={(span) => ({ - ...span, - tag: tagSelection, - color: tagColors[tagSelection], - })} - renderMark={(props) => ( - - props.onClick({ - start: props.start, - end: props.end, - tag: props.tag, - color: props.color, - content: props.content, - }) + {!text ? ( + <> + {!loading ? ( +
+ - {props.content}{" "} - +
+ +
+
+ ) : ( +
+ +
+ )} + + ) : ( + <> +
+ handleChange(value)} + getSpan={(span) => ({ + ...span, + tag: tagSelection, + color: tagColors[tagSelection], + })} + renderMark={(props) => ( + + props.onClick({ + start: props.start, + end: props.end, + tag: props.tag, + color: props.color, + content: props.content, + }) + } style={{ - boxSizing: "border-box", - content: "attr(data-entity)", - fontSize: ".55em", + padding: ".2em .3em", + margin: "0 .25em", lineHeight: "1", - padding: ".35em .35em", - borderRadius: ".35em", - textTransform: "uppercase", display: "inline-block", - verticalAlign: "middle", - margin: "0 0 .15rem .5rem", - background: "#fff", - fontWeight: "700", + borderRadius: ".25em", + background: tagColors[props.tag], }} > - {" "} - {props.tag} - - - )} - /> -
-
- -
- + {props.content}{" "} + + {" "} + {props.tag} + +
+ )} + /> +
+
+
+ +
+
+ +
+
+ + )} ); }; diff --git a/frontends/web/src/new_front/types/createSamples/createSamples/annotationContext.ts b/frontends/web/src/new_front/types/createSamples/createSamples/annotationContext.ts index 82cff94b..f8fe7db5 100644 --- a/frontends/web/src/new_front/types/createSamples/createSamples/annotationContext.ts +++ b/frontends/web/src/new_front/types/createSamples/createSamples/annotationContext.ts @@ -5,6 +5,7 @@ export type ContextConfigType = { metadata?: any; field_names_for_the_model: any; generative_context: GenerativeContext; + tags?: string[]; }; export type GenerativeContext = { diff --git a/frontends/web/src/new_front/types/createSamples/createSamples/configurationTask.ts b/frontends/web/src/new_front/types/createSamples/createSamples/configurationTask.ts index 57572da9..5404d75f 100644 --- a/frontends/web/src/new_front/types/createSamples/createSamples/configurationTask.ts +++ b/frontends/web/src/new_front/types/createSamples/createSamples/configurationTask.ts @@ -6,7 +6,7 @@ export type InfoContextTask = { }; export type ConfigurationTask = { - goal: object; + goal: object | null; context: object; user_input: object[]; required_fields: string[]; diff --git a/frontends/web/src/new_front/utils/helpers/functions/GenerateRandomLightColor.tsx b/frontends/web/src/new_front/utils/helpers/functions/GenerateRandomLightColor.tsx new file mode 100644 index 00000000..b7947556 --- /dev/null +++ b/frontends/web/src/new_front/utils/helpers/functions/GenerateRandomLightColor.tsx @@ -0,0 +1,26 @@ +export default function GenerateRandomLightColor(): string { + const getRelativeLuminance = (r: number, g: number, b: number): number => { + const rs = r / 255; + const gs = g / 255; + const bs = b / 255; + + const rL = rs <= 0.03928 ? rs / 12.92 : Math.pow((rs + 0.055) / 1.055, 2.4); + const gL = gs <= 0.03928 ? gs / 12.92 : Math.pow((gs + 0.055) / 1.055, 2.4); + const bL = bs <= 0.03928 ? bs / 12.92 : Math.pow((bs + 0.055) / 1.055, 2.4); + + return 0.2126 * rL + 0.7152 * gL + 0.0722 * bL; + }; + let color; + let luminance; + + do { + const r = Math.floor(Math.random() * 256); + const g = Math.floor(Math.random() * 256); + const b = Math.floor(Math.random() * 256); + + color = `rgb(${r}, ${g}, ${b})`; + luminance = getRelativeLuminance(r, g, b); + } while (luminance < 0.7); // Adjust the threshold as needed + + return color; +} From e6dc1cb2a2eb50878c135a18e0cc7b1b9617cf8a Mon Sep 17 00:00:00 2001 From: Sara H Date: Tue, 23 Jul 2024 22:08:57 -0500 Subject: [PATCH 04/11] Use content from endpoint and implement back_label --- .../SelectMultipleTextMultipleTags.tsx | 48 +++++++++++-------- .../components/Inputs/DropdownSearch.tsx | 6 +-- .../createSamples/annotationContext.ts | 2 +- 3 files changed, 32 insertions(+), 24 deletions(-) diff --git a/frontends/web/src/new_front/components/CreateSamples/CreateSamples/AnnotationInterfaces/Contexts/SelectMultipleTextMultipleTags.tsx b/frontends/web/src/new_front/components/CreateSamples/CreateSamples/AnnotationInterfaces/Contexts/SelectMultipleTextMultipleTags.tsx index cd008268..c39a7833 100644 --- a/frontends/web/src/new_front/components/CreateSamples/CreateSamples/AnnotationInterfaces/Contexts/SelectMultipleTextMultipleTags.tsx +++ b/frontends/web/src/new_front/components/CreateSamples/CreateSamples/AnnotationInterfaces/Contexts/SelectMultipleTextMultipleTags.tsx @@ -47,14 +47,18 @@ const SelectMultipleTextMultipleTags: FC< const tempTags: any[] = []; const colors: string[] = []; const tempTagColors: any = {}; - tags?.forEach((tag: string) => { + tags?.forEach((tag: any) => { let color = generateLightRandomColor(); while (colors.includes(color)) { color = generateLightRandomColor(); } colors.push(color); - tempTags.push({ value: tag, color: color }); - tempTagColors[tag] = color; + tempTags.push({ + value: tag?.display_label, + color: color, + back_label: tag?.back_label, + }); + tempTagColors[tag.back_label] = color; }); setLocalTags(tempTags); setTagColors(tempTagColors); @@ -66,7 +70,9 @@ const SelectMultipleTextMultipleTags: FC< useEffect(() => { if (preferedTag) { setTagSelection(localTags.find((tag: any) => tag.value === preferedTag)); - handleSubmit(localTags.find((tag: any) => tag.value === preferedTag)); + handleSubmit( + localTags.find((tag: any) => tag.value === preferedTag)?.back_label + ); submitButton && (submitButton.hidden = false); } }, [preferedTag]); @@ -78,24 +84,20 @@ const SelectMultipleTextMultipleTags: FC< ((submitButton as any).disabled = false); }, [text]); + useEffect(() => {}, [localTags]); + const handleSubmit = async (value: string | null) => { - console.log("in handle submit"); - !value && (value = tagSelection.value); + !value && (value = tagSelection.back_label); submitButton && (submitButton.hidden = false); - /* const payload = { - key_name: field_names_for_the_model?.tag_name_search, - key_value: value, - }; */ const bringContext = await post( - `/context/get_random_context_from_key_value`, + "/context/get_random_context_from_key_value/", { key_name: field_names_for_the_model?.tag_name_search, - key_value: "ace-Arab", + key_value: value, } ); - console.log(bringContext); if (response.ok) { - setText(bringContext.text); + setText(bringContext.content); } }; @@ -105,9 +107,9 @@ const SelectMultipleTextMultipleTags: FC< { start: 0, end: tokens?.length, - tag: tagSelection, + tag: tagSelection.back_label, tokens: tokens, - color: tagColors[tagSelection], + color: tagColors[tagSelection.back_label], }, ]); }; @@ -141,7 +143,7 @@ const SelectMultipleTextMultipleTags: FC< handleSubmit(null)} + disabled={!tagSelection} > Select @@ -172,8 +175,8 @@ const SelectMultipleTextMultipleTags: FC< onChange={(value) => handleChange(value)} getSpan={(span) => ({ ...span, - tag: tagSelection, - color: tagColors[tagSelection], + tag: tagSelection.back_label, + color: tagColors[tagSelection.back_label], })} renderMark={(props) => ( diff --git a/frontends/web/src/new_front/components/Inputs/DropdownSearch.tsx b/frontends/web/src/new_front/components/Inputs/DropdownSearch.tsx index adba5e73..93d8a60e 100644 --- a/frontends/web/src/new_front/components/Inputs/DropdownSearch.tsx +++ b/frontends/web/src/new_front/components/Inputs/DropdownSearch.tsx @@ -16,14 +16,14 @@ const DropdownSearch: FC = ({ const [open, setOpen] = useState(false); const [searchTerm, setSearchTerm] = useState(""); - const filteredOptions = options.filter((option) => - option.value.toLowerCase().includes(searchTerm.toLowerCase()) + const filteredOptions = options.filter( + (option) => option.value?.toLowerCase().includes(searchTerm.toLowerCase()), ); const handleOnClick = (option: any) => { setOpen(false); setSearchTerm(""); - onChange(option.value); + onChange(option); }; return ( diff --git a/frontends/web/src/new_front/types/createSamples/createSamples/annotationContext.ts b/frontends/web/src/new_front/types/createSamples/createSamples/annotationContext.ts index f8fe7db5..8e896438 100644 --- a/frontends/web/src/new_front/types/createSamples/createSamples/annotationContext.ts +++ b/frontends/web/src/new_front/types/createSamples/createSamples/annotationContext.ts @@ -5,7 +5,7 @@ export type ContextConfigType = { metadata?: any; field_names_for_the_model: any; generative_context: GenerativeContext; - tags?: string[]; + tags?: object[]; }; export type GenerativeContext = { From 881be20f051ad5fd2b3b3756bb318fae246d4006 Mon Sep 17 00:00:00 2001 From: Sara H Date: Tue, 30 Jul 2024 11:21:57 -0500 Subject: [PATCH 05/11] Select Multiple tags component --- .../Contexts/AnnotationContextStrategy.tsx | 2 + .../SelectMultipleTextMultipleTags.tsx | 158 ++++++++++++------ .../pages/CreateSamples/CreateInterface.tsx | 1 + .../createSamples/annotationContext.ts | 2 +- .../createSamples/annotationFactory.ts | 1 + 5 files changed, 113 insertions(+), 51 deletions(-) diff --git a/frontends/web/src/new_front/components/CreateSamples/CreateSamples/AnnotationInterfaces/Contexts/AnnotationContextStrategy.tsx b/frontends/web/src/new_front/components/CreateSamples/CreateSamples/AnnotationInterfaces/Contexts/AnnotationContextStrategy.tsx index 546cd06e..ae8aba68 100644 --- a/frontends/web/src/new_front/components/CreateSamples/CreateSamples/AnnotationInterfaces/Contexts/AnnotationContextStrategy.tsx +++ b/frontends/web/src/new_front/components/CreateSamples/CreateSamples/AnnotationInterfaces/Contexts/AnnotationContextStrategy.tsx @@ -34,6 +34,7 @@ const AnnotationContextStrategy: FC = ({ hidden, setIsGenerativeContext, setPartialSampleId, + userId, }) => { const [goalRender, setGoalRender] = useState>(); @@ -51,6 +52,7 @@ const AnnotationContextStrategy: FC = ({ hidden, setIsGenerativeContext, setPartialSampleId, + userId, ...config, }} />, diff --git a/frontends/web/src/new_front/components/CreateSamples/CreateSamples/AnnotationInterfaces/Contexts/SelectMultipleTextMultipleTags.tsx b/frontends/web/src/new_front/components/CreateSamples/CreateSamples/AnnotationInterfaces/Contexts/SelectMultipleTextMultipleTags.tsx index c39a7833..f24464fd 100644 --- a/frontends/web/src/new_front/components/CreateSamples/CreateSamples/AnnotationInterfaces/Contexts/SelectMultipleTextMultipleTags.tsx +++ b/frontends/web/src/new_front/components/CreateSamples/CreateSamples/AnnotationInterfaces/Contexts/SelectMultipleTextMultipleTags.tsx @@ -3,9 +3,9 @@ import { Button } from "react-bootstrap"; import { TokenAnnotator } from "react-text-annotate"; import useFetch from "use-http"; import { PacmanLoader } from "react-spinners"; +import Swal from "sweetalert2"; import { ContextConfigType } from "new_front/types/createSamples/createSamples/annotationContext"; -import { CreateInterfaceContext } from "new_front/context/CreateInterface/Context"; import { ContextAnnotationFactoryType } from "new_front/types/createSamples/createSamples/annotationFactory"; import AnnotationInstruction from "new_front/components/OverlayInstructions/Annotation"; @@ -17,37 +17,56 @@ type MultipleTagsTypes = { preselectedTag?: string; }; +type Dictionary = { [key: string]: any }; + +const cleanUpSelection = ( + selection: Array, + keyToRemove: string, +) => { + const result: Array> = []; + + selection.forEach((dictionary) => { + const newDictionary: Dictionary = {}; + + for (const key in dictionary) { + if (dictionary.hasOwnProperty(key) && key !== keyToRemove) { + newDictionary[key] = dictionary[key]; + } + } + + result.push(newDictionary); + }); + + return result; +}; + const SelectMultipleTextMultipleTags: FC< ContextAnnotationFactoryType & ContextConfigType & MultipleTagsTypes -> = ({ field_names_for_the_model, context, instruction, metadata, tags }) => { +> = ({ + field_names_for_the_model, + instruction, + userId, + taskId, + generative_context, +}) => { const { post, loading, response } = useFetch(); - const { updateModelInputs } = useContext(CreateInterfaceContext); const [selectionInfo, setSelectionInfo] = useState([]); const [localTags, setLocalTags] = useState([]); const [tagSelection, setTagSelection] = useState(null); const [tagColors, setTagColors] = useState(undefined); const [preferedTag, setPreferedTag] = useState(null); - const [text, setText] = useState(context); + const [text, setText] = useState(undefined); + const [contextId, setContextId] = useState(null); + const [realRoundId, setRealRoundId] = useState(null); const submitButton: HTMLElement | null = document.getElementById("submit"); useEffect(() => { - updateModelInputs( - { - [field_names_for_the_model.context]: context.context, - }, - metadata.context - ); - - if (submitButton) { - submitButton.hidden = true; - (submitButton as any).disabled = true; - } const tempTags: any[] = []; const colors: string[] = []; const tempTagColors: any = {}; - tags?.forEach((tag: any) => { + generative_context?.artifacts?.tags?.forEach((tag: any) => { let color = generateLightRandomColor(); while (colors.includes(color)) { color = generateLightRandomColor(); @@ -71,21 +90,11 @@ const SelectMultipleTextMultipleTags: FC< if (preferedTag) { setTagSelection(localTags.find((tag: any) => tag.value === preferedTag)); handleSubmit( - localTags.find((tag: any) => tag.value === preferedTag)?.back_label + localTags.find((tag: any) => tag.value === preferedTag)?.back_label, ); - submitButton && (submitButton.hidden = false); } }, [preferedTag]); - useEffect(() => { - text && - text.length > 0 && - submitButton && - ((submitButton as any).disabled = false); - }, [text]); - - useEffect(() => {}, [localTags]); - const handleSubmit = async (value: string | null) => { !value && (value = tagSelection.back_label); submitButton && (submitButton.hidden = false); @@ -94,10 +103,22 @@ const SelectMultipleTextMultipleTags: FC< { key_name: field_names_for_the_model?.tag_name_search, key_value: value, - } + }, ); if (response.ok) { - setText(bringContext.content); + !bringContext && + Swal.fire({ + title: instruction?.context_alert_title, + text: instruction?.context_alert_text, + icon: "warning", + confirmButtonText: "Ok", + }).then(() => { + handleSubmit(field_names_for_the_model?.default_tag); + }); + console.log("bringContext", bringContext); + setText(bringContext?.content); + setContextId(bringContext?.id); + setRealRoundId(bringContext?.round_id); } }; @@ -114,25 +135,38 @@ const SelectMultipleTextMultipleTags: FC< ]); }; + const handleSubmitExample = async () => { + const newSelectionInfo = cleanUpSelection(selectionInfo, "color"); + const response = await post("/example/create_example/", { + context_id: contextId, + user_id: userId, + input_json: { labels: newSelectionInfo }, + text: text, + task_id: taskId, + round_id: realRoundId, + increment_context: true, + }); + if (response.ok) { + Swal.fire({ + title: "Success", + text: "The data has been saved", + icon: "success", + confirmButtonText: "Ok", + }).then(() => { + handleSubmit(null); + }); + } + }; + const handleChange = (value: any) => { setSelectionInfo(value); - console.log("selection", value); - /* updateModelInputs( - { - [field_names_for_the_model.answer ?? "selectable_text"]: context.context - .split(" ") - .slice(value[0].start, value[0].end) - .join(" "), - }, - metadata.answer - ); */ }; return ( @@ -140,13 +174,16 @@ const SelectMultipleTextMultipleTags: FC< <> {!loading ? (
+ {instruction?.preselection && ( +
+ {instruction?.preselection} +
+ )} @@ -161,14 +198,32 @@ const SelectMultipleTextMultipleTags: FC<
) : ( -
+
+
+ Data is being prepared, please wait... +
)} ) : ( <> -
+
+
+ {instruction?.selection_note && ( +
+ {instruction?.selection_note} +
+ )} +
+ +
+
-
-
+
+
-
+
+
+
diff --git a/frontends/web/src/new_front/pages/CreateSamples/CreateInterface.tsx b/frontends/web/src/new_front/pages/CreateSamples/CreateInterface.tsx index 3dd2a581..04c18b77 100644 --- a/frontends/web/src/new_front/pages/CreateSamples/CreateInterface.tsx +++ b/frontends/web/src/new_front/pages/CreateSamples/CreateInterface.tsx @@ -198,6 +198,7 @@ const CreateInterface = () => { hidden={hidden} setPartialSampleId={setPartialSampleId} setIsGenerativeContext={setIsGenerativeContext} + userId={user.id!} /> )}
diff --git a/frontends/web/src/new_front/types/createSamples/createSamples/annotationContext.ts b/frontends/web/src/new_front/types/createSamples/createSamples/annotationContext.ts index 8e896438..24cd3c06 100644 --- a/frontends/web/src/new_front/types/createSamples/createSamples/annotationContext.ts +++ b/frontends/web/src/new_front/types/createSamples/createSamples/annotationContext.ts @@ -11,5 +11,5 @@ export type ContextConfigType = { export type GenerativeContext = { is_generative: boolean; type: string; - artifacts: object; + artifacts: any; }; diff --git a/frontends/web/src/new_front/types/createSamples/createSamples/annotationFactory.ts b/frontends/web/src/new_front/types/createSamples/createSamples/annotationFactory.ts index e5425564..85950663 100644 --- a/frontends/web/src/new_front/types/createSamples/createSamples/annotationFactory.ts +++ b/frontends/web/src/new_front/types/createSamples/createSamples/annotationFactory.ts @@ -10,4 +10,5 @@ export type ContextAnnotationFactoryType = AnnotationFactoryType & { contextId: number; taskId?: number; realRoundId: number; + userId?: number; }; From 1b63ee2688e2e4cb006143ac1265a2fee42e2b3c Mon Sep 17 00:00:00 2001 From: Sara H Date: Tue, 30 Jul 2024 11:50:15 -0500 Subject: [PATCH 06/11] missing creation interface option update --- .../web/src/new_front/utils/creation_interface_options.json | 1 + 1 file changed, 1 insertion(+) diff --git a/frontends/web/src/new_front/utils/creation_interface_options.json b/frontends/web/src/new_front/utils/creation_interface_options.json index 995cbc28..b444fbac 100644 --- a/frontends/web/src/new_front/utils/creation_interface_options.json +++ b/frontends/web/src/new_front/utils/creation_interface_options.json @@ -8,6 +8,7 @@ "context": { "plain-text": "PlainText", "selectable-text": "SelectableText", + "select-multiple-text-multiple-tags": "SelectMultipleTextMultipleTags", "zoom_image": "ZoomImage", "audio": "Audio", "modify-original-text": "ModifyOriginalText", From 6d3ab932c69f73e1e5e48eab4817311ff865f7fd Mon Sep 17 00:00:00 2001 From: Sara H Date: Tue, 30 Jul 2024 15:23:38 -0500 Subject: [PATCH 07/11] change name of tooltip instruction variable --- .../Contexts/SelectMultipleTextMultipleTags.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontends/web/src/new_front/components/CreateSamples/CreateSamples/AnnotationInterfaces/Contexts/SelectMultipleTextMultipleTags.tsx b/frontends/web/src/new_front/components/CreateSamples/CreateSamples/AnnotationInterfaces/Contexts/SelectMultipleTextMultipleTags.tsx index f24464fd..45446ea2 100644 --- a/frontends/web/src/new_front/components/CreateSamples/CreateSamples/AnnotationInterfaces/Contexts/SelectMultipleTextMultipleTags.tsx +++ b/frontends/web/src/new_front/components/CreateSamples/CreateSamples/AnnotationInterfaces/Contexts/SelectMultipleTextMultipleTags.tsx @@ -166,7 +166,7 @@ const SelectMultipleTextMultipleTags: FC< From 7ebfda0d8cde0ca07a74e557ba17ad4558a8a550 Mon Sep 17 00:00:00 2001 From: Sara H Date: Thu, 1 Aug 2024 12:27:24 -0500 Subject: [PATCH 08/11] move dropdown to top add loading after example submition add button to skip example --- .../SelectMultipleTextMultipleTags.tsx | 136 +++++++++++------- .../components/Inputs/DropdownSearch.tsx | 4 +- .../pages/CreateSamples/CreateInterface.tsx | 2 +- 3 files changed, 89 insertions(+), 53 deletions(-) diff --git a/frontends/web/src/new_front/components/CreateSamples/CreateSamples/AnnotationInterfaces/Contexts/SelectMultipleTextMultipleTags.tsx b/frontends/web/src/new_front/components/CreateSamples/CreateSamples/AnnotationInterfaces/Contexts/SelectMultipleTextMultipleTags.tsx index 45446ea2..1e5e3acb 100644 --- a/frontends/web/src/new_front/components/CreateSamples/CreateSamples/AnnotationInterfaces/Contexts/SelectMultipleTextMultipleTags.tsx +++ b/frontends/web/src/new_front/components/CreateSamples/CreateSamples/AnnotationInterfaces/Contexts/SelectMultipleTextMultipleTags.tsx @@ -1,9 +1,9 @@ -import React, { FC, useEffect, useState, useContext } from "react"; +import React, { FC, useEffect, useState } from "react"; import { Button } from "react-bootstrap"; import { TokenAnnotator } from "react-text-annotate"; -import useFetch from "use-http"; import { PacmanLoader } from "react-spinners"; import Swal from "sweetalert2"; +import useFetch from "use-http"; import { ContextConfigType } from "new_front/types/createSamples/createSamples/annotationContext"; import { ContextAnnotationFactoryType } from "new_front/types/createSamples/createSamples/annotationFactory"; @@ -59,6 +59,7 @@ const SelectMultipleTextMultipleTags: FC< const [text, setText] = useState(undefined); const [contextId, setContextId] = useState(null); const [realRoundId, setRealRoundId] = useState(null); + const [loading2, setLoading2] = useState(false); const submitButton: HTMLElement | null = document.getElementById("submit"); @@ -95,31 +96,47 @@ const SelectMultipleTextMultipleTags: FC< } }, [preferedTag]); - const handleSubmit = async (value: string | null) => { + useEffect(() => { + text?.length && setLoading2(false); + }, [text]); + + const handleSubmit = (value: string | null) => { !value && (value = tagSelection.back_label); submitButton && (submitButton.hidden = false); - const bringContext = await post( - "/context/get_random_context_from_key_value/", + setLoading2(true); + setSelectionInfo([]); + fetch( + `${process.env.REACT_APP_API_HOST_2}/context/get_random_context_from_key_value/`, { - key_name: field_names_for_the_model?.tag_name_search, - key_value: value, + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + key_name: field_names_for_the_model?.tag_name_search, + key_value: value, + }), }, - ); - if (response.ok) { - !bringContext && - Swal.fire({ - title: instruction?.context_alert_title, - text: instruction?.context_alert_text, - icon: "warning", - confirmButtonText: "Ok", - }).then(() => { - handleSubmit(field_names_for_the_model?.default_tag); - }); - console.log("bringContext", bringContext); - setText(bringContext?.content); - setContextId(bringContext?.id); - setRealRoundId(bringContext?.round_id); - } + ) + .then((response) => response.json()) + .then((data) => { + !data && + Swal.fire({ + title: instruction?.context_alert_title, + text: instruction?.context_alert_text, + icon: "warning", + confirmButtonText: "Ok", + }).then(() => { + handleSubmit(field_names_for_the_model?.default_tag); + }); + console.log("bringContext", data); + setText(data?.content); + setContextId(data?.id); + setRealRoundId(data?.round_id); + }) + .catch((error) => { + console.warn("error", error); + }); }; const handleSelectAll = async () => { @@ -137,11 +154,13 @@ const SelectMultipleTextMultipleTags: FC< const handleSubmitExample = async () => { const newSelectionInfo = cleanUpSelection(selectionInfo, "color"); - const response = await post("/example/create_example/", { + const sendText = text; + setText(undefined); + await post("/example/create_example/", { context_id: contextId, user_id: userId, input_json: { labels: newSelectionInfo }, - text: text, + text: sendText, task_id: taskId, round_id: realRoundId, increment_context: true, @@ -172,7 +191,7 @@ const SelectMultipleTextMultipleTags: FC< > {!text ? ( <> - {!loading ? ( + {!loading && !loading2 ? (
{instruction?.preselection && (
@@ -202,7 +221,11 @@ const SelectMultipleTextMultipleTags: FC<
Data is being prepared, please wait...
- +
)} @@ -224,6 +247,20 @@ const SelectMultipleTextMultipleTags: FC<
+
+
+ +
+
)} /> -
-
-
- -
-
-
-
- +
+
+ +
+
+ +
diff --git a/frontends/web/src/new_front/components/Inputs/DropdownSearch.tsx b/frontends/web/src/new_front/components/Inputs/DropdownSearch.tsx index 93d8a60e..24a3fb37 100644 --- a/frontends/web/src/new_front/components/Inputs/DropdownSearch.tsx +++ b/frontends/web/src/new_front/components/Inputs/DropdownSearch.tsx @@ -40,7 +40,9 @@ const DropdownSearch: FC = ({
{value}
) : ( -
+
From 57b7f471d6c3b279dbc97ded41b798acf35f8d09 Mon Sep 17 00:00:00 2001 From: Sara H Date: Wed, 7 Aug 2024 13:03:15 -0500 Subject: [PATCH 09/11] use regex for any kind of spaces for token split --- .../Contexts/SelectMultipleTextMultipleTags.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontends/web/src/new_front/components/CreateSamples/CreateSamples/AnnotationInterfaces/Contexts/SelectMultipleTextMultipleTags.tsx b/frontends/web/src/new_front/components/CreateSamples/CreateSamples/AnnotationInterfaces/Contexts/SelectMultipleTextMultipleTags.tsx index 1e5e3acb..f90e95af 100644 --- a/frontends/web/src/new_front/components/CreateSamples/CreateSamples/AnnotationInterfaces/Contexts/SelectMultipleTextMultipleTags.tsx +++ b/frontends/web/src/new_front/components/CreateSamples/CreateSamples/AnnotationInterfaces/Contexts/SelectMultipleTextMultipleTags.tsx @@ -262,7 +262,7 @@ const SelectMultipleTextMultipleTags: FC<
handleChange(value)} getSpan={(span) => ({ From 32c6ead8df8ef63a7ba28fe3ac3fbd7cef5dec4d Mon Sep 17 00:00:00 2001 From: Sara H Date: Fri, 9 Aug 2024 16:21:51 -0500 Subject: [PATCH 10/11] Add Validation Options to allow user use their own options to validate --- backend/app/domain/services/base/example.py | 1 + .../src/new_front/pages/CreateSamples/ValidateSamples.tsx | 8 +++++++- .../createSamples/createSamples/configurationTask.ts | 1 + 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/backend/app/domain/services/base/example.py b/backend/app/domain/services/base/example.py index 00339747..803c3e25 100644 --- a/backend/app/domain/services/base/example.py +++ b/backend/app/domain/services/base/example.py @@ -226,6 +226,7 @@ def get_validate_configuration(self, task_id: int) -> dict: context_info = { "validation_user_input": config_yaml.get("validation_user_input"), "validation_context": config_yaml.get("validation_context"), + "validation_options": config_yaml.get("validation_options"), } return context_info diff --git a/frontends/web/src/new_front/pages/CreateSamples/ValidateSamples.tsx b/frontends/web/src/new_front/pages/CreateSamples/ValidateSamples.tsx index 62d9f8e9..fb4ce3a8 100644 --- a/frontends/web/src/new_front/pages/CreateSamples/ValidateSamples.tsx +++ b/frontends/web/src/new_front/pages/CreateSamples/ValidateSamples.tsx @@ -141,7 +141,13 @@ const ValidateSamples: FC = () => { )} { setLabel(input.label); diff --git a/frontends/web/src/new_front/types/createSamples/createSamples/configurationTask.ts b/frontends/web/src/new_front/types/createSamples/createSamples/configurationTask.ts index 5404d75f..27d2138c 100644 --- a/frontends/web/src/new_front/types/createSamples/createSamples/configurationTask.ts +++ b/frontends/web/src/new_front/types/createSamples/createSamples/configurationTask.ts @@ -20,6 +20,7 @@ export type ConfigurationTask = { export type ValidationConfigurationTask = { validation_user_input: object[]; validation_context: object[]; + validation_options?: string[]; }; type ModelOutput = { From e299c55e65cbd5021c54675d1fb6e097d18b7606 Mon Sep 17 00:00:00 2001 From: Sara H Date: Mon, 12 Aug 2024 14:49:32 -0500 Subject: [PATCH 11/11] add safe and unsafe to the enum in the validation table --- backend/app/infrastructure/models/models.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/backend/app/infrastructure/models/models.py b/backend/app/infrastructure/models/models.py index 183dc14f..28df46b0 100644 --- a/backend/app/infrastructure/models/models.py +++ b/backend/app/infrastructure/models/models.py @@ -466,7 +466,9 @@ class Validation(Base): id = Column(Integer, primary_key=True) uid = Column(ForeignKey("users.id"), index=True) eid = Column(ForeignKey("examples.id"), nullable=False, index=True) - label = Column(Enum("flagged", "correct", "incorrect", "placeholder")) + label = Column( + Enum("flagged", "correct", "incorrect", "placeholder", "safe", "unsafe") + ) mode = Column(Enum("user", "owner")) metadata_json = Column(Text)