@smart-cloud/ai-kit-ui 1.3.7 → 1.3.9
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/dist/index.cjs +9 -9
- package/dist/index.js +9 -9
- package/package.json +1 -1
- package/src/doc-search/DocSearch.tsx +190 -146
package/package.json
CHANGED
|
@@ -140,6 +140,7 @@ const DocSearchBase: FC<Props> = (props) => {
|
|
|
140
140
|
useAiRun<SearchResult>();
|
|
141
141
|
|
|
142
142
|
const autoRunOnceRef = useRef(false);
|
|
143
|
+
const prevSelectedCategoriesRef = useRef<string[]>([]);
|
|
143
144
|
|
|
144
145
|
const sessionId = result?.sessionId;
|
|
145
146
|
const citationDocs = result?.citations?.docs ?? [];
|
|
@@ -188,6 +189,31 @@ const DocSearchBase: FC<Props> = (props) => {
|
|
|
188
189
|
return Boolean((text && text.trim().length > 0) || audioBlob);
|
|
189
190
|
}, [inputText, busy, audioBlob, featureOpen]);
|
|
190
191
|
|
|
192
|
+
const hasValidFilterOptions = useMemo(() => {
|
|
193
|
+
if (!metadataOptions) return false;
|
|
194
|
+
const hasCategories =
|
|
195
|
+
Object.keys(metadataOptions.allowedCategories).length > 0;
|
|
196
|
+
const hasTags = metadataOptions.allowedTags.length > 0;
|
|
197
|
+
return hasCategories || hasTags;
|
|
198
|
+
}, [metadataOptions]);
|
|
199
|
+
|
|
200
|
+
const subcategories = useMemo(() => {
|
|
201
|
+
if (selectedCategories.length === 0 || !metadataOptions) {
|
|
202
|
+
return [];
|
|
203
|
+
}
|
|
204
|
+
return selectedCategories
|
|
205
|
+
.flatMap(
|
|
206
|
+
(cat) =>
|
|
207
|
+
metadataOptions.allowedCategories[
|
|
208
|
+
cat
|
|
209
|
+
] || [],
|
|
210
|
+
)
|
|
211
|
+
.filter(
|
|
212
|
+
(subcat, index, self) =>
|
|
213
|
+
self.indexOf(subcat) === index,
|
|
214
|
+
)
|
|
215
|
+
}, [selectedCategories, metadataOptions]);
|
|
216
|
+
|
|
191
217
|
const startRecording = useCallback(async () => {
|
|
192
218
|
try {
|
|
193
219
|
// Clear query input when starting audio recording
|
|
@@ -390,7 +416,7 @@ const DocSearchBase: FC<Props> = (props) => {
|
|
|
390
416
|
"Reusing cached audio (no re-upload needed within",
|
|
391
417
|
Math.round(
|
|
392
418
|
(AUDIO_CACHE_TTL - (now - audioCacheRef.current!.uploadTimestamp)) /
|
|
393
|
-
|
|
419
|
+
1000,
|
|
394
420
|
),
|
|
395
421
|
"seconds)",
|
|
396
422
|
);
|
|
@@ -405,14 +431,15 @@ const DocSearchBase: FC<Props> = (props) => {
|
|
|
405
431
|
...(audioBlob && { audio: audioBlob }), // Pass Blob directly
|
|
406
432
|
topK,
|
|
407
433
|
// Include user-selected filters if enabled
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
434
|
+
// Always send userSelectedCategories array when enableUserFilters is true (even if empty)
|
|
435
|
+
// to prevent backend from applying its own kb-filter
|
|
436
|
+
...(enableUserFilters && {
|
|
437
|
+
userSelectedCategories: selectedCategories,
|
|
438
|
+
}),
|
|
412
439
|
...(enableUserFilters &&
|
|
413
440
|
selectedSubcategories.length > 0 && {
|
|
414
|
-
|
|
415
|
-
|
|
441
|
+
userSelectedSubcategories: selectedSubcategories,
|
|
442
|
+
}),
|
|
416
443
|
...(enableUserFilters &&
|
|
417
444
|
selectedTags.length > 0 && { userSelectedTags: selectedTags }),
|
|
418
445
|
},
|
|
@@ -458,6 +485,24 @@ const DocSearchBase: FC<Props> = (props) => {
|
|
|
458
485
|
}
|
|
459
486
|
}, [canSearch]);
|
|
460
487
|
|
|
488
|
+
// Reset session when main categories change
|
|
489
|
+
useEffect(() => {
|
|
490
|
+
const prev = prevSelectedCategoriesRef.current;
|
|
491
|
+
const current = selectedCategories;
|
|
492
|
+
|
|
493
|
+
// Check if categories changed (different length or different items)
|
|
494
|
+
const categoriesChanged =
|
|
495
|
+
prev.length !== current.length ||
|
|
496
|
+
!current.every((cat) => prev.includes(cat));
|
|
497
|
+
|
|
498
|
+
if (categoriesChanged && prev.length > 0) {
|
|
499
|
+
// Reset session only if we had categories before (not on initial mount)
|
|
500
|
+
reset();
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
prevSelectedCategoriesRef.current = [...current];
|
|
504
|
+
}, [selectedCategories, reset]);
|
|
505
|
+
|
|
461
506
|
const grouped = useMemo(() => groupChunksByDoc(result), [result]);
|
|
462
507
|
|
|
463
508
|
const docNumberMap = useMemo(() => {
|
|
@@ -717,9 +762,9 @@ const DocSearchBase: FC<Props> = (props) => {
|
|
|
717
762
|
style={
|
|
718
763
|
recording
|
|
719
764
|
? {
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
765
|
+
transform: `scale(${1 + audioLevel / 300})`,
|
|
766
|
+
transition: "transform 0.1s ease-out",
|
|
767
|
+
}
|
|
723
768
|
: undefined
|
|
724
769
|
}
|
|
725
770
|
>
|
|
@@ -760,142 +805,141 @@ const DocSearchBase: FC<Props> = (props) => {
|
|
|
760
805
|
) : null}
|
|
761
806
|
|
|
762
807
|
{/* User filter collapse */}
|
|
763
|
-
{enableUserFilters &&
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
808
|
+
{enableUserFilters &&
|
|
809
|
+
metadataOptions &&
|
|
810
|
+
hasValidFilterOptions && (
|
|
811
|
+
<Stack gap="xs">
|
|
812
|
+
<Button
|
|
813
|
+
variant="subtle"
|
|
814
|
+
size="xs"
|
|
815
|
+
onClick={() => setFiltersOpen(!filtersOpen)}
|
|
816
|
+
leftSection={
|
|
817
|
+
filtersOpen ? (
|
|
818
|
+
<IconChevronDown size={14} />
|
|
819
|
+
) : (
|
|
820
|
+
<IconChevronRight size={14} />
|
|
821
|
+
)
|
|
822
|
+
}
|
|
823
|
+
style={{ alignSelf: "flex-start" }}
|
|
824
|
+
>
|
|
825
|
+
{I18n.get("Filters")}
|
|
826
|
+
</Button>
|
|
780
827
|
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
category,
|
|
799
|
-
)}
|
|
800
|
-
onChange={(e) => {
|
|
801
|
-
if (e.currentTarget.checked) {
|
|
802
|
-
setSelectedCategories([
|
|
803
|
-
...selectedCategories,
|
|
828
|
+
<Collapse in={filtersOpen}>
|
|
829
|
+
<Stack gap="md">
|
|
830
|
+
{/* Main categories as checkboxes */}
|
|
831
|
+
{Object.keys(metadataOptions.allowedCategories)
|
|
832
|
+
.length > 0 && (
|
|
833
|
+
<div>
|
|
834
|
+
<Text size="sm" fw={500} mb="xs">
|
|
835
|
+
{I18n.get("Categories")}
|
|
836
|
+
</Text>
|
|
837
|
+
<Group gap="md">
|
|
838
|
+
{Object.keys(
|
|
839
|
+
metadataOptions.allowedCategories,
|
|
840
|
+
).map((category) => (
|
|
841
|
+
<Checkbox
|
|
842
|
+
key={category}
|
|
843
|
+
label={I18n.get(category)}
|
|
844
|
+
checked={selectedCategories.includes(
|
|
804
845
|
category,
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
846
|
+
)}
|
|
847
|
+
onChange={(e) => {
|
|
848
|
+
if (e.currentTarget.checked) {
|
|
849
|
+
setSelectedCategories([
|
|
850
|
+
...selectedCategories,
|
|
851
|
+
category,
|
|
852
|
+
]);
|
|
853
|
+
} else {
|
|
854
|
+
setSelectedCategories(
|
|
855
|
+
selectedCategories.filter(
|
|
856
|
+
(c) => c !== category,
|
|
857
|
+
),
|
|
858
|
+
);
|
|
859
|
+
// Remove subcategories of unchecked category
|
|
860
|
+
const subcatsToRemove =
|
|
861
|
+
metadataOptions.allowedCategories[
|
|
862
|
+
category
|
|
863
|
+
] || [];
|
|
864
|
+
setSelectedSubcategories(
|
|
865
|
+
selectedSubcategories.filter(
|
|
866
|
+
(sc) =>
|
|
867
|
+
!subcatsToRemove.includes(sc),
|
|
868
|
+
),
|
|
869
|
+
);
|
|
870
|
+
}
|
|
871
|
+
}}
|
|
872
|
+
disabled={busy || loadingMetadata}
|
|
873
|
+
/>
|
|
874
|
+
))}
|
|
875
|
+
</Group>
|
|
876
|
+
</div>
|
|
877
|
+
)}
|
|
878
|
+
|
|
879
|
+
{/* Subcategories for selected categories */}
|
|
880
|
+
{subcategories.length > 0 && (
|
|
881
|
+
<div>
|
|
882
|
+
<Text size="sm" fw={500} mb="xs">
|
|
883
|
+
{I18n.get("Subcategories")}
|
|
884
|
+
</Text>
|
|
885
|
+
<Group gap="md">
|
|
886
|
+
{subcategories
|
|
887
|
+
.map((subcat) => (
|
|
888
|
+
<Checkbox
|
|
889
|
+
key={subcat}
|
|
890
|
+
label={I18n.get(subcat)}
|
|
891
|
+
checked={selectedSubcategories.includes(
|
|
892
|
+
subcat,
|
|
893
|
+
)}
|
|
894
|
+
onChange={(e) => {
|
|
895
|
+
if (e.currentTarget.checked) {
|
|
896
|
+
setSelectedSubcategories([
|
|
897
|
+
...selectedSubcategories,
|
|
898
|
+
subcat,
|
|
899
|
+
]);
|
|
900
|
+
} else {
|
|
901
|
+
setSelectedSubcategories(
|
|
902
|
+
selectedSubcategories.filter(
|
|
903
|
+
(sc) => sc !== subcat,
|
|
904
|
+
),
|
|
905
|
+
);
|
|
906
|
+
}
|
|
907
|
+
}}
|
|
908
|
+
disabled={busy || loadingMetadata}
|
|
909
|
+
/>
|
|
910
|
+
))}
|
|
911
|
+
</Group>
|
|
912
|
+
</div>
|
|
913
|
+
)}
|
|
914
|
+
|
|
915
|
+
{/* Tags input */}
|
|
916
|
+
{metadataOptions.allowedTags.length > 0 && (
|
|
917
|
+
<MultiSelect
|
|
918
|
+
label={I18n.get("Tags")}
|
|
919
|
+
placeholder={I18n.get(
|
|
920
|
+
"Select or type tags...",
|
|
921
|
+
)}
|
|
922
|
+
data={metadataOptions.allowedTags.map(
|
|
923
|
+
(tag) => ({
|
|
924
|
+
value: tag,
|
|
925
|
+
label: I18n.get(tag),
|
|
926
|
+
}),
|
|
927
|
+
)}
|
|
928
|
+
value={selectedTags}
|
|
929
|
+
onChange={setSelectedTags}
|
|
930
|
+
searchValue={tagSearchValue}
|
|
931
|
+
onSearchChange={setTagSearchValue}
|
|
932
|
+
disabled={busy || loadingMetadata}
|
|
933
|
+
searchable
|
|
934
|
+
clearable
|
|
935
|
+
maxDropdownHeight={200}
|
|
936
|
+
limit={20}
|
|
937
|
+
/>
|
|
938
|
+
)}
|
|
939
|
+
</Stack>
|
|
940
|
+
</Collapse>
|
|
941
|
+
</Stack>
|
|
942
|
+
)}
|
|
899
943
|
|
|
900
944
|
{
|
|
901
945
|
/* Audio level indicator when recording */ USE_AUDIO && (
|
|
@@ -982,8 +1026,8 @@ const DocSearchBase: FC<Props> = (props) => {
|
|
|
982
1026
|
) : null}
|
|
983
1027
|
|
|
984
1028
|
{showSources &&
|
|
985
|
-
|
|
986
|
-
|
|
1029
|
+
(result?.citations?.docs?.length ||
|
|
1030
|
+
result?.citations?.chunks?.length) ? (
|
|
987
1031
|
<>
|
|
988
1032
|
<Divider />
|
|
989
1033
|
<Stack gap="sm" data-doc-search-sources>
|