@smart-cloud/ai-kit-ui 1.3.6 → 1.3.8
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.d.cts +3 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +9 -9
- package/package.json +2 -2
- package/src/doc-search/DocSearch.tsx +313 -13
- package/src/i18n/ar.ts +16 -10
- package/src/i18n/de.ts +16 -10
- package/src/i18n/en.ts +6 -0
- package/src/i18n/es.ts +16 -10
- package/src/i18n/fr.ts +16 -10
- package/src/i18n/he.ts +16 -10
- package/src/i18n/hi.ts +16 -10
- package/src/i18n/hu.ts +16 -10
- package/src/i18n/id.ts +16 -10
- package/src/i18n/it.ts +16 -10
- package/src/i18n/ja.ts +16 -10
- package/src/i18n/ko.ts +16 -10
- package/src/i18n/nb.ts +16 -10
- package/src/i18n/nl.ts +16 -10
- package/src/i18n/pl.ts +16 -10
- package/src/i18n/pt.ts +16 -10
- package/src/i18n/ru.ts +16 -10
- package/src/i18n/sv.ts +16 -10
- package/src/i18n/th.ts +16 -10
- package/src/i18n/tr.ts +16 -10
- package/src/i18n/ua.ts +16 -10
- package/src/i18n/zh.ts +16 -10
- package/src/withAiKitShell.tsx +34 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@smart-cloud/ai-kit-ui",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.8",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.cjs",
|
|
6
6
|
"module": "./dist/index.js",
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"@emotion/cache": "^11.14.0",
|
|
21
21
|
"@emotion/react": "^11.14.0",
|
|
22
22
|
"@mantine/colors-generator": "^8.3.15",
|
|
23
|
-
"@smart-cloud/ai-kit-core": "^1.3.
|
|
23
|
+
"@smart-cloud/ai-kit-core": "^1.3.6",
|
|
24
24
|
"@smart-cloud/wpsuite-core": "^2.2.6",
|
|
25
25
|
"@tabler/icons-react": "^3.36.1",
|
|
26
26
|
"chroma-js": "^3.2.0",
|
|
@@ -2,10 +2,13 @@ import {
|
|
|
2
2
|
Alert,
|
|
3
3
|
Anchor,
|
|
4
4
|
Button,
|
|
5
|
+
Checkbox,
|
|
6
|
+
Collapse,
|
|
5
7
|
Divider,
|
|
6
8
|
Group,
|
|
7
9
|
Loader,
|
|
8
10
|
Modal,
|
|
11
|
+
MultiSelect,
|
|
9
12
|
Paper,
|
|
10
13
|
Progress,
|
|
11
14
|
Stack,
|
|
@@ -15,6 +18,9 @@ import {
|
|
|
15
18
|
} from "@mantine/core";
|
|
16
19
|
import {
|
|
17
20
|
AiKitDocSearchIcon,
|
|
21
|
+
CapabilityDecision,
|
|
22
|
+
dispatchBackend,
|
|
23
|
+
resolveBackend,
|
|
18
24
|
sendSearchMessage,
|
|
19
25
|
type AiKitStatusEvent,
|
|
20
26
|
type DocSearchProps,
|
|
@@ -26,14 +32,20 @@ import ReactMarkdown from "react-markdown";
|
|
|
26
32
|
import rehypeRaw from "rehype-raw";
|
|
27
33
|
import remarkGfm from "remark-gfm";
|
|
28
34
|
|
|
29
|
-
import {
|
|
30
|
-
|
|
35
|
+
import {
|
|
36
|
+
IconChevronDown,
|
|
37
|
+
IconChevronRight,
|
|
38
|
+
IconMicrophone,
|
|
39
|
+
IconMicrophoneOff,
|
|
40
|
+
IconSearch,
|
|
41
|
+
IconX,
|
|
42
|
+
} from "@tabler/icons-react";
|
|
31
43
|
|
|
32
44
|
import { AiFeatureBorder } from "../ai-feature/AiFeatureBorder";
|
|
33
45
|
import { translations } from "../i18n";
|
|
46
|
+
import { PoweredBy } from "../poweredBy";
|
|
34
47
|
import { useAiRun } from "../useAiRun";
|
|
35
48
|
import { AiKitShellInjectedProps, withAiKitShell } from "../withAiKitShell";
|
|
36
|
-
import { PoweredBy } from "../poweredBy";
|
|
37
49
|
|
|
38
50
|
I18n.putVocabularies(translations);
|
|
39
51
|
|
|
@@ -80,6 +92,9 @@ const DocSearchBase: FC<Props> = (props) => {
|
|
|
80
92
|
showSources = true,
|
|
81
93
|
topK = 10,
|
|
82
94
|
getSearchText,
|
|
95
|
+
enableUserFilters = false,
|
|
96
|
+
availableCategories,
|
|
97
|
+
availableTags,
|
|
83
98
|
|
|
84
99
|
variation,
|
|
85
100
|
rootElement,
|
|
@@ -98,6 +113,20 @@ const DocSearchBase: FC<Props> = (props) => {
|
|
|
98
113
|
const audioChunksRef = useRef<Blob[]>([]);
|
|
99
114
|
const audioContextRef = useRef<AudioContext | null>(null);
|
|
100
115
|
const analyserRef = useRef<AnalyserNode | null>(null);
|
|
116
|
+
|
|
117
|
+
// User filter states
|
|
118
|
+
const [filtersOpen, setFiltersOpen] = useState(false);
|
|
119
|
+
const [selectedCategories, setSelectedCategories] = useState<string[]>([]);
|
|
120
|
+
const [selectedSubcategories, setSelectedSubcategories] = useState<string[]>(
|
|
121
|
+
[],
|
|
122
|
+
);
|
|
123
|
+
const [selectedTags, setSelectedTags] = useState<string[]>([]);
|
|
124
|
+
const [tagSearchValue, setTagSearchValue] = useState<string>("");
|
|
125
|
+
const [metadataOptions, setMetadataOptions] = useState<{
|
|
126
|
+
allowedCategories: Record<string, string[]>;
|
|
127
|
+
allowedTags: string[];
|
|
128
|
+
} | null>(null);
|
|
129
|
+
const [loadingMetadata, setLoadingMetadata] = useState(false);
|
|
101
130
|
const animationFrameRef = useRef<number | null>(null);
|
|
102
131
|
|
|
103
132
|
// Audio cache: store uploaded audio to avoid re-uploading within session
|
|
@@ -111,6 +140,7 @@ const DocSearchBase: FC<Props> = (props) => {
|
|
|
111
140
|
useAiRun<SearchResult>();
|
|
112
141
|
|
|
113
142
|
const autoRunOnceRef = useRef(false);
|
|
143
|
+
const prevSelectedCategoriesRef = useRef<string[]>([]);
|
|
114
144
|
|
|
115
145
|
const sessionId = result?.sessionId;
|
|
116
146
|
const citationDocs = result?.citations?.docs ?? [];
|
|
@@ -159,6 +189,14 @@ const DocSearchBase: FC<Props> = (props) => {
|
|
|
159
189
|
return Boolean((text && text.trim().length > 0) || audioBlob);
|
|
160
190
|
}, [inputText, busy, audioBlob, featureOpen]);
|
|
161
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
|
+
|
|
162
200
|
const startRecording = useCallback(async () => {
|
|
163
201
|
try {
|
|
164
202
|
// Clear query input when starting audio recording
|
|
@@ -265,6 +303,68 @@ const DocSearchBase: FC<Props> = (props) => {
|
|
|
265
303
|
};
|
|
266
304
|
}, []);
|
|
267
305
|
|
|
306
|
+
// Load metadata options when user filters are enabled
|
|
307
|
+
useEffect(() => {
|
|
308
|
+
if (!enableUserFilters) return;
|
|
309
|
+
|
|
310
|
+
// Use provided options if available
|
|
311
|
+
if (availableCategories || availableTags) {
|
|
312
|
+
setMetadataOptions({
|
|
313
|
+
allowedCategories: availableCategories || {},
|
|
314
|
+
allowedTags: availableTags || [],
|
|
315
|
+
});
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
// Otherwise fetch from backend
|
|
320
|
+
const loadMetadata = async () => {
|
|
321
|
+
setLoadingMetadata(true);
|
|
322
|
+
try {
|
|
323
|
+
const backend = await resolveBackend();
|
|
324
|
+
|
|
325
|
+
if (!backend.available) {
|
|
326
|
+
console.error("Backend not available for metadata options");
|
|
327
|
+
return;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
const decision: CapabilityDecision = {
|
|
331
|
+
feature: "prompt",
|
|
332
|
+
source: "backend",
|
|
333
|
+
mode: "backend-only",
|
|
334
|
+
onDeviceAvailable: false,
|
|
335
|
+
backendAvailable: backend.available,
|
|
336
|
+
backendTransport: backend.transport,
|
|
337
|
+
backendApiName: backend.apiName,
|
|
338
|
+
backendBaseUrl: backend.baseUrl,
|
|
339
|
+
reason: backend.reason ?? "",
|
|
340
|
+
};
|
|
341
|
+
|
|
342
|
+
const data = (await dispatchBackend(
|
|
343
|
+
decision,
|
|
344
|
+
context ?? "frontend",
|
|
345
|
+
"/kb/metadata-options",
|
|
346
|
+
"GET",
|
|
347
|
+
null,
|
|
348
|
+
{},
|
|
349
|
+
)) as {
|
|
350
|
+
allowedCategories: Record<string, string[]>;
|
|
351
|
+
allowedTags: string[];
|
|
352
|
+
};
|
|
353
|
+
|
|
354
|
+
setMetadataOptions({
|
|
355
|
+
allowedCategories: data.allowedCategories || {},
|
|
356
|
+
allowedTags: data.allowedTags || [],
|
|
357
|
+
});
|
|
358
|
+
} catch (error) {
|
|
359
|
+
console.error("Failed to load metadata options:", error);
|
|
360
|
+
} finally {
|
|
361
|
+
setLoadingMetadata(false);
|
|
362
|
+
}
|
|
363
|
+
};
|
|
364
|
+
|
|
365
|
+
void loadMetadata();
|
|
366
|
+
}, [enableUserFilters, availableCategories, availableTags, context]);
|
|
367
|
+
|
|
268
368
|
const onSearch = useCallback(async () => {
|
|
269
369
|
let q: string | undefined;
|
|
270
370
|
|
|
@@ -313,16 +413,40 @@ const DocSearchBase: FC<Props> = (props) => {
|
|
|
313
413
|
...(q && { query: q }),
|
|
314
414
|
...(audioBlob && { audio: audioBlob }), // Pass Blob directly
|
|
315
415
|
topK,
|
|
416
|
+
// Include user-selected filters if enabled
|
|
417
|
+
// Always send userSelectedCategories array when enableUserFilters is true (even if empty)
|
|
418
|
+
// to prevent backend from applying its own kb-filter
|
|
419
|
+
...(enableUserFilters && {
|
|
420
|
+
userSelectedCategories: selectedCategories,
|
|
421
|
+
}),
|
|
422
|
+
...(enableUserFilters &&
|
|
423
|
+
selectedSubcategories.length > 0 && {
|
|
424
|
+
userSelectedSubcategories: selectedSubcategories,
|
|
425
|
+
}),
|
|
426
|
+
...(enableUserFilters &&
|
|
427
|
+
selectedTags.length > 0 && { userSelectedTags: selectedTags }),
|
|
316
428
|
},
|
|
317
429
|
{ signal, onStatus, context },
|
|
318
430
|
);
|
|
319
431
|
});
|
|
320
|
-
}, [
|
|
432
|
+
}, [
|
|
433
|
+
context,
|
|
434
|
+
inputText,
|
|
435
|
+
audioBlob,
|
|
436
|
+
run,
|
|
437
|
+
reset,
|
|
438
|
+
topK,
|
|
439
|
+
sessionId,
|
|
440
|
+
enableUserFilters,
|
|
441
|
+
selectedCategories,
|
|
442
|
+
selectedSubcategories,
|
|
443
|
+
selectedTags,
|
|
444
|
+
]);
|
|
321
445
|
|
|
322
446
|
const close = useCallback(async () => {
|
|
323
447
|
setFeatureOpen(false);
|
|
324
448
|
reset();
|
|
325
|
-
autoRunOnceRef.current = false;
|
|
449
|
+
//autoRunOnceRef.current = false;
|
|
326
450
|
if (!showOpenButton) {
|
|
327
451
|
onClose();
|
|
328
452
|
}
|
|
@@ -344,6 +468,24 @@ const DocSearchBase: FC<Props> = (props) => {
|
|
|
344
468
|
}
|
|
345
469
|
}, [canSearch]);
|
|
346
470
|
|
|
471
|
+
// Reset session when main categories change
|
|
472
|
+
useEffect(() => {
|
|
473
|
+
const prev = prevSelectedCategoriesRef.current;
|
|
474
|
+
const current = selectedCategories;
|
|
475
|
+
|
|
476
|
+
// Check if categories changed (different length or different items)
|
|
477
|
+
const categoriesChanged =
|
|
478
|
+
prev.length !== current.length ||
|
|
479
|
+
!current.every((cat) => prev.includes(cat));
|
|
480
|
+
|
|
481
|
+
if (categoriesChanged && prev.length > 0) {
|
|
482
|
+
// Reset session only if we had categories before (not on initial mount)
|
|
483
|
+
reset();
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
prevSelectedCategoriesRef.current = [...current];
|
|
487
|
+
}, [selectedCategories, reset]);
|
|
488
|
+
|
|
347
489
|
const grouped = useMemo(() => groupChunksByDoc(result), [result]);
|
|
348
490
|
|
|
349
491
|
const docNumberMap = useMemo(() => {
|
|
@@ -423,7 +565,7 @@ const DocSearchBase: FC<Props> = (props) => {
|
|
|
423
565
|
variation === "modal" ? Modal.Body : Group;
|
|
424
566
|
|
|
425
567
|
useEffect(() => {
|
|
426
|
-
if (variation !== "modal") {
|
|
568
|
+
if (variation !== "modal" || !featureOpen) {
|
|
427
569
|
return;
|
|
428
570
|
}
|
|
429
571
|
document.body.style.overflow = "hidden";
|
|
@@ -438,7 +580,7 @@ const DocSearchBase: FC<Props> = (props) => {
|
|
|
438
580
|
document.body.style.overflow = "";
|
|
439
581
|
document.body.onkeydown = null;
|
|
440
582
|
};
|
|
441
|
-
}, [close, variation]);
|
|
583
|
+
}, [close, variation, featureOpen]);
|
|
442
584
|
|
|
443
585
|
return (
|
|
444
586
|
<>
|
|
@@ -487,6 +629,8 @@ const DocSearchBase: FC<Props> = (props) => {
|
|
|
487
629
|
w="100%"
|
|
488
630
|
style={{
|
|
489
631
|
left: 0,
|
|
632
|
+
...(variation === "modal" &&
|
|
633
|
+
!result?.result && { overflow: "visible" }),
|
|
490
634
|
}}
|
|
491
635
|
>
|
|
492
636
|
{variation === "modal" && (
|
|
@@ -496,7 +640,14 @@ const DocSearchBase: FC<Props> = (props) => {
|
|
|
496
640
|
<Modal.CloseButton />
|
|
497
641
|
</Modal.Header>
|
|
498
642
|
)}
|
|
499
|
-
<BodyComponent
|
|
643
|
+
<BodyComponent
|
|
644
|
+
w="100%"
|
|
645
|
+
style={{
|
|
646
|
+
zIndex: 1001,
|
|
647
|
+
...(variation === "modal" &&
|
|
648
|
+
!result?.result && { overflow: "visible" }),
|
|
649
|
+
}}
|
|
650
|
+
>
|
|
500
651
|
<AiFeatureBorder
|
|
501
652
|
enabled={variation !== "modal"}
|
|
502
653
|
working={busy}
|
|
@@ -629,6 +780,160 @@ const DocSearchBase: FC<Props> = (props) => {
|
|
|
629
780
|
) : null}
|
|
630
781
|
</Group>
|
|
631
782
|
|
|
783
|
+
{/* Empty state */}
|
|
784
|
+
{!busy && !error && !result?.result ? (
|
|
785
|
+
<Text size="sm" c="dimmed" data-doc-search-no-results>
|
|
786
|
+
{I18n.get("Enter a search query to start.")}
|
|
787
|
+
</Text>
|
|
788
|
+
) : null}
|
|
789
|
+
|
|
790
|
+
{/* User filter collapse */}
|
|
791
|
+
{enableUserFilters &&
|
|
792
|
+
metadataOptions &&
|
|
793
|
+
hasValidFilterOptions && (
|
|
794
|
+
<Stack gap="xs">
|
|
795
|
+
<Button
|
|
796
|
+
variant="subtle"
|
|
797
|
+
size="xs"
|
|
798
|
+
onClick={() => setFiltersOpen(!filtersOpen)}
|
|
799
|
+
leftSection={
|
|
800
|
+
filtersOpen ? (
|
|
801
|
+
<IconChevronDown size={14} />
|
|
802
|
+
) : (
|
|
803
|
+
<IconChevronRight size={14} />
|
|
804
|
+
)
|
|
805
|
+
}
|
|
806
|
+
style={{ alignSelf: "flex-start" }}
|
|
807
|
+
>
|
|
808
|
+
{I18n.get("Filters")}
|
|
809
|
+
</Button>
|
|
810
|
+
|
|
811
|
+
<Collapse in={filtersOpen}>
|
|
812
|
+
<Stack gap="md">
|
|
813
|
+
{/* Main categories as checkboxes */}
|
|
814
|
+
{Object.keys(metadataOptions.allowedCategories)
|
|
815
|
+
.length > 0 && (
|
|
816
|
+
<div>
|
|
817
|
+
<Text size="sm" fw={500} mb="xs">
|
|
818
|
+
{I18n.get("Categories")}
|
|
819
|
+
</Text>
|
|
820
|
+
<Group gap="md">
|
|
821
|
+
{Object.keys(
|
|
822
|
+
metadataOptions.allowedCategories,
|
|
823
|
+
).map((category) => (
|
|
824
|
+
<Checkbox
|
|
825
|
+
key={category}
|
|
826
|
+
label={I18n.get(category)}
|
|
827
|
+
checked={selectedCategories.includes(
|
|
828
|
+
category,
|
|
829
|
+
)}
|
|
830
|
+
onChange={(e) => {
|
|
831
|
+
if (e.currentTarget.checked) {
|
|
832
|
+
setSelectedCategories([
|
|
833
|
+
...selectedCategories,
|
|
834
|
+
category,
|
|
835
|
+
]);
|
|
836
|
+
} else {
|
|
837
|
+
setSelectedCategories(
|
|
838
|
+
selectedCategories.filter(
|
|
839
|
+
(c) => c !== category,
|
|
840
|
+
),
|
|
841
|
+
);
|
|
842
|
+
// Remove subcategories of unchecked category
|
|
843
|
+
const subcatsToRemove =
|
|
844
|
+
metadataOptions.allowedCategories[
|
|
845
|
+
category
|
|
846
|
+
] || [];
|
|
847
|
+
setSelectedSubcategories(
|
|
848
|
+
selectedSubcategories.filter(
|
|
849
|
+
(sc) =>
|
|
850
|
+
!subcatsToRemove.includes(sc),
|
|
851
|
+
),
|
|
852
|
+
);
|
|
853
|
+
}
|
|
854
|
+
}}
|
|
855
|
+
disabled={busy || loadingMetadata}
|
|
856
|
+
/>
|
|
857
|
+
))}
|
|
858
|
+
</Group>
|
|
859
|
+
</div>
|
|
860
|
+
)}
|
|
861
|
+
|
|
862
|
+
{/* Subcategories for selected categories */}
|
|
863
|
+
{selectedCategories.length > 0 && (
|
|
864
|
+
<div>
|
|
865
|
+
<Text size="sm" fw={500} mb="xs">
|
|
866
|
+
{I18n.get("Subcategories")}
|
|
867
|
+
</Text>
|
|
868
|
+
<Group gap="md">
|
|
869
|
+
{selectedCategories
|
|
870
|
+
.flatMap(
|
|
871
|
+
(cat) =>
|
|
872
|
+
metadataOptions.allowedCategories[
|
|
873
|
+
cat
|
|
874
|
+
] || [],
|
|
875
|
+
)
|
|
876
|
+
.filter(
|
|
877
|
+
(subcat, index, self) =>
|
|
878
|
+
self.indexOf(subcat) === index,
|
|
879
|
+
)
|
|
880
|
+
.map((subcat) => (
|
|
881
|
+
<Checkbox
|
|
882
|
+
key={subcat}
|
|
883
|
+
label={I18n.get(subcat)}
|
|
884
|
+
checked={selectedSubcategories.includes(
|
|
885
|
+
subcat,
|
|
886
|
+
)}
|
|
887
|
+
onChange={(e) => {
|
|
888
|
+
if (e.currentTarget.checked) {
|
|
889
|
+
setSelectedSubcategories([
|
|
890
|
+
...selectedSubcategories,
|
|
891
|
+
subcat,
|
|
892
|
+
]);
|
|
893
|
+
} else {
|
|
894
|
+
setSelectedSubcategories(
|
|
895
|
+
selectedSubcategories.filter(
|
|
896
|
+
(sc) => sc !== subcat,
|
|
897
|
+
),
|
|
898
|
+
);
|
|
899
|
+
}
|
|
900
|
+
}}
|
|
901
|
+
disabled={busy || loadingMetadata}
|
|
902
|
+
/>
|
|
903
|
+
))}
|
|
904
|
+
</Group>
|
|
905
|
+
</div>
|
|
906
|
+
)}
|
|
907
|
+
|
|
908
|
+
{/* Tags input */}
|
|
909
|
+
{metadataOptions.allowedTags.length > 0 && (
|
|
910
|
+
<MultiSelect
|
|
911
|
+
label={I18n.get("Tags")}
|
|
912
|
+
placeholder={I18n.get(
|
|
913
|
+
"Select or type tags...",
|
|
914
|
+
)}
|
|
915
|
+
data={metadataOptions.allowedTags.map(
|
|
916
|
+
(tag) => ({
|
|
917
|
+
value: tag,
|
|
918
|
+
label: I18n.get(tag),
|
|
919
|
+
}),
|
|
920
|
+
)}
|
|
921
|
+
value={selectedTags}
|
|
922
|
+
onChange={setSelectedTags}
|
|
923
|
+
searchValue={tagSearchValue}
|
|
924
|
+
onSearchChange={setTagSearchValue}
|
|
925
|
+
disabled={busy || loadingMetadata}
|
|
926
|
+
searchable
|
|
927
|
+
clearable
|
|
928
|
+
maxDropdownHeight={200}
|
|
929
|
+
limit={20}
|
|
930
|
+
/>
|
|
931
|
+
)}
|
|
932
|
+
</Stack>
|
|
933
|
+
</Collapse>
|
|
934
|
+
</Stack>
|
|
935
|
+
)}
|
|
936
|
+
|
|
632
937
|
{
|
|
633
938
|
/* Audio level indicator when recording */ USE_AUDIO && (
|
|
634
939
|
<>
|
|
@@ -816,11 +1121,6 @@ const DocSearchBase: FC<Props> = (props) => {
|
|
|
816
1121
|
</Stack>
|
|
817
1122
|
</>
|
|
818
1123
|
) : null}
|
|
819
|
-
{!busy && !error && !result?.result ? (
|
|
820
|
-
<Text size="sm" c="dimmed" data-doc-search-no-results>
|
|
821
|
-
{I18n.get("Enter a search query to start.")}
|
|
822
|
-
</Text>
|
|
823
|
-
) : null}
|
|
824
1124
|
<PoweredBy variation={variation} />
|
|
825
1125
|
</Stack>
|
|
826
1126
|
</Paper>
|
package/src/i18n/ar.ts
CHANGED
|
@@ -20,19 +20,20 @@ export const arDict: Record<string, string> = {
|
|
|
20
20
|
"Ask me": "اسألني",
|
|
21
21
|
Assistant: "المساعد",
|
|
22
22
|
"Assistant is thinking…": "المساعد يفكر…",
|
|
23
|
-
"Audio message": "
|
|
24
|
-
"Audio no longer available": "
|
|
25
|
-
"Audio recorded": "
|
|
23
|
+
"Audio message": "",
|
|
24
|
+
"Audio no longer available": "",
|
|
25
|
+
"Audio recorded": "",
|
|
26
26
|
auto: "آلي",
|
|
27
27
|
"Auto-detect": "الكشف التلقائي",
|
|
28
28
|
Cancel: "يلغي",
|
|
29
29
|
Caption: "التسمية التوضيحية",
|
|
30
30
|
Casual: "غير رسمي",
|
|
31
31
|
casual: "غير رسمي",
|
|
32
|
+
Categories: "الفئات",
|
|
32
33
|
"Checking capabilities…": "إمكانيات الفحص…",
|
|
33
34
|
Chinese: "الصينية",
|
|
34
|
-
Clear: "
|
|
35
|
-
"Clear audio": "
|
|
35
|
+
Clear: "",
|
|
36
|
+
"Clear audio": "",
|
|
36
37
|
"Click again to confirm": "انقر مرة أخرى للتأكيد",
|
|
37
38
|
Close: "يغلق",
|
|
38
39
|
"Close chat": "إغلاق الدردشة",
|
|
@@ -57,6 +58,7 @@ export const arDict: Record<string, string> = {
|
|
|
57
58
|
"Enter a search query to start.": "أدخل عبارة بحث للبدء.",
|
|
58
59
|
Error: "خطأ",
|
|
59
60
|
Excerpt: "مقتطفات",
|
|
61
|
+
Filters: "عوامل التصفية",
|
|
60
62
|
Formal: "رَسمِيّ",
|
|
61
63
|
formal: "رَسمِيّ",
|
|
62
64
|
French: "فرنسي",
|
|
@@ -77,7 +79,7 @@ export const arDict: Record<string, string> = {
|
|
|
77
79
|
HTML: "HTML",
|
|
78
80
|
Hungarian: "المجرية",
|
|
79
81
|
"I'm ready to assist you.": "أنا جاهز لمساعدتك.",
|
|
80
|
-
"Image no longer available": "
|
|
82
|
+
"Image no longer available": "",
|
|
81
83
|
Indonesian: "إندونيسيا",
|
|
82
84
|
"Initializing on-device AI…": "جارٍ تهيئة الذكاء الاصطناعي على الجهاز…",
|
|
83
85
|
"Inlining images as base64": "تضمين الصور بصيغة base64",
|
|
@@ -129,9 +131,10 @@ export const arDict: Record<string, string> = {
|
|
|
129
131
|
"Ready.": "جاهز.",
|
|
130
132
|
"Received backend response.": "تم استلام رد من الخادم الخلفي.",
|
|
131
133
|
"Receiving response...": "جارٍ استلام الرد...",
|
|
132
|
-
Record: "
|
|
133
|
-
"Record audio": "
|
|
134
|
-
"
|
|
134
|
+
Record: "",
|
|
135
|
+
"Record audio": "",
|
|
136
|
+
"Recorded audio:": "صوت مسجّل:",
|
|
137
|
+
"Recording...": "",
|
|
135
138
|
Reference: "مرجع",
|
|
136
139
|
References: "المراجع",
|
|
137
140
|
Regenerate: "تجديد",
|
|
@@ -153,6 +156,7 @@ export const arDict: Record<string, string> = {
|
|
|
153
156
|
"Search the documentation…": "ابحث في الوثائق…",
|
|
154
157
|
"Search with AI-Kit": "البحث باستخدام مجموعة أدوات الذكاء الاصطناعي",
|
|
155
158
|
"Searching…": "جارٍ البحث…",
|
|
159
|
+
"Select or type tags…": "اختر أو اكتب الوسوم…",
|
|
156
160
|
Send: "إرسال",
|
|
157
161
|
"Sending request to backend…": "إرسال الطلب إلى الواجهة الخلفية…",
|
|
158
162
|
"Sending request to server...": "جارٍ إرسال الطلب إلى الخادم...",
|
|
@@ -165,13 +169,15 @@ export const arDict: Record<string, string> = {
|
|
|
165
169
|
Sources: "مصادر",
|
|
166
170
|
Spanish: "الأسبانية",
|
|
167
171
|
Stop: "قف",
|
|
168
|
-
"Stop recording": "
|
|
172
|
+
"Stop recording": "",
|
|
173
|
+
Subcategories: "الفئات الفرعية",
|
|
169
174
|
"Suggested change": "التغيير المقترح",
|
|
170
175
|
Summarize: "لخص",
|
|
171
176
|
"Summarize again": "أعد التلخيص",
|
|
172
177
|
"Summarize on Backend": "تلخيص على الواجهة الخلفية",
|
|
173
178
|
Summarizing: "ملخص",
|
|
174
179
|
Swedish: "السويدية",
|
|
180
|
+
Tags: "الوسوم",
|
|
175
181
|
Teaser: "إعلان تشويقي",
|
|
176
182
|
teaser: "إعلان تشويقي",
|
|
177
183
|
Thai: "تايلاندي",
|
package/src/i18n/de.ts
CHANGED
|
@@ -20,19 +20,20 @@ export const deDict: Record<string, string> = {
|
|
|
20
20
|
"Ask me": "Frag mich",
|
|
21
21
|
Assistant: "Assistent",
|
|
22
22
|
"Assistant is thinking…": "Der Assistent denkt nach…",
|
|
23
|
-
"Audio message": "
|
|
24
|
-
"Audio no longer available": "
|
|
25
|
-
"Audio recorded": "
|
|
23
|
+
"Audio message": "",
|
|
24
|
+
"Audio no longer available": "",
|
|
25
|
+
"Audio recorded": "",
|
|
26
26
|
auto: "automatisch",
|
|
27
27
|
"Auto-detect": "Automatisch erkennen",
|
|
28
28
|
Cancel: "Abbrechen",
|
|
29
29
|
Caption: "Bildunterschrift",
|
|
30
30
|
Casual: "Locker",
|
|
31
31
|
casual: "locker",
|
|
32
|
+
Categories: "Kategorien",
|
|
32
33
|
"Checking capabilities…": "Fähigkeiten werden geprüft…",
|
|
33
34
|
Chinese: "Chinesisch",
|
|
34
|
-
Clear: "
|
|
35
|
-
"Clear audio": "
|
|
35
|
+
Clear: "",
|
|
36
|
+
"Clear audio": "",
|
|
36
37
|
"Click again to confirm": "Zum Bestätigen erneut klicken",
|
|
37
38
|
Close: "Schließen",
|
|
38
39
|
"Close chat": "Chat schließen",
|
|
@@ -57,6 +58,7 @@ export const deDict: Record<string, string> = {
|
|
|
57
58
|
"Enter a search query to start.": "Geben Sie zunächst eine Suchanfrage ein.",
|
|
58
59
|
Error: "Fehler",
|
|
59
60
|
Excerpt: "Auszug",
|
|
61
|
+
Filters: "Filter",
|
|
60
62
|
Formal: "Formell",
|
|
61
63
|
formal: "formell",
|
|
62
64
|
French: "Französisch",
|
|
@@ -77,7 +79,7 @@ export const deDict: Record<string, string> = {
|
|
|
77
79
|
HTML: "HTML",
|
|
78
80
|
Hungarian: "Ungarisch",
|
|
79
81
|
"I'm ready to assist you.": "Ich bin bereit, dir zu helfen.",
|
|
80
|
-
"Image no longer available": "
|
|
82
|
+
"Image no longer available": "",
|
|
81
83
|
Indonesian: "Indonesisch",
|
|
82
84
|
"Initializing on-device AI…": "On-Device-KI wird initialisiert…",
|
|
83
85
|
"Inlining images as base64": "Bilder werden als Base64 eingebettet",
|
|
@@ -129,9 +131,10 @@ export const deDict: Record<string, string> = {
|
|
|
129
131
|
"Ready.": "Bereit.",
|
|
130
132
|
"Received backend response.": "Backend-Antwort erhalten.",
|
|
131
133
|
"Receiving response...": "Antwort wird empfangen...",
|
|
132
|
-
Record: "
|
|
133
|
-
"Record audio": "
|
|
134
|
-
"
|
|
134
|
+
Record: "",
|
|
135
|
+
"Record audio": "",
|
|
136
|
+
"Recorded audio:": "Aufgenommenes Audio:",
|
|
137
|
+
"Recording...": "",
|
|
135
138
|
Reference: "Referenz",
|
|
136
139
|
References: "Referenzen",
|
|
137
140
|
Regenerate: "Neu generieren",
|
|
@@ -153,6 +156,7 @@ export const deDict: Record<string, string> = {
|
|
|
153
156
|
"Search the documentation…": "Durchsuchen Sie die Dokumentation…",
|
|
154
157
|
"Search with AI-Kit": "Suche mit AI-Kit",
|
|
155
158
|
"Searching…": "Suche…",
|
|
159
|
+
"Select or type tags…": "Tags auswählen oder eingeben…",
|
|
156
160
|
Send: "Senden",
|
|
157
161
|
"Sending request to backend…": "Anfrage wird an das Backend gesendet…",
|
|
158
162
|
"Sending request to server...": "Anfrage wird an den Server gesendet...",
|
|
@@ -165,13 +169,15 @@ export const deDict: Record<string, string> = {
|
|
|
165
169
|
Sources: "Quellen",
|
|
166
170
|
Spanish: "Spanisch",
|
|
167
171
|
Stop: "Stoppen",
|
|
168
|
-
"Stop recording": "
|
|
172
|
+
"Stop recording": "",
|
|
173
|
+
Subcategories: "Unterkategorien",
|
|
169
174
|
"Suggested change": "Vorgeschlagene Änderung",
|
|
170
175
|
Summarize: "Zusammenfassen",
|
|
171
176
|
"Summarize again": "Erneut zusammenfassen",
|
|
172
177
|
"Summarize on Backend": "Serverseitig zusammenfassen",
|
|
173
178
|
Summarizing: "Zusammenfassung",
|
|
174
179
|
Swedish: "Schwedisch",
|
|
180
|
+
Tags: "Tags",
|
|
175
181
|
Teaser: "Teaser",
|
|
176
182
|
teaser: "Teaser",
|
|
177
183
|
Thai: "Thailändisch",
|
package/src/i18n/en.ts
CHANGED
|
@@ -29,6 +29,7 @@ export const enDict: Record<string, string> = {
|
|
|
29
29
|
Caption: "Caption",
|
|
30
30
|
Casual: "Casual",
|
|
31
31
|
casual: "casual",
|
|
32
|
+
Categories: "Categories",
|
|
32
33
|
"Checking capabilities…": "Checking capabilities…",
|
|
33
34
|
Chinese: "Chinese",
|
|
34
35
|
Clear: "Clear",
|
|
@@ -57,6 +58,7 @@ export const enDict: Record<string, string> = {
|
|
|
57
58
|
"Enter a search query to start.": "Enter a search query to start.",
|
|
58
59
|
Error: "Error",
|
|
59
60
|
Excerpt: "Excerpt",
|
|
61
|
+
Filters: "Filters",
|
|
60
62
|
Formal: "Formal",
|
|
61
63
|
formal: "formal",
|
|
62
64
|
French: "French",
|
|
@@ -131,6 +133,7 @@ export const enDict: Record<string, string> = {
|
|
|
131
133
|
"Receiving response...": "Receiving response...",
|
|
132
134
|
Record: "Record",
|
|
133
135
|
"Record audio": "Record audio",
|
|
136
|
+
"Recorded audio:": "Recorded audio:",
|
|
134
137
|
"Recording...": "Recording...",
|
|
135
138
|
Reference: "Reference",
|
|
136
139
|
References: "References",
|
|
@@ -153,6 +156,7 @@ export const enDict: Record<string, string> = {
|
|
|
153
156
|
"Search the documentation…": "Search the documentation…",
|
|
154
157
|
"Search with AI-Kit": "Search with AI-Kit",
|
|
155
158
|
"Searching…": "Searching…",
|
|
159
|
+
"Select or type tags…": "Select or type tags…",
|
|
156
160
|
Send: "Send",
|
|
157
161
|
"Sending request to backend…": "Sending request to backend…",
|
|
158
162
|
"Sending request to server...": "Sending request to server...",
|
|
@@ -166,12 +170,14 @@ export const enDict: Record<string, string> = {
|
|
|
166
170
|
Spanish: "Spanish",
|
|
167
171
|
Stop: "Stop",
|
|
168
172
|
"Stop recording": "Stop recording",
|
|
173
|
+
Subcategories: "Subcategories",
|
|
169
174
|
"Suggested change": "Suggested change",
|
|
170
175
|
Summarize: "Summarize",
|
|
171
176
|
"Summarize again": "Summarize again",
|
|
172
177
|
"Summarize on Backend": "Summarize on Backend",
|
|
173
178
|
Summarizing: "Summarizing",
|
|
174
179
|
Swedish: "Swedish",
|
|
180
|
+
Tags: "Tags",
|
|
175
181
|
Teaser: "Teaser",
|
|
176
182
|
teaser: "teaser",
|
|
177
183
|
Thai: "Thai",
|