@smart-cloud/ai-kit-ui 1.4.7 → 1.4.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.js +9 -9
- package/package.json +2 -2
- package/src/ai-feature/AiFeature.tsx +122 -44
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.8",
|
|
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,19 @@ 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
|
disabled={ai.busy}
|
|
1325
|
+
leftSection={
|
|
1326
|
+
selectedLanguageOption?.countryCode ? (
|
|
1327
|
+
<LanguageFlag
|
|
1328
|
+
countryCode={selectedLanguageOption.countryCode}
|
|
1329
|
+
size={18}
|
|
1330
|
+
/>
|
|
1331
|
+
) : null
|
|
1332
|
+
}
|
|
1295
1333
|
onChange={(value) => {
|
|
1296
1334
|
const nextLanguage = normalizeLang(value);
|
|
1297
1335
|
|
|
@@ -1312,33 +1350,57 @@ Follow these additional instructions: ${instructions}`
|
|
|
1312
1350
|
|
|
1313
1351
|
return (
|
|
1314
1352
|
<Group gap="xs" wrap="nowrap">
|
|
1315
|
-
|
|
1316
|
-
|
|
1353
|
+
{languageOption.countryCode ? (
|
|
1354
|
+
<LanguageFlag
|
|
1355
|
+
countryCode={languageOption.countryCode}
|
|
1356
|
+
size={18}
|
|
1357
|
+
/>
|
|
1358
|
+
) : null}
|
|
1359
|
+
<span>{I18n.get(languageOption.label)}</span>
|
|
1317
1360
|
</Group>
|
|
1318
1361
|
);
|
|
1319
1362
|
}}
|
|
1363
|
+
rightSection={null}
|
|
1320
1364
|
searchable={false}
|
|
1321
1365
|
size={size}
|
|
1322
1366
|
styles={{
|
|
1367
|
+
dropdown: {
|
|
1368
|
+
minWidth: 220,
|
|
1369
|
+
},
|
|
1323
1370
|
input: {
|
|
1371
|
+
backgroundColor: "transparent",
|
|
1372
|
+
border: 0,
|
|
1373
|
+
boxShadow: "none",
|
|
1374
|
+
color: "inherit",
|
|
1324
1375
|
fontSize: 18,
|
|
1325
1376
|
lineHeight: 1,
|
|
1326
1377
|
minHeight: size === "sm" ? 36 : 28,
|
|
1327
|
-
paddingInlineStart:
|
|
1328
|
-
paddingInlineEnd:
|
|
1329
|
-
|
|
1330
|
-
width: size === "sm" ?
|
|
1378
|
+
paddingInlineStart: 0,
|
|
1379
|
+
paddingInlineEnd: 0,
|
|
1380
|
+
backgroundImage: "none",
|
|
1381
|
+
width: size === "sm" ? 44 : 36,
|
|
1382
|
+
},
|
|
1383
|
+
option: {
|
|
1384
|
+
color: "inherit",
|
|
1331
1385
|
},
|
|
1332
1386
|
section: {
|
|
1333
|
-
|
|
1387
|
+
color: "inherit",
|
|
1388
|
+
alignItems: "center",
|
|
1389
|
+
display: "flex",
|
|
1390
|
+
height: "100%",
|
|
1391
|
+
insetInlineStart: 0,
|
|
1392
|
+
justifyContent: "center",
|
|
1393
|
+
pointerEvents: "none",
|
|
1394
|
+
width: "100%",
|
|
1334
1395
|
},
|
|
1335
1396
|
}}
|
|
1336
1397
|
value={selectedLanguageOption?.value || null}
|
|
1337
|
-
w={size === "sm" ?
|
|
1398
|
+
w={size === "sm" ? 44 : 36}
|
|
1338
1399
|
/>
|
|
1339
1400
|
),
|
|
1340
1401
|
[
|
|
1341
1402
|
ai.busy,
|
|
1403
|
+
selectedLanguageOption?.countryCode,
|
|
1342
1404
|
selectedLanguageOption?.value,
|
|
1343
1405
|
setLanguageOverride,
|
|
1344
1406
|
supportedLanguageOptions,
|
|
@@ -1408,15 +1470,23 @@ Follow these additional instructions: ${instructions}`
|
|
|
1408
1470
|
{variation === "modal" && <Modal.Overlay />}
|
|
1409
1471
|
<ContentComponent
|
|
1410
1472
|
w="100%"
|
|
1473
|
+
dir={effectiveDirection}
|
|
1411
1474
|
style={{
|
|
1412
1475
|
left: 0,
|
|
1413
1476
|
}}
|
|
1414
1477
|
>
|
|
1415
1478
|
{variation === "modal" && (
|
|
1416
|
-
<Modal.Header style={{ zIndex: 1000 }}>
|
|
1479
|
+
<Modal.Header dir={effectiveDirection} style={{ zIndex: 1000 }}>
|
|
1417
1480
|
{getOpenButtonDefaultIcon("ai-feature-title-icon")}
|
|
1418
1481
|
<Modal.Title>{I18n.get(defaultTitle)}</Modal.Title>
|
|
1419
|
-
<div
|
|
1482
|
+
<div
|
|
1483
|
+
style={{
|
|
1484
|
+
display: "flex",
|
|
1485
|
+
flex: 1,
|
|
1486
|
+
justifyContent: "flex-start",
|
|
1487
|
+
marginRight: 8,
|
|
1488
|
+
}}
|
|
1489
|
+
>
|
|
1420
1490
|
{renderLanguageOverrideSelect("xs")}
|
|
1421
1491
|
</div>
|
|
1422
1492
|
<Modal.CloseButton />
|
|
@@ -2080,7 +2150,7 @@ Follow these additional instructions: ${instructions}`
|
|
|
2080
2150
|
mode !== "generatePostMetadata" &&
|
|
2081
2151
|
typeof generated === "string" && (
|
|
2082
2152
|
<MarkdownResult
|
|
2083
|
-
contentLanguage={
|
|
2153
|
+
contentLanguage={generatedContentLanguage}
|
|
2084
2154
|
value={generated}
|
|
2085
2155
|
editable={!!editable}
|
|
2086
2156
|
onChange={(v) => {
|
|
@@ -2092,7 +2162,7 @@ Follow these additional instructions: ${instructions}`
|
|
|
2092
2162
|
)}
|
|
2093
2163
|
{generated === "" && (
|
|
2094
2164
|
<MarkdownResult
|
|
2095
|
-
contentLanguage={
|
|
2165
|
+
contentLanguage={generatedContentLanguage}
|
|
2096
2166
|
value={generated}
|
|
2097
2167
|
editable={false}
|
|
2098
2168
|
/>
|
|
@@ -2193,7 +2263,12 @@ function MarkdownResult(props: {
|
|
|
2193
2263
|
|
|
2194
2264
|
if (editable) {
|
|
2195
2265
|
return (
|
|
2196
|
-
<Stack
|
|
2266
|
+
<Stack
|
|
2267
|
+
p={0}
|
|
2268
|
+
gap="sm"
|
|
2269
|
+
dir={contentDirection}
|
|
2270
|
+
style={{ textAlign: contentAlign }}
|
|
2271
|
+
>
|
|
2197
2272
|
<Input.Label>{I18n.get("Generated content")}</Input.Label>
|
|
2198
2273
|
<Textarea
|
|
2199
2274
|
value={value}
|
|
@@ -2203,6 +2278,9 @@ function MarkdownResult(props: {
|
|
|
2203
2278
|
maxRows={12}
|
|
2204
2279
|
p={0}
|
|
2205
2280
|
className="ai-feature-generated-content ai-feature-editor"
|
|
2281
|
+
styles={{
|
|
2282
|
+
input: { direction: contentDirection, textAlign: contentAlign },
|
|
2283
|
+
}}
|
|
2206
2284
|
/>
|
|
2207
2285
|
|
|
2208
2286
|
<Input.Label>{I18n.get("Preview")}</Input.Label>
|