From 2c81d1014715f1104fc0e82faa2f7084ccf2d463 Mon Sep 17 00:00:00 2001 From: Valentin Date: Wed, 20 Dec 2023 17:13:33 +0100 Subject: [PATCH 01/77] Deepfake v4 translation (#387) * Matomo update (#351) * refactoring, added matomo tracking * Pre master (#349) * Bugfixes + Added tracking (#292) (#293) * rename Feeback * mv2 fix for build * thumbnail * remove console * roll back publicpath * Added trackEvent --------- Co-authored-by: AFPMedialab <40788591+AFPMedialab@users.noreply.github.com> Co-authored-by: Bertrand Goupil Co-authored-by: Valentin Porcellini * Changed dbkf img format (#299) (#300) Co-authored-by: Valentin Porcellini * Bugfixes (#303) * Changed dbkf img format (#299) Co-authored-by: Valentin Porcellini * DBKF and Thumbnail Fixes (#301) * Changed dbkf img format * Fixed download keyframe URI --------- Co-authored-by: Valentin Porcellini * Prevent tab deletion for reverse search calls (#302) * Changed dbkf img format * Fixed download keyframe URI * Added parameter to prevent tab deletion for app reverse search calls --------- Co-authored-by: Valentin Porcellini --------- Co-authored-by: Valentin Porcellini * Merge fix and cleanup (#305) * Changed dbkf img format (#299) Co-authored-by: Valentin Porcellini * DBKF and Thumbnail Fixes (#301) * Changed dbkf img format * Fixed download keyframe URI --------- Co-authored-by: Valentin Porcellini * Prevent tab deletion for reverse search calls (#302) * Changed dbkf img format * Fixed download keyframe URI * Added parameter to prevent tab deletion for app reverse search calls --------- Co-authored-by: Valentin Porcellini * Merge fix and cleanup (#304) * Changed dbkf img format * Fixed download keyframe URI * Added parameter to prevent tab deletion for app reverse search calls * Deleted mv2 file * Fixed merge issue --------- Co-authored-by: Valentin Porcellini --------- Co-authored-by: Valentin Porcellini * Pre master (#307) * Changed dbkf img format (#299) Co-authored-by: Valentin Porcellini * DBKF and Thumbnail Fixes (#301) * Changed dbkf img format * Fixed download keyframe URI --------- Co-authored-by: Valentin Porcellini * Prevent tab deletion for reverse search calls (#302) * Changed dbkf img format * Fixed download keyframe URI * Added parameter to prevent tab deletion for app reverse search calls --------- Co-authored-by: Valentin Porcellini * Merge fix and cleanup (#304) * Changed dbkf img format * Fixed download keyframe URI * Added parameter to prevent tab deletion for app reverse search calls * Deleted mv2 file * Fixed merge issue --------- Co-authored-by: Valentin Porcellini * Permission cleanup mv3 (#306) * Changed dbkf img format * Fixed download keyframe URI * Added parameter to prevent tab deletion for app reverse search calls * Deleted mv2 file * Fixed merge issue * Removed unused permission --------- Co-authored-by: Valentin Porcellini --------- Co-authored-by: Valentin Porcellini * Update README.md * Update README.md * Update README.md * Update README.md * Added base UI for img results * Added diffusion scores * Refactoring, added video detection methods * Better layout, fixed load state bug, added warning text, rank img detection from highest to lowest, async API calls * bigger detection text * Refactoring * Sort video detection by decreasing detection percentage * Prevent error * auto resize rectangles + refactoring * Added textfield url type * Improved layout, error handling, added tsv support * Fixed issue where the previous video was not replaced with the new video + cleanup * Fixed state issue when submitting a new video after a first one * Layout improvements for better readability * Removed unnecessary header * Fix lint error * Fixed undefined error + better deepfake rectangle layout * add i18n react support * Check if string can be a URL + added error message * Removed fixed height * Added role restriction for FTCN method * (wip) synthetic image tool, added jsconfig, fixed lint errors * change default tsv path * (wip) * Removed diffusion, fixed lint error * Fixed deepfake tool * missing tsv file * sync tansalation * Fixed display issue * Fixed url error msg + added other languages * Fixed url error msg + added other languages (#317) Co-authored-by: Valentin Porcellini * Added unina credits * Added restriction for other tools * Fixes + translations + credits (#318) * Fixed url error msg + added other languages * Added unina credits * Added restriction for other tools --------- Co-authored-by: Valentin Porcellini * redux keep last process url in textfield * Enhanced UI * externalize role hook * Enhanced UI + refactoring (#319) Co-authored-by: Valentin Porcellini * Deepfake v4 (#320) * Fixed url error msg + added other languages * Added unina credits * Added restriction for other tools * redux keep last process url in textfield * Enhanced UI * externalize role hook * Enhanced UI + refactoring (#319) Co-authored-by: Valentin Porcellini --------- Co-authored-by: Valentin Porcellini Co-authored-by: Bertrand Goupil * lens support url * Only show Google Lens if the image is from an URL * add remove button for video deepfake * Bugfixes (#321) * Fixed url error msg + added other languages * Added unina credits * Added restriction for other tools * redux keep last process url in textfield * Enhanced UI * externalize role hook * Enhanced UI + refactoring (#319) Co-authored-by: Valentin Porcellini * lens support url * Only show Google Lens if the image is from an URL * add remove button for video deepfake --------- Co-authored-by: Bertrand Goupil * matomo update + package upgrade * Matomo tracking + packages upgrade (#323) * Fixed url error msg + added other languages * Added unina credits * Added restriction for other tools * redux keep last process url in textfield * Enhanced UI * externalize role hook * Enhanced UI + refactoring (#319) Co-authored-by: Valentin Porcellini * lens support url * Only show Google Lens if the image is from an URL * add remove button for video deepfake * matomo update + package upgrade --------- Co-authored-by: Bertrand Goupil * increase status request to 3 seconds * Disable Google lens for data blob * fix dattime picker * remove console log * bug fix checkGif loop X advance search date control * geolocate url * Geoloc fix feature * Add detection progess bar * bug fix test if sevice is sending results * bug fix url in error * Revert "Merge branch 'deepfake-v4-translation' into deepfake-v4" This reverts commit c8aa9809d94f1bb8c536a61116067a884c9c0be2, reversing changes made to e04e89cb3bc5a9df26b2fc645e38ff21c7ba61fa. * bug fix GMT disable * remove log * remove log --------- Co-authored-by: AFPMedialab <40788591+AFPMedialab@users.noreply.github.com> Co-authored-by: Bertrand Goupil Co-authored-by: dteyssou --------- Co-authored-by: AFPMedialab <40788591+AFPMedialab@users.noreply.github.com> Co-authored-by: Bertrand Goupil Co-authored-by: dteyssou * Matomo update (#353) * refactoring, added matomo tracking * Pre master (#349) * Bugfixes + Added tracking (#292) (#293) * rename Feeback * mv2 fix for build * thumbnail * remove console * roll back publicpath * Added trackEvent --------- Co-authored-by: AFPMedialab <40788591+AFPMedialab@users.noreply.github.com> Co-authored-by: Bertrand Goupil Co-authored-by: Valentin Porcellini * Changed dbkf img format (#299) (#300) Co-authored-by: Valentin Porcellini * Bugfixes (#303) * Changed dbkf img format (#299) Co-authored-by: Valentin Porcellini * DBKF and Thumbnail Fixes (#301) * Changed dbkf img format * Fixed download keyframe URI --------- Co-authored-by: Valentin Porcellini * Prevent tab deletion for reverse search calls (#302) * Changed dbkf img format * Fixed download keyframe URI * Added parameter to prevent tab deletion for app reverse search calls --------- Co-authored-by: Valentin Porcellini --------- Co-authored-by: Valentin Porcellini * Merge fix and cleanup (#305) * Changed dbkf img format (#299) Co-authored-by: Valentin Porcellini * DBKF and Thumbnail Fixes (#301) * Changed dbkf img format * Fixed download keyframe URI --------- Co-authored-by: Valentin Porcellini * Prevent tab deletion for reverse search calls (#302) * Changed dbkf img format * Fixed download keyframe URI * Added parameter to prevent tab deletion for app reverse search calls --------- Co-authored-by: Valentin Porcellini * Merge fix and cleanup (#304) * Changed dbkf img format * Fixed download keyframe URI * Added parameter to prevent tab deletion for app reverse search calls * Deleted mv2 file * Fixed merge issue --------- Co-authored-by: Valentin Porcellini --------- Co-authored-by: Valentin Porcellini * Pre master (#307) * Changed dbkf img format (#299) Co-authored-by: Valentin Porcellini * DBKF and Thumbnail Fixes (#301) * Changed dbkf img format * Fixed download keyframe URI --------- Co-authored-by: Valentin Porcellini * Prevent tab deletion for reverse search calls (#302) * Changed dbkf img format * Fixed download keyframe URI * Added parameter to prevent tab deletion for app reverse search calls --------- Co-authored-by: Valentin Porcellini * Merge fix and cleanup (#304) * Changed dbkf img format * Fixed download keyframe URI * Added parameter to prevent tab deletion for app reverse search calls * Deleted mv2 file * Fixed merge issue --------- Co-authored-by: Valentin Porcellini * Permission cleanup mv3 (#306) * Changed dbkf img format * Fixed download keyframe URI * Added parameter to prevent tab deletion for app reverse search calls * Deleted mv2 file * Fixed merge issue * Removed unused permission --------- Co-authored-by: Valentin Porcellini --------- Co-authored-by: Valentin Porcellini * Update README.md * Update README.md * Update README.md * Update README.md * Added base UI for img results * Added diffusion scores * Refactoring, added video detection methods * Better layout, fixed load state bug, added warning text, rank img detection from highest to lowest, async API calls * bigger detection text * Refactoring * Sort video detection by decreasing detection percentage * Prevent error * auto resize rectangles + refactoring * Added textfield url type * Improved layout, error handling, added tsv support * Fixed issue where the previous video was not replaced with the new video + cleanup * Fixed state issue when submitting a new video after a first one * Layout improvements for better readability * Removed unnecessary header * Fix lint error * Fixed undefined error + better deepfake rectangle layout * add i18n react support * Check if string can be a URL + added error message * Removed fixed height * Added role restriction for FTCN method * (wip) synthetic image tool, added jsconfig, fixed lint errors * change default tsv path * (wip) * Removed diffusion, fixed lint error * Fixed deepfake tool * missing tsv file * sync tansalation * Fixed display issue * Fixed url error msg + added other languages * Fixed url error msg + added other languages (#317) Co-authored-by: Valentin Porcellini * Added unina credits * Added restriction for other tools * Fixes + translations + credits (#318) * Fixed url error msg + added other languages * Added unina credits * Added restriction for other tools --------- Co-authored-by: Valentin Porcellini * redux keep last process url in textfield * Enhanced UI * externalize role hook * Enhanced UI + refactoring (#319) Co-authored-by: Valentin Porcellini * Deepfake v4 (#320) * Fixed url error msg + added other languages * Added unina credits * Added restriction for other tools * redux keep last process url in textfield * Enhanced UI * externalize role hook * Enhanced UI + refactoring (#319) Co-authored-by: Valentin Porcellini --------- Co-authored-by: Valentin Porcellini Co-authored-by: Bertrand Goupil * lens support url * Only show Google Lens if the image is from an URL * add remove button for video deepfake * Bugfixes (#321) * Fixed url error msg + added other languages * Added unina credits * Added restriction for other tools * redux keep last process url in textfield * Enhanced UI * externalize role hook * Enhanced UI + refactoring (#319) Co-authored-by: Valentin Porcellini * lens support url * Only show Google Lens if the image is from an URL * add remove button for video deepfake --------- Co-authored-by: Bertrand Goupil * matomo update + package upgrade * Matomo tracking + packages upgrade (#323) * Fixed url error msg + added other languages * Added unina credits * Added restriction for other tools * redux keep last process url in textfield * Enhanced UI * externalize role hook * Enhanced UI + refactoring (#319) Co-authored-by: Valentin Porcellini * lens support url * Only show Google Lens if the image is from an URL * add remove button for video deepfake * matomo update + package upgrade --------- Co-authored-by: Bertrand Goupil * increase status request to 3 seconds * Disable Google lens for data blob * fix dattime picker * remove console log * bug fix checkGif loop X advance search date control * geolocate url * Geoloc fix feature * Add detection progess bar * bug fix test if sevice is sending results * bug fix url in error * Revert "Merge branch 'deepfake-v4-translation' into deepfake-v4" This reverts commit c8aa9809d94f1bb8c536a61116067a884c9c0be2, reversing changes made to e04e89cb3bc5a9df26b2fc645e38ff21c7ba61fa. * bug fix GMT disable * remove log * remove log --------- Co-authored-by: AFPMedialab <40788591+AFPMedialab@users.noreply.github.com> Co-authored-by: Bertrand Goupil Co-authored-by: dteyssou * Matomo update (#350) * Bugfixes + Added tracking (#292) (#293) * rename Feeback * mv2 fix for build * thumbnail * remove console * roll back publicpath * Added trackEvent --------- Co-authored-by: AFPMedialab <40788591+AFPMedialab@users.noreply.github.com> Co-authored-by: Bertrand Goupil Co-authored-by: Valentin Porcellini * Changed dbkf img format (#299) (#300) Co-authored-by: Valentin Porcellini * Bugfixes (#303) * Changed dbkf img format (#299) Co-authored-by: Valentin Porcellini * DBKF and Thumbnail Fixes (#301) * Changed dbkf img format * Fixed download keyframe URI --------- Co-authored-by: Valentin Porcellini * Prevent tab deletion for reverse search calls (#302) * Changed dbkf img format * Fixed download keyframe URI * Added parameter to prevent tab deletion for app reverse search calls --------- Co-authored-by: Valentin Porcellini --------- Co-authored-by: Valentin Porcellini * Merge fix and cleanup (#305) * Changed dbkf img format (#299) Co-authored-by: Valentin Porcellini * DBKF and Thumbnail Fixes (#301) * Changed dbkf img format * Fixed download keyframe URI --------- Co-authored-by: Valentin Porcellini * Prevent tab deletion for reverse search calls (#302) * Changed dbkf img format * Fixed download keyframe URI * Added parameter to prevent tab deletion for app reverse search calls --------- Co-authored-by: Valentin Porcellini * Merge fix and cleanup (#304) * Changed dbkf img format * Fixed download keyframe URI * Added parameter to prevent tab deletion for app reverse search calls * Deleted mv2 file * Fixed merge issue --------- Co-authored-by: Valentin Porcellini --------- Co-authored-by: Valentin Porcellini * Pre master (#307) * Changed dbkf img format (#299) Co-authored-by: Valentin Porcellini * DBKF and Thumbnail Fixes (#301) * Changed dbkf img format * Fixed download keyframe URI --------- Co-authored-by: Valentin Porcellini * Prevent tab deletion for reverse search calls (#302) * Changed dbkf img format * Fixed download keyframe URI * Added parameter to prevent tab deletion for app reverse search calls --------- Co-authored-by: Valentin Porcellini * Merge fix and cleanup (#304) * Changed dbkf img format * Fixed download keyframe URI * Added parameter to prevent tab deletion for app reverse search calls * Deleted mv2 file * Fixed merge issue --------- Co-authored-by: Valentin Porcellini * Permission cleanup mv3 (#306) * Changed dbkf img format * Fixed download keyframe URI * Added parameter to prevent tab deletion for app reverse search calls * Deleted mv2 file * Fixed merge issue * Removed unused permission --------- Co-authored-by: Valentin Porcellini --------- Co-authored-by: Valentin Porcellini * Update README.md * Update README.md * Update README.md * Update README.md * Added base UI for img results * Added diffusion scores * Refactoring, added video detection methods * Better layout, fixed load state bug, added warning text, rank img detection from highest to lowest, async API calls * bigger detection text * Refactoring * Sort video detection by decreasing detection percentage * Prevent error * auto resize rectangles + refactoring * Added textfield url type * Improved layout, error handling, added tsv support * Fixed issue where the previous video was not replaced with the new video + cleanup * Fixed state issue when submitting a new video after a first one * Layout improvements for better readability * Removed unnecessary header * Fix lint error * Fixed undefined error + better deepfake rectangle layout * add i18n react support * Check if string can be a URL + added error message * Removed fixed height * Added role restriction for FTCN method * (wip) synthetic image tool, added jsconfig, fixed lint errors * change default tsv path * (wip) * Removed diffusion, fixed lint error * Fixed deepfake tool * missing tsv file * sync tansalation * Fixed display issue * Fixed url error msg + added other languages * Fixed url error msg + added other languages (#317) Co-authored-by: Valentin Porcellini * Added unina credits * Added restriction for other tools * Fixes + translations + credits (#318) * Fixed url error msg + added other languages * Added unina credits * Added restriction for other tools --------- Co-authored-by: Valentin Porcellini * redux keep last process url in textfield * Enhanced UI * externalize role hook * Enhanced UI + refactoring (#319) Co-authored-by: Valentin Porcellini * Deepfake v4 (#320) * Fixed url error msg + added other languages * Added unina credits * Added restriction for other tools * redux keep last process url in textfield * Enhanced UI * externalize role hook * Enhanced UI + refactoring (#319) Co-authored-by: Valentin Porcellini --------- Co-authored-by: Valentin Porcellini Co-authored-by: Bertrand Goupil * lens support url * Only show Google Lens if the image is from an URL * add remove button for video deepfake * Bugfixes (#321) * Fixed url error msg + added other languages * Added unina credits * Added restriction for other tools * redux keep last process url in textfield * Enhanced UI * externalize role hook * Enhanced UI + refactoring (#319) Co-authored-by: Valentin Porcellini * lens support url * Only show Google Lens if the image is from an URL * add remove button for video deepfake --------- Co-authored-by: Bertrand Goupil * matomo update + package upgrade * Matomo tracking + packages upgrade (#323) * Fixed url error msg + added other languages * Added unina credits * Added restriction for other tools * redux keep last process url in textfield * Enhanced UI * externalize role hook * Enhanced UI + refactoring (#319) Co-authored-by: Valentin Porcellini * lens support url * Only show Google Lens if the image is from an URL * add remove button for video deepfake * matomo update + package upgrade --------- Co-authored-by: Bertrand Goupil * increase status request to 3 seconds * Disable Google lens for data blob * fix dattime picker * remove console log * bug fix checkGif loop X advance search date control * geolocate url * Geoloc fix feature * Add detection progess bar * bug fix test if sevice is sending results * bug fix url in error * Revert "Merge branch 'deepfake-v4-translation' into deepfake-v4" This reverts commit c8aa9809d94f1bb8c536a61116067a884c9c0be2, reversing changes made to e04e89cb3bc5a9df26b2fc645e38ff21c7ba61fa. * bug fix GMT disable * remove log * remove log * refactoring, added matomo tracking --------- Co-authored-by: AFPMedialab <40788591+AFPMedialab@users.noreply.github.com> Co-authored-by: Bertrand Goupil Co-authored-by: dteyssou * Added matomo analytics, fixed lint errors * Fixed layout and bugs --------- Co-authored-by: AFPMedialab <40788591+AFPMedialab@users.noreply.github.com> Co-authored-by: Bertrand Goupil Co-authored-by: dteyssou * Removed transition property to fix blank page error * Bumped version * Feedback email field (#367) * Added email field * Added email keywords * Allow to proceed if the email field is empty * Added label on top of the email field * 365 deepfake improve no face detection result parsing (#371) * #365 * Refactored variables. Removed non helping helper popup. Hide clip ui. Added translation * Removed console logs * Removed duplicate call, use async await, better error check (#375) * #361 matomo duplicate call at startup (#377) * Feedback email field (#367) (#368) * Added email field * Added email keywords * Allow to proceed if the email field is empty * Added label on top of the email field * 365 deepfake improve no face detection result parsing (#370) * Feedback email field (#367) * Added email field * Added email keywords * Allow to proceed if the email field is empty * Added label on top of the email field * #365 * Refactored variables. Removed non helping helper popup. Hide clip ui. Added translation * Removed console logs * Added new forensics api call * Fixes #361 --------- Co-authored-by: AFPMedialab <40788591+AFPMedialab@users.noreply.github.com> * Add sensible error messages when assistant fails. (#373) * allow x.com versions of twitter links (#382) Co-authored-by: davidwilby <6062469-davidwilby@users.noreply.gitlab.com> * Upgrade to Forensics API v4 (#385) * Feedback email field (#367) (#368) * Added email field * Added email keywords * Allow to proceed if the email field is empty * Added label on top of the email field * 365 deepfake improve no face detection result parsing (#370) * Feedback email field (#367) * Added email field * Added email keywords * Allow to proceed if the email field is empty * Added label on top of the email field * #365 * Refactored variables. Removed non helping helper popup. Hide clip ui. Added translation * Removed console logs * Added new forensics api call * Fixed typo * Added canvas component, create a mako scale from grayscale images * Enhanced the color scale. Fixed the mask display on hover. Added miniature canvases. Re-added fade animation. Added optional inverted grayscale support. Added optional unprocessed masking. Refactored code. * Fix the popup gif display for the forensic tool * Fixed #363, squashed some bugs, Refactoring * Fixed #363, squashed some bugs, Refactoring * WIP * WIP for CheckGIF * support checkGif with api for url and canvas * canvas big fix 1 * WIP * WIP Fixed bug where height for filter was not set well sometimes * WIP Fixed filter ratio to adjust the ratio to be the same as the original image, cleanup * Refactoring, fixed lint errors * Exclude CMFD filter from using color scale * Fix #381 --------- Co-authored-by: AFPMedialab <40788591+AFPMedialab@users.noreply.github.com> Co-authored-by: Bertrand Goupil * package upgrade * User friendly error messages * Display error message if there is no detection result --------- Co-authored-by: AFPMedialab <40788591+AFPMedialab@users.noreply.github.com> Co-authored-by: Bertrand Goupil Co-authored-by: dteyssou Co-authored-by: Twin Karmakharm Co-authored-by: David Wilby <24752124+davidwilby@users.noreply.github.com> Co-authored-by: davidwilby <6062469-davidwilby@users.noreply.gitlab.com> --- package-lock.json | 79 +----- .../NavItems/Assistant/AssistantRuleBook.jsx | 2 +- .../NavItems/tools/Analysis/Analysis.jsx | 2 +- .../Analysis/Results/AFacebookResults.jsx | 2 +- .../tools/Analysis/Results/TwitterResults.jsx | 2 +- .../tools/Analysis/Results/YoutubeResults.jsx | 2 +- .../tools/Analysis_images/Analysis.jsx | 2 +- .../Results/TwitterResults.jsx | 2 +- .../NavItems/tools/Deepfake/DeepfakeImage.jsx | 2 +- .../NavItems/tools/Deepfake/DeepfakeVideo.jsx | 2 +- .../NavItems/tools/Forensic/Forensic.jsx | 2 +- .../tools/Forensic/Results/ForensicResult.jsx | 255 ++++++++++++------ .../components/imageCanvas/imageCanvas.jsx | 24 ++ .../components/imageCanvas/useImageCanvas.jsx | 82 ++++++ .../NavItems/tools/Forensic/utils/index.jsx | 69 +++++ .../tools/Geolocation/Geolocation.jsx | 2 +- .../Results/GeolocationResults.jsx | 6 +- .../NavItems/tools/Gif/AnimatedGif.jsx | 83 +++--- .../NavItems/tools/Gif/CheckGif.jsx | 4 +- .../NavItems/tools/Gif/Hooks/useGetGif.jsx | 24 +- .../NavItems/tools/Keyframes/Keyframes.jsx | 2 +- .../Keyframes/Results/KeyFramesResults.jsx | 2 +- .../NavItems/tools/Magnifier/Magnifier.jsx | 2 +- .../tools/Magnifier/Results/ImageResult.jsx | 2 +- .../NavItems/tools/Metadata/Metadata.jsx | 2 +- .../Metadata/Results/MetadataImageResult.jsx | 2 +- .../Metadata/Results/MetadataVideoResult.jsx | 2 +- src/components/NavItems/tools/OCR/OCR.jsx | 2 +- .../tools/SyntheticImageDetection/index.jsx | 27 +- .../syntheticImageDetectionResults.jsx | 30 ++- .../NavItems/tools/Thumbnails/Thumbnails.jsx | 4 +- .../TwitterAdvancedSearch.jsx | 2 +- .../NavItems/tools/TwitterSna/TwitterSna.jsx | 2 +- .../Results/VideoRightsResults.jsx | 2 +- .../tools/VideoRights/VideoRights.jsx | 2 +- .../Shared/MaterialUiStyles/useMyStyles.jsx | 21 +- .../ReverseSearch/reverseSearchUtils.jsx | 1 + src/redux/actions/tools/forensicActions.jsx | 2 + src/redux/reducers/tools/forensicReducer.jsx | 4 + 39 files changed, 516 insertions(+), 245 deletions(-) create mode 100644 src/components/NavItems/tools/Forensic/components/imageCanvas/imageCanvas.jsx create mode 100644 src/components/NavItems/tools/Forensic/components/imageCanvas/useImageCanvas.jsx create mode 100644 src/components/NavItems/tools/Forensic/utils/index.jsx diff --git a/package-lock.json b/package-lock.json index f8244cd9..1f881406 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4222,9 +4222,9 @@ "license": "MIT" }, "node_modules/axios": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.5.1.tgz", - "integrity": "sha512-Q28iYCWzNHjAm+yEAot5QaAMxhMghWLFVf7rRdwhUI+c2jix2DUXjAHXVi+s1ibs3mjPO/cCgbA++3BjD0vP/A==", + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.2.tgz", + "integrity": "sha512-7i24Ri4pmDRfJTR7LDBhsOTtcm+9kjX5WiY1X3wIisx6G9So3pfMkEiU7emUBe46oceVImccTEM3k6C5dbVW8A==", "dependencies": { "follow-redirects": "^1.15.0", "form-data": "^4.0.0", @@ -8905,70 +8905,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/lint-staged/node_modules/onetime": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", - "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", - "dev": true, - "dependencies": { - "mimic-fn": "^4.0.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/lint-staged/node_modules/path-key": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", - "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/lint-staged/node_modules/restore-cursor": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-4.0.0.tgz", - "integrity": "sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==", - "dev": true, - "dependencies": { - "onetime": "^5.1.0", - "signal-exit": "^3.0.2" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/lint-staged/node_modules/restore-cursor/node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/lint-staged/node_modules/mimic-fn": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", - "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", - "dev": true, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/lint-staged/node_modules/npm-run-path": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz", @@ -9029,15 +8965,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/lint-staged/node_modules/restore-cursor/node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, "node_modules/lint-staged/node_modules/restore-cursor/node_modules/onetime": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", diff --git a/src/components/NavItems/Assistant/AssistantRuleBook.jsx b/src/components/NavItems/Assistant/AssistantRuleBook.jsx index cbade6d1..4af2fea0 100644 --- a/src/components/NavItems/Assistant/AssistantRuleBook.jsx +++ b/src/components/NavItems/Assistant/AssistantRuleBook.jsx @@ -42,7 +42,7 @@ export const TYPE_PATTERNS = [ export const KNOWN_LINK_PATTERNS = [ { key: KNOWN_LINKS.TWITTER, - patterns: ["((https?:/{2})?(www.)?twitter.com/\\w{1,15}/status/\\d*)"], + patterns: ["((https?:/{2})?(www.)?(twitter|x).com/\\w{1,15}/status/\\d*)"], }, { key: KNOWN_LINKS.TIKTOK, diff --git a/src/components/NavItems/tools/Analysis/Analysis.jsx b/src/components/NavItems/tools/Analysis/Analysis.jsx index e2565d75..18e14dc4 100644 --- a/src/components/NavItems/tools/Analysis/Analysis.jsx +++ b/src/components/NavItems/tools/Analysis/Analysis.jsx @@ -141,7 +141,7 @@ const Analysis = () => {
diff --git a/src/components/NavItems/tools/Analysis/Results/AFacebookResults.jsx b/src/components/NavItems/tools/Analysis/Results/AFacebookResults.jsx index bf6f518f..a9d092f8 100644 --- a/src/components/NavItems/tools/Analysis/Results/AFacebookResults.jsx +++ b/src/components/NavItems/tools/Analysis/Results/AFacebookResults.jsx @@ -91,7 +91,7 @@ const AFacebookResults = (props) => { { { {
diff --git a/src/components/NavItems/tools/Analysis_images/Results/TwitterResults.jsx b/src/components/NavItems/tools/Analysis_images/Results/TwitterResults.jsx index 3d5b6581..64537d2e 100644 --- a/src/components/NavItems/tools/Analysis_images/Results/TwitterResults.jsx +++ b/src/components/NavItems/tools/Analysis_images/Results/TwitterResults.jsx @@ -35,7 +35,7 @@ const TwitterResults = (props) => { { {keyword("deepfake_image_link")} } - className={classes.headerUpladedImage} + className={classes.headerUploadedImage} /> diff --git a/src/components/NavItems/tools/Deepfake/DeepfakeVideo.jsx b/src/components/NavItems/tools/Deepfake/DeepfakeVideo.jsx index 4889689e..a29f26c8 100644 --- a/src/components/NavItems/tools/Deepfake/DeepfakeVideo.jsx +++ b/src/components/NavItems/tools/Deepfake/DeepfakeVideo.jsx @@ -86,7 +86,7 @@ const Deepfake = () => { {keyword("deepfake_video_link")} } - className={classes.headerUpladedImage} + className={classes.headerUploadedImage} /> diff --git a/src/components/NavItems/tools/Forensic/Forensic.jsx b/src/components/NavItems/tools/Forensic/Forensic.jsx index f97d2679..d1d3019b 100644 --- a/src/components/NavItems/tools/Forensic/Forensic.jsx +++ b/src/components/NavItems/tools/Forensic/Forensic.jsx @@ -171,7 +171,7 @@ const Forensic = () => { diff --git a/src/components/NavItems/tools/Forensic/Results/ForensicResult.jsx b/src/components/NavItems/tools/Forensic/Results/ForensicResult.jsx index d2ba1149..df9758c9 100644 --- a/src/components/NavItems/tools/Forensic/Results/ForensicResult.jsx +++ b/src/components/NavItems/tools/Forensic/Results/ForensicResult.jsx @@ -1,10 +1,9 @@ import Box from "@mui/material/Box"; import Grid from "@mui/material/Grid"; -import React, { useState, Component, useRef, useEffect } from "react"; +import React, { useState, useRef, useEffect } from "react"; import { useDispatch, useSelector } from "react-redux"; import Card from "@mui/material/Card"; import CardHeader from "@mui/material/CardHeader"; -import CardMedia from "@mui/material/CardMedia"; import Typography from "@mui/material/Typography"; import { i18nLoadNamespace } from "components/Shared/Languages/i18nLoadNamespace"; import useMyStyles from "../../../../Shared/MaterialUiStyles/useMyStyles"; @@ -23,8 +22,10 @@ import GifIcon from "@mui/icons-material/Gif"; import Fab from "@mui/material/Fab"; import NavigateNextIcon from "@mui/icons-material/NavigateNext"; import NavigateBeforeIcon from "@mui/icons-material/NavigateBefore"; -import Fade from "@mui/material/Fade"; -import { cleanForensicState } from "../../../../../redux/actions/tools/forensicActions"; +import { + cleanForensicState, + setForensicImageRatio, +} from "../../../../../redux/actions/tools/forensicActions"; import { setStateInit, setStateBackResults, @@ -37,6 +38,9 @@ import Alert from "@mui/material/Alert"; import EmojiObjectsIcon from "@mui/icons-material/EmojiObjects"; import AnimatedGif from "../../Gif/AnimatedGif"; import { DetectionProgressBar } from "components/Shared/DetectionProgressBar/DetectionProgressBar"; +import ImageCanvas from "../components/imageCanvas/imageCanvas"; +import Fade from "@mui/material/Fade"; +import CardMedia from "@mui/material/CardMedia"; function TabPanel(props) { const { children, value, index, ...other } = props; @@ -57,16 +61,10 @@ function TabPanel(props) {
); } -export class Instructions extends Component { - render() { - return ; - } -} const ForensicResults = (props) => { const dispatch = useDispatch(); const displayItem = useSelector((state) => state.forensic.displayItem); - const theme = createTheme({ components: { MuiCardHeader: { @@ -77,7 +75,7 @@ const ForensicResults = (props) => { title: { color: "white", fontSize: 20, - fontweight: 500, + fontWeight: 500, }, }, }, @@ -108,8 +106,6 @@ const ForensicResults = (props) => { const keyword = i18nLoadNamespace("components/NavItems/tools/Forensic"); const keywordWarning = i18nLoadNamespace("components/Shared/OnWarningInfo"); const results = props.result; - //const masks = props.masksData; - //console.log(results); const userAuthenticated = useSelector( (state) => state.userSession && state.userSession.userAuthenticated, @@ -151,8 +147,6 @@ const ForensicResults = (props) => { const idStartCloning = 11; const idStartLenses = 13; - //console.log(results); - const filters = useRef( filtersIDs.map((value) => { let filter; @@ -170,16 +164,10 @@ const ForensicResults = (props) => { filter = { id: value, name: keyword("forensic_title_" + value), - map: [ - results[value]["forgery"], - //results[value]["votemap"]["colormap"], - ], + map: [results[value]["forgery"]], currentDisplayed: 0, arrows: [false, false], - mask: [ - results[value]["forgery"], - //results[value]["votemap"]["transparent"], - ], + mask: [results[value]["forgery"]], popover: false, }; @@ -188,10 +176,10 @@ const ForensicResults = (props) => { filter = { id: value, name: keyword("forensic_title_" + value), - map: results[value]["maps"], + map: results[value]["arrays"], currentDisplayed: 0, arrows: [false, false], - mask: results[value]["maps"], + mask: results[value]["arrays"], popover: false, }; @@ -204,14 +192,14 @@ const ForensicResults = (props) => { keyword("forensic_title_cagiInversed"), ], map: [ - results[value]["cagiNormalReport"]["map"], - results[value]["cagiInversedReport"]["map"], + results[value]["cagiNormalReport"]["array"], + results[value]["cagiInversedReport"]["array"], ], currentDisplayed: 0, arrows: [false, false], mask: [ - results[value]["cagiNormalReport"]["map"], - results[value]["cagiInversedReport"]["map"], + results[value]["cagiNormalReport"]["array"], + results[value]["cagiInversedReport"]["array"], ], popover: false, }; @@ -225,6 +213,14 @@ const ForensicResults = (props) => { mask: results[value].map, popover: false, }; + } else if (value === "cmfd_report") { + filter = { + id: value, + name: keyword("forensic_title_" + value), + map: results[value].map, + mask: results[value].map, + popover: false, + }; //LENSES } else if ( @@ -242,8 +238,8 @@ const ForensicResults = (props) => { filter = { id: value, name: keyword("forensic_title_" + value), - map: results[value]["map"], - mask: results[value]["map"], + map: results[value]["array"], + mask: results[value]["array"], popover: false, }; } @@ -257,16 +253,55 @@ const ForensicResults = (props) => { //Hover effect of the filters //============================================================================================ const [filterHoverEnabled, setFilterHoverEnabled] = React.useState(false); + const [filterSelected, setFilterSelected] = useState(null); const [filterHover, setFilterHover] = useState(displayItem); + const [isHoveredFilterInverted, setIsHoveredFilterInverted] = useState(false); + + const [applyColorScale, setApplyColorScale] = useState(false); function displayFilterHover(map) { setFilterHover(map); setFilterHoverEnabled(true); } + /** + * Returns true if the given filter is using an inverted grayscale to show detection (black means 100% detection) + * @param filter {Object} The filter to verify for + * @param filter.id {string} The filter name + * @param filter.currentDisplayed {number} The current filter displayed in the UI if the filter has multiple masks + * @returns {boolean} + */ + const isFilterUsingAnInvertedScale = (filter) => { + if (!filter) return false; + + return filter.id === "cagi_report" && filter.currentDisplayed === 1; + }; + + /** + * Returns true if the filter is using a grayscale detection mask for which we need to compute the new color scale + * @param filter {object} The filter to verify for + * @returns {boolean} + */ + const isFilterUsingColorScale = (filter) => { + return !( + filter.id === "ela_report" || + filter.id === "laplacian_report" || + filter.id === "median_report" || + filter.id === "rcmfd_report" || + filter.id === "cmfd_report" + ); + }; + + useEffect(() => { + if (!filterSelected) return; + + setIsHoveredFilterInverted(isFilterUsingAnInvertedScale(filterSelected)); + + setApplyColorScale(isFilterUsingColorScale(filterSelected)); + }, [filterSelected]); + function hideFilterHover() { setFilterHoverEnabled(false); - setFilterHover(displayItem); } //Button analyze new image @@ -309,8 +344,8 @@ const ForensicResults = (props) => { function arrowsToDisplay(filter) { //left, right - var arrows = [false, false]; - var filterData = filters.current.find((x) => x.id === filter); + const arrows = [false, false]; + const filterData = filters.current.find((x) => x.id === filter); if (filterData.map.length === 1) { return; } @@ -329,7 +364,15 @@ const ForensicResults = (props) => { function clickArrowFilter(filter, arrow) { filters.current.find((x) => x.id === filter).currentDisplayed += arrow; + arrowsToDisplay(filter); + + setFilterSelected(filters.current.find((x) => x.id === filter)); + + filterSelected.id === "cagi_report" && filterSelected.currentDisplayed === 1 + ? setIsHoveredFilterInverted(true) + : setIsHoveredFilterInverted(false); + displayFilterHover( filters.current.find((x) => x.id === filter).mask[ filters.current.find((x) => x.id === filter).currentDisplayed @@ -342,10 +385,7 @@ const ForensicResults = (props) => { const [anchorGifPopover, setAnchorGifPopover] = React.useState(false); const openGifPopover = Boolean(anchorGifPopover); const gifPopover = openGifPopover ? "simple-popover" : undefined; - const gifImage = displayItem; const [gifFilter, setGifFilter] = React.useState(displayItem); - //const gifFilterMask = useSelector(state => state.forensic.maskUrl); - //console.log(gifFilterMask); //const [interval, setIntervalVar] = React.useState(null); @@ -354,22 +394,19 @@ const ForensicResults = (props) => { function clickGifPopover(event, filter) { if (userAuthenticated) { - var url; if ( filter === "zero_report" || filter === "ghost_report" || filter === "cagi_report" ) { - url = filters.current.find((x) => x.id === filter).mask[ + const url = filters.current.find((x) => x.id === filter).mask[ filters.current.find((x) => x.id === filter).currentDisplayed ]; setGifFilter(url); - //console.log(url); //setReadyTransparency(true); } else { - url = filters.current.find((x) => x.id === filter).mask; + const url = filters.current.find((x) => x.id === filter).mask; setGifFilter(url); - //console.log(url); //setReadyTransparency(true); } dispatch(setStateBackResults()); @@ -395,8 +432,6 @@ const ForensicResults = (props) => { setValue(newValue); }; - //console.log("Downloading: " + downloading); - //Copy url to clipboard const [openToast, setOpenToast] = React.useState(false); @@ -419,7 +454,6 @@ const ForensicResults = (props) => { const [filterPopover, setFilterPopover] = React.useState(false); const [textCagiPopover, setTextCagiPopover] = React.useState(null); const [titleCagiPopover, setTitleCagiPopover] = React.useState(null); - const handleOpenFilterExplanation = (event, filter) => { if (filter === "cagi") { if ( @@ -471,6 +505,24 @@ const ForensicResults = (props) => { const currentLang = useSelector((state) => state.language); const isCurrentLanguageLeftToRight = currentLang !== "ar"; + const submittedImageRef = useRef(); + + useEffect(() => { + if ( + !submittedImageRef.current.naturalWidth || + !submittedImageRef.current.naturalHeight + ) { + return; + } + + dispatch( + setForensicImageRatio( + submittedImageRef.current.naturalWidth / + submittedImageRef.current.naturalHeight, + ), + ); + }, [submittedImageRef.current]); + return (
{ } - className={classes.headerUpladedImage} + className={classes.headerUploadedImage} />
- - + { + } + + + +
@@ -656,20 +715,27 @@ const ForensicResults = (props) => { .map((value, key) => { return ( - - displayFilterHover(value.map) - } - onMouseLeave={hideFilterHover} + imgSrc={value.map} + isGrayscaleInverted={false} + applyColorScale={false} + threshold={0} + onMouseOver={() => { + displayFilterHover(value.map); + setFilterSelected(value); + }} + onMouseLeave={() => { + hideFilterHover(); + // setFilterSelected(null); + }} /> - {value.name} + {keyword("forensic_title_" + value.id)} { alignItems="stretch" > - {value.name} + {keyword("forensic_title_" + value.id)} { @@ -805,10 +872,10 @@ const ForensicResults = (props) => { {tabs.map((valueTab, keyTab) => { - var filtersTab = []; - var textDescription = ""; - var textLook = ""; - var textIgnore = ""; + let filtersTab; + let textDescription; + let textLook; + let textIgnore; if (valueTab === 0) { filtersTab = filters.current.slice( @@ -865,13 +932,6 @@ const ForensicResults = (props) => { ) { arrowsToDisplay(value.id); } - - /* - if (value.id === "ghost_report") { - value.mask = ghostMasks; - } - */ - return ( {value.id === "zero_report" || @@ -879,18 +939,25 @@ const ForensicResults = (props) => { value.id === "cagi_report" ? (
+ onMouseOver={() => { displayFilterHover( value.mask[value.currentDisplayed], - ) - } + ); + setFilterSelected(value); + }} onMouseLeave={hideFilterHover} > - -
{ value.id !== "" && (
- displayFilterHover(value.mask) - } + onMouseOver={() => { + displayFilterHover(value.mask); + setFilterSelected(value); + }} onMouseLeave={hideFilterHover} > - -
{ ) : ( - {value.name} + {keyword("forensic_title_" + value.id)} { ) : ( - {value.name} + {keyword( + "forensic_title_" + value.id, + )} )} @@ -1195,9 +1269,12 @@ const ForensicResults = (props) => { diff --git a/src/components/NavItems/tools/Forensic/components/imageCanvas/imageCanvas.jsx b/src/components/NavItems/tools/Forensic/components/imageCanvas/imageCanvas.jsx new file mode 100644 index 00000000..b83271b8 --- /dev/null +++ b/src/components/NavItems/tools/Forensic/components/imageCanvas/imageCanvas.jsx @@ -0,0 +1,24 @@ +import React from "react"; +import { useImageCanvas } from "./useImageCanvas"; + +const ImageCanvas = (props) => { + const { + imgSrc, + isGrayscaleInverted, + applyColorScale, + threshold: threshold, + filterDataURL, + ...args + } = props; + const canvasRef = useImageCanvas( + imgSrc, + isGrayscaleInverted, + applyColorScale, + threshold, + filterDataURL, + ); + + return ; +}; + +export default ImageCanvas; diff --git a/src/components/NavItems/tools/Forensic/components/imageCanvas/useImageCanvas.jsx b/src/components/NavItems/tools/Forensic/components/imageCanvas/useImageCanvas.jsx new file mode 100644 index 00000000..e1d3f174 --- /dev/null +++ b/src/components/NavItems/tools/Forensic/components/imageCanvas/useImageCanvas.jsx @@ -0,0 +1,82 @@ +import { useRef, useEffect } from "react"; +import { applyThresholdAndGradient, preloadImage } from "../../utils"; +import { useSelector } from "react-redux"; + +/** + * hook to perform the image processing in the canvas + * @param imgSrc {string} image url + * @param isGrayscaleColorInverted {boolean} set to true if working with an inverted grayscale + * @param applyColorScale {boolean} set to true if working with a color scale + * @param threshold {number} the threshold value between 0 and 255. The detection starts from 50% + * @param filterDataUrl {function(string)} function to retrieve the DataUrl computed by the component + * @returns {React.MutableRefObject} + */ +const useImageCanvas = ( + imgSrc, + isGrayscaleColorInverted, + applyColorScale, + threshold, + filterDataURL, +) => { + const canvasRef = useRef(); + + let imageRatio = useSelector((state) => state.forensic.imageRatio); + + useEffect(() => { + if (!imgSrc) return; + async function loadAndProcessImage(imgSrc) { + const canvas = canvasRef.current; + + if (!canvas || !(canvas instanceof HTMLCanvasElement)) return; + + const context = canvas.getContext("2d", { + willReadFrequently: true, + desynchronized: true, + }); + + const image = await preloadImage(imgSrc); + + // Resize image to the forensic image ratio if possible + if (!imageRatio) { + imageRatio = image.naturalWidth / image.naturalHeight; + } + canvas.width = canvas.offsetWidth; + canvas.height = canvas.offsetWidth / imageRatio; + + context.clearRect(0, 0, canvas.width, canvas.height); + + // Invert the grayscale for the inverted filters + if (isGrayscaleColorInverted) context.filter = "invert(1)"; + + context.drawImage( + image, + 0, + 0, + image.naturalWidth, + image.naturalHeight, + 0, + 0, + context.canvas.width, + context.canvas.height, + ); + + let imageData = context.getImageData( + 0, + 0, + context.canvas.width, + context.canvas.height, + ); + + if (applyColorScale) applyThresholdAndGradient(imageData, threshold); + + context.putImageData(imageData, 0, 0); + + if (filterDataURL) filterDataURL(canvas.toDataURL()); + } + loadAndProcessImage(imgSrc); + }, [imgSrc, threshold, isGrayscaleColorInverted, applyColorScale]); + + return canvasRef; +}; + +export { useImageCanvas }; diff --git a/src/components/NavItems/tools/Forensic/utils/index.jsx b/src/components/NavItems/tools/Forensic/utils/index.jsx new file mode 100644 index 00000000..04418c05 --- /dev/null +++ b/src/components/NavItems/tools/Forensic/utils/index.jsx @@ -0,0 +1,69 @@ +/** + * From a given grayscale ImageData in a canvas, return a colored scale image with a threshold + * The grayscale values under the threshold will be returned with an alpha channel of 0. + * @param imageData {ImageData} the ImageData element to process. + * @param threshold {number} the threshold for applying the colored scale with a number in the [0, 255] range. + */ +export function applyThresholdAndGradient(imageData, threshold) { + let data = imageData.data; + + const mako0 = [10, 2, 3]; + const mako12 = [37, 23, 51]; + const mako30 = [50, 47, 113]; + const mako50 = [42, 99, 145]; + const mako70 = [46, 146, 155]; + const mako88 = [105, 208, 158]; + const mako100 = [215, 244, 223]; + + const colorScale = [mako0, mako12, mako30, mako50, mako70, mako88, mako100]; + + for (let i = 0; i < data.length; i += 4) { + const grayscale = (data[i] + data[i + 1] + data[i + 2]) / 3; + + let closestColorIndex = 0; + + for (let j = 0; j < colorScale.length - 1; j++) { + if ( + grayscale >= (j * 255) / (colorScale.length - 1) && + grayscale <= ((j + 1) * 255) / (colorScale.length - 1) + ) { + closestColorIndex = j; + break; + } + } + + // determine the values for each color channel based on linear interpolation + let color1 = colorScale[closestColorIndex]; + let color2 = colorScale[closestColorIndex + 1]; + + let factor = + (grayscale - (closestColorIndex * 255) / (colorScale.length - 1)) / + (255 / (colorScale.length - 1)); + + imageData.data[i] = color1[0] + (color2[0] - color1[0]) * factor; + imageData.data[i + 1] = color1[1] + (color2[1] - color1[1]) * factor; + imageData.data[i + 2] = color1[2] + (color2[2] - color1[2]) * factor; + + // Set the alpha channel based on the threshold value + imageData.data[i + 3] = grayscale >= threshold ? 255 : 0; + } + + return data; +} + +/** + * Load an image to canvas asynchronously + * @param url {string} The image url + * @returns {Promise} A promise that resolves with the image element + */ +export function preloadImage(url) { + return new Promise((resolve, reject) => { + const image = new Image(); + + image.src = url; + image.crossOrigin = "Anonymous"; + + image.onload = () => resolve(image); + image.onerror = () => reject(`Image failed to load: ${url}`); + }); +} diff --git a/src/components/NavItems/tools/Geolocation/Geolocation.jsx b/src/components/NavItems/tools/Geolocation/Geolocation.jsx index e68cb033..3e30a0ed 100644 --- a/src/components/NavItems/tools/Geolocation/Geolocation.jsx +++ b/src/components/NavItems/tools/Geolocation/Geolocation.jsx @@ -61,7 +61,7 @@ const Geolocation = () => { diff --git a/src/components/NavItems/tools/Geolocation/Results/GeolocationResults.jsx b/src/components/NavItems/tools/Geolocation/Results/GeolocationResults.jsx index 4fbd3588..6a49e793 100644 --- a/src/components/NavItems/tools/Geolocation/Results/GeolocationResults.jsx +++ b/src/components/NavItems/tools/Geolocation/Results/GeolocationResults.jsx @@ -51,7 +51,7 @@ const GeolocationResults = (props) => {
{
{
diff --git a/src/components/NavItems/tools/Gif/AnimatedGif.jsx b/src/components/NavItems/tools/Gif/AnimatedGif.jsx index d01df391..dc8b6bc8 100644 --- a/src/components/NavItems/tools/Gif/AnimatedGif.jsx +++ b/src/components/NavItems/tools/Gif/AnimatedGif.jsx @@ -11,14 +11,27 @@ import { import useMyStyles from "../../../Shared/MaterialUiStyles/useMyStyles"; import { i18nLoadNamespace } from "components/Shared/Languages/i18nLoadNamespace"; import { useState, useEffect } from "react"; +import ImageCanvas from "../Forensic/components/imageCanvas/imageCanvas"; -const AnimatedGif = ({ toolState, homoImg1, homoImg2, isPopup }) => { +const AnimatedGif = ({ + toolState, + homoImg1, + homoImg2, + isPopup, + isGrayscaleInverted, + applyColorScale, + isCanvas, +}) => { const classes = useMyStyles(); const keyword = i18nLoadNamespace("components/NavItems/tools/CheckGIF"); const [filesForGif, setFilesForGif] = useState(null); const [delayGif, setDelayGif] = useState(null); const [enableDownload, setEnableDownload] = useState(false); const [downloadType, setDownloadType] = useState(null); + + const [imageDataURL, setImageDataURL] = React.useState(); + const [filterDataURL, setFilterDataURL] = React.useState(); + //=== SPEED SLIDER === const [speed, setSpeed] = useState(1100); @@ -83,9 +96,10 @@ const AnimatedGif = ({ toolState, homoImg1, homoImg2, isPopup }) => { //Function to prepare the files to trigger the download const handleDownload = (type) => { //console.log(toolState); - var files = { - image1: homoImg1, - image2: homoImg2, + + let files = { + image1: isCanvas ? imageDataURL : homoImg1, + image2: isCanvas ? filterDataURL : homoImg2, }; setFilesForGif(files); @@ -99,7 +113,7 @@ const AnimatedGif = ({ toolState, homoImg1, homoImg2, isPopup }) => { //console.log(toolState); //Call to the API - useGetGif(filesForGif, delayGif, enableDownload, downloadType); + useGetGif(filesForGif, delayGif, enableDownload, downloadType, isCanvas); if (toolState === 7 && enableDownload) { setEnableDownload(false); } @@ -113,25 +127,32 @@ const AnimatedGif = ({ toolState, homoImg1, homoImg2, isPopup }) => { alignItems="flex-start" > - - + {/**/} + + - {true && ( - + - )} + { max={-500} scale={(x) => -x} onChange={(e, val) => changeSpeed(val)} - onChangeCommitted={(e) => commitChangeSpeed(speed)} + onChangeCommitted={() => commitChangeSpeed(speed)} /> { variant="contained" color="primary" disabled={toolState === 7} - onClick={(e) => handleDownload("gif")} + onClick={() => handleDownload("gif")} > {keyword("button_download")} @@ -181,7 +202,7 @@ const AnimatedGif = ({ toolState, homoImg1, homoImg2, isPopup }) => { variant="contained" color="primary" disabled={toolState === 7} - onClick={(e) => handleDownload("mp4")} + onClick={() => handleDownload("mp4")} > {keyword("button_video")} @@ -208,14 +229,12 @@ const AnimatedGif = ({ toolState, homoImg1, homoImg2, isPopup }) => { className={classes.imagesGifImage} image={homoImg1} /> - {true && ( - - )} + { {keyword("cardTitle_source")} } - className={classes.headerUpladedImage} + className={classes.headerUploadedImage} /> @@ -498,7 +498,7 @@ const CheckGif = () => { } - className={classes.headerUpladedImage} + className={classes.headerUploadedImage} /> diff --git a/src/components/NavItems/tools/Gif/Hooks/useGetGif.jsx b/src/components/NavItems/tools/Gif/Hooks/useGetGif.jsx index 3b0c8cc7..cfde4f00 100644 --- a/src/components/NavItems/tools/Gif/Hooks/useGetGif.jsx +++ b/src/components/NavItems/tools/Gif/Hooks/useGetGif.jsx @@ -9,7 +9,13 @@ import { import { saveAs } from "file-saver"; import useAuthenticatedRequest from "../../../../Shared/Authentication/useAuthenticatedRequest"; -const useGetGif = (images, delayInput, enableDownload, downloadType) => { +const useGetGif = ( + images, + delayInput, + enableDownload, + downloadType, + isCanvas, +) => { const keyword = i18nLoadNamespace("components/NavItems/tools/Forensic"); const dispatch = useDispatch(); const authenticatedRequest = useAuthenticatedRequest(); @@ -50,11 +56,23 @@ const useGetGif = (images, delayInput, enableDownload, downloadType) => { if (enableDownload) { dispatch(setStateDownloading()); - var body = { + let body = { inputURLs: [images.image1, images.image2], + createVideo: downloadType === "mp4", delay: delayInput, }; - let endpoint = downloadType === "mp4" ? "/video" : "/animated"; + if (isCanvas) { + body = { + delay: delayInput, + createVideo: downloadType === "mp4", + original: images.image1, + maskFilter: images.image2, + }; + } + //let endpoint = downloadType === "mp4" ? "/video" : "/animated"; + //let endpoint = downloadType === "mp4" ? "/video" : "/animatedbase64"; + let endpoint = isCanvas ? "/animatedbase64" : "/animated"; + const axiosConfig = { method: "post", url: baseURL + endpoint, diff --git a/src/components/NavItems/tools/Keyframes/Keyframes.jsx b/src/components/NavItems/tools/Keyframes/Keyframes.jsx index d887045e..eecd74ca 100644 --- a/src/components/NavItems/tools/Keyframes/Keyframes.jsx +++ b/src/components/NavItems/tools/Keyframes/Keyframes.jsx @@ -192,7 +192,7 @@ const Keyframes = () => { diff --git a/src/components/NavItems/tools/Keyframes/Results/KeyFramesResults.jsx b/src/components/NavItems/tools/Keyframes/Results/KeyFramesResults.jsx index cba92ed4..2d684544 100644 --- a/src/components/NavItems/tools/Keyframes/Results/KeyFramesResults.jsx +++ b/src/components/NavItems/tools/Keyframes/Results/KeyFramesResults.jsx @@ -273,7 +273,7 @@ const KeyFramesResults = (props) => { } - className={classes.headerUpladedImage} + className={classes.headerUploadedImage} action={ { diff --git a/src/components/NavItems/tools/Magnifier/Results/ImageResult.jsx b/src/components/NavItems/tools/Magnifier/Results/ImageResult.jsx index 9175e141..8b5ae257 100644 --- a/src/components/NavItems/tools/Magnifier/Results/ImageResult.jsx +++ b/src/components/NavItems/tools/Magnifier/Results/ImageResult.jsx @@ -119,7 +119,7 @@ const ImageResult = () => { { diff --git a/src/components/NavItems/tools/Metadata/Results/MetadataImageResult.jsx b/src/components/NavItems/tools/Metadata/Results/MetadataImageResult.jsx index c86e3775..570f15e1 100644 --- a/src/components/NavItems/tools/Metadata/Results/MetadataImageResult.jsx +++ b/src/components/NavItems/tools/Metadata/Results/MetadataImageResult.jsx @@ -31,7 +31,7 @@ const MetadataImageResult = (props) => { { { diff --git a/src/components/NavItems/tools/SyntheticImageDetection/index.jsx b/src/components/NavItems/tools/SyntheticImageDetection/index.jsx index 75f1b81d..7431d378 100644 --- a/src/components/NavItems/tools/SyntheticImageDetection/index.jsx +++ b/src/components/NavItems/tools/SyntheticImageDetection/index.jsx @@ -55,7 +55,7 @@ const SyntheticImageDetection = () => { dispatch(setSyntheticImageDetectionLoading(true)); modeURL = "images/"; - services = "gan,unina"; + services = "gan,unina,progan_r50_grip,adm_r50_grip"; if (!modeURL) { return; @@ -63,6 +63,21 @@ const SyntheticImageDetection = () => { const baseURL = process.env.REACT_APP_CAA_DEEPFAKE_URL; + const getUserFriendlyError = (error) => { + // Default error + if (!error) { + return keyword("synthetic_image_detection_error_generic"); + } + + if ( + error.includes("Received status code 400") || + error.includes("Cannot open image from") + ) + return keyword("synthetic_image_detection_error_400"); + + return keyword("synthetic_image_detection_error_generic"); + }; + const handleError = (e) => { dispatch(setError(e)); dispatch(setSyntheticImageDetectionLoading(false)); @@ -80,7 +95,10 @@ const SyntheticImageDetection = () => { params: { url: url, services: services }, }); } catch (error) { - handleError("error_" + error.status); + const processedError = getUserFriendlyError( + error?.response?.data?.message ?? "error_" + error.status, + ); + handleError(processedError); } const getResult = async (id) => { @@ -119,6 +137,9 @@ const SyntheticImageDetection = () => { } }; + + if (!res || !res.data) return; + await waitUntilFinish(res.data.id); }; @@ -164,7 +185,7 @@ const SyntheticImageDetection = () => { {keyword("synthetic_image_detection_link")} } - className={classes.headerUpladedImage} + className={classes.headerUploadedImage} /> diff --git a/src/components/NavItems/tools/SyntheticImageDetection/syntheticImageDetectionResults.jsx b/src/components/NavItems/tools/SyntheticImageDetection/syntheticImageDetectionResults.jsx index 5f9bfe45..b3e389f9 100644 --- a/src/components/NavItems/tools/SyntheticImageDetection/syntheticImageDetectionResults.jsx +++ b/src/components/NavItems/tools/SyntheticImageDetection/syntheticImageDetectionResults.jsx @@ -36,6 +36,14 @@ const SyntheticImageDetectionResults = (props) => { name: keyword("synthetic_image_detection_diffusion_name"), description: keyword("synthetic_image_detection_diffusion_description"), }, + progan_r50_grip: { + name: keyword("synthetic_image_detection_progan_name"), + description: keyword("synthetic_image_detection_progan_description"), + }, + adm_r50_grip: { + name: keyword("synthetic_image_detection_adm_name"), + description: keyword("synthetic_image_detection_adm_description"), + }, }; const results = props.result; const url = props.url; @@ -64,7 +72,17 @@ const SyntheticImageDetectionResults = (props) => { results.gan_report.prediction * 100, ); - const res = [diffusionScore, ganScore].sort( + const proganScore = new DeepfakeResult( + Object.keys(DeepfakeImageDetectionMethodNames)[2], + results.progan_r50_grip_report.prediction * 100, + ); + + const admScore = new DeepfakeResult( + Object.keys(DeepfakeImageDetectionMethodNames)[3], + results.adm_r50_grip_report.prediction * 100, + ); + + const res = [diffusionScore, ganScore, proganScore, admScore].sort( (a, b) => b.predictionScore - a.predictionScore, ); @@ -143,11 +161,11 @@ const SyntheticImageDetectionResults = (props) => { syntheticImageScores[0].predictionScore && syntheticImageScores[0].predictionScore >= 70 && ( - {keyword("synthetic_image_detection_detection_alert") + + {keyword("synthetic_image_detection_alert") + DeepfakeImageDetectionMethodNames[ syntheticImageScores[0].methodName ].name + - keyword("synthetic_image_detection_detection_alert_2")} + keyword("synthetic_image_detection_alert_2")} )} {syntheticImageScores && @@ -181,7 +199,7 @@ const SyntheticImageDetectionResults = (props) => { ); })} - {syntheticImageScores && ( + {syntheticImageScores?.length > 0 ? ( { }} /> + ) : ( + + {keyword("synthetic_image_detection_error_400")} + )} diff --git a/src/components/NavItems/tools/Thumbnails/Thumbnails.jsx b/src/components/NavItems/tools/Thumbnails/Thumbnails.jsx index 72ad6dd7..a5c706f1 100644 --- a/src/components/NavItems/tools/Thumbnails/Thumbnails.jsx +++ b/src/components/NavItems/tools/Thumbnails/Thumbnails.jsx @@ -246,7 +246,7 @@ const Thumbnails = () => { @@ -332,7 +332,7 @@ const Thumbnails = () => { {
{largeInputList.map((value, key) => { diff --git a/src/components/NavItems/tools/TwitterSna/TwitterSna.jsx b/src/components/NavItems/tools/TwitterSna/TwitterSna.jsx index 3b090ace..f67a317d 100644 --- a/src/components/NavItems/tools/TwitterSna/TwitterSna.jsx +++ b/src/components/NavItems/tools/TwitterSna/TwitterSna.jsx @@ -546,7 +546,7 @@ const TwitterSna = () => { diff --git a/src/components/NavItems/tools/VideoRights/Results/VideoRightsResults.jsx b/src/components/NavItems/tools/VideoRights/Results/VideoRightsResults.jsx index bd28cee4..11390029 100644 --- a/src/components/NavItems/tools/VideoRights/Results/VideoRightsResults.jsx +++ b/src/components/NavItems/tools/VideoRights/Results/VideoRightsResults.jsx @@ -83,7 +83,7 @@ const VideoRightsResults = (props) => { { diff --git a/src/components/Shared/MaterialUiStyles/useMyStyles.jsx b/src/components/Shared/MaterialUiStyles/useMyStyles.jsx index 23a9125d..686a0448 100644 --- a/src/components/Shared/MaterialUiStyles/useMyStyles.jsx +++ b/src/components/Shared/MaterialUiStyles/useMyStyles.jsx @@ -563,16 +563,19 @@ const styles = (theme) => ({ imageUploaded: { objectFit: "contain", - objectPosition: "center top", + objectPosition: "center", + height: "100%", + width: "100%", }, imageFilter: { height: "13vh", + width: "100%", backgroundPosition: "center", backgroundSize: "contain", }, - headerUpladedImage: { + headerUploadedImage: { paddingTop: "11px!important", paddingBottom: "11px!important", }, @@ -604,6 +607,8 @@ const styles = (theme) => ({ left: 0, bottom: 0, right: 0, + width: "100%", + height: "100%", }, wrapperImageFilter: { @@ -615,21 +620,21 @@ const styles = (theme) => ({ backgroundSize: "contain", objectFit: "contain", objectPosition: "top", - position: "relative", top: 0, left: 0, }, imagesGifFilter: { - backgroundPosition: "center", - backgroundSize: "contain", - objectFit: "contain", - objectPosition: "top", - position: "absolute", + objectFit: "contain", + objectPosition: "center top", top: 0, left: 0, + bottom: 0, + right: 0, + width: "100%", + height: "100%", }, sliderClass: { diff --git a/src/components/Shared/ReverseSearch/reverseSearchUtils.jsx b/src/components/Shared/ReverseSearch/reverseSearchUtils.jsx index f20dbefd..335dc788 100644 --- a/src/components/Shared/ReverseSearch/reverseSearchUtils.jsx +++ b/src/components/Shared/ReverseSearch/reverseSearchUtils.jsx @@ -569,6 +569,7 @@ const retrieveImgObjectForSearchEngine = async ( //console.log("DEBUG info ", info); //console.log("DEBUG getiknfo ", getImgUrl(info)); + return new ImageObject(getImgUrl(info), IMAGE_FORMATS.URI); } diff --git a/src/redux/actions/tools/forensicActions.jsx b/src/redux/actions/tools/forensicActions.jsx index ce50a22f..fa898bae 100644 --- a/src/redux/actions/tools/forensicActions.jsx +++ b/src/redux/actions/tools/forensicActions.jsx @@ -92,3 +92,5 @@ export const setForensicInputFile = createAction("SET_FORENSIC_LOCAL_FILE"); } } }*/ + +export const setForensicImageRatio = createAction("SET_FORENSIC_IMAGE_RATIO"); diff --git a/src/redux/reducers/tools/forensicReducer.jsx b/src/redux/reducers/tools/forensicReducer.jsx index 22739b25..381dff7d 100644 --- a/src/redux/reducers/tools/forensicReducer.jsx +++ b/src/redux/reducers/tools/forensicReducer.jsx @@ -9,6 +9,7 @@ const defaultState = { displayItem: "", errorKey: null, localurl: "", + imageRatio: null, }; const forensicReducer = (state = defaultState, action) => { @@ -37,6 +38,7 @@ const forensicReducer = (state = defaultState, action) => { maskUrl: "", displayItem: "", errorKey: null, + imageRatio: null, }; case "SET_FORENSIC_GIF_HIDE": return { ...state, gifAnimation: false }; @@ -46,6 +48,8 @@ const forensicReducer = (state = defaultState, action) => { return { ...state, maskUrl: action.payload }; case "SET_FORENSIC_DISPLAY_ITEM": return { ...state, displayItem: action.payload }; + case "SET_FORENSIC_IMAGE_RATIO": + return { ...state, imageRatio: action.payload }; case "SET_FORENSIC_LOCAL_FILE": case "SET_FORENSIC_IMAGE_BINARY": case "SET_FORENSIC_ERROR_KEY": From 23ef10c5882597b5c56d32edab6c04e7d490f0cf Mon Sep 17 00:00:00 2001 From: Valentin Date: Thu, 4 Jan 2024 10:47:24 +0100 Subject: [PATCH 02/77] Cleanup (#390) * Matomo update (#351) * refactoring, added matomo tracking * Pre master (#349) * Bugfixes + Added tracking (#292) (#293) * rename Feeback * mv2 fix for build * thumbnail * remove console * roll back publicpath * Added trackEvent --------- Co-authored-by: AFPMedialab <40788591+AFPMedialab@users.noreply.github.com> Co-authored-by: Bertrand Goupil Co-authored-by: Valentin Porcellini * Changed dbkf img format (#299) (#300) Co-authored-by: Valentin Porcellini * Bugfixes (#303) * Changed dbkf img format (#299) Co-authored-by: Valentin Porcellini * DBKF and Thumbnail Fixes (#301) * Changed dbkf img format * Fixed download keyframe URI --------- Co-authored-by: Valentin Porcellini * Prevent tab deletion for reverse search calls (#302) * Changed dbkf img format * Fixed download keyframe URI * Added parameter to prevent tab deletion for app reverse search calls --------- Co-authored-by: Valentin Porcellini --------- Co-authored-by: Valentin Porcellini * Merge fix and cleanup (#305) * Changed dbkf img format (#299) Co-authored-by: Valentin Porcellini * DBKF and Thumbnail Fixes (#301) * Changed dbkf img format * Fixed download keyframe URI --------- Co-authored-by: Valentin Porcellini * Prevent tab deletion for reverse search calls (#302) * Changed dbkf img format * Fixed download keyframe URI * Added parameter to prevent tab deletion for app reverse search calls --------- Co-authored-by: Valentin Porcellini * Merge fix and cleanup (#304) * Changed dbkf img format * Fixed download keyframe URI * Added parameter to prevent tab deletion for app reverse search calls * Deleted mv2 file * Fixed merge issue --------- Co-authored-by: Valentin Porcellini --------- Co-authored-by: Valentin Porcellini * Pre master (#307) * Changed dbkf img format (#299) Co-authored-by: Valentin Porcellini * DBKF and Thumbnail Fixes (#301) * Changed dbkf img format * Fixed download keyframe URI --------- Co-authored-by: Valentin Porcellini * Prevent tab deletion for reverse search calls (#302) * Changed dbkf img format * Fixed download keyframe URI * Added parameter to prevent tab deletion for app reverse search calls --------- Co-authored-by: Valentin Porcellini * Merge fix and cleanup (#304) * Changed dbkf img format * Fixed download keyframe URI * Added parameter to prevent tab deletion for app reverse search calls * Deleted mv2 file * Fixed merge issue --------- Co-authored-by: Valentin Porcellini * Permission cleanup mv3 (#306) * Changed dbkf img format * Fixed download keyframe URI * Added parameter to prevent tab deletion for app reverse search calls * Deleted mv2 file * Fixed merge issue * Removed unused permission --------- Co-authored-by: Valentin Porcellini --------- Co-authored-by: Valentin Porcellini * Update README.md * Update README.md * Update README.md * Update README.md * Added base UI for img results * Added diffusion scores * Refactoring, added video detection methods * Better layout, fixed load state bug, added warning text, rank img detection from highest to lowest, async API calls * bigger detection text * Refactoring * Sort video detection by decreasing detection percentage * Prevent error * auto resize rectangles + refactoring * Added textfield url type * Improved layout, error handling, added tsv support * Fixed issue where the previous video was not replaced with the new video + cleanup * Fixed state issue when submitting a new video after a first one * Layout improvements for better readability * Removed unnecessary header * Fix lint error * Fixed undefined error + better deepfake rectangle layout * add i18n react support * Check if string can be a URL + added error message * Removed fixed height * Added role restriction for FTCN method * (wip) synthetic image tool, added jsconfig, fixed lint errors * change default tsv path * (wip) * Removed diffusion, fixed lint error * Fixed deepfake tool * missing tsv file * sync tansalation * Fixed display issue * Fixed url error msg + added other languages * Fixed url error msg + added other languages (#317) Co-authored-by: Valentin Porcellini * Added unina credits * Added restriction for other tools * Fixes + translations + credits (#318) * Fixed url error msg + added other languages * Added unina credits * Added restriction for other tools --------- Co-authored-by: Valentin Porcellini * redux keep last process url in textfield * Enhanced UI * externalize role hook * Enhanced UI + refactoring (#319) Co-authored-by: Valentin Porcellini * Deepfake v4 (#320) * Fixed url error msg + added other languages * Added unina credits * Added restriction for other tools * redux keep last process url in textfield * Enhanced UI * externalize role hook * Enhanced UI + refactoring (#319) Co-authored-by: Valentin Porcellini --------- Co-authored-by: Valentin Porcellini Co-authored-by: Bertrand Goupil * lens support url * Only show Google Lens if the image is from an URL * add remove button for video deepfake * Bugfixes (#321) * Fixed url error msg + added other languages * Added unina credits * Added restriction for other tools * redux keep last process url in textfield * Enhanced UI * externalize role hook * Enhanced UI + refactoring (#319) Co-authored-by: Valentin Porcellini * lens support url * Only show Google Lens if the image is from an URL * add remove button for video deepfake --------- Co-authored-by: Bertrand Goupil * matomo update + package upgrade * Matomo tracking + packages upgrade (#323) * Fixed url error msg + added other languages * Added unina credits * Added restriction for other tools * redux keep last process url in textfield * Enhanced UI * externalize role hook * Enhanced UI + refactoring (#319) Co-authored-by: Valentin Porcellini * lens support url * Only show Google Lens if the image is from an URL * add remove button for video deepfake * matomo update + package upgrade --------- Co-authored-by: Bertrand Goupil * increase status request to 3 seconds * Disable Google lens for data blob * fix dattime picker * remove console log * bug fix checkGif loop X advance search date control * geolocate url * Geoloc fix feature * Add detection progess bar * bug fix test if sevice is sending results * bug fix url in error * Revert "Merge branch 'deepfake-v4-translation' into deepfake-v4" This reverts commit c8aa9809d94f1bb8c536a61116067a884c9c0be2, reversing changes made to e04e89cb3bc5a9df26b2fc645e38ff21c7ba61fa. * bug fix GMT disable * remove log * remove log --------- Co-authored-by: AFPMedialab <40788591+AFPMedialab@users.noreply.github.com> Co-authored-by: Bertrand Goupil Co-authored-by: dteyssou --------- Co-authored-by: AFPMedialab <40788591+AFPMedialab@users.noreply.github.com> Co-authored-by: Bertrand Goupil Co-authored-by: dteyssou * Matomo update (#353) * refactoring, added matomo tracking * Pre master (#349) * Bugfixes + Added tracking (#292) (#293) * rename Feeback * mv2 fix for build * thumbnail * remove console * roll back publicpath * Added trackEvent --------- Co-authored-by: AFPMedialab <40788591+AFPMedialab@users.noreply.github.com> Co-authored-by: Bertrand Goupil Co-authored-by: Valentin Porcellini * Changed dbkf img format (#299) (#300) Co-authored-by: Valentin Porcellini * Bugfixes (#303) * Changed dbkf img format (#299) Co-authored-by: Valentin Porcellini * DBKF and Thumbnail Fixes (#301) * Changed dbkf img format * Fixed download keyframe URI --------- Co-authored-by: Valentin Porcellini * Prevent tab deletion for reverse search calls (#302) * Changed dbkf img format * Fixed download keyframe URI * Added parameter to prevent tab deletion for app reverse search calls --------- Co-authored-by: Valentin Porcellini --------- Co-authored-by: Valentin Porcellini * Merge fix and cleanup (#305) * Changed dbkf img format (#299) Co-authored-by: Valentin Porcellini * DBKF and Thumbnail Fixes (#301) * Changed dbkf img format * Fixed download keyframe URI --------- Co-authored-by: Valentin Porcellini * Prevent tab deletion for reverse search calls (#302) * Changed dbkf img format * Fixed download keyframe URI * Added parameter to prevent tab deletion for app reverse search calls --------- Co-authored-by: Valentin Porcellini * Merge fix and cleanup (#304) * Changed dbkf img format * Fixed download keyframe URI * Added parameter to prevent tab deletion for app reverse search calls * Deleted mv2 file * Fixed merge issue --------- Co-authored-by: Valentin Porcellini --------- Co-authored-by: Valentin Porcellini * Pre master (#307) * Changed dbkf img format (#299) Co-authored-by: Valentin Porcellini * DBKF and Thumbnail Fixes (#301) * Changed dbkf img format * Fixed download keyframe URI --------- Co-authored-by: Valentin Porcellini * Prevent tab deletion for reverse search calls (#302) * Changed dbkf img format * Fixed download keyframe URI * Added parameter to prevent tab deletion for app reverse search calls --------- Co-authored-by: Valentin Porcellini * Merge fix and cleanup (#304) * Changed dbkf img format * Fixed download keyframe URI * Added parameter to prevent tab deletion for app reverse search calls * Deleted mv2 file * Fixed merge issue --------- Co-authored-by: Valentin Porcellini * Permission cleanup mv3 (#306) * Changed dbkf img format * Fixed download keyframe URI * Added parameter to prevent tab deletion for app reverse search calls * Deleted mv2 file * Fixed merge issue * Removed unused permission --------- Co-authored-by: Valentin Porcellini --------- Co-authored-by: Valentin Porcellini * Update README.md * Update README.md * Update README.md * Update README.md * Added base UI for img results * Added diffusion scores * Refactoring, added video detection methods * Better layout, fixed load state bug, added warning text, rank img detection from highest to lowest, async API calls * bigger detection text * Refactoring * Sort video detection by decreasing detection percentage * Prevent error * auto resize rectangles + refactoring * Added textfield url type * Improved layout, error handling, added tsv support * Fixed issue where the previous video was not replaced with the new video + cleanup * Fixed state issue when submitting a new video after a first one * Layout improvements for better readability * Removed unnecessary header * Fix lint error * Fixed undefined error + better deepfake rectangle layout * add i18n react support * Check if string can be a URL + added error message * Removed fixed height * Added role restriction for FTCN method * (wip) synthetic image tool, added jsconfig, fixed lint errors * change default tsv path * (wip) * Removed diffusion, fixed lint error * Fixed deepfake tool * missing tsv file * sync tansalation * Fixed display issue * Fixed url error msg + added other languages * Fixed url error msg + added other languages (#317) Co-authored-by: Valentin Porcellini * Added unina credits * Added restriction for other tools * Fixes + translations + credits (#318) * Fixed url error msg + added other languages * Added unina credits * Added restriction for other tools --------- Co-authored-by: Valentin Porcellini * redux keep last process url in textfield * Enhanced UI * externalize role hook * Enhanced UI + refactoring (#319) Co-authored-by: Valentin Porcellini * Deepfake v4 (#320) * Fixed url error msg + added other languages * Added unina credits * Added restriction for other tools * redux keep last process url in textfield * Enhanced UI * externalize role hook * Enhanced UI + refactoring (#319) Co-authored-by: Valentin Porcellini --------- Co-authored-by: Valentin Porcellini Co-authored-by: Bertrand Goupil * lens support url * Only show Google Lens if the image is from an URL * add remove button for video deepfake * Bugfixes (#321) * Fixed url error msg + added other languages * Added unina credits * Added restriction for other tools * redux keep last process url in textfield * Enhanced UI * externalize role hook * Enhanced UI + refactoring (#319) Co-authored-by: Valentin Porcellini * lens support url * Only show Google Lens if the image is from an URL * add remove button for video deepfake --------- Co-authored-by: Bertrand Goupil * matomo update + package upgrade * Matomo tracking + packages upgrade (#323) * Fixed url error msg + added other languages * Added unina credits * Added restriction for other tools * redux keep last process url in textfield * Enhanced UI * externalize role hook * Enhanced UI + refactoring (#319) Co-authored-by: Valentin Porcellini * lens support url * Only show Google Lens if the image is from an URL * add remove button for video deepfake * matomo update + package upgrade --------- Co-authored-by: Bertrand Goupil * increase status request to 3 seconds * Disable Google lens for data blob * fix dattime picker * remove console log * bug fix checkGif loop X advance search date control * geolocate url * Geoloc fix feature * Add detection progess bar * bug fix test if sevice is sending results * bug fix url in error * Revert "Merge branch 'deepfake-v4-translation' into deepfake-v4" This reverts commit c8aa9809d94f1bb8c536a61116067a884c9c0be2, reversing changes made to e04e89cb3bc5a9df26b2fc645e38ff21c7ba61fa. * bug fix GMT disable * remove log * remove log --------- Co-authored-by: AFPMedialab <40788591+AFPMedialab@users.noreply.github.com> Co-authored-by: Bertrand Goupil Co-authored-by: dteyssou * Matomo update (#350) * Bugfixes + Added tracking (#292) (#293) * rename Feeback * mv2 fix for build * thumbnail * remove console * roll back publicpath * Added trackEvent --------- Co-authored-by: AFPMedialab <40788591+AFPMedialab@users.noreply.github.com> Co-authored-by: Bertrand Goupil Co-authored-by: Valentin Porcellini * Changed dbkf img format (#299) (#300) Co-authored-by: Valentin Porcellini * Bugfixes (#303) * Changed dbkf img format (#299) Co-authored-by: Valentin Porcellini * DBKF and Thumbnail Fixes (#301) * Changed dbkf img format * Fixed download keyframe URI --------- Co-authored-by: Valentin Porcellini * Prevent tab deletion for reverse search calls (#302) * Changed dbkf img format * Fixed download keyframe URI * Added parameter to prevent tab deletion for app reverse search calls --------- Co-authored-by: Valentin Porcellini --------- Co-authored-by: Valentin Porcellini * Merge fix and cleanup (#305) * Changed dbkf img format (#299) Co-authored-by: Valentin Porcellini * DBKF and Thumbnail Fixes (#301) * Changed dbkf img format * Fixed download keyframe URI --------- Co-authored-by: Valentin Porcellini * Prevent tab deletion for reverse search calls (#302) * Changed dbkf img format * Fixed download keyframe URI * Added parameter to prevent tab deletion for app reverse search calls --------- Co-authored-by: Valentin Porcellini * Merge fix and cleanup (#304) * Changed dbkf img format * Fixed download keyframe URI * Added parameter to prevent tab deletion for app reverse search calls * Deleted mv2 file * Fixed merge issue --------- Co-authored-by: Valentin Porcellini --------- Co-authored-by: Valentin Porcellini * Pre master (#307) * Changed dbkf img format (#299) Co-authored-by: Valentin Porcellini * DBKF and Thumbnail Fixes (#301) * Changed dbkf img format * Fixed download keyframe URI --------- Co-authored-by: Valentin Porcellini * Prevent tab deletion for reverse search calls (#302) * Changed dbkf img format * Fixed download keyframe URI * Added parameter to prevent tab deletion for app reverse search calls --------- Co-authored-by: Valentin Porcellini * Merge fix and cleanup (#304) * Changed dbkf img format * Fixed download keyframe URI * Added parameter to prevent tab deletion for app reverse search calls * Deleted mv2 file * Fixed merge issue --------- Co-authored-by: Valentin Porcellini * Permission cleanup mv3 (#306) * Changed dbkf img format * Fixed download keyframe URI * Added parameter to prevent tab deletion for app reverse search calls * Deleted mv2 file * Fixed merge issue * Removed unused permission --------- Co-authored-by: Valentin Porcellini --------- Co-authored-by: Valentin Porcellini * Update README.md * Update README.md * Update README.md * Update README.md * Added base UI for img results * Added diffusion scores * Refactoring, added video detection methods * Better layout, fixed load state bug, added warning text, rank img detection from highest to lowest, async API calls * bigger detection text * Refactoring * Sort video detection by decreasing detection percentage * Prevent error * auto resize rectangles + refactoring * Added textfield url type * Improved layout, error handling, added tsv support * Fixed issue where the previous video was not replaced with the new video + cleanup * Fixed state issue when submitting a new video after a first one * Layout improvements for better readability * Removed unnecessary header * Fix lint error * Fixed undefined error + better deepfake rectangle layout * add i18n react support * Check if string can be a URL + added error message * Removed fixed height * Added role restriction for FTCN method * (wip) synthetic image tool, added jsconfig, fixed lint errors * change default tsv path * (wip) * Removed diffusion, fixed lint error * Fixed deepfake tool * missing tsv file * sync tansalation * Fixed display issue * Fixed url error msg + added other languages * Fixed url error msg + added other languages (#317) Co-authored-by: Valentin Porcellini * Added unina credits * Added restriction for other tools * Fixes + translations + credits (#318) * Fixed url error msg + added other languages * Added unina credits * Added restriction for other tools --------- Co-authored-by: Valentin Porcellini * redux keep last process url in textfield * Enhanced UI * externalize role hook * Enhanced UI + refactoring (#319) Co-authored-by: Valentin Porcellini * Deepfake v4 (#320) * Fixed url error msg + added other languages * Added unina credits * Added restriction for other tools * redux keep last process url in textfield * Enhanced UI * externalize role hook * Enhanced UI + refactoring (#319) Co-authored-by: Valentin Porcellini --------- Co-authored-by: Valentin Porcellini Co-authored-by: Bertrand Goupil * lens support url * Only show Google Lens if the image is from an URL * add remove button for video deepfake * Bugfixes (#321) * Fixed url error msg + added other languages * Added unina credits * Added restriction for other tools * redux keep last process url in textfield * Enhanced UI * externalize role hook * Enhanced UI + refactoring (#319) Co-authored-by: Valentin Porcellini * lens support url * Only show Google Lens if the image is from an URL * add remove button for video deepfake --------- Co-authored-by: Bertrand Goupil * matomo update + package upgrade * Matomo tracking + packages upgrade (#323) * Fixed url error msg + added other languages * Added unina credits * Added restriction for other tools * redux keep last process url in textfield * Enhanced UI * externalize role hook * Enhanced UI + refactoring (#319) Co-authored-by: Valentin Porcellini * lens support url * Only show Google Lens if the image is from an URL * add remove button for video deepfake * matomo update + package upgrade --------- Co-authored-by: Bertrand Goupil * increase status request to 3 seconds * Disable Google lens for data blob * fix dattime picker * remove console log * bug fix checkGif loop X advance search date control * geolocate url * Geoloc fix feature * Add detection progess bar * bug fix test if sevice is sending results * bug fix url in error * Revert "Merge branch 'deepfake-v4-translation' into deepfake-v4" This reverts commit c8aa9809d94f1bb8c536a61116067a884c9c0be2, reversing changes made to e04e89cb3bc5a9df26b2fc645e38ff21c7ba61fa. * bug fix GMT disable * remove log * remove log * refactoring, added matomo tracking --------- Co-authored-by: AFPMedialab <40788591+AFPMedialab@users.noreply.github.com> Co-authored-by: Bertrand Goupil Co-authored-by: dteyssou * Added matomo analytics, fixed lint errors * Fixed layout and bugs --------- Co-authored-by: AFPMedialab <40788591+AFPMedialab@users.noreply.github.com> Co-authored-by: Bertrand Goupil Co-authored-by: dteyssou * Removed transition property to fix blank page error * Bumped version * Feedback email field (#367) * Added email field * Added email keywords * Allow to proceed if the email field is empty * Added label on top of the email field * 365 deepfake improve no face detection result parsing (#371) * #365 * Refactored variables. Removed non helping helper popup. Hide clip ui. Added translation * Removed console logs * Removed duplicate call, use async await, better error check (#375) * #361 matomo duplicate call at startup (#377) * Feedback email field (#367) (#368) * Added email field * Added email keywords * Allow to proceed if the email field is empty * Added label on top of the email field * 365 deepfake improve no face detection result parsing (#370) * Feedback email field (#367) * Added email field * Added email keywords * Allow to proceed if the email field is empty * Added label on top of the email field * #365 * Refactored variables. Removed non helping helper popup. Hide clip ui. Added translation * Removed console logs * Added new forensics api call * Fixes #361 --------- Co-authored-by: AFPMedialab <40788591+AFPMedialab@users.noreply.github.com> * Add sensible error messages when assistant fails. (#373) * allow x.com versions of twitter links (#382) Co-authored-by: davidwilby <6062469-davidwilby@users.noreply.gitlab.com> * Upgrade to Forensics API v4 (#385) * Feedback email field (#367) (#368) * Added email field * Added email keywords * Allow to proceed if the email field is empty * Added label on top of the email field * 365 deepfake improve no face detection result parsing (#370) * Feedback email field (#367) * Added email field * Added email keywords * Allow to proceed if the email field is empty * Added label on top of the email field * #365 * Refactored variables. Removed non helping helper popup. Hide clip ui. Added translation * Removed console logs * Added new forensics api call * Fixed typo * Added canvas component, create a mako scale from grayscale images * Enhanced the color scale. Fixed the mask display on hover. Added miniature canvases. Re-added fade animation. Added optional inverted grayscale support. Added optional unprocessed masking. Refactored code. * Fix the popup gif display for the forensic tool * Fixed #363, squashed some bugs, Refactoring * Fixed #363, squashed some bugs, Refactoring * WIP * WIP for CheckGIF * support checkGif with api for url and canvas * canvas big fix 1 * WIP * WIP Fixed bug where height for filter was not set well sometimes * WIP Fixed filter ratio to adjust the ratio to be the same as the original image, cleanup * Refactoring, fixed lint errors * Exclude CMFD filter from using color scale * Fix #381 --------- Co-authored-by: AFPMedialab <40788591+AFPMedialab@users.noreply.github.com> Co-authored-by: Bertrand Goupil * package upgrade * User friendly error messages * Display error message if there is no detection result * Fixed lint errors + cleanup --------- Co-authored-by: AFPMedialab <40788591+AFPMedialab@users.noreply.github.com> Co-authored-by: Bertrand Goupil Co-authored-by: dteyssou Co-authored-by: Twin Karmakharm Co-authored-by: David Wilby <24752124+davidwilby@users.noreply.github.com> Co-authored-by: davidwilby <6062469-davidwilby@users.noreply.gitlab.com> --- .../tools/Forensic/Hooks/useGetImages.jsx | 10 +---- .../Forensic/Hooks/useGetTransparent.jsx | 41 ------------------- 2 files changed, 1 insertion(+), 50 deletions(-) delete mode 100644 src/components/NavItems/tools/Forensic/Hooks/useGetTransparent.jsx diff --git a/src/components/NavItems/tools/Forensic/Hooks/useGetImages.jsx b/src/components/NavItems/tools/Forensic/Hooks/useGetImages.jsx index 2e052c04..c4678431 100644 --- a/src/components/NavItems/tools/Forensic/Hooks/useGetImages.jsx +++ b/src/components/NavItems/tools/Forensic/Hooks/useGetImages.jsx @@ -13,11 +13,6 @@ const useGetImages = (url, type, keyword) => { const dispatch = useDispatch(); - //const gifTransparencyMasks = []; - - const threshold = 0.4; - const colormap = "mako"; - useEffect(() => { const handleError = (e) => { //console.log("error key", e) @@ -31,7 +26,6 @@ const useGetImages = (url, type, keyword) => { .get(forensic_base_url + "/images/reports/" + reportId) .then((response) => { if (response.data != null) { - //getTransparent(response.data.id, url, response.data) dispatch( setForensicsResult({ url: type === "local" ? response.data.displayItem : url, @@ -52,7 +46,6 @@ const useGetImages = (url, type, keyword) => { }; const waitUntilFinish = (id) => { - //console.log("TEST2"); axios .get(forensic_base_url + "images/jobs/" + id) .then((response) => { @@ -104,7 +97,7 @@ const useGetImages = (url, type, keyword) => { if (url) { dispatch(setForensicsLoading(true)); - //console.log("TEST1"); + axios(configService(type)) .then((response) => waitUntilFinish(response.data.id)) .catch((error) => { @@ -122,7 +115,6 @@ const useGetImages = (url, type, keyword) => { } }); } - // eslint-disable-next-line }, [url]); }; export default useGetImages; diff --git a/src/components/NavItems/tools/Forensic/Hooks/useGetTransparent.jsx b/src/components/NavItems/tools/Forensic/Hooks/useGetTransparent.jsx deleted file mode 100644 index 2d8924e5..00000000 --- a/src/components/NavItems/tools/Forensic/Hooks/useGetTransparent.jsx +++ /dev/null @@ -1,41 +0,0 @@ -import { useEffect } from "react"; -import axios from "axios"; -import { useDispatch } from "react-redux"; -import { - setForensicsLoading, - setForensicMaskGif, -} from "../../../../../redux/actions/tools/forensicActions"; -import { setError } from "../../../../../redux/actions/errorActions"; -import { i18nLoadNamespace } from "components/Shared/Languages/i18nLoadNamespace"; - -const useGetTransparent = (url, ready) => { - const envisu4_utils_base_url = process.env.REACT_APP_CAA_ENVISU4_UTILS_URL; - const keyword = i18nLoadNamespace("components/NavItems/tools/Forensic"); - const dispatch = useDispatch(); - - useEffect(() => { - const handleError = (e) => { - if (keyword(e) !== "") dispatch(setError(keyword(e))); - else dispatch(setError(keyword("please_give_a_correct_link"))); - dispatch(setForensicsLoading(false)); - }; - - if (url && ready) { - axios - .get(envisu4_utils_base_url + "mask?url=" + url) - .then((response) => { - //console.log(response); - if (response.data != null) { - dispatch(setForensicMaskGif(response.data.mask)); - } else { - handleError("forensic_error_" + response.data.status); - } - }) - .catch((error) => { - handleError("forensic_error_" + error.status); - }); - } - // eslint-disable-next-line - }, [url, ready]); -}; -export default useGetTransparent; From a2dcb5a0896a8a70309d435ffa2d085951ef19b6 Mon Sep 17 00:00:00 2001 From: Valentin Porcellini Date: Fri, 5 Jan 2024 17:20:46 +0100 Subject: [PATCH 03/77] Added new tool and main UI (WIP) --- package.json | 1 + src/App.jsx | 24 ++- .../NavBar/DrawerItem/DrawerItem.jsx | 12 +- src/components/NavBar/NavBar.jsx | 48 ++++-- .../components/CheckboxesTags.jsx | 41 +++++ .../SemanticSearch/components/SelectSmall.jsx | 40 +++++ .../NavItems/tools/SemanticSearch/index.jsx | 146 ++++++++++++++++++ .../SemanticSearch/semanticSearchResults.jsx | 50 ++++++ 8 files changed, 344 insertions(+), 18 deletions(-) create mode 100644 src/components/NavItems/tools/SemanticSearch/components/CheckboxesTags.jsx create mode 100644 src/components/NavItems/tools/SemanticSearch/components/SelectSmall.jsx create mode 100644 src/components/NavItems/tools/SemanticSearch/index.jsx create mode 100644 src/components/NavItems/tools/SemanticSearch/semanticSearchResults.jsx diff --git a/package.json b/package.json index 0c80ad22..9a9cb8ab 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,7 @@ "axios": "^1.5.1", "d3-selection": "^3.0.0", "dateformat": "^5.0.3", + "dayjs": "^1.11.10", "exif-js": "^2.3.0", "file-saver": "^2.0.5", "history": "^5.3.0", diff --git a/src/App.jsx b/src/App.jsx index 73d0de8c..10230bfd 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -5,6 +5,14 @@ import { HashRouter, Route, Routes } from "react-router-dom"; import PopUp from "./components/PopUp/PopUp"; import NavBar from "./components/NavBar/NavBar"; import useAuthenticationAPI from "./components/Shared/Authentication/useAuthenticationAPI"; +import { LocalizationProvider } from "@mui/x-date-pickers/LocalizationProvider"; +import { useSelector } from "react-redux"; +import { AdapterDayjs } from "@mui/x-date-pickers/AdapterDayjs"; +import "dayjs/locale/en"; +import "dayjs/locale/fr"; +import "dayjs/locale/es"; +import "dayjs/locale/el"; +import "dayjs/locale/ar"; const theme = createTheme({ palette: { @@ -64,13 +72,21 @@ const App = () => { } } } + + const currentLang = useSelector((state) => state.language); + return ( - - } /> - } /> - + + + } /> + } /> + + ); diff --git a/src/components/NavBar/DrawerItem/DrawerItem.jsx b/src/components/NavBar/DrawerItem/DrawerItem.jsx index 2b1a84dc..bc0bc5b3 100644 --- a/src/components/NavBar/DrawerItem/DrawerItem.jsx +++ b/src/components/NavBar/DrawerItem/DrawerItem.jsx @@ -2,7 +2,7 @@ import React, { useEffect } from "react"; import PropTypes from "prop-types"; import { Container } from "@mui/material"; import Fade from "@mui/material/Fade"; -import { useSelector, useDispatch } from "react-redux"; +import { useDispatch, useSelector } from "react-redux"; import { selectTool } from "../../../redux/reducers/tools/toolReducer"; import AllTools from "../../NavItems/tools/Alltools/AllTools"; import Analysis from "../../NavItems/tools/Analysis/Analysis"; @@ -25,12 +25,10 @@ import Geolocation from "../../NavItems/tools/Geolocation/Geolocation"; import useMyStyles from "../../Shared/MaterialUiStyles/useMyStyles"; import { createTheme, ThemeProvider } from "@mui/material/styles"; import AnalysisImg from "../../NavItems/tools/Analysis_images/Analysis"; -import { - //trackPageView, - getclientId, -} from "../../Shared/GoogleAnalytics/MatomoAnalytics"; +import { getclientId } from "../../Shared/GoogleAnalytics/MatomoAnalytics"; import { useTrackPageView } from "../../../Hooks/useAnalytics"; import Archive from "../../NavItems/tools/Archive"; +import SemanticSearch from "../../NavItems/tools/SemanticSearch"; const DrawerItem = ({ drawerItems }) => { const drawerItemsContent = [ @@ -103,6 +101,10 @@ const DrawerItem = ({ drawerItems }) => { content: , footer: