@nyris/nyris-webapp 0.3.1 → 0.3.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/asset-manifest.json +11 -11
- package/build/index.html +1 -1
- package/build/js/test.js +14 -20
- package/build/{precache-manifest.3e7aa489925304848e8f04e3015d8567.js → precache-manifest.9800bdc87f5a2c5d6d8a5d1a5287598f.js} +10 -10
- package/build/service-worker.js +1 -1
- package/build/static/css/{main.b731b101.chunk.css → main.6676fe1f.chunk.css} +2 -2
- package/build/static/css/main.6676fe1f.chunk.css.map +1 -0
- package/build/static/js/2.29ddd567.chunk.js +3 -0
- package/build/static/js/{2.8297cb74.chunk.js.LICENSE.txt → 2.29ddd567.chunk.js.LICENSE.txt} +0 -9
- package/build/static/js/2.29ddd567.chunk.js.map +1 -0
- package/build/static/js/main.c35ded37.chunk.js +2 -0
- package/build/static/js/main.c35ded37.chunk.js.map +1 -0
- package/package.json +3 -3
- package/public/js/test.js +14 -20
- package/src/App.tsx +2 -5
- package/src/Store/Nyris.ts +7 -7
- package/src/Store/Search.ts +11 -10
- package/src/Store/Store.ts +12 -5
- package/src/components/CustomHits/index.tsx +57 -0
- package/src/components/DragDropFile.tsx +9 -9
- package/src/components/ExampleImages.tsx +2 -2
- package/src/components/Feedback.tsx +2 -2
- package/src/components/FilterComponent.tsx +5 -19
- package/src/components/Footer.tsx +1 -1
- package/src/components/HeaderMd.tsx +4 -5
- package/src/components/LoadingScreen/index.tsx +0 -13
- package/src/components/default-select.tsx +1 -2
- package/src/index.tsx +2 -1
- package/src/modules/LandingPage/{indexApp.tsx → App.tsx} +52 -208
- package/src/modules/LandingPage/{indexAppMD.tsx → AppMD.tsx} +52 -147
- package/src/modules/LandingPage/common.scss +18 -2
- package/src/modules/LandingPage/index.tsx +193 -0
- package/src/modules/LandingPage/indexNewVersion.tsx +10 -18
- package/src/modules/LandingPage/propsType.ts +43 -0
- package/src/page/result/index.tsx +14 -28
- package/src/services/findRegionsCustom.ts +0 -197
- package/src/services/image.ts +11 -14
- package/src/services/session.ts +6 -6
- package/src/services/types.ts +1 -15
- package/src/types.ts +0 -1
- package/build/static/css/main.b731b101.chunk.css.map +0 -1
- package/build/static/js/2.8297cb74.chunk.js +0 -3
- package/build/static/js/2.8297cb74.chunk.js.map +0 -1
- package/build/static/js/main.05909665.chunk.js +0 -2
- package/build/static/js/main.05909665.chunk.js.map +0 -1
- package/src/App.test.tsx +0 -49
- package/src/Store/epics/feedback.ts +0 -59
- package/src/Store/epics/types.ts +0 -12
- package/src/components/preview/preview.tsx +0 -433
|
@@ -574,6 +574,8 @@ button {
|
|
|
574
574
|
}
|
|
575
575
|
.exampleImages {
|
|
576
576
|
padding-bottom: 0px !important;
|
|
577
|
+
display: flex;
|
|
578
|
+
justify-content: center;
|
|
577
579
|
}
|
|
578
580
|
.useExampleImg {
|
|
579
581
|
margin-top: 0px !important;
|
|
@@ -652,8 +654,13 @@ button {
|
|
|
652
654
|
width: 100%;
|
|
653
655
|
height: 100%;
|
|
654
656
|
position: relative;
|
|
655
|
-
|
|
656
|
-
|
|
657
|
+
@media screen and (min-width: 2047px) {
|
|
658
|
+
position: initial;
|
|
659
|
+
.loadingSpinCT{
|
|
660
|
+
top: 0;
|
|
661
|
+
bottom: 0;
|
|
662
|
+
}
|
|
663
|
+
}
|
|
657
664
|
|
|
658
665
|
.box-content-drop {
|
|
659
666
|
display: flex;
|
|
@@ -677,6 +684,9 @@ button {
|
|
|
677
684
|
animation: gradient 15s ease infinite;
|
|
678
685
|
position: relative;
|
|
679
686
|
background-size: 100% 100%;
|
|
687
|
+
@media screen and (min-width: 2047px) {
|
|
688
|
+
position: initial;
|
|
689
|
+
}
|
|
680
690
|
@keyframes gradient {
|
|
681
691
|
0% {
|
|
682
692
|
background-position: 0% 50%;
|
|
@@ -693,6 +703,9 @@ button {
|
|
|
693
703
|
background: #1e1f31;
|
|
694
704
|
padding: 21px;
|
|
695
705
|
height: 100%;
|
|
706
|
+
@media screen and (min-width: 2047px) {
|
|
707
|
+
position: inherit;
|
|
708
|
+
}
|
|
696
709
|
}
|
|
697
710
|
.box-border {
|
|
698
711
|
border: 2px dashed #aaabb5;
|
|
@@ -861,6 +874,9 @@ button {
|
|
|
861
874
|
// overflow: auto;
|
|
862
875
|
.box-item-result {
|
|
863
876
|
max-width: 714px;
|
|
877
|
+
@media screen and (min-width: 2047px) {
|
|
878
|
+
max-width: 1300px;
|
|
879
|
+
}
|
|
864
880
|
margin: 16px 0;
|
|
865
881
|
// margin-right: auto !important;
|
|
866
882
|
ul {
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
import React, { useCallback, useEffect, useState } from "react";
|
|
2
|
+
import {
|
|
3
|
+
RectCoords,
|
|
4
|
+
cadExtensions,
|
|
5
|
+
isCadFile,
|
|
6
|
+
isImageFile,
|
|
7
|
+
ImageSearchOptions,
|
|
8
|
+
} from "@nyris/nyris-api";
|
|
9
|
+
|
|
10
|
+
import { useAppDispatch, useAppSelector } from "Store/Store";
|
|
11
|
+
import {
|
|
12
|
+
loadCadFileLoad,
|
|
13
|
+
setSearchResults,
|
|
14
|
+
loadFileSelectRegion,
|
|
15
|
+
loadingActionRegions,
|
|
16
|
+
loadingActionResults,
|
|
17
|
+
searchFileImageNonRegion,
|
|
18
|
+
} from "Store/Search";
|
|
19
|
+
import {
|
|
20
|
+
feedbackNegative,
|
|
21
|
+
feedbackSubmitPositive,
|
|
22
|
+
hideFeedback,
|
|
23
|
+
showCamera,
|
|
24
|
+
showFeedback,
|
|
25
|
+
showResults,
|
|
26
|
+
showStart,
|
|
27
|
+
} from "Store/Nyris";
|
|
28
|
+
import { serviceImage, serviceImageNonRegion } from "services/image";
|
|
29
|
+
import { findByImage } from "services/findByImage";
|
|
30
|
+
import { debounce, isEmpty } from "lodash";
|
|
31
|
+
import { feedbackClickEpic } from "services/Feedback";
|
|
32
|
+
import AppMD from "./AppMD";
|
|
33
|
+
import App from "./App";
|
|
34
|
+
import {AppHandlers, AppProps} from "./propsType";
|
|
35
|
+
import {defaultMdSettings} from "../../defaults";
|
|
36
|
+
|
|
37
|
+
const LandingPageApp = () => {
|
|
38
|
+
const dispatch = useAppDispatch();
|
|
39
|
+
const searchState = useAppSelector((state) => state);
|
|
40
|
+
const [rectCoords, setRectCoords] = useState<any>();
|
|
41
|
+
const defaultSelection = {x1: 0.1, x2: 0.9, y1: 0.1, y2: 0.9};
|
|
42
|
+
const [selection, setSelection] = useState<RectCoords>(defaultSelection);
|
|
43
|
+
|
|
44
|
+
const { settings, search, nyris } = searchState;
|
|
45
|
+
const {
|
|
46
|
+
fetchingRegions,
|
|
47
|
+
fetchingResults,
|
|
48
|
+
requestImage,
|
|
49
|
+
selectedRegion,
|
|
50
|
+
} = search;
|
|
51
|
+
const { showPart } = nyris;
|
|
52
|
+
|
|
53
|
+
const isDefaultRect = (r: RectCoords) => r.x1 === 0 && r.x2 === 1 && r.y1 === 0 && r.y2 === 1;
|
|
54
|
+
|
|
55
|
+
// update selection, if it is not the default one
|
|
56
|
+
useEffect(() => {
|
|
57
|
+
if (!isDefaultRect(selectedRegion)) {
|
|
58
|
+
setSelection(selectedRegion);
|
|
59
|
+
}
|
|
60
|
+
}, [selectedRegion]);
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
useEffect(() => {
|
|
64
|
+
if (isEmpty(rectCoords)) {
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
onSearchOffersForImage(rectCoords);
|
|
68
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
69
|
+
}, [rectCoords]);
|
|
70
|
+
|
|
71
|
+
const acceptTypes = ["image/*"]
|
|
72
|
+
.concat(settings.cadSearch ? cadExtensions : [])
|
|
73
|
+
.join(",");
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
function scrollTop() {
|
|
77
|
+
// TODO might require polyfill for ios and edge
|
|
78
|
+
window.scrollTo({ top: 0, left: 0, behavior: "smooth" });
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const onLinkClick = (_position: number, url: string) => {
|
|
82
|
+
feedbackClickEpic(searchState, _position).catch(console.warn);
|
|
83
|
+
if (url) {
|
|
84
|
+
window.open(url);
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
// TODO: search image file home page
|
|
88
|
+
const isCheckImageFile = (file: any) => {
|
|
89
|
+
dispatch(loadingActionResults());
|
|
90
|
+
dispatch(showResults());
|
|
91
|
+
dispatch(showFeedback());
|
|
92
|
+
if (isImageFile(file) || typeof file === "string") {
|
|
93
|
+
return serviceImage(file, searchState.settings).then((res) => {
|
|
94
|
+
dispatch(setSearchResults(res));
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
if (isCadFile(file)) {
|
|
98
|
+
return dispatch(loadCadFileLoad(file));
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
//
|
|
102
|
+
|
|
103
|
+
const searchByUrl = (url: string, position?: number) => {
|
|
104
|
+
dispatch(loadingActionResults());
|
|
105
|
+
dispatch(showResults());
|
|
106
|
+
if (position) {
|
|
107
|
+
feedbackClickEpic(searchState, position);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
if (settings.regions) {
|
|
111
|
+
serviceImage(url, searchState.settings).then((res) => {
|
|
112
|
+
dispatch(setSearchResults(res));
|
|
113
|
+
dispatch(showFeedback());
|
|
114
|
+
});
|
|
115
|
+
} else {
|
|
116
|
+
serviceImageNonRegion(url, searchState, rectCoords).then((res) => {
|
|
117
|
+
dispatch(searchFileImageNonRegion(res));
|
|
118
|
+
dispatch(showFeedback());
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
const handlerRectCoords = debounce((value) => {
|
|
124
|
+
return setRectCoords(value);
|
|
125
|
+
}, 1200);
|
|
126
|
+
|
|
127
|
+
const debouncedSetRectCoords = useCallback(
|
|
128
|
+
(value) => handlerRectCoords(value),
|
|
129
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
130
|
+
[]
|
|
131
|
+
);
|
|
132
|
+
|
|
133
|
+
const onSearchOffersForImage = (r: RectCoords) => {
|
|
134
|
+
const { canvas }: any = requestImage;
|
|
135
|
+
let options: ImageSearchOptions = {
|
|
136
|
+
cropRect: r,
|
|
137
|
+
};
|
|
138
|
+
dispatch(loadingActionRegions());
|
|
139
|
+
return findByImage(canvas, options, settings).then((res) => {
|
|
140
|
+
dispatch(loadFileSelectRegion(res));
|
|
141
|
+
return dispatch(showFeedback());
|
|
142
|
+
});
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
const handlers : AppHandlers = {
|
|
146
|
+
onExampleImageClick: url => searchByUrl(url),
|
|
147
|
+
onCameraClick: () => dispatch(showCamera),
|
|
148
|
+
onCaptureCanceled: () => dispatch(showStart),
|
|
149
|
+
onCaptureComplete: (i) => isCheckImageFile(i),
|
|
150
|
+
onCloseFeedback: () => dispatch(hideFeedback),
|
|
151
|
+
onFileDropped: (f) => isCheckImageFile(f),
|
|
152
|
+
onImageClick: (position, url) => searchByUrl(url, position),
|
|
153
|
+
onLinkClick: onLinkClick,
|
|
154
|
+
onPositiveFeedback: () => {
|
|
155
|
+
dispatch(feedbackSubmitPositive());
|
|
156
|
+
// TODO submit positive feedback to the api
|
|
157
|
+
},
|
|
158
|
+
onNegativeFeedback: () => {
|
|
159
|
+
dispatch(feedbackNegative());
|
|
160
|
+
// TODO submit negative feedback to the api
|
|
161
|
+
},
|
|
162
|
+
onSelectFile: (f) => isCheckImageFile(f),
|
|
163
|
+
onSelectionChange: r => {
|
|
164
|
+
setSelection(r);
|
|
165
|
+
debouncedSetRectCoords(r);
|
|
166
|
+
},
|
|
167
|
+
onShowStart: () => {
|
|
168
|
+
dispatch(showStart());
|
|
169
|
+
scrollTop();
|
|
170
|
+
}
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
let props : AppProps = {
|
|
174
|
+
search: {
|
|
175
|
+
...search,
|
|
176
|
+
previewSelection: selection
|
|
177
|
+
},
|
|
178
|
+
settings,
|
|
179
|
+
previewImage: search.requestImage,
|
|
180
|
+
acceptTypes,
|
|
181
|
+
showPart,
|
|
182
|
+
handlers,
|
|
183
|
+
loading: fetchingRegions || fetchingResults,
|
|
184
|
+
mdSettings: settings.themePage.materialDesign || defaultMdSettings,
|
|
185
|
+
feedbackState: nyris.feedbackState,
|
|
186
|
+
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
return settings.themePage.materialDesign?.active? <AppMD {...props}/> : <App {...props}/>;
|
|
190
|
+
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
export default LandingPageApp;
|
|
@@ -14,39 +14,30 @@ import {
|
|
|
14
14
|
} from "react-instantsearch-dom";
|
|
15
15
|
import algoliasearch from "algoliasearch/lite";
|
|
16
16
|
import CustomSearchBox from "components/input/inputSearch";
|
|
17
|
-
import
|
|
17
|
+
import {createSessionByApi} from "../../services/session";
|
|
18
18
|
|
|
19
19
|
interface Props {}
|
|
20
20
|
|
|
21
21
|
function AppNewVersion(props: Props) {
|
|
22
|
-
// const searchClient = algoliasearch(appId, apiKey);
|
|
23
|
-
// const index = searchClient.initIndex(indexName);
|
|
24
22
|
const dispatch = useAppDispatch();
|
|
25
23
|
const history = useHistory();
|
|
26
24
|
const searchState = useAppSelector((state) => state);
|
|
27
25
|
const { settings, search }: any = searchState;
|
|
28
26
|
const [searchStateInput, setSearchStateInput] = useState<any>({});
|
|
29
27
|
const [isLoading, setLoading] = useState<boolean>(false);
|
|
30
|
-
const nyrisApi = new NyrisAPICT(settings);
|
|
31
28
|
const { apiKeyAlgolia, appIdAlgolia, indexNameAlgolia } = settings;
|
|
32
29
|
const searchClient = algoliasearch(appIdAlgolia, apiKeyAlgolia);
|
|
33
30
|
searchClient.initIndex(indexNameAlgolia);
|
|
34
31
|
|
|
35
32
|
useEffect(() => {
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
const payload: any = {
|
|
40
|
-
sessionId: res.data.session,
|
|
41
|
-
requestId: res.data.id,
|
|
42
|
-
};
|
|
43
|
-
dispatch(setUpdateSession(payload));
|
|
44
|
-
});
|
|
45
|
-
} catch (error) {}
|
|
33
|
+
const createSession = async () => {
|
|
34
|
+
let payload = await createSessionByApi(searchState.settings);
|
|
35
|
+
dispatch(setUpdateSession(payload));
|
|
46
36
|
};
|
|
47
37
|
|
|
48
|
-
|
|
49
|
-
|
|
38
|
+
createSession().catch(console.log);
|
|
39
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
40
|
+
}, []);
|
|
50
41
|
|
|
51
42
|
const acceptTypes = ["image/*"]
|
|
52
43
|
.concat(settings.cadSearch ? cadExtensions : [])
|
|
@@ -65,9 +56,10 @@ function AppNewVersion(props: Props) {
|
|
|
65
56
|
const nonEmptyFilter: any[] = !search?.requestImage
|
|
66
57
|
? []
|
|
67
58
|
: ["sku:DOES_NOT_EXIST<score=1>"];
|
|
59
|
+
// Build filter using reverse position for stable item order
|
|
68
60
|
const filterSkus: any = search?.results
|
|
69
|
-
? search?.results.map(
|
|
70
|
-
(f: any) => `sku:'${f.sku}'<score=${
|
|
61
|
+
? search?.results.slice().reverse().map(
|
|
62
|
+
(f: any, i: number) => `sku:'${f.sku}'<score=${i}>`
|
|
71
63
|
)
|
|
72
64
|
: "";
|
|
73
65
|
const filtersString = [...nonEmptyFilter, ...filterSkus].join(" OR ");
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import {CategoryPrediction, Code, RectCoords, Region} from "@nyris/nyris-api";
|
|
2
|
+
import {AppSettings, CanvasWithId, MDSettings} from "../../types";
|
|
3
|
+
import {NyrisAppPart, NyrisFeedbackState} from "../../Store/Nyris";
|
|
4
|
+
|
|
5
|
+
export interface AppHandlers {
|
|
6
|
+
onExampleImageClick: (url: string) => void;
|
|
7
|
+
onImageClick: (position: number, url: string) => void;
|
|
8
|
+
onLinkClick: (position: number, url: string) => void;
|
|
9
|
+
onFileDropped: (file: File) => void;
|
|
10
|
+
onCaptureComplete: (image: HTMLCanvasElement) => void;
|
|
11
|
+
onCaptureCanceled: () => void;
|
|
12
|
+
onSelectFile: (f: File) => void;
|
|
13
|
+
onCameraClick: () => void;
|
|
14
|
+
onShowStart: () => void;
|
|
15
|
+
onSelectionChange: (r: RectCoords) => void;
|
|
16
|
+
onPositiveFeedback: () => void;
|
|
17
|
+
onNegativeFeedback: () => void;
|
|
18
|
+
onCloseFeedback: () => void;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
export interface AppProps {
|
|
23
|
+
search: {
|
|
24
|
+
results: any[];
|
|
25
|
+
requestId?: string;
|
|
26
|
+
duration?: number;
|
|
27
|
+
categoryPredictions: CategoryPrediction[];
|
|
28
|
+
codes: Code[];
|
|
29
|
+
filterOptions: string[];
|
|
30
|
+
errorMessage?: string;
|
|
31
|
+
regions: Region[];
|
|
32
|
+
previewSelection: RectCoords;
|
|
33
|
+
toastErrorMessage?: string;
|
|
34
|
+
};
|
|
35
|
+
acceptTypes: string,
|
|
36
|
+
previewImage?: CanvasWithId;
|
|
37
|
+
settings: AppSettings;
|
|
38
|
+
loading: boolean;
|
|
39
|
+
showPart: NyrisAppPart;
|
|
40
|
+
feedbackState: NyrisFeedbackState;
|
|
41
|
+
handlers: AppHandlers;
|
|
42
|
+
mdSettings: MDSettings;
|
|
43
|
+
}
|
|
@@ -31,7 +31,7 @@ import DetailItem from "components/DetailItem";
|
|
|
31
31
|
import FileCopyOutlinedIcon from "@material-ui/icons/FileCopyOutlined";
|
|
32
32
|
import { RectCoords } from "@nyris/nyris-api";
|
|
33
33
|
import {
|
|
34
|
-
|
|
34
|
+
setSearchResults,
|
|
35
35
|
loadingActionResults,
|
|
36
36
|
searchFileImageNonRegion,
|
|
37
37
|
selectionChanged,
|
|
@@ -52,9 +52,9 @@ import {
|
|
|
52
52
|
serviceImage,
|
|
53
53
|
serviceImageNonRegion,
|
|
54
54
|
} from "services/image";
|
|
55
|
-
import Preview from "components/preview/preview";
|
|
56
55
|
import NyrisAPI from "@nyris/nyris-api";
|
|
57
56
|
import LoadingScreenCustom from "components/LoadingScreen";
|
|
57
|
+
import { Preview } from "@nyris/nyris-react-components";
|
|
58
58
|
|
|
59
59
|
interface Props {}
|
|
60
60
|
|
|
@@ -144,7 +144,7 @@ function ResultComponent(props: Props) {
|
|
|
144
144
|
};
|
|
145
145
|
dispatch(updateResultChangePosition(payload));
|
|
146
146
|
setLoading(false);
|
|
147
|
-
return dispatch(showFeedback(
|
|
147
|
+
return dispatch(showFeedback());
|
|
148
148
|
});
|
|
149
149
|
} else {
|
|
150
150
|
serviceImageNonRegion(canvas, StateGlobal, null).then((res: any) => {
|
|
@@ -153,7 +153,7 @@ function ResultComponent(props: Props) {
|
|
|
153
153
|
requestImage: requestImage,
|
|
154
154
|
};
|
|
155
155
|
dispatch(updateResultChangePosition(payload));
|
|
156
|
-
return dispatch(showFeedback(
|
|
156
|
+
return dispatch(showFeedback());
|
|
157
157
|
});
|
|
158
158
|
}
|
|
159
159
|
};
|
|
@@ -202,17 +202,18 @@ function ResultComponent(props: Props) {
|
|
|
202
202
|
|
|
203
203
|
// Search image with url or file
|
|
204
204
|
const getUrlToCanvasFile = (url: string, position?: number) => {
|
|
205
|
-
dispatch(showResults(
|
|
206
|
-
dispatch(loadingActionResults(
|
|
205
|
+
dispatch(showResults());
|
|
206
|
+
dispatch(loadingActionResults());
|
|
207
207
|
if (position) {
|
|
208
208
|
feedbackClickEpic(StateGlobal, position);
|
|
209
209
|
return;
|
|
210
210
|
}
|
|
211
211
|
if (settings.regions) {
|
|
212
|
-
serviceImage(url,
|
|
213
|
-
|
|
212
|
+
serviceImage(url, settings).then((res ) => {
|
|
213
|
+
console.log("res", res)
|
|
214
|
+
dispatch(setSearchResults(res));
|
|
214
215
|
setLoading(false);
|
|
215
|
-
return dispatch(showFeedback(
|
|
216
|
+
return dispatch(showFeedback());
|
|
216
217
|
});
|
|
217
218
|
|
|
218
219
|
return;
|
|
@@ -256,8 +257,6 @@ function ResultComponent(props: Props) {
|
|
|
256
257
|
)
|
|
257
258
|
: "";
|
|
258
259
|
const filtersString = [...nonEmptyFilter, ...filterSkus].join(" OR ");
|
|
259
|
-
console.log("isLoading", isLoading);
|
|
260
|
-
|
|
261
260
|
return (
|
|
262
261
|
<Box className={`wrap-main-result loading`}>
|
|
263
262
|
<>
|
|
@@ -284,14 +283,7 @@ function ResultComponent(props: Props) {
|
|
|
284
283
|
<CustomSearchBox />
|
|
285
284
|
</Box>
|
|
286
285
|
{/* <Box className="box-filter">
|
|
287
|
-
<FilterComponent
|
|
288
|
-
dataFieldOne={dataFieldOne}
|
|
289
|
-
dataFieldTow={dataFieldTow}
|
|
290
|
-
dataFieldThree={dataFieldThree}
|
|
291
|
-
dataFieldFour={dataFieldFour}
|
|
292
|
-
dataFieldFive={dataFieldFive}
|
|
293
|
-
dataFieldSix={dataFieldSix}
|
|
294
|
-
/>
|
|
286
|
+
<FilterComponent />
|
|
295
287
|
</Box> */}
|
|
296
288
|
</div>
|
|
297
289
|
<Box className="box-result">
|
|
@@ -322,13 +314,7 @@ function ResultComponent(props: Props) {
|
|
|
322
314
|
return;
|
|
323
315
|
}}
|
|
324
316
|
image={requestImage?.canvas}
|
|
325
|
-
|
|
326
|
-
!selectedRegion
|
|
327
|
-
? regions[0]
|
|
328
|
-
? regions[0]
|
|
329
|
-
: { x1: 0, x2: 1, y1: 0, y2: 1 }
|
|
330
|
-
: selectedRegion
|
|
331
|
-
}
|
|
317
|
+
selection={selectedRegion}
|
|
332
318
|
regions={regions}
|
|
333
319
|
maxWidth={400}
|
|
334
320
|
maxHeight={500}
|
|
@@ -390,8 +376,8 @@ function ResultComponent(props: Props) {
|
|
|
390
376
|
results={dataResult}
|
|
391
377
|
onHandlerModalShare={() => setOpenModalShare(true)}
|
|
392
378
|
onSearchImage={(url: string) => {
|
|
393
|
-
setLoading(true)
|
|
394
|
-
getUrlToCanvasFile(url)
|
|
379
|
+
setLoading(true);
|
|
380
|
+
getUrlToCanvasFile(url);
|
|
395
381
|
}}
|
|
396
382
|
/>
|
|
397
383
|
</DefaultModal>
|
|
@@ -13,200 +13,3 @@ import {
|
|
|
13
13
|
toCanvas,
|
|
14
14
|
} from "./nyris";
|
|
15
15
|
|
|
16
|
-
export interface RegionData {
|
|
17
|
-
rect: {
|
|
18
|
-
x: number;
|
|
19
|
-
y: number;
|
|
20
|
-
w: number;
|
|
21
|
-
h: number;
|
|
22
|
-
};
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
interface SearchResult {
|
|
26
|
-
results: Result[];
|
|
27
|
-
requestId: string;
|
|
28
|
-
categoryPredictions: any[];
|
|
29
|
-
codes: any[];
|
|
30
|
-
duration: number;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export default class NyrisAPICT {
|
|
34
|
-
private readonly httpClient: AxiosInstance;
|
|
35
|
-
private readonly imageMatchingUrl: string;
|
|
36
|
-
private readonly regionProposalUrl: string;
|
|
37
|
-
private readonly responseFormat: string;
|
|
38
|
-
private imageMatchingUrlBySku: string;
|
|
39
|
-
private imageMatchingSubmitManualUrl: string;
|
|
40
|
-
private feedbackUrl: string;
|
|
41
|
-
|
|
42
|
-
constructor(private settings: SearchServiceSettings) {
|
|
43
|
-
this.httpClient = axios.create();
|
|
44
|
-
this.imageMatchingUrl =
|
|
45
|
-
this.settings.imageMatchingUrl || "https://api.nyris.io/find/v1";
|
|
46
|
-
this.imageMatchingUrlBySku =
|
|
47
|
-
this.settings.imageMatchingUrlBySku ||
|
|
48
|
-
"https://api.nyris.io/recommend/v1/";
|
|
49
|
-
this.imageMatchingSubmitManualUrl =
|
|
50
|
-
this.settings.imageMatchingSubmitManualUrl ||
|
|
51
|
-
"https://api.nyris.io/find/v1/manual/";
|
|
52
|
-
this.feedbackUrl =
|
|
53
|
-
this.settings.feedbackUrl || "https://api.nyris.io/feedback/v1/";
|
|
54
|
-
this.regionProposalUrl =
|
|
55
|
-
this.settings.regionProposalUrl ||
|
|
56
|
-
"https://api.nyris.io/find/v1/regions/";
|
|
57
|
-
this.responseFormat =
|
|
58
|
-
this.settings.responseFormat || "application/offers.nyris+json";
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* Find significant sections in the image.
|
|
63
|
-
* @param canvas Canvas, video or image to search with.
|
|
64
|
-
* @param options See [[ImageSearchOptions]].
|
|
65
|
-
* @returns A list of regions, see [[Region]].
|
|
66
|
-
*/
|
|
67
|
-
async findRegions(
|
|
68
|
-
canvas: HTMLCanvasElement | HTMLVideoElement | HTMLImageElement,
|
|
69
|
-
options: ImageSearchOptions
|
|
70
|
-
): Promise<Region[]> {
|
|
71
|
-
let [origW, origH] = getElementSize(canvas);
|
|
72
|
-
let { w: scaledW, h: scaledH } = getThumbSizeArea(
|
|
73
|
-
options.maxWidth,
|
|
74
|
-
options.maxHeight,
|
|
75
|
-
origW,
|
|
76
|
-
origH
|
|
77
|
-
);
|
|
78
|
-
let resizedCroppedCanvas = toCanvas(canvas, { w: scaledW, h: scaledH });
|
|
79
|
-
let blob = await canvasToJpgBlob(resizedCroppedCanvas, options.jpegQuality);
|
|
80
|
-
|
|
81
|
-
const headers = {
|
|
82
|
-
"Content-Type": "image/jpeg",
|
|
83
|
-
"X-Api-Key": this.settings.apiKey,
|
|
84
|
-
};
|
|
85
|
-
let response = await this.httpClient.request<any[]>({
|
|
86
|
-
method: "POST",
|
|
87
|
-
url: this.regionProposalUrl,
|
|
88
|
-
data: blob,
|
|
89
|
-
headers,
|
|
90
|
-
});
|
|
91
|
-
let regions: any[] = response.data;
|
|
92
|
-
return regions.map((r) => ({
|
|
93
|
-
className: r.className,
|
|
94
|
-
confidence: r.confidence,
|
|
95
|
-
x1: r.region.left / scaledW,
|
|
96
|
-
x2: r.region.right / scaledW,
|
|
97
|
-
y1: r.region.top / scaledH,
|
|
98
|
-
y2: r.region.bottom / scaledH,
|
|
99
|
-
}));
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
private async prepareImage(
|
|
103
|
-
canvas: HTMLCanvasElement | HTMLImageElement | HTMLVideoElement,
|
|
104
|
-
options: ImageSearchOptions
|
|
105
|
-
): Promise<{ bytes: Blob; region?: RegionData }> {
|
|
106
|
-
let [w, h] = getElementSize(canvas);
|
|
107
|
-
let crop = options.crop
|
|
108
|
-
? options.crop
|
|
109
|
-
: {
|
|
110
|
-
x: 0,
|
|
111
|
-
y: 0,
|
|
112
|
-
w: w,
|
|
113
|
-
h: h,
|
|
114
|
-
};
|
|
115
|
-
let region: RegionData | undefined = undefined;
|
|
116
|
-
if (options.crop) {
|
|
117
|
-
region = {
|
|
118
|
-
rect: {
|
|
119
|
-
w: Math.min(1, crop.w / w),
|
|
120
|
-
h: Math.min(1, crop.h / h),
|
|
121
|
-
x: Math.min(1, crop.x / w),
|
|
122
|
-
y: Math.min(1, crop.y / h),
|
|
123
|
-
},
|
|
124
|
-
};
|
|
125
|
-
}
|
|
126
|
-
let scaledSize = getThumbSizeArea(
|
|
127
|
-
options.maxWidth,
|
|
128
|
-
options.maxHeight,
|
|
129
|
-
crop.w,
|
|
130
|
-
crop.h
|
|
131
|
-
);
|
|
132
|
-
let resizedCroppedCanvas = toCanvas(canvas, scaledSize, undefined, crop);
|
|
133
|
-
let bytes = await canvasToJpgBlob(
|
|
134
|
-
resizedCroppedCanvas,
|
|
135
|
-
options.jpegQuality
|
|
136
|
-
);
|
|
137
|
-
|
|
138
|
-
return { bytes, region };
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
async findByImage(
|
|
142
|
-
canvas: HTMLCanvasElement | HTMLImageElement | HTMLVideoElement,
|
|
143
|
-
options: ImageSearchOptions
|
|
144
|
-
): Promise<SearchResult> {
|
|
145
|
-
const image = await this.prepareImage(canvas, options);
|
|
146
|
-
|
|
147
|
-
if (this.settings.customSearchRequest)
|
|
148
|
-
return this.settings.customSearchRequest(image.bytes, this.httpClient); // TODO check if the interface is ok for hooks
|
|
149
|
-
|
|
150
|
-
let headers: any = {
|
|
151
|
-
"Content-Type": "image/jpeg",
|
|
152
|
-
"X-Api-Key": this.settings.apiKey,
|
|
153
|
-
"Accept-Language": "de,*;q=0.5",
|
|
154
|
-
Accept: this.responseFormat,
|
|
155
|
-
};
|
|
156
|
-
const xOptions = [];
|
|
157
|
-
if (this.settings.xOptions) xOptions.push(this.settings.xOptions as string);
|
|
158
|
-
if (options.useRecommendations) xOptions.push("+recommendations");
|
|
159
|
-
if (xOptions.length > 0) headers["X-Options"] = xOptions.join(" ");
|
|
160
|
-
let params = options.geoLocation
|
|
161
|
-
? {
|
|
162
|
-
lat: options.geoLocation.lat.toString(),
|
|
163
|
-
lon: options.geoLocation.lon.toString(),
|
|
164
|
-
dist: options.geoLocation.dist.toString(),
|
|
165
|
-
}
|
|
166
|
-
: {};
|
|
167
|
-
// console.log("p", params, image.bytes);
|
|
168
|
-
let res: any = await this.httpClient.request<any>({
|
|
169
|
-
method: "POST",
|
|
170
|
-
url: this.imageMatchingUrl,
|
|
171
|
-
data: image.bytes,
|
|
172
|
-
params,
|
|
173
|
-
headers,
|
|
174
|
-
responseType: "json",
|
|
175
|
-
});
|
|
176
|
-
// console.log(res);
|
|
177
|
-
const categoryPredictions = Object.entries(
|
|
178
|
-
res.data.predicted_category || {}
|
|
179
|
-
)
|
|
180
|
-
.map(([name, score]) => ({
|
|
181
|
-
name: name,
|
|
182
|
-
score: score as number,
|
|
183
|
-
}))
|
|
184
|
-
.sort((a, b) => b.score - a.score);
|
|
185
|
-
let codes = res.data.barcodes || [];
|
|
186
|
-
|
|
187
|
-
let responseData = this.settings.responseHook
|
|
188
|
-
? this.settings.responseHook(res.data)
|
|
189
|
-
: res.data;
|
|
190
|
-
|
|
191
|
-
let results: Result[] = responseData?.results.map(
|
|
192
|
-
(r: Result, i: number) => ({
|
|
193
|
-
...r,
|
|
194
|
-
position: i,
|
|
195
|
-
})
|
|
196
|
-
);
|
|
197
|
-
const requestId = res.headers["x-matching-request"];
|
|
198
|
-
const duration = res.data.durationSeconds;
|
|
199
|
-
return { results, requestId, duration, categoryPredictions, codes };
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
async createSession(): Promise<{ data: any }> {
|
|
203
|
-
let headers: any = {
|
|
204
|
-
"X-Api-Key": this.settings.apiKey,
|
|
205
|
-
};
|
|
206
|
-
return await this.httpClient.request({
|
|
207
|
-
method: "POST",
|
|
208
|
-
url: `${this.imageMatchingUrl}/session`,
|
|
209
|
-
headers,
|
|
210
|
-
});
|
|
211
|
-
}
|
|
212
|
-
}
|