@nyris/nyris-webapp 0.3.91 → 0.3.92
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 +6 -6
- package/build/data/related-parts.json +83 -0
- package/build/index.html +1 -1
- package/build/js/settings.example.js +3 -0
- package/build/static/css/main.5ea01690.css +4 -0
- package/build/static/css/main.5ea01690.css.map +1 -0
- package/build/static/js/main.36b77705.js +3 -0
- package/build/static/js/{main.f2255597.js.map → main.36b77705.js.map} +1 -1
- package/package.json +4 -3
- package/public/data/related-parts.json +83 -0
- package/public/js/settings.example.js +3 -0
- package/src/App.test.tsx +0 -1
- package/src/App.tsx +0 -1
- package/src/assets/arrow_down_expanded.svg +3 -0
- package/src/assets/arrow_enter.svg +3 -0
- package/src/assets/camera.svg +3 -0
- package/src/assets/close.svg +3 -0
- package/src/assets/enter.svg +3 -0
- package/src/assets/refresh.svg +3 -0
- package/src/assets/vizo_avatar.svg +16 -0
- package/src/components/Cadenas/CadenasWebViewer.tsx +1 -1
- package/src/components/Cart.tsx +48 -36
- package/src/components/ChatAssistant/ChatAssistant.tsx +289 -0
- package/src/components/ChatAssistant/MobileChatAssistant.tsx +291 -0
- package/src/components/ChatAssistant/OptionChip.tsx +78 -0
- package/src/components/ChatAssistant/index.ts +3 -0
- package/src/components/ChatAssistant/useChatAssistantLogic.ts +745 -0
- package/src/components/CurrentRefinements.tsx +2 -2
- package/src/components/CustomCameraDrawer.tsx +56 -13
- package/src/components/DragDropFile.tsx +5 -5
- package/src/components/ExperienceVisualSearch/ExperienceVisualSearch.tsx +1 -1
- package/src/components/Header.tsx +116 -96
- package/src/components/Hint.tsx +1 -2
- package/src/components/HitsPerPage.tsx +9 -3
- package/src/components/ImagePreview.tsx +32 -17
- package/src/components/ImageUpload.tsx +16 -8
- package/src/components/Inquiry/InquiryBanner.tsx +1 -1
- package/src/components/Inquiry/InquiryModal.tsx +35 -29
- package/src/components/ItemSpecification.tsx +58 -126
- package/src/components/LocationInfoPopup.tsx +33 -33
- package/src/components/MatchNotificationBanner.tsx +90 -36
- package/src/components/PostFilter/PostFilter.tsx +1 -1
- package/src/components/PostFilter/PostFilterComponent.tsx +0 -1
- package/src/components/PostFilter/PostFilterFindApi.tsx +0 -1
- package/src/components/PoweredBy.tsx +1 -1
- package/src/components/PreFilter/PreFilter.tsx +14 -3
- package/src/components/PreFilter/PreFilterModal.tsx +0 -1
- package/src/components/Product/Product.tsx +15 -11
- package/src/components/Product/ProductAttribute.tsx +4 -5
- package/src/components/Product/ProductDetailViewModal.tsx +2 -4
- package/src/components/Product/ProductList.tsx +26 -13
- package/src/components/Rfq/RfqModal.tsx +1 -1
- package/src/components/SidePanel.tsx +124 -91
- package/src/components/SmartFilter.tsx +320 -0
- package/src/components/TextSearch.tsx +134 -70
- package/src/components/UploadDisclaimer.tsx +1 -1
- package/src/hooks/useBadResultsRecovery.ts +407 -0
- package/src/hooks/useEffectiveGroundingResults.ts +54 -0
- package/src/hooks/useGoodResultsChat.ts +651 -0
- package/src/hooks/useGroundedSearch.ts +88 -0
- package/src/hooks/useImageSearch.ts +139 -187
- package/src/hooks/useResultEvaluator.ts +417 -0
- package/src/index.css +1 -1
- package/src/index.tsx +0 -1
- package/src/layouts/AppLayout.tsx +53 -2
- package/src/pages/Home.tsx +11 -52
- package/src/pages/Login.tsx +1 -2
- package/src/pages/Logout.tsx +1 -1
- package/src/pages/Result.tsx +198 -200
- package/src/providers/AuthProvider.tsx +0 -1
- package/src/services/Feedback.ts +1 -1
- package/src/services/visualSearch.ts +0 -21
- package/src/services/vizo.ts +192 -4
- package/src/stores/chat/chatStore.ts +150 -0
- package/src/stores/chat/conversationStore.ts +300 -0
- package/src/stores/request/Misc/misc.slice.ts +2 -2
- package/src/stores/request/filter/filter.slice.ts +8 -8
- package/src/stores/request/query/query.slice.ts +2 -2
- package/src/stores/request/requestImage/requestImage.slice.ts +6 -6
- package/src/stores/request/specifications/specifications.slice.ts +10 -7
- package/src/stores/result/detectedRegions/detectedRegions.slice.ts +1 -1
- package/src/stores/result/prodcuts/products.initialState.ts +12 -0
- package/src/stores/result/prodcuts/products.slice.ts +28 -8
- package/src/stores/result/session/session.slice.ts +2 -2
- package/src/stores/smartFilters/smartFiltersStore.ts +270 -0
- package/src/stores/types.ts +41 -0
- package/src/stores/ui/ai/ai.initialState.ts +5 -0
- package/src/stores/ui/ai/ai.slice.ts +15 -0
- package/src/stores/ui/banner/banner.initialState.ts +6 -0
- package/src/stores/ui/banner/banner.slice.ts +14 -0
- package/src/stores/ui/feedback/feedback.slice.ts +1 -1
- package/src/stores/ui/loading/loading.slice.ts +4 -4
- package/src/stores/ui/uiStore.ts +7 -1
- package/src/styles/product.scss +0 -2
- package/src/types.ts +3 -7
- package/src/utils/cropImageToBase64.ts +32 -0
- package/src/utils/fetchProductImage.ts +109 -0
- package/src/utils/imageConverters.ts +124 -0
- package/src/utils/relatedParts.ts +35 -0
- package/src/utils/specificationFilter.ts +1 -5
- package/tailwind.config.js +3 -2
- package/build/static/css/main.734b52e1.css +0 -4
- package/build/static/css/main.734b52e1.css.map +0 -1
- package/build/static/js/main.f2255597.js +0 -3
- package/src/utils/addAssets.ts +0 -40
- /package/build/static/js/{main.f2255597.js.LICENSE.txt → main.36b77705.js.LICENSE.txt} +0 -0
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { useCallback } from 'react';
|
|
2
|
+
import {
|
|
3
|
+
groundedSearch,
|
|
4
|
+
groundedSearchFilter,
|
|
5
|
+
groundingSearchQuery,
|
|
6
|
+
} from 'services/vizo';
|
|
7
|
+
import useResultStore from 'stores/result/resultStore';
|
|
8
|
+
import useRequestStore from 'stores/request/requestStore';
|
|
9
|
+
import useUiStore from 'stores/ui/uiStore';
|
|
10
|
+
import { RectCoords } from '@nyris/nyris-api';
|
|
11
|
+
|
|
12
|
+
export const useGroundedSearch = () => {
|
|
13
|
+
const setGoogleGroundingResponse = useResultStore(
|
|
14
|
+
state => state.setGoogleGroundingResponse,
|
|
15
|
+
);
|
|
16
|
+
const setGroundingFilterResult = useResultStore(
|
|
17
|
+
state => state.setGroundingFilterResult,
|
|
18
|
+
);
|
|
19
|
+
const setGroundingError = useResultStore(state => state.setGroundingError);
|
|
20
|
+
const setIsGoogleGroundingLoading = useUiStore(
|
|
21
|
+
state => state.setIsGoogleGroundingLoading,
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
const groundedSearchCallback = useCallback(
|
|
25
|
+
(
|
|
26
|
+
requestImage: File | HTMLCanvasElement,
|
|
27
|
+
products: any[] = [],
|
|
28
|
+
region?: RectCoords,
|
|
29
|
+
) => {
|
|
30
|
+
setIsGoogleGroundingLoading(true);
|
|
31
|
+
// setGroundingError('Unable to search the Internet.');
|
|
32
|
+
setGroundingError(null);
|
|
33
|
+
groundedSearch(requestImage, region)
|
|
34
|
+
.then(groundingRes => {
|
|
35
|
+
const groundingSpecs = {
|
|
36
|
+
product_name: groundingRes.product_name,
|
|
37
|
+
brand: groundingRes.brand,
|
|
38
|
+
part_number: groundingRes.part_number,
|
|
39
|
+
key_specs: groundingRes.key_specs,
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
groundedSearchFilter({
|
|
43
|
+
products: products || [],
|
|
44
|
+
groundingSummary: groundingRes?.grounding_summary || '',
|
|
45
|
+
apiKey: window.settings.aiApiKey || '',
|
|
46
|
+
})
|
|
47
|
+
.then((filterRes: any) => {
|
|
48
|
+
setGroundingFilterResult(filterRes?.matches || []);
|
|
49
|
+
|
|
50
|
+
if (
|
|
51
|
+
filterRes?.matches?.length === 0 &&
|
|
52
|
+
window.settings.vizo?.fallbackToElasticSearch
|
|
53
|
+
) {
|
|
54
|
+
groundingSearchQuery({
|
|
55
|
+
groundingSummary: JSON.stringify(groundingRes),
|
|
56
|
+
apiKey: window.settings.aiApiKey || '',
|
|
57
|
+
}).then((queryRes: any) => {
|
|
58
|
+
useRequestStore.getState().setGroundingQuery(queryRes?.query);
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
})
|
|
62
|
+
.catch(error => {
|
|
63
|
+
console.log('Grounding Filter API error:', error);
|
|
64
|
+
setGroundingError('Unable to search the Internet.');
|
|
65
|
+
})
|
|
66
|
+
.finally(() => {
|
|
67
|
+
setIsGoogleGroundingLoading(false);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
setGoogleGroundingResponse(groundingSpecs);
|
|
71
|
+
})
|
|
72
|
+
.catch(error => {
|
|
73
|
+
console.log('Grounding API error:', error);
|
|
74
|
+
setGroundingError('Unable to search the Internet.');
|
|
75
|
+
setIsGoogleGroundingLoading(false);
|
|
76
|
+
})
|
|
77
|
+
.finally(() => {});
|
|
78
|
+
},
|
|
79
|
+
[
|
|
80
|
+
setGoogleGroundingResponse,
|
|
81
|
+
setGroundingFilterResult,
|
|
82
|
+
setGroundingError,
|
|
83
|
+
setIsGoogleGroundingLoading,
|
|
84
|
+
],
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
return { groundedSearch: groundedSearchCallback };
|
|
88
|
+
};
|
|
@@ -2,7 +2,6 @@ import { useCallback } from 'react';
|
|
|
2
2
|
import { RectCoords } from '@nyris/nyris-api';
|
|
3
3
|
import { isEmpty, isUndefined } from 'lodash';
|
|
4
4
|
|
|
5
|
-
import { decode } from 'tiff';
|
|
6
5
|
import { createImage, find, findRegions } from 'services/visualSearch';
|
|
7
6
|
|
|
8
7
|
import useResultStore from 'stores/result/resultStore';
|
|
@@ -10,25 +9,18 @@ import useRequestStore from 'stores/request/requestStore';
|
|
|
10
9
|
|
|
11
10
|
import { AppSettings } from 'types';
|
|
12
11
|
import { compressImage } from 'utils/compressImage';
|
|
12
|
+
import { pdfToImage, tiffToJpg } from 'utils/imageConverters';
|
|
13
13
|
import useUiStore from 'stores/ui/uiStore';
|
|
14
14
|
import { useClearRefinements } from 'react-instantsearch';
|
|
15
15
|
import { isHEIC } from 'utils/misc';
|
|
16
16
|
|
|
17
|
-
import
|
|
18
|
-
import
|
|
17
|
+
import useResultEvaluator from './useResultEvaluator';
|
|
18
|
+
import useConversationStore from 'stores/chat/conversationStore';
|
|
19
|
+
import { useGroundedSearch } from './useGroundedSearch';
|
|
20
|
+
import { generateSmartFilters } from '../services/vizo';
|
|
19
21
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
import {
|
|
23
|
-
groundedSearch,
|
|
24
|
-
groundedSearchFilter,
|
|
25
|
-
groundingSearchQuery,
|
|
26
|
-
} from 'services/vizo';
|
|
27
|
-
|
|
28
|
-
GlobalWorkerOptions.workerSrc = new URL(
|
|
29
|
-
pdfjsWorker,
|
|
30
|
-
import.meta.url,
|
|
31
|
-
).toString();
|
|
22
|
+
const DEFAULT_SMART_FILTER_PROMPT =
|
|
23
|
+
'Extract at most 4 relevant product intent filters from the request image. Return strict JSON only.';
|
|
32
24
|
|
|
33
25
|
export const useImageSearch = () => {
|
|
34
26
|
const setRegions = useRequestStore(state => state.setRegions);
|
|
@@ -73,129 +65,18 @@ export const useImageSearch = () => {
|
|
|
73
65
|
const setGoogleGroundingResponse = useResultStore(
|
|
74
66
|
state => state.setGoogleGroundingResponse,
|
|
75
67
|
);
|
|
76
|
-
const setIsGoogleGroundingLoading = useUiStore(
|
|
77
|
-
state => state.setIsGoogleGroundingLoading,
|
|
78
|
-
);
|
|
79
68
|
|
|
80
69
|
const setGroundingFilterResult = useResultStore(
|
|
81
70
|
state => state.setGroundingFilterResult,
|
|
82
71
|
);
|
|
72
|
+
const setSmartFilters = useResultStore(state => state.setSmartFilters);
|
|
83
73
|
|
|
84
|
-
const
|
|
85
|
-
|
|
86
|
-
const tiffToJpg = async (file: File): Promise<Blob> => {
|
|
87
|
-
return new Promise((resolve, reject) => {
|
|
88
|
-
const reader = new FileReader();
|
|
89
|
-
|
|
90
|
-
reader.onload = (event: ProgressEvent<FileReader>) => {
|
|
91
|
-
if (event.target?.result) {
|
|
92
|
-
try {
|
|
93
|
-
const tiffArray = new Uint8Array(
|
|
94
|
-
event.target.result as ArrayBuffer,
|
|
95
|
-
);
|
|
96
|
-
const tiffImages = decode(tiffArray);
|
|
97
|
-
const firstImage = tiffImages[0];
|
|
98
|
-
const { width, height, data } = firstImage;
|
|
99
|
-
const canvas = document.createElement('canvas');
|
|
100
|
-
const ctx = canvas.getContext('2d');
|
|
101
|
-
let firstImageData: any = data;
|
|
102
|
-
|
|
103
|
-
if (!ctx) {
|
|
104
|
-
reject(new Error('Failed to get canvas context.'));
|
|
105
|
-
return;
|
|
106
|
-
}
|
|
107
|
-
// Convert RGB to RGBA by adding an alpha channel
|
|
108
|
-
if (data.length === width * height * 3) {
|
|
109
|
-
const fixedData = new Uint8ClampedArray(width * height * 4);
|
|
110
|
-
for (let i = 0, j = 0; i < data.length; i += 3, j += 4) {
|
|
111
|
-
fixedData[j] = data[i];
|
|
112
|
-
fixedData[j + 1] = data[i + 1];
|
|
113
|
-
fixedData[j + 2] = data[i + 2];
|
|
114
|
-
fixedData[j + 3] = 255;
|
|
115
|
-
}
|
|
116
|
-
firstImageData = fixedData;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
canvas.width = firstImage.width;
|
|
120
|
-
canvas.height = firstImage.height;
|
|
74
|
+
const setGroundingError = useResultStore(state => state.setGroundingError);
|
|
121
75
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
);
|
|
127
|
-
ctx.putImageData(imageData, 0, 0);
|
|
128
|
-
|
|
129
|
-
canvas.toBlob(blob => {
|
|
130
|
-
if (blob) {
|
|
131
|
-
resolve(blob);
|
|
132
|
-
} else {
|
|
133
|
-
reject(new Error('Failed to convert TIFF to JPG.'));
|
|
134
|
-
}
|
|
135
|
-
}, 'image/jpeg');
|
|
136
|
-
} catch (error) {
|
|
137
|
-
console.log(error);
|
|
138
|
-
reject(new Error('Error decoding TIFF file.'));
|
|
139
|
-
}
|
|
140
|
-
} else {
|
|
141
|
-
reject(new Error('FileReader failed to load file.'));
|
|
142
|
-
}
|
|
143
|
-
};
|
|
144
|
-
|
|
145
|
-
reader.onerror = () => reject(new Error('Error reading TIFF file.'));
|
|
146
|
-
reader.readAsArrayBuffer(file);
|
|
147
|
-
});
|
|
148
|
-
};
|
|
149
|
-
|
|
150
|
-
const pdfToImage = async (file: File): Promise<Blob> => {
|
|
151
|
-
return new Promise((resolve, reject) => {
|
|
152
|
-
const reader = new FileReader();
|
|
153
|
-
reader.readAsArrayBuffer(file);
|
|
154
|
-
reader.onload = async () => {
|
|
155
|
-
if (!reader.result) {
|
|
156
|
-
reject(new Error('FileReader failed to load file.'));
|
|
157
|
-
return;
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
try {
|
|
161
|
-
const loadingTask = pdfjsLib.getDocument(
|
|
162
|
-
new Uint8Array(reader.result as ArrayBuffer),
|
|
163
|
-
);
|
|
164
|
-
const pdf = await loadingTask.promise;
|
|
165
|
-
const page = await pdf.getPage(1); // Get first page
|
|
166
|
-
|
|
167
|
-
const scale = 2; // Adjust for better resolution
|
|
168
|
-
const viewport = page.getViewport({ scale });
|
|
169
|
-
|
|
170
|
-
const canvas = document.createElement('canvas');
|
|
171
|
-
const context = canvas.getContext('2d');
|
|
172
|
-
if (!context) {
|
|
173
|
-
reject(new Error('Failed to get canvas context.'));
|
|
174
|
-
return;
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
canvas.width = viewport.width;
|
|
178
|
-
canvas.height = viewport.height;
|
|
179
|
-
|
|
180
|
-
await page.render({ canvasContext: context, viewport }).promise;
|
|
181
|
-
|
|
182
|
-
canvas.toBlob(blob => {
|
|
183
|
-
if (blob) {
|
|
184
|
-
resolve(blob);
|
|
185
|
-
} else {
|
|
186
|
-
reject(new Error('Failed to convert PDF to image.'));
|
|
187
|
-
}
|
|
188
|
-
}, 'image/png');
|
|
189
|
-
} catch (error) {
|
|
190
|
-
console.log({ error });
|
|
191
|
-
|
|
192
|
-
reject(new Error('Error processing PDF file.'));
|
|
193
|
-
}
|
|
194
|
-
};
|
|
195
|
-
|
|
196
|
-
reader.onerror = () => reject(new Error('Error reading PDF file.'));
|
|
197
|
-
});
|
|
198
|
-
};
|
|
76
|
+
const { refine } = useClearRefinements();
|
|
77
|
+
const { evaluateResults } = useResultEvaluator();
|
|
78
|
+
const { groundedSearch } = useGroundedSearch();
|
|
79
|
+
const startNewSession = useConversationStore(s => s.startNewSession);
|
|
199
80
|
|
|
200
81
|
const singleImageSearch = useCallback(
|
|
201
82
|
async ({
|
|
@@ -208,7 +89,6 @@ export const useImageSearch = () => {
|
|
|
208
89
|
preFilterParams,
|
|
209
90
|
clearPostFilter,
|
|
210
91
|
text,
|
|
211
|
-
grounding,
|
|
212
92
|
}: {
|
|
213
93
|
image?: any;
|
|
214
94
|
settings: AppSettings;
|
|
@@ -219,16 +99,33 @@ export const useImageSearch = () => {
|
|
|
219
99
|
preFilterParams?: Record<string, boolean>;
|
|
220
100
|
clearPostFilter?: boolean;
|
|
221
101
|
text?: string;
|
|
222
|
-
grounding?: boolean;
|
|
223
102
|
}) => {
|
|
103
|
+
const isSmartFiltersEnabled = !!settings.useSmartFilters;
|
|
224
104
|
setIsFindApiLoading(true);
|
|
225
105
|
// setAlgoliaProducts([]);
|
|
106
|
+
useRequestStore.getState().setGroundingQuery('');
|
|
107
|
+
|
|
108
|
+
useUiStore.getState().resetBanner();
|
|
109
|
+
startNewSession();
|
|
226
110
|
|
|
227
111
|
if (newSearch) {
|
|
228
112
|
setGroundingFilterResult([]);
|
|
229
113
|
setGoogleGroundingResponse(null);
|
|
114
|
+
setGroundingError(null);
|
|
115
|
+
if (isSmartFiltersEnabled) {
|
|
116
|
+
setSmartFilters({
|
|
117
|
+
status: 'idle',
|
|
118
|
+
filters: [],
|
|
119
|
+
selectedFilterKey: null,
|
|
120
|
+
selectedFilterValue: null,
|
|
121
|
+
rerankedSkus: [],
|
|
122
|
+
rerankStatus: 'idle',
|
|
123
|
+
errorMessage: null,
|
|
124
|
+
});
|
|
125
|
+
}
|
|
230
126
|
useRequestStore.getState().setGroundingQuery('');
|
|
231
127
|
useResultStore.getState().setShowingGroundingFilterResult(false);
|
|
128
|
+
startNewSession();
|
|
232
129
|
}
|
|
233
130
|
|
|
234
131
|
let region: RectCoords | undefined = imageRegion;
|
|
@@ -297,6 +194,88 @@ export const useImageSearch = () => {
|
|
|
297
194
|
},
|
|
298
195
|
];
|
|
299
196
|
|
|
197
|
+
let smartFilterPromise: Promise<void> | null = null;
|
|
198
|
+
if (isSmartFiltersEnabled && requestImage && newSearch) {
|
|
199
|
+
setSmartFilters({
|
|
200
|
+
status: 'loading',
|
|
201
|
+
filters: [],
|
|
202
|
+
selectedFilterKey: null,
|
|
203
|
+
selectedFilterValue: null,
|
|
204
|
+
rerankedSkus: [],
|
|
205
|
+
rerankStatus: 'idle',
|
|
206
|
+
errorMessage: null,
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
smartFilterPromise = generateSmartFilters({
|
|
210
|
+
image: requestImage,
|
|
211
|
+
prompt: DEFAULT_SMART_FILTER_PROMPT,
|
|
212
|
+
})
|
|
213
|
+
.then(response => {
|
|
214
|
+
const rawFilters = response?.filters;
|
|
215
|
+
if (!rawFilters || typeof rawFilters !== 'object') {
|
|
216
|
+
setSmartFilters({
|
|
217
|
+
status: 'error',
|
|
218
|
+
filters: [],
|
|
219
|
+
selectedFilterKey: null,
|
|
220
|
+
selectedFilterValue: null,
|
|
221
|
+
rerankedSkus: [],
|
|
222
|
+
rerankStatus: 'idle',
|
|
223
|
+
errorMessage: 'Could not generate smart filters.',
|
|
224
|
+
});
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
const normalizedFilters = Object.entries(rawFilters)
|
|
229
|
+
.slice(0, 4)
|
|
230
|
+
.map(([key, value]) => {
|
|
231
|
+
const normalizedValue = Array.isArray(value)
|
|
232
|
+
? String(value[0] || '')
|
|
233
|
+
: String(value || '');
|
|
234
|
+
return {
|
|
235
|
+
key: String(key),
|
|
236
|
+
label: String(key),
|
|
237
|
+
value: normalizedValue,
|
|
238
|
+
selected: false,
|
|
239
|
+
};
|
|
240
|
+
})
|
|
241
|
+
.filter(filter => filter.value.trim().length > 0);
|
|
242
|
+
|
|
243
|
+
const rerankedSkus =
|
|
244
|
+
response?.rerankedSkus ||
|
|
245
|
+
response?.filtered_items?.map(item => String(item.sku)) ||
|
|
246
|
+
[];
|
|
247
|
+
const rerankingApplied =
|
|
248
|
+
response?.rerankingApplied ??
|
|
249
|
+
(rerankedSkus.length > 0 ? true : false);
|
|
250
|
+
|
|
251
|
+
setSmartFilters({
|
|
252
|
+
status: 'success',
|
|
253
|
+
filters: normalizedFilters,
|
|
254
|
+
selectedFilterKey: null,
|
|
255
|
+
selectedFilterValue: null,
|
|
256
|
+
rerankedSkus,
|
|
257
|
+
rerankStatus: 'idle',
|
|
258
|
+
errorMessage: null,
|
|
259
|
+
});
|
|
260
|
+
})
|
|
261
|
+
.catch(error => {
|
|
262
|
+
const timeout = String(error?.message || '').includes(
|
|
263
|
+
'SMART_FILTER_TIMEOUT',
|
|
264
|
+
);
|
|
265
|
+
setSmartFilters({
|
|
266
|
+
status: 'error',
|
|
267
|
+
filters: [],
|
|
268
|
+
selectedFilterKey: null,
|
|
269
|
+
selectedFilterValue: null,
|
|
270
|
+
rerankedSkus: [],
|
|
271
|
+
rerankStatus: 'idle',
|
|
272
|
+
errorMessage: timeout
|
|
273
|
+
? 'Smart filters are unavailable right now.'
|
|
274
|
+
: 'Could not generate smart filters.',
|
|
275
|
+
});
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
|
|
300
279
|
try {
|
|
301
280
|
res = await find({
|
|
302
281
|
image: requestImage,
|
|
@@ -319,7 +298,7 @@ export const useImageSearch = () => {
|
|
|
319
298
|
: text
|
|
320
299
|
: undefined,
|
|
321
300
|
});
|
|
322
|
-
|
|
301
|
+
useResultStore.getState().resetGrounding();
|
|
323
302
|
if (clearPostFilter) {
|
|
324
303
|
refine();
|
|
325
304
|
clearPostFilterSelections();
|
|
@@ -333,58 +312,23 @@ export const useImageSearch = () => {
|
|
|
333
312
|
const specification = res?.image_analysis?.specification || {};
|
|
334
313
|
const hasOcr = Object.keys(specification).length > 0;
|
|
335
314
|
|
|
336
|
-
if (
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
315
|
+
if (
|
|
316
|
+
hasOcr &&
|
|
317
|
+
window.settings.vizo?.groundingEnabled &&
|
|
318
|
+
res?.results.length > 0
|
|
319
|
+
) {
|
|
340
320
|
groundedSearch(
|
|
341
321
|
requestImage || canvasImage,
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
groundedSearchFilter({
|
|
353
|
-
products: res?.results || [],
|
|
354
|
-
groundingSummary: groundingRes?.grounding_summary || '',
|
|
355
|
-
apiKey: window.settings.aiApiKey || '',
|
|
356
|
-
})
|
|
357
|
-
.then((filterRes: any) => {
|
|
358
|
-
setGroundingFilterResult(filterRes?.matches || []);
|
|
359
|
-
|
|
360
|
-
if (
|
|
361
|
-
filterRes?.matches?.length === 0 &&
|
|
362
|
-
window.settings.vizo?.fallbackToElasticSearch
|
|
363
|
-
) {
|
|
364
|
-
groundingSearchQuery({
|
|
365
|
-
groundingSummary: JSON.stringify(groundingRes),
|
|
366
|
-
apiKey: window.settings.aiApiKey || '',
|
|
367
|
-
}).then((queryRes: any) => {
|
|
368
|
-
useRequestStore
|
|
369
|
-
.getState()
|
|
370
|
-
.setGroundingQuery(queryRes?.query);
|
|
371
|
-
});
|
|
372
|
-
}
|
|
373
|
-
})
|
|
374
|
-
.catch(error => {
|
|
375
|
-
console.log('Grounding Filter API error:', error);
|
|
376
|
-
});
|
|
377
|
-
|
|
378
|
-
setGoogleGroundingResponse(groundingSpecs);
|
|
379
|
-
})
|
|
380
|
-
.catch(error => {
|
|
381
|
-
console.log('Grounding API error:', error);
|
|
382
|
-
})
|
|
383
|
-
.finally(() => {
|
|
384
|
-
setIsGoogleGroundingLoading(false);
|
|
385
|
-
});
|
|
322
|
+
res?.results || [],
|
|
323
|
+
region,
|
|
324
|
+
);
|
|
325
|
+
}
|
|
326
|
+
if (window.settings.vizo.chat) {
|
|
327
|
+
evaluateResults({
|
|
328
|
+
activeProducts: res?.results || [],
|
|
329
|
+
imageAnalysis: res?.image_analysis,
|
|
330
|
+
});
|
|
386
331
|
}
|
|
387
|
-
|
|
388
332
|
const nonEmptyFilter: any[] = ['sku:DOES_NOT_EXIST<score=1> '];
|
|
389
333
|
const filterSkus: any = res?.results
|
|
390
334
|
? res?.results
|
|
@@ -400,6 +344,8 @@ export const useImageSearch = () => {
|
|
|
400
344
|
if (showFeedback) {
|
|
401
345
|
setShowFeedback(true);
|
|
402
346
|
}
|
|
347
|
+
|
|
348
|
+
// setGroundingError(null);
|
|
403
349
|
// go back
|
|
404
350
|
if (firstSearchResults.length === 0 || newSearch) {
|
|
405
351
|
setFirstSearchResults(res?.results);
|
|
@@ -411,11 +357,17 @@ export const useImageSearch = () => {
|
|
|
411
357
|
setIsFindApiLoading(false);
|
|
412
358
|
}
|
|
413
359
|
|
|
360
|
+
if (smartFilterPromise) {
|
|
361
|
+
void smartFilterPromise;
|
|
362
|
+
}
|
|
363
|
+
|
|
414
364
|
return res;
|
|
415
365
|
},
|
|
366
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
416
367
|
[
|
|
417
368
|
setIsFindApiLoading,
|
|
418
369
|
preFilter,
|
|
370
|
+
startNewSession,
|
|
419
371
|
setRequestImages,
|
|
420
372
|
setSpecificationFilter,
|
|
421
373
|
setDetectedRegions,
|
|
@@ -430,14 +382,14 @@ export const useImageSearch = () => {
|
|
|
430
382
|
firstSearchResults.length,
|
|
431
383
|
refine,
|
|
432
384
|
clearPostFilterSelections,
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
setGroundingFilterResult,
|
|
385
|
+
groundedSearch,
|
|
386
|
+
evaluateResults,
|
|
436
387
|
setShowFeedback,
|
|
437
388
|
setFirstSearchResults,
|
|
438
389
|
setFirstSearchImage,
|
|
439
390
|
setFirstSearchPreFilter,
|
|
440
391
|
setFirstRequestImageAnalysis,
|
|
392
|
+
setSmartFilters,
|
|
441
393
|
],
|
|
442
394
|
);
|
|
443
395
|
|