From 98d71992490ce9c38550d783742dbee359da8691 Mon Sep 17 00:00:00 2001 From: remg1997 Date: Wed, 22 May 2024 09:56:41 -0500 Subject: [PATCH 1/8] Include ID for errors --- .../domain/services/utils/image_generators.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/backend/app/domain/services/utils/image_generators.py b/backend/app/domain/services/utils/image_generators.py index 5a59c59d..73569819 100644 --- a/backend/app/domain/services/utils/image_generators.py +++ b/backend/app/domain/services/utils/image_generators.py @@ -122,6 +122,7 @@ def generate_images( "generator": self.provider_name(), "message": error_code, "images": None, + "id": None, } def provider_name(self): @@ -187,6 +188,7 @@ def generate_images( "generator": self.provider_name(), "message": error_code, "images": None, + "id": None, } def provider_name(self): @@ -240,6 +242,7 @@ def generate_images( "generator": self.provider_name(), "message": error_code, "images": None, + "id": None, } def provider_name(self): @@ -293,6 +296,7 @@ def generate_images( "generator": self.provider_name(), "message": error_code, "images": None, + "id": None, } def provider_name(self): @@ -345,6 +349,7 @@ def generate_images( "generator": self.provider_name(), "message": error_code, "images": None, + "id": None, } def provider_name(self): @@ -397,6 +402,7 @@ def generate_images( "generator": self.provider_name(), "message": error_code, "images": None, + "id": None, } def provider_name(self): @@ -449,6 +455,7 @@ def generate_images( "generator": self.provider_name(), "message": error_code, "images": None, + "id": None, } def provider_name(self): @@ -501,6 +508,7 @@ def generate_images( "generator": self.provider_name(), "message": error_code, "images": None, + "id": None, } def provider_name(self): @@ -553,6 +561,7 @@ def generate_images( "generator": self.provider_name(), "message": error_code, "images": None, + "id": None, } def provider_name(self): @@ -605,6 +614,7 @@ def generate_images( "generator": self.provider_name(), "message": error_code, "images": None, + "id": None, } def provider_name(self): @@ -657,6 +667,7 @@ def generate_images( "generator": self.provider_name(), "message": error_code, "images": None, + "id": None, } def provider_name(self): @@ -709,6 +720,7 @@ def generate_images( "generator": self.provider_name(), "message": error_code, "images": None, + "id": None, } def provider_name(self): @@ -761,6 +773,7 @@ def generate_images( "generator": self.provider_name(), "message": error_code, "images": None, + "id": None, } def provider_name(self): @@ -813,6 +826,7 @@ def generate_images( "generator": self.provider_name(), "message": error_code, "images": None, + "id": None, } def provider_name(self): @@ -865,6 +879,7 @@ def generate_images( "generator": self.provider_name(), "message": error_code, "images": None, + "id": None, } def provider_name(self): @@ -917,6 +932,7 @@ def generate_images( "generator": self.provider_name(), "message": error_code, "images": None, + "id": None, } def provider_name(self): @@ -969,6 +985,7 @@ def generate_images( "generator": self.provider_name(), "message": error_code, "images": None, + "id": None, } def provider_name(self): @@ -1020,6 +1037,7 @@ def generate_images( "generator": self.provider_name(), "message": error_code, "images": None, + "id": None, } def provider_name(self): From c77cb277779fcc928e695e22bb3706391ea4e3f5 Mon Sep 17 00:00:00 2001 From: remg1997 Date: Wed, 22 May 2024 10:50:11 -0500 Subject: [PATCH 2/8] Fix help-med --- .../Contexts/ChatWithInstructions.tsx | 33 ++++++++++--------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/frontends/web/src/new_front/components/CreateSamples/CreateSamples/AnnotationInterfaces/Contexts/ChatWithInstructions.tsx b/frontends/web/src/new_front/components/CreateSamples/CreateSamples/AnnotationInterfaces/Contexts/ChatWithInstructions.tsx index dd5a4285..98ddee53 100644 --- a/frontends/web/src/new_front/components/CreateSamples/CreateSamples/AnnotationInterfaces/Contexts/ChatWithInstructions.tsx +++ b/frontends/web/src/new_front/components/CreateSamples/CreateSamples/AnnotationInterfaces/Contexts/ChatWithInstructions.tsx @@ -54,7 +54,9 @@ const ChatWithInstructions: FC< const location = useLocation(); const queryParams = queryString.parse(location.search); let treatmentId = queryParams.treatmentId ? queryParams.treatmentId : "2"; - let prolificId = queryParams.assignmentId ? queryParams.assignmentId : Math.floor(100000 + Math.random() * 900000).toString(); + let prolificId = queryParams.assignmentId + ? queryParams.assignmentId + : Math.floor(100000 + Math.random() * 900000).toString(); function getTreatmentValue(treatmentId: TreatmentId): string { switch (treatmentId) { @@ -250,30 +252,31 @@ const ChatWithInstructions: FC<

{treatmentValue !== "control" ? ( - <> -

+

We are interested in understanding how you use the language model provided and how well it works for you. Therefore, it is essential that you{" "} only use your own words, and do not copy - and paste from the scenario text, or from any other source. - + and paste from the scenario text, or from any other + source. +

) : ( <>

- To assist in completing the scenarios, - please use a search engine or any other methods you - might ordinarily use at home. We are interested in - understanding what tools you use and how well they work - for you. This may be an online resource, a book, or - anything else. It is essential that you{" "} - only use your own words, and do not copy - and paste from the scenario text, or from any other source. + To assist in completing the scenarios, please use a + search engine or any other methods you might ordinarily + use at home. We are interested in understanding what + tools you use and how well they work for you. This may + be an online resource, a book, or anything else. It is + essential that you{" "} + only use your own words, and do not + copy and paste from the scenario text, or from any other + source.

)}

- After completing the first scenario, you will return to this + After completing the first scenario, you will return to this page for a different second scenario.

@@ -306,7 +309,7 @@ const ChatWithInstructions: FC< )}

-

Scenario

+

Scenario

From 9cfbb3385a63068d02d4309a78ba6387d21b58db Mon Sep 17 00:00:00 2001 From: Sara H Date: Wed, 22 May 2024 15:37:27 -0500 Subject: [PATCH 3/8] Restart catefory and concept once the country and the language have changed --- .../Contexts/DescribeImage.tsx | 8 +++++- .../context/CreateInterface/Context.tsx | 27 ++++++++++++++++--- 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/frontends/web/src/new_front/components/CreateSamples/CreateSamples/AnnotationInterfaces/Contexts/DescribeImage.tsx b/frontends/web/src/new_front/components/CreateSamples/CreateSamples/AnnotationInterfaces/Contexts/DescribeImage.tsx index 1efa9f15..5a4abf8f 100644 --- a/frontends/web/src/new_front/components/CreateSamples/CreateSamples/AnnotationInterfaces/Contexts/DescribeImage.tsx +++ b/frontends/web/src/new_front/components/CreateSamples/CreateSamples/AnnotationInterfaces/Contexts/DescribeImage.tsx @@ -143,7 +143,7 @@ const DescribeImage: FC = ({ ); const [file, setFile] = useState(); const BASE_URL_2 = process.env.REACT_APP_API_HOST_2; - const { modelInputs, updateModelInputs } = useContext(CreateInterfaceContext); + const { modelInputs, updateModelInputs, removeItem } = useContext(CreateInterfaceContext); const handleGetLanguages = async (e: any) => { if (!e.value) return; @@ -243,6 +243,12 @@ const DescribeImage: FC = ({ useEffect(() => { localStorage.setItem("language", language); localStorage.setItem("country", country); + localStorage.removeItem("selectedCategory"); + localStorage.removeItem("selectedConcept"); + removeItem("category"); + removeItem("concept"); + setSelectedCategory(null); + setSelectedConcept(null); }, [language, country]); useEffect(() => { diff --git a/frontends/web/src/new_front/context/CreateInterface/Context.tsx b/frontends/web/src/new_front/context/CreateInterface/Context.tsx index e1b9222e..ed9f0c41 100644 --- a/frontends/web/src/new_front/context/CreateInterface/Context.tsx +++ b/frontends/web/src/new_front/context/CreateInterface/Context.tsx @@ -1,12 +1,23 @@ import React, { createContext, useState, FC } from "react"; +import { set } from "react-ga"; import useFetch from "use-http"; -export const CreateInterfaceContext = createContext({ +interface CreateInterfaceContextType { + modelInputs: Record; + metadataExample: Record; + updateModelInputs: (input: object, metadata?: boolean) => void; + amountExamplesCreatedToday: number; + updateAmountExamplesCreatedToday: (realRoundId: number, userId: number) => void; + removeItem: (key: string) => void; +} + +export const CreateInterfaceContext = createContext({ modelInputs: {}, metadataExample: {}, - updateModelInputs: (input: object, metadata?: boolean) => {}, + updateModelInputs: () => {}, amountExamplesCreatedToday: 0, - updateAmountExamplesCreatedToday: (realRoundId: number, userId: number) => {}, + updateAmountExamplesCreatedToday: () => {}, + removeItem: () => {}, }); type CreateInterfaceProviderProps = { @@ -16,7 +27,7 @@ type CreateInterfaceProviderProps = { export const CreateInterfaceProvider: FC = ({ children, }) => { - const [modelInputs, setModelInputs] = useState({}); + const [modelInputs, setModelInputs] = useState>({}); const [metadataExample, setMetadataExample] = useState({}); const [amountExamplesCreatedToday, setAmountExamplesCreatedToday] = useState(0); @@ -50,6 +61,13 @@ export const CreateInterfaceProvider: FC = ({ } }; + const removeItem = (key: string) => { + setModelInputs((prevModelInputs) => { + const {[key]: _, ...newObject} = prevModelInputs + return newObject; + }); + } + return ( = ({ updateModelInputs, amountExamplesCreatedToday, updateAmountExamplesCreatedToday, + removeItem, }} > {children} From 08205a03de8ae180c77b54cff1e54321aece65fa Mon Sep 17 00:00:00 2001 From: Sara H Date: Thu, 23 May 2024 12:48:16 -0500 Subject: [PATCH 4/8] Just one popup --- .../SelectBetweenImagesGenerative.tsx | 23 ++++++++++++------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/frontends/web/src/new_front/components/CreateSamples/CreateSamples/AnnotationInterfaces/Contexts/SelectBetweenImagesGenerative.tsx b/frontends/web/src/new_front/components/CreateSamples/CreateSamples/AnnotationInterfaces/Contexts/SelectBetweenImagesGenerative.tsx index b4d67e79..8c95e22f 100644 --- a/frontends/web/src/new_front/components/CreateSamples/CreateSamples/AnnotationInterfaces/Contexts/SelectBetweenImagesGenerative.tsx +++ b/frontends/web/src/new_front/components/CreateSamples/CreateSamples/AnnotationInterfaces/Contexts/SelectBetweenImagesGenerative.tsx @@ -12,8 +12,6 @@ import { getIdFromImageString } from "new_front/utils/helpers/functions/DataMani import { PacmanLoader } from "react-spinners"; import Swal from "sweetalert2"; import useFetch from "use-http"; -import useFetchSSE from "new_front/utils/helpers/functions/FetchSSE"; -import { swap } from "formik"; const SelectBetweenImagesGenerative: FC< ContextAnnotationFactoryType & ContextConfigType @@ -30,7 +28,7 @@ const SelectBetweenImagesGenerative: FC< const [promptHistory, setPromptHistory] = useState([]); const [showQueue, setShowQueue] = useState(false); const [positionQueue, setPositionQueue] = useState({}); - const [firstMessageReceived, setFirstMessageReceived] = useState(false); + const [firstMessageReceived, setFirstMessageReceived] = useState(false); const [allowsGeneration, setAllowsGeneration] = useState(true); const [showLoader, setShowLoader] = useState(false); const [showImages, setShowImages] = useState([]); @@ -96,6 +94,14 @@ const SelectBetweenImagesGenerative: FC< } }; + const handlePopUp = () => { + Swal.fire({ + title: "Example already submitted", + text: "You selected a prompt from your history and we are showing the images previously generated for this prompt. Modify the prompt to get new image generation.", + icon: "info", + }); + } + const runCheckers = async (prompt: string) => { const checkIfPromptExistsForUser = await post( "/historical_data/check_if_historical_data_exists", @@ -106,11 +112,7 @@ const SelectBetweenImagesGenerative: FC< }, ); if (checkIfPromptExistsForUser) { - Swal.fire({ - title: "Example already submitted", - text: "You selected a prompt from your history and we are showing the images previously generated for this prompt. Modify the prompt to get new image generation.", - icon: "info", - }); + setFirstMessageReceived(true); } const promptWithMoreThanOneHundredSubmissions = await post( "/historical_data/get_occurrences_with_more_than_one_hundred", @@ -118,6 +120,7 @@ const SelectBetweenImagesGenerative: FC< task_id: taskId, }, ); + const checkIfPromptIsInOccurrences = promptWithMoreThanOneHundredSubmissions.some( (item: any) => item.data === prompt.trim(), @@ -356,6 +359,10 @@ const SelectBetweenImagesGenerative: FC< } }, [selectedImage]); + useEffect(() => { + firstMessageReceived && handlePopUp(); + }, [firstMessageReceived]) + return ( <> {!showLoader ? ( From 34fd070cbb7fa90c0cd438895bf4a0eceb07a7ec Mon Sep 17 00:00:00 2001 From: Sara H Date: Thu, 23 May 2024 20:21:57 -0500 Subject: [PATCH 5/8] Fix provider bug --- backend/app/domain/services/utils/llm.py | 41 ++++++++++++++++-------- 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/backend/app/domain/services/utils/llm.py b/backend/app/domain/services/utils/llm.py index 9489db73..69d860f2 100644 --- a/backend/app/domain/services/utils/llm.py +++ b/backend/app/domain/services/utils/llm.py @@ -70,6 +70,7 @@ async def generate_text( provider, is_conversational: bool = False, ) -> str: + provider = provider if type(provider) == str else self.provider_name() model_name = model[provider]["model_name"] frequency_penalty = model[provider]["frequency_penalty"] presence_penalty = model[provider]["presence_penalty"] @@ -111,8 +112,9 @@ async def generate_text( return None async def conversational_generation( - self, prompt: str, model: dict, history: dict, provider: str + self, prompt: str, model: dict, history: dict, provider=None ) -> str: + provider = provider if type(provider) == str else self.provider_name() head_template = model[provider]["templates"]["header"] foot_template = model[provider]["templates"]["footer"] formatted_conversation = [] @@ -156,7 +158,7 @@ def generate_text(self, prompt: str, model: dict) -> str: # return sample def conversational_generation( - self, prompt: str, model: dict, history: dict, provider: str + self, prompt: str, model: dict, history: dict, provider: str = None ) -> str: return @@ -171,8 +173,9 @@ def __init__(self): @async_timeout(30) async def generate_text( - self, prompt: str, model: dict, provider, is_conversational: bool = False + self, prompt: str, model: dict, provider = None, is_conversational: bool = False ) -> str: + provider = provider if type(provider) == str else self.provider_name() head_template = model[provider]["templates"]["header"] foot_template = model[provider]["templates"]["footer"] if is_conversational: @@ -207,8 +210,9 @@ async def generate_text( return None async def conversational_generation( - self, prompt: str, model: dict, history: dict, provider: str + self, prompt: str, model: dict, history: dict, provider: str = None ) -> str: + provider = provider if type(provider) == str else self.provider_name() head_template = model[provider]["templates"]["header"] foot_template = model[provider]["templates"]["footer"] formatted_conversation = [] @@ -250,10 +254,11 @@ async def generate_text( self, prompt: str, model: dict, - provider, + provider = None, is_conversational: bool = False, chat_history=[], ) -> str: + provider = provider if type(provider) == str else self.provider_name() head_template = model[provider]["templates"]["header"] foot_template = model[provider]["templates"]["footer"] model_name = model[provider]["model_name"] @@ -299,8 +304,9 @@ async def generate_text( return None async def conversational_generation( - self, prompt: str, model: dict, history: dict, provider: str + self, prompt: str, model: dict, history: dict, provider: str = None ) -> str: + provider = provider if type(provider) == str else self.provider_name() head_template = model[provider]["templates"]["header"] foot_template = model[provider]["templates"]["footer"] formatted_conversation = [] @@ -335,8 +341,9 @@ def __init__(self): @async_timeout(30) async def generate_text( - self, prompt: str, model: dict, provider, is_conversational: bool = False + self, prompt: str, model: dict, provider=None, is_conversational: bool = False ) -> str: + provider = provider if type(provider) == str else self.provider_name() head_template = model[provider]["templates"]["header"] # foot_template = model[provider]["templates"]["footer"] params = { @@ -380,8 +387,9 @@ async def generate_text( return None async def conversational_generation( - self, prompt: str, model: dict, history: dict, provider: str + self, prompt: str, model: dict, history: dict, provider: str = None ) -> str: + provider = provider if type(provider) == str else self.provider_name() head_template = model[provider]["templates"]["header"] # foot_template = model[provider]["templates"]["footer"] formatted_conversation = [] @@ -418,8 +426,9 @@ def __init__(self): @async_timeout(30) async def generate_text( - self, prompt: str, model: dict, provider, is_conversational: bool = False + self, prompt: str, model: dict, provider=None, is_conversational: bool = False ) -> str: + provider = provider if type(provider) == str else self.provider_name() model_name = model[provider]["model_name"] temperature = model[provider]["temperature"] top_p = model[provider]["top_p"] @@ -450,8 +459,9 @@ async def generate_text( return None async def conversational_generation( - self, prompt: str, model: dict, history: dict, provider: str + self, prompt: str, model: dict, history: dict, provider: str = None ) -> str: + provider = provider if type(provider) == str else self.provider_name() head_template = model[provider]["templates"]["header"] foot_template = model[provider]["templates"]["footer"] formatted_conversation = [] @@ -488,8 +498,9 @@ def __init__(self): @async_timeout(30) def generate_text( - self, prompt: str, model: dict, provider, is_conversational: bool = False + self, prompt: str, model: dict, provider=None, is_conversational: bool = False ) -> str: + provider = provider if type(provider) == str else self.provider_name() head_template = model[provider]["templates"]["header"] foot_template = model[provider]["templates"]["footer"] model_name = model[provider]["model_name"] @@ -522,7 +533,7 @@ def generate_text( return None def conversational_generation( - self, prompt: str, model: dict, history: dict, provider: str + self, prompt: str, model: dict, history: dict, provider: str = None ) -> str: head_template = model[provider]["templates"]["header"] foot_template = model[provider]["templates"]["footer"] @@ -563,8 +574,9 @@ def __init__(self): @async_timeout(30) async def generate_text( - self, prompt: str, model: dict, provider, is_conversational=False + self, prompt: str, model: dict, provider=None, is_conversational=False ) -> str: + provider = provider if type(provider) == str else self.provider_name() is_llama = model[provider]["is_llama"] is_falcon = model[provider]["is_falcon"] is_pythia = model[provider]["is_pythia"] @@ -643,8 +655,9 @@ async def generate_text( return None async def conversational_generation( - self, prompt: str, model: dict, history: dict, provider: str + self, prompt: str, model: dict, history: dict, provider: str = None ) -> str: + provider = provider if type(provider) == str else self.provider_name() head_template = model[provider]["templates"]["header"] foot_template = model[provider]["templates"]["footer"] is_llama = model[provider]["is_llama"] From 0278409a18dd4ce1f26a0d7b00849f155baa0660 Mon Sep 17 00:00:00 2001 From: Sara H Date: Fri, 24 May 2024 18:09:48 -0500 Subject: [PATCH 6/8] run black --- backend/app/domain/services/utils/llm.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/app/domain/services/utils/llm.py b/backend/app/domain/services/utils/llm.py index 69d860f2..967b2922 100644 --- a/backend/app/domain/services/utils/llm.py +++ b/backend/app/domain/services/utils/llm.py @@ -173,7 +173,7 @@ def __init__(self): @async_timeout(30) async def generate_text( - self, prompt: str, model: dict, provider = None, is_conversational: bool = False + self, prompt: str, model: dict, provider=None, is_conversational: bool = False ) -> str: provider = provider if type(provider) == str else self.provider_name() head_template = model[provider]["templates"]["header"] @@ -254,7 +254,7 @@ async def generate_text( self, prompt: str, model: dict, - provider = None, + provider=None, is_conversational: bool = False, chat_history=[], ) -> str: From f2c11eebf52d5d6a6dda4711852af32546f9e66c Mon Sep 17 00:00:00 2001 From: Sara H Date: Tue, 4 Jun 2024 15:28:36 -0500 Subject: [PATCH 7/8] Use of Redux-persist avoid the use of three kind of storage --- frontends/web/package-lock.json | 96 ++ frontends/web/package.json | 3 + frontends/web/src/containers/App.js | 891 +++++++++--------- .../Contexts/DescribeImage.tsx | 220 +++-- .../components/Inputs/DoubleDropDown.tsx | 67 +- frontends/web/src/state/store.tsx | 25 + .../web/src/state/wonders/wondersSlice.tsx | 54 ++ 7 files changed, 782 insertions(+), 574 deletions(-) create mode 100644 frontends/web/src/state/store.tsx create mode 100644 frontends/web/src/state/wonders/wondersSlice.tsx diff --git a/frontends/web/package-lock.json b/frontends/web/package-lock.json index f99b9f0a..101d0d78 100644 --- a/frontends/web/package-lock.json +++ b/frontends/web/package-lock.json @@ -13,6 +13,7 @@ "@microsoft/fetch-event-source": "^2.0.1", "@mui/icons-material": "^5.14.3", "@mui/material": "^5.14.3", + "@reduxjs/toolkit": "^2.2.5", "@tailwindcss/line-clamp": "^0.4.2", "@testing-library/jest-dom": "^4.2.4", "@testing-library/react": "^9.5.0", @@ -58,6 +59,7 @@ "react-multi-carousel": "^2.8.2", "react-player": "^2.6.2", "react-powerplug": "^1.0.0", + "react-redux": "^9.1.2", "react-router-dom": "^5.2.0", "react-router-hash-link": "^2.4.3", "react-scripts": "5.0.1", @@ -69,6 +71,7 @@ "react-table": "^7.7.0", "react-text-annotate": "^0.3.0", "recharts": "^1.8.5", + "redux-persist": "^6.0.0", "set-value": "^4.0.1", "style-loader": "^1.2.1", "sweetalert2": "^11.6.14", @@ -4695,6 +4698,38 @@ "url": "https://opencollective.com/popperjs" } }, + "node_modules/@reduxjs/toolkit": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-2.2.5.tgz", + "integrity": "sha512-aeFA/s5NCG7NoJe/MhmwREJxRkDs0ZaSqt0MxhWUrwCf1UQXpwR87RROJEql0uAkLI6U7snBOYOcKw83ew3FPg==", + "dependencies": { + "immer": "^10.0.3", + "redux": "^5.0.1", + "redux-thunk": "^3.1.0", + "reselect": "^5.1.0" + }, + "peerDependencies": { + "react": "^16.9.0 || ^17.0.0 || ^18", + "react-redux": "^7.2.1 || ^8.1.3 || ^9.0.0" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "react-redux": { + "optional": true + } + } + }, + "node_modules/@reduxjs/toolkit/node_modules/immer": { + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/immer/-/immer-10.1.1.tgz", + "integrity": "sha512-s2MPrmjovJcoMaHtx6K11Ra7oD05NT97w1IC5zpMkT6Atjr7H8LjaDd81iIxUYpMKSRRNMJE703M1Fhr/TctHw==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/immer" + } + }, "node_modules/@restart/context": { "version": "2.1.4", "resolved": "https://registry.npmjs.org/@restart/context/-/context-2.1.4.tgz", @@ -5961,6 +5996,11 @@ "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.8.tgz", "integrity": "sha512-d0XxK3YTObnWVp6rZuev3c49+j4Lo8g4L1ZRm9z5L0xpoZycUPshHgczK5gsUMaZOstjVYYi09p5gYvUtfChYw==" }, + "node_modules/@types/use-sync-external-store": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz", + "integrity": "sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA==" + }, "node_modules/@types/warning": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@types/warning/-/warning-3.0.0.tgz", @@ -21472,6 +21512,28 @@ "resolved": "https://registry.npmjs.org/react-property/-/react-property-2.0.0.tgz", "integrity": "sha512-kzmNjIgU32mO4mmH5+iUyrqlpFQhF8K2k7eZ4fdLSOPFrD1XgEuSBv9LDEgxRXTMBqMd8ppT0x6TIzqE5pdGdw==" }, + "node_modules/react-redux": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.1.2.tgz", + "integrity": "sha512-0OA4dhM1W48l3uzmv6B7TXPCGmokUU4p1M44DGN2/D9a1FjVPukVjER1PcPX97jIg6aUeLq1XJo1IpfbgULn0w==", + "dependencies": { + "@types/use-sync-external-store": "^0.0.3", + "use-sync-external-store": "^1.0.0" + }, + "peerDependencies": { + "@types/react": "^18.2.25", + "react": "^18.0", + "redux": "^5.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "redux": { + "optional": true + } + } + }, "node_modules/react-refresh": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.11.0.tgz", @@ -22904,6 +22966,27 @@ "balanced-match": "^1.0.0" } }, + "node_modules/redux": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz", + "integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==" + }, + "node_modules/redux-persist": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/redux-persist/-/redux-persist-6.0.0.tgz", + "integrity": "sha512-71LLMbUq2r02ng2We9S215LtPu3fY0KgaGE0k8WRgl6RkqxtGfl7HUozz1Dftwsb0D/5mZ8dwAaPbtnzfvbEwQ==", + "peerDependencies": { + "redux": ">4.0.0" + } + }, + "node_modules/redux-thunk": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-3.1.0.tgz", + "integrity": "sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw==", + "peerDependencies": { + "redux": "^5.0.0" + } + }, "node_modules/reflect.getprototypeof": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.4.tgz", @@ -24156,6 +24239,11 @@ "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==" }, + "node_modules/reselect": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/reselect/-/reselect-5.1.0.tgz", + "integrity": "sha512-aw7jcGLDpSgNDyWBQLv2cedml85qd95/iszJjN988zX1t7AVRJi19d9kto5+W7oCfQ94gyo40dVbT6g2k4/kXg==" + }, "node_modules/resize-observer-polyfill": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz", @@ -26922,6 +27010,14 @@ "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0" } }, + "node_modules/use-sync-external-store": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.2.tgz", + "integrity": "sha512-PElTlVMwpblvbNqQ82d2n6RjStvdSoNe9FG28kNfz3WiXilJm4DdNkEzRhCZuIDwY8U08WVihhGR5iRqAwfDiw==", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", diff --git a/frontends/web/package.json b/frontends/web/package.json index de8a8c1b..6583f326 100644 --- a/frontends/web/package.json +++ b/frontends/web/package.json @@ -8,6 +8,7 @@ "@microsoft/fetch-event-source": "^2.0.1", "@mui/icons-material": "^5.14.3", "@mui/material": "^5.14.3", + "@reduxjs/toolkit": "^2.2.5", "@tailwindcss/line-clamp": "^0.4.2", "@testing-library/jest-dom": "^4.2.4", "@testing-library/react": "^9.5.0", @@ -53,6 +54,7 @@ "react-multi-carousel": "^2.8.2", "react-player": "^2.6.2", "react-powerplug": "^1.0.0", + "react-redux": "^9.1.2", "react-router-dom": "^5.2.0", "react-router-hash-link": "^2.4.3", "react-scripts": "5.0.1", @@ -64,6 +66,7 @@ "react-table": "^7.7.0", "react-text-annotate": "^0.3.0", "recharts": "^1.8.5", + "redux-persist": "^6.0.0", "set-value": "^4.0.1", "style-loader": "^1.2.1", "sweetalert2": "^11.6.14", diff --git a/frontends/web/src/containers/App.js b/frontends/web/src/containers/App.js index 804409c3..352ce849 100644 --- a/frontends/web/src/containers/App.js +++ b/frontends/web/src/containers/App.js @@ -66,6 +66,9 @@ import OthersTaskLanding from "new_front/pages/CommunitiesLandingPages/OthersTas import logoBlack from "new_front/assets/logo_black.png"; import logoWhite from "new_front/assets/logo_mlcommos_white.png"; import OverlayInstructionsProvider from "new_front/context/OverlayInstructions/Context"; +import { Provider } from "react-redux"; +import { PersistGate } from "redux-persist/integration/react"; +import { store, persistor } from "state/store.tsx"; const BASE_URL_2 = process.env.REACT_APP_API_HOST_2; @@ -155,456 +158,460 @@ class App extends React.Component { - - - - - - ( - - )} - /> - {!showContentOnly && ( - - + + + + + + + ( + + )} /> - - MLCommons Logo - - - Dynabench - - - - + + + + )} +
+ + + + + + - )} - /> - ( - - )} - /> - ( - + + + } + /> + ( + + )} + /> + ( + + )} + /> + ( + + )} + /> + + + + + + + + + + + - )} - /> - - - - - - - - - - - - - - - - - - - - - - - - - - -
- {!showContentOnly && ( -
- - -
- Copyright © 2023 MLCommons, Inc. -
-
- - Contact - -
-
- - Terms of Use - -
-
- - Data Policy - -
-
-
-
- )} -
-
-
-
+ + + + + + + + + + + + + + + +
+ {!showContentOnly && ( +
+ + +
+ Copyright © 2023 MLCommons, Inc. +
+
+ + Contact + +
+
+ + Terms of Use + +
+
+ + Data Policy + +
+
+
+
+ )} + + + + + + diff --git a/frontends/web/src/new_front/components/CreateSamples/CreateSamples/AnnotationInterfaces/Contexts/DescribeImage.tsx b/frontends/web/src/new_front/components/CreateSamples/CreateSamples/AnnotationInterfaces/Contexts/DescribeImage.tsx index 5a4abf8f..8d0d2067 100644 --- a/frontends/web/src/new_front/components/CreateSamples/CreateSamples/AnnotationInterfaces/Contexts/DescribeImage.tsx +++ b/frontends/web/src/new_front/components/CreateSamples/CreateSamples/AnnotationInterfaces/Contexts/DescribeImage.tsx @@ -1,22 +1,32 @@ -import GeneralButton from "new_front/components/Buttons/GeneralButton"; -import BasicInput from "new_front/components/Inputs/BasicInput"; -import { ContextConfigType } from "new_front/types/createSamples/createSamples/annotationContext"; -import { ContextAnnotationFactoryType } from "new_front/types/createSamples/createSamples/annotationFactory"; import React, { FC, useContext, useEffect, useState } from "react"; -import DoubleDropDown from "new_front/components/Inputs/DoubleDropDown"; +import { useDispatch, useSelector } from "react-redux"; +import { PacmanLoader } from "react-spinners"; +import MDEditor from "@uiw/react-md-editor"; +import { Modal } from "react-bootstrap"; import Select from "react-select"; import useFetch from "use-http"; -import { PacmanLoader } from "react-spinners"; -import { CreateInterfaceContext } from "new_front/context/CreateInterface/Context"; import axios from "axios"; -import { Modal } from "react-bootstrap"; -import MDEditor from "@uiw/react-md-editor"; + +import { CreateInterfaceContext } from "new_front/context/CreateInterface/Context"; +import { + updateCountry, + updatelanguage, + resetCategoryAndConcept, + resetAllButCountry, +} from "state/wonders/wondersSlice"; +import { RootState } from "state/store"; + +import GeneralButton from "new_front/components/Buttons/GeneralButton"; +import DoubleDropDown from "new_front/components/Inputs/DoubleDropDown"; +import { ContextConfigType } from "new_front/types/createSamples/createSamples/annotationContext"; +import { ContextAnnotationFactoryType } from "new_front/types/createSamples/createSamples/annotationFactory"; type ImageUploadProps = { image: string; setFile: (file: File) => void; setImage: (image: string) => void; updateModelInputs: (input: object, metadata?: boolean) => void; + letMagnifier?: boolean; }; const ImageUpload = ({ @@ -24,8 +34,16 @@ const ImageUpload = ({ setFile, setImage, updateModelInputs, + letMagnifier, }: ImageUploadProps) => { const [dragging, setDragging] = useState(false); + const magnifierHeight = 200; + const magnifieWidth = 200; + const zoomLevel = 1.5; + const [imgWidth, setImgWidth] = useState(0); + const [imgHeight, setImgHeight] = useState(0); + const [showMagnifier, setShowMagnifier] = useState(false); + const [[x, y], setXY] = useState([0, 0]); const handleDragEnter = (e: React.DragEvent) => { e.preventDefault(); @@ -61,18 +79,37 @@ const ImageUpload = ({ } }; + const handleMouseEnter = (e: any) => { + const elem = e.currentTarget; + const { width, height } = elem.getBoundingClientRect(); + setImgWidth(width); + setImgHeight(height); + setShowMagnifier(true); + }; + + const handleMouseMove = (e: any) => { + const elem = e.currentTarget; + const { top, left } = elem.getBoundingClientRect(); + const x = e.pageX - left - window.scrollX; + const y = e.pageY - top - window.scrollY; + setXY([x, y]); + }; + return (
-
+
src setShowMagnifier(false)} onClick={() => { const input = document.getElementById("fileInput"); if (input) { @@ -80,6 +117,24 @@ const ImageUpload = ({ } }} /> + {letMagnifier && showMagnifier && ( +
+ )}
= ({ setIsGenerativeContext, generative_context, }) => { + const BASE_URL_2 = process.env.REACT_APP_API_HOST_2; + const { post, response, loading } = useFetch(); + const dispatch = useDispatch(); + const { updateModelInputs } = useContext(CreateInterfaceContext); + const country = useSelector((state: RootState) => state.wonders.country); + const language = useSelector((state: RootState) => state.wonders.language); + const selectedCategory = useSelector( + (state: RootState) => state.wonders.selectedCategory + ); + const selectedConcept = useSelector( + (state: RootState) => state.wonders.selectedConcept + ); + const [filterContext, setFilterContext] = useState(); const [image, setImage] = useState( - "https://w7.pngwing.com/pngs/527/625/png-transparent-scalable-graphics-computer-icons-upload-uploading-cdr-angle-text-thumbnail.png", + "https://w7.pngwing.com/pngs/527/625/png-transparent-scalable-graphics-computer-icons-upload-uploading-cdr-angle-text-thumbnail.png" ); const [description, setDescription] = useState(""); - const [selectedCategory, setSelectedCategory] = useState( - localStorage.getItem("selectedCategory") - ? JSON.parse(localStorage.getItem("selectedCategory") || "") - : null, - ); - const [selectedConcept, setSelectedConcept] = useState( - localStorage.getItem("selectedConcept") - ? JSON.parse(localStorage.getItem("selectedConcept") || "") - : null, - ); const [showExample, setShowExample] = useState(false); - const { post, response, loading } = useFetch(); const [countries, setCountries] = useState([]); - const [country, setCountry] = useState( - localStorage.getItem("country") || "", - ); const [languages, setLanguages] = useState([]); - const [language, setLanguage] = useState( - localStorage.getItem("language") || "", - ); const [file, setFile] = useState(); - const BASE_URL_2 = process.env.REACT_APP_API_HOST_2; - const { modelInputs, updateModelInputs, removeItem } = useContext(CreateInterfaceContext); - const handleGetLanguages = async (e: any) => { - if (!e.value) return; - setCountry(e.value); + const handleGetLanguages = async (country: string) => { // @ts-ignore const extractedLanguages = generative_context.artifacts.options.reduce( (acc: string[], item: any) => { - if (item.primary === e.value) acc.push(...item.secondary); + if (item.primary === country) acc.push(...item.secondary); return acc; }, - [] as string[], + [] as string[] ); - setLanguage(""); + dispatch(resetAllButCountry()); setLanguages(extractedLanguages); setFilterContext(null); updateModelInputs({ - origin_primary: e.value, + origin_primary: country, origin_secondary: extractedLanguages[0], }); }; + const handleCountryChange = (e: any) => { + if (!e.value) return; + dispatch(updateCountry(e.value)); + handleGetLanguages(e.value); + dispatch(resetCategoryAndConcept()); + }; + const handleLanguageChange = (e: any) => { - setLanguage(e.value); + dispatch(updatelanguage(e.value)); updateModelInputs({ origin_primary: country, origin_secondary: e.value }); }; @@ -190,14 +244,20 @@ const DescribeImage: FC = ({ }; const handleSaveData = async () => { - if (description.length < 20) { - alert("Please enter a description with at least 20 characters."); + if (!selectedCategory) { + alert("Please pick a category."); return; } - if (!file || !description || !selectedCategory || !selectedConcept) { - alert( - "Please choose an image, describe it, and pick a category and concept.", - ); + if (!selectedConcept) { + alert("Please pick a concept."); + return; + } + if (!file) { + alert("Please choose an image."); + return; + } + if (description.length < 20) { + alert("Please enter a description with at least 20 characters."); return; } const formData = new FormData(); @@ -228,50 +288,28 @@ const DescribeImage: FC = ({ // @ts-ignore const extractedCountries = generative_context.artifacts.options.map( // @ts-ignore - (item) => item.primary, + (item) => item.primary ); setCountries(extractedCountries); } }, [generative_context]); useEffect(() => { + if (country && !language) { + handleGetLanguages(country); + } if (country && language) { handleGetCategories(); } - }, [country, language]); - - useEffect(() => { - localStorage.setItem("language", language); - localStorage.setItem("country", country); - localStorage.removeItem("selectedCategory"); - localStorage.removeItem("selectedConcept"); - removeItem("category"); - removeItem("concept"); - setSelectedCategory(null); - setSelectedConcept(null); }, [language, country]); useEffect(() => { - if (localStorage.getItem("language") && localStorage.getItem("country")) { - updateModelInputs({ - origin_primary: localStorage.getItem("country"), - origin_secondary: localStorage.getItem("language"), - }); - } - if (localStorage.getItem("selectedCategory")) { - updateModelInputs({ category: selectedCategory.value }); - } - if (localStorage.getItem("selectedConcept")) { - updateModelInputs({ concept: selectedConcept.value }); - } - }, [localStorage]); + selectedCategory && updateModelInputs({ category: selectedCategory.value }); + }, [selectedCategory]); useEffect(() => { - // If language and country are already selected then fetch the context - if (localStorage.getItem("language") && localStorage.getItem("country")) { - handleGetCategories(); - } - }, [localStorage.getItem("language")]); + selectedConcept && updateModelInputs({ concept: selectedConcept.value }); + }, [selectedConcept]); return ( <> @@ -307,21 +345,22 @@ const DescribeImage: FC = ({
-
-
+
+

Country

({ value: language, label: language, @@ -336,9 +381,9 @@ const DescribeImage: FC = ({ onChange={handleLanguageChange} placeholder="Select a language" defaultValue={ - localStorage.getItem("language") && { - value: localStorage.getItem("language"), - label: localStorage.getItem("language"), + language && { + value: language, + label: language, } } /> @@ -351,10 +396,6 @@ const DescribeImage: FC = ({
@@ -371,7 +412,7 @@ const DescribeImage: FC = ({
@@ -386,6 +427,7 @@ const DescribeImage: FC = ({ setFile={setFile} setImage={setImage} updateModelInputs={updateModelInputs} + letMagnifier={file ? true : false} /> void; }; const DoubleDropDown = ({ filterContext, - selectedCategory, - setSelectedCategory, - selectedConcept, - setSelectedConcept, updateModelInputs, }: DoubleDropDownProps) => { + const dispatch = useDispatch(); + const selectedCategory = useSelector( + (state: RootState) => state.wonders.selectedCategory + ); + const selectedConcept = useSelector( + (state: RootState) => state.wonders.selectedConcept + ); + const handleCategoryChange = (selectedOption: any) => { - setSelectedCategory(selectedOption); updateModelInputs({ category: selectedOption.value }); - setSelectedConcept(null); + dispatch(updateCategory(selectedOption)); + dispatch(updateConcept(null)); }; const handleConceptChange = (selectedOption: any) => { updateModelInputs({ concept: selectedOption.value }); - setSelectedConcept(selectedOption); + dispatch(updateConcept(selectedOption)); }; - useEffect(() => { - if (selectedCategory) { - localStorage.setItem( - "selectedCategory", - selectedCategory ? JSON.stringify(selectedCategory) : "", - ); - } - if (selectedConcept) { - localStorage.setItem( - "selectedConcept", - selectedConcept ? JSON.stringify(selectedConcept) : "", - ); - } - }, [selectedCategory, selectedConcept]); - - const actualCategory = localStorage.getItem("selectedCategory") - ? JSON.parse(localStorage.getItem("selectedCategory") || "") - : null; - const actualConcept = localStorage.getItem("selectedConcept") - ? JSON.parse(localStorage.getItem("selectedConcept") || "") - : null; - return ( <> {filterContext && ( -
-
+
+

Category