@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.
Files changed (49) hide show
  1. package/build/asset-manifest.json +11 -11
  2. package/build/index.html +1 -1
  3. package/build/js/test.js +14 -20
  4. package/build/{precache-manifest.3e7aa489925304848e8f04e3015d8567.js → precache-manifest.9800bdc87f5a2c5d6d8a5d1a5287598f.js} +10 -10
  5. package/build/service-worker.js +1 -1
  6. package/build/static/css/{main.b731b101.chunk.css → main.6676fe1f.chunk.css} +2 -2
  7. package/build/static/css/main.6676fe1f.chunk.css.map +1 -0
  8. package/build/static/js/2.29ddd567.chunk.js +3 -0
  9. package/build/static/js/{2.8297cb74.chunk.js.LICENSE.txt → 2.29ddd567.chunk.js.LICENSE.txt} +0 -9
  10. package/build/static/js/2.29ddd567.chunk.js.map +1 -0
  11. package/build/static/js/main.c35ded37.chunk.js +2 -0
  12. package/build/static/js/main.c35ded37.chunk.js.map +1 -0
  13. package/package.json +3 -3
  14. package/public/js/test.js +14 -20
  15. package/src/App.tsx +2 -5
  16. package/src/Store/Nyris.ts +7 -7
  17. package/src/Store/Search.ts +11 -10
  18. package/src/Store/Store.ts +12 -5
  19. package/src/components/CustomHits/index.tsx +57 -0
  20. package/src/components/DragDropFile.tsx +9 -9
  21. package/src/components/ExampleImages.tsx +2 -2
  22. package/src/components/Feedback.tsx +2 -2
  23. package/src/components/FilterComponent.tsx +5 -19
  24. package/src/components/Footer.tsx +1 -1
  25. package/src/components/HeaderMd.tsx +4 -5
  26. package/src/components/LoadingScreen/index.tsx +0 -13
  27. package/src/components/default-select.tsx +1 -2
  28. package/src/index.tsx +2 -1
  29. package/src/modules/LandingPage/{indexApp.tsx → App.tsx} +52 -208
  30. package/src/modules/LandingPage/{indexAppMD.tsx → AppMD.tsx} +52 -147
  31. package/src/modules/LandingPage/common.scss +18 -2
  32. package/src/modules/LandingPage/index.tsx +193 -0
  33. package/src/modules/LandingPage/indexNewVersion.tsx +10 -18
  34. package/src/modules/LandingPage/propsType.ts +43 -0
  35. package/src/page/result/index.tsx +14 -28
  36. package/src/services/findRegionsCustom.ts +0 -197
  37. package/src/services/image.ts +11 -14
  38. package/src/services/session.ts +6 -6
  39. package/src/services/types.ts +1 -15
  40. package/src/types.ts +0 -1
  41. package/build/static/css/main.b731b101.chunk.css.map +0 -1
  42. package/build/static/js/2.8297cb74.chunk.js +0 -3
  43. package/build/static/js/2.8297cb74.chunk.js.map +0 -1
  44. package/build/static/js/main.05909665.chunk.js +0 -2
  45. package/build/static/js/main.05909665.chunk.js.map +0 -1
  46. package/src/App.test.tsx +0 -49
  47. package/src/Store/epics/feedback.ts +0 -59
  48. package/src/Store/epics/types.ts +0 -12
  49. 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
- // background: #1e1f31;
656
- // padding: 21px;
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 NyrisAPICT from "services/findRegionsCustom";
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 createSecssion = async () => {
37
- try {
38
- await nyrisApi.createSession().then((res: any) => {
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
- createSecssion();
49
- }, [dispatch, nyrisApi]);
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=${Math.round(100 * f.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
- loadFile,
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, StateGlobal).then((res: any) => {
213
- dispatch(loadFile(res));
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
- initialRegion={
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
- }