@smart-cloud/ai-kit-ui 1.4.7 → 1.4.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 +2 -2
- package/src/ai-feature/AiFeature.tsx +122 -45
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@smart-cloud/ai-kit-ui",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.9",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.cjs",
|
|
6
6
|
"module": "./dist/index.js",
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"@smart-cloud/wpsuite-core": "^2.2.10",
|
|
25
25
|
"@tabler/icons-react": "^3.40.0",
|
|
26
26
|
"chroma-js": "^3.2.0",
|
|
27
|
-
"country-
|
|
27
|
+
"country-flag-icons": "^1.6.15",
|
|
28
28
|
"react-markdown": "^10.1.0",
|
|
29
29
|
"rehype-parse": "^9.0.1",
|
|
30
30
|
"rehype-raw": "^7.0.0",
|
|
@@ -41,7 +41,7 @@ import {
|
|
|
41
41
|
type WriteArgs,
|
|
42
42
|
} from "@smart-cloud/ai-kit-core";
|
|
43
43
|
import { I18n } from "aws-amplify/utils";
|
|
44
|
-
import
|
|
44
|
+
import * as CountryFlagIcons from "country-flag-icons/react/3x2";
|
|
45
45
|
import {
|
|
46
46
|
type ComponentProps,
|
|
47
47
|
FC,
|
|
@@ -93,8 +93,6 @@ type LanguageSelectorOption = {
|
|
|
93
93
|
value: AiKitLanguageCode;
|
|
94
94
|
label: string;
|
|
95
95
|
countryCode: string;
|
|
96
|
-
countryName: string;
|
|
97
|
-
flag: string;
|
|
98
96
|
};
|
|
99
97
|
|
|
100
98
|
type WriterTone = "neutral" | "formal" | "casual";
|
|
@@ -137,12 +135,33 @@ const LANGUAGE_TO_COUNTRY_CODE: Record<AiKitLanguageCode, string> = {
|
|
|
137
135
|
|
|
138
136
|
const RTL_LANGUAGES = new Set<AiKitLanguageCode>(["ar", "he"]);
|
|
139
137
|
|
|
140
|
-
|
|
138
|
+
function LanguageFlag(props: { countryCode?: string; size?: number }) {
|
|
139
|
+
const { countryCode, size = 18 } = props;
|
|
141
140
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
141
|
+
if (!countryCode) {
|
|
142
|
+
return null;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
const Flag = CountryFlagIcons[
|
|
146
|
+
countryCode as keyof typeof CountryFlagIcons
|
|
147
|
+
] as FC<ComponentProps<"svg">> | undefined;
|
|
148
|
+
|
|
149
|
+
if (!Flag) {
|
|
150
|
+
return null;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
return (
|
|
154
|
+
<Flag
|
|
155
|
+
aria-hidden="true"
|
|
156
|
+
focusable="false"
|
|
157
|
+
style={{
|
|
158
|
+
display: "block",
|
|
159
|
+
flex: "none",
|
|
160
|
+
height: size,
|
|
161
|
+
width: Math.round(size * (4 / 3)),
|
|
162
|
+
}}
|
|
163
|
+
/>
|
|
164
|
+
);
|
|
146
165
|
}
|
|
147
166
|
|
|
148
167
|
function isRtlLanguage(code?: AiKitLanguageCode | "" | null): boolean {
|
|
@@ -157,8 +176,6 @@ function getSupportedLanguageOptions(): LanguageSelectorOption[] {
|
|
|
157
176
|
value: languageOption.value,
|
|
158
177
|
label: languageOption.label,
|
|
159
178
|
countryCode,
|
|
160
|
-
countryName: countryLookup[countryCode]?.name || languageOption.label,
|
|
161
|
-
flag: getFlagEmoji(countryCode),
|
|
162
179
|
};
|
|
163
180
|
});
|
|
164
181
|
}
|
|
@@ -407,6 +424,8 @@ const AiFeatureBase: FC<AiFeatureProps & AiKitShellInjectedProps> = (props) => {
|
|
|
407
424
|
>();
|
|
408
425
|
|
|
409
426
|
const effectiveUiLanguage = languageOverride ?? normalizeLang(language);
|
|
427
|
+
I18n.setLanguage(effectiveUiLanguage || "en");
|
|
428
|
+
const currentUiLanguage = effectiveUiLanguage || "en";
|
|
410
429
|
const effectiveDirection = useMemo(() => {
|
|
411
430
|
const activeDirection = languageOverride ? directionOverride : direction;
|
|
412
431
|
|
|
@@ -475,6 +494,9 @@ const AiFeatureBase: FC<AiFeatureProps & AiKitShellInjectedProps> = (props) => {
|
|
|
475
494
|
defaults?.tone,
|
|
476
495
|
);
|
|
477
496
|
const [type, setType] = useState<SummarizerType | undefined>(defaults?.type);
|
|
497
|
+
const [generatedContentLanguage, setGeneratedContentLanguage] = useState<
|
|
498
|
+
AiKitLanguageCode | ""
|
|
499
|
+
>("");
|
|
478
500
|
|
|
479
501
|
const autoRunOnceRef = useRef(false);
|
|
480
502
|
const supportedLanguageOptions = useMemo(
|
|
@@ -621,6 +643,18 @@ const AiFeatureBase: FC<AiFeatureProps & AiKitShellInjectedProps> = (props) => {
|
|
|
621
643
|
const statusText =
|
|
622
644
|
formatAiKitStatus(ai.statusEvent) ?? (state ? I18n.get(state) : null);
|
|
623
645
|
|
|
646
|
+
const setGeneratedResultLanguage = useCallback(
|
|
647
|
+
(nextLanguage?: AiKitLanguageCode | "auto" | "" | null) => {
|
|
648
|
+
if (nextLanguage && nextLanguage !== "auto") {
|
|
649
|
+
setGeneratedContentLanguage(nextLanguage);
|
|
650
|
+
return;
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
setGeneratedContentLanguage(readDefaultOutputLanguage() || "");
|
|
654
|
+
},
|
|
655
|
+
[],
|
|
656
|
+
);
|
|
657
|
+
|
|
624
658
|
const runGenerate = useCallback(
|
|
625
659
|
async (modeOverride?: AiModePreference) => {
|
|
626
660
|
if (!canGenerate) {
|
|
@@ -639,11 +673,11 @@ const AiFeatureBase: FC<AiFeatureProps & AiKitShellInjectedProps> = (props) => {
|
|
|
639
673
|
typeof input === "function" ? await Promise.resolve(input()) : input;
|
|
640
674
|
switch (mode) {
|
|
641
675
|
case "summarize": {
|
|
676
|
+
const outLang =
|
|
677
|
+
(outputLanguage && outputLanguage !== "auto"
|
|
678
|
+
? outputLanguage
|
|
679
|
+
: null) || readDefaultOutputLanguage();
|
|
642
680
|
const res = await ai.run(async ({ signal, onStatus }) => {
|
|
643
|
-
const outLang =
|
|
644
|
-
(outputLanguage && outputLanguage !== "auto"
|
|
645
|
-
? outputLanguage
|
|
646
|
-
: null) || readDefaultOutputLanguage();
|
|
647
681
|
const args: SummarizeArgs = {
|
|
648
682
|
text: text!.trim(),
|
|
649
683
|
format:
|
|
@@ -665,6 +699,7 @@ const AiFeatureBase: FC<AiFeatureProps & AiKitShellInjectedProps> = (props) => {
|
|
|
665
699
|
const out = await summarize(args, featureOptions);
|
|
666
700
|
return out.result;
|
|
667
701
|
});
|
|
702
|
+
setGeneratedResultLanguage(outLang || "");
|
|
668
703
|
setGenerated((res as never) ?? "");
|
|
669
704
|
break;
|
|
670
705
|
}
|
|
@@ -707,6 +742,10 @@ const AiFeatureBase: FC<AiFeatureProps & AiKitShellInjectedProps> = (props) => {
|
|
|
707
742
|
break;
|
|
708
743
|
}
|
|
709
744
|
case "translate": {
|
|
745
|
+
const outLang =
|
|
746
|
+
(outputLanguage && outputLanguage !== "auto"
|
|
747
|
+
? outputLanguage
|
|
748
|
+
: null) || readDefaultOutputLanguage();
|
|
710
749
|
const res = await ai.run(async ({ signal, onStatus }) => {
|
|
711
750
|
let inputLang = inputLanguage ?? "auto";
|
|
712
751
|
if (inputLang === "auto") {
|
|
@@ -722,10 +761,6 @@ const AiFeatureBase: FC<AiFeatureProps & AiKitShellInjectedProps> = (props) => {
|
|
|
722
761
|
} else {
|
|
723
762
|
setDetectedLanguage(inputLang);
|
|
724
763
|
}
|
|
725
|
-
const outLang =
|
|
726
|
-
(outputLanguage && outputLanguage !== "auto"
|
|
727
|
-
? outputLanguage
|
|
728
|
-
: null) || readDefaultOutputLanguage();
|
|
729
764
|
if (outLang === inputLang) {
|
|
730
765
|
console.warn(
|
|
731
766
|
"AI Kit: input and output languages are the same",
|
|
@@ -759,10 +794,12 @@ const AiFeatureBase: FC<AiFeatureProps & AiKitShellInjectedProps> = (props) => {
|
|
|
759
794
|
const out = await translate(args, featureOptions);
|
|
760
795
|
return out.result;
|
|
761
796
|
});
|
|
797
|
+
setGeneratedResultLanguage(outLang || "");
|
|
762
798
|
setGenerated((res as never) ?? "");
|
|
763
799
|
break;
|
|
764
800
|
}
|
|
765
801
|
case "rewrite": {
|
|
802
|
+
let generatedLanguage: AiKitLanguageCode | "" = "";
|
|
766
803
|
const res = await ai.run(async ({ signal, onStatus }) => {
|
|
767
804
|
let outLang =
|
|
768
805
|
(outputLanguage && outputLanguage !== "auto"
|
|
@@ -779,6 +816,7 @@ const AiFeatureBase: FC<AiFeatureProps & AiKitShellInjectedProps> = (props) => {
|
|
|
779
816
|
});
|
|
780
817
|
setOutputLanguage(outLang);
|
|
781
818
|
}
|
|
819
|
+
generatedLanguage = outLang || "";
|
|
782
820
|
const args: RewriteArgs = {
|
|
783
821
|
text: text!.trim(),
|
|
784
822
|
context: instructions?.trim() || undefined,
|
|
@@ -801,6 +839,7 @@ const AiFeatureBase: FC<AiFeatureProps & AiKitShellInjectedProps> = (props) => {
|
|
|
801
839
|
const out = await rewrite(args, featureOptions);
|
|
802
840
|
return out.result;
|
|
803
841
|
});
|
|
842
|
+
setGeneratedResultLanguage(generatedLanguage);
|
|
804
843
|
setGenerated((res as never) ?? "");
|
|
805
844
|
break;
|
|
806
845
|
}
|
|
@@ -864,6 +903,7 @@ const AiFeatureBase: FC<AiFeatureProps & AiKitShellInjectedProps> = (props) => {
|
|
|
864
903
|
});
|
|
865
904
|
return out.result;
|
|
866
905
|
});
|
|
906
|
+
setGeneratedResultLanguage(outLang || "");
|
|
867
907
|
setGenerated((res as never) ?? "");
|
|
868
908
|
break;
|
|
869
909
|
}
|
|
@@ -1265,20 +1305,11 @@ Follow these additional instructions: ${instructions}`
|
|
|
1265
1305
|
const selectedLanguageOption = useMemo(
|
|
1266
1306
|
() =>
|
|
1267
1307
|
supportedLanguageOptions.find(
|
|
1268
|
-
(option) =>
|
|
1269
|
-
option.value === (languageOverride ?? normalizeLang(language)),
|
|
1308
|
+
(option) => option.value === currentUiLanguage,
|
|
1270
1309
|
) ?? supportedLanguageOptions[0],
|
|
1271
|
-
[
|
|
1310
|
+
[currentUiLanguage, supportedLanguageOptions],
|
|
1272
1311
|
);
|
|
1273
1312
|
|
|
1274
|
-
const renderedOutputLanguage = useMemo(() => {
|
|
1275
|
-
if (outputLanguage && outputLanguage !== "auto") {
|
|
1276
|
-
return outputLanguage;
|
|
1277
|
-
}
|
|
1278
|
-
|
|
1279
|
-
return languageOverride || readDefaultOutputLanguage() || "";
|
|
1280
|
-
}, [languageOverride, outputLanguage]);
|
|
1281
|
-
|
|
1282
1313
|
const renderLanguageOverrideSelect = useCallback(
|
|
1283
1314
|
(size: "xs" | "sm" = "sm") => (
|
|
1284
1315
|
<Select
|
|
@@ -1286,12 +1317,18 @@ Follow these additional instructions: ${instructions}`
|
|
|
1286
1317
|
aria-label={I18n.get("Interface language")}
|
|
1287
1318
|
checkIconPosition="right"
|
|
1288
1319
|
className="ai-feature-language-selector"
|
|
1289
|
-
comboboxProps={{ width: 220 }}
|
|
1290
1320
|
data={supportedLanguageOptions.map((option) => ({
|
|
1291
1321
|
value: option.value,
|
|
1292
|
-
label:
|
|
1322
|
+
label: "",
|
|
1293
1323
|
}))}
|
|
1294
|
-
|
|
1324
|
+
leftSection={
|
|
1325
|
+
selectedLanguageOption?.countryCode ? (
|
|
1326
|
+
<LanguageFlag
|
|
1327
|
+
countryCode={selectedLanguageOption.countryCode}
|
|
1328
|
+
size={18}
|
|
1329
|
+
/>
|
|
1330
|
+
) : null
|
|
1331
|
+
}
|
|
1295
1332
|
onChange={(value) => {
|
|
1296
1333
|
const nextLanguage = normalizeLang(value);
|
|
1297
1334
|
|
|
@@ -1312,33 +1349,57 @@ Follow these additional instructions: ${instructions}`
|
|
|
1312
1349
|
|
|
1313
1350
|
return (
|
|
1314
1351
|
<Group gap="xs" wrap="nowrap">
|
|
1315
|
-
|
|
1316
|
-
|
|
1352
|
+
{languageOption.countryCode ? (
|
|
1353
|
+
<LanguageFlag
|
|
1354
|
+
countryCode={languageOption.countryCode}
|
|
1355
|
+
size={18}
|
|
1356
|
+
/>
|
|
1357
|
+
) : null}
|
|
1358
|
+
<span>{I18n.get(languageOption.label)}</span>
|
|
1317
1359
|
</Group>
|
|
1318
1360
|
);
|
|
1319
1361
|
}}
|
|
1362
|
+
rightSection={null}
|
|
1320
1363
|
searchable={false}
|
|
1321
1364
|
size={size}
|
|
1322
1365
|
styles={{
|
|
1366
|
+
dropdown: {
|
|
1367
|
+
minWidth: 220,
|
|
1368
|
+
},
|
|
1323
1369
|
input: {
|
|
1370
|
+
backgroundColor: "transparent",
|
|
1371
|
+
border: 0,
|
|
1372
|
+
boxShadow: "none",
|
|
1373
|
+
color: "inherit",
|
|
1324
1374
|
fontSize: 18,
|
|
1325
1375
|
lineHeight: 1,
|
|
1326
1376
|
minHeight: size === "sm" ? 36 : 28,
|
|
1327
|
-
paddingInlineStart:
|
|
1328
|
-
paddingInlineEnd:
|
|
1329
|
-
|
|
1330
|
-
width: size === "sm" ?
|
|
1377
|
+
paddingInlineStart: 0,
|
|
1378
|
+
paddingInlineEnd: 0,
|
|
1379
|
+
backgroundImage: "none",
|
|
1380
|
+
width: size === "sm" ? 44 : 36,
|
|
1381
|
+
},
|
|
1382
|
+
option: {
|
|
1383
|
+
color: "inherit",
|
|
1331
1384
|
},
|
|
1332
1385
|
section: {
|
|
1333
|
-
|
|
1386
|
+
color: "inherit",
|
|
1387
|
+
alignItems: "center",
|
|
1388
|
+
display: "flex",
|
|
1389
|
+
height: "100%",
|
|
1390
|
+
insetInlineStart: 0,
|
|
1391
|
+
justifyContent: "center",
|
|
1392
|
+
pointerEvents: "none",
|
|
1393
|
+
width: "100%",
|
|
1334
1394
|
},
|
|
1335
1395
|
}}
|
|
1336
1396
|
value={selectedLanguageOption?.value || null}
|
|
1337
|
-
w={size === "sm" ?
|
|
1397
|
+
w={size === "sm" ? 44 : 36}
|
|
1338
1398
|
/>
|
|
1339
1399
|
),
|
|
1340
1400
|
[
|
|
1341
1401
|
ai.busy,
|
|
1402
|
+
selectedLanguageOption?.countryCode,
|
|
1342
1403
|
selectedLanguageOption?.value,
|
|
1343
1404
|
setLanguageOverride,
|
|
1344
1405
|
supportedLanguageOptions,
|
|
@@ -1408,15 +1469,23 @@ Follow these additional instructions: ${instructions}`
|
|
|
1408
1469
|
{variation === "modal" && <Modal.Overlay />}
|
|
1409
1470
|
<ContentComponent
|
|
1410
1471
|
w="100%"
|
|
1472
|
+
dir={effectiveDirection}
|
|
1411
1473
|
style={{
|
|
1412
1474
|
left: 0,
|
|
1413
1475
|
}}
|
|
1414
1476
|
>
|
|
1415
1477
|
{variation === "modal" && (
|
|
1416
|
-
<Modal.Header style={{ zIndex: 1000 }}>
|
|
1478
|
+
<Modal.Header dir={effectiveDirection} style={{ zIndex: 1000 }}>
|
|
1417
1479
|
{getOpenButtonDefaultIcon("ai-feature-title-icon")}
|
|
1418
1480
|
<Modal.Title>{I18n.get(defaultTitle)}</Modal.Title>
|
|
1419
|
-
<div
|
|
1481
|
+
<div
|
|
1482
|
+
style={{
|
|
1483
|
+
display: "flex",
|
|
1484
|
+
flex: 1,
|
|
1485
|
+
justifyContent: "flex-start",
|
|
1486
|
+
marginRight: 8,
|
|
1487
|
+
}}
|
|
1488
|
+
>
|
|
1420
1489
|
{renderLanguageOverrideSelect("xs")}
|
|
1421
1490
|
</div>
|
|
1422
1491
|
<Modal.CloseButton />
|
|
@@ -2080,7 +2149,7 @@ Follow these additional instructions: ${instructions}`
|
|
|
2080
2149
|
mode !== "generatePostMetadata" &&
|
|
2081
2150
|
typeof generated === "string" && (
|
|
2082
2151
|
<MarkdownResult
|
|
2083
|
-
contentLanguage={
|
|
2152
|
+
contentLanguage={generatedContentLanguage}
|
|
2084
2153
|
value={generated}
|
|
2085
2154
|
editable={!!editable}
|
|
2086
2155
|
onChange={(v) => {
|
|
@@ -2092,7 +2161,7 @@ Follow these additional instructions: ${instructions}`
|
|
|
2092
2161
|
)}
|
|
2093
2162
|
{generated === "" && (
|
|
2094
2163
|
<MarkdownResult
|
|
2095
|
-
contentLanguage={
|
|
2164
|
+
contentLanguage={generatedContentLanguage}
|
|
2096
2165
|
value={generated}
|
|
2097
2166
|
editable={false}
|
|
2098
2167
|
/>
|
|
@@ -2193,7 +2262,12 @@ function MarkdownResult(props: {
|
|
|
2193
2262
|
|
|
2194
2263
|
if (editable) {
|
|
2195
2264
|
return (
|
|
2196
|
-
<Stack
|
|
2265
|
+
<Stack
|
|
2266
|
+
p={0}
|
|
2267
|
+
gap="sm"
|
|
2268
|
+
dir={contentDirection}
|
|
2269
|
+
style={{ textAlign: contentAlign }}
|
|
2270
|
+
>
|
|
2197
2271
|
<Input.Label>{I18n.get("Generated content")}</Input.Label>
|
|
2198
2272
|
<Textarea
|
|
2199
2273
|
value={value}
|
|
@@ -2203,6 +2277,9 @@ function MarkdownResult(props: {
|
|
|
2203
2277
|
maxRows={12}
|
|
2204
2278
|
p={0}
|
|
2205
2279
|
className="ai-feature-generated-content ai-feature-editor"
|
|
2280
|
+
styles={{
|
|
2281
|
+
input: { direction: contentDirection, textAlign: contentAlign },
|
|
2282
|
+
}}
|
|
2206
2283
|
/>
|
|
2207
2284
|
|
|
2208
2285
|
<Input.Label>{I18n.get("Preview")}</Input.Label>
|