@slicemachine/manager 0.24.4-alpha.xru-kong-obelix-services.2 → 0.24.4-alpha.xru-poc-ai.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -36,6 +36,10 @@ import { API_ENDPOINTS } from "../../constants/API_ENDPOINTS";
36
36
  import { UnauthenticatedError, UnauthorizedError } from "../../errors";
37
37
 
38
38
  import { BaseManager } from "../BaseManager";
39
+ import {
40
+ BedrockRuntimeClient,
41
+ ConverseCommand,
42
+ } from "@aws-sdk/client-bedrock-runtime";
39
43
 
40
44
  type SlicesManagerReadSliceLibraryReturnType = {
41
45
  sliceIDs: string[];
@@ -207,6 +211,18 @@ type SliceMachineManagerConvertLegacySliceToSharedSliceReturnType = {
207
211
  errors: (DecodeError | HookError)[];
208
212
  };
209
213
 
214
+ type SliceMachineManagerGenerateSliceArgs = {
215
+ userPrompt: string;
216
+ libraryID: string;
217
+ slice: SharedSlice;
218
+ imageFile?: Buffer;
219
+ };
220
+
221
+ type SliceMachineManagerGenerateSliceReturnType = {
222
+ slice?: SharedSlice;
223
+ errors: (DecodeError | HookError)[];
224
+ };
225
+
210
226
  export class SlicesManager extends BaseManager {
211
227
  async readSliceLibrary(
212
228
  args: SliceLibraryReadHookData,
@@ -1110,4 +1126,726 @@ export class SlicesManager extends BaseManager {
1110
1126
 
1111
1127
  return { errors: customTypeReadErrors };
1112
1128
  }
1129
+
1130
+ async generateSlice(
1131
+ args: SliceMachineManagerGenerateSliceArgs,
1132
+ ): Promise<SliceMachineManagerGenerateSliceReturnType> {
1133
+ assertPluginsInitialized(this.sliceMachinePluginRunner);
1134
+
1135
+ const AWS_REGION = "us-east-1";
1136
+ const AWS_ACCESS_KEY_ID = process.env.AWS_ACCESS_KEY_ID;
1137
+ const AWS_SECRET_ACCESS_KEY = process.env.AWS_SECRET_ACCESS_KEY;
1138
+
1139
+ if (!AWS_ACCESS_KEY_ID || !AWS_SECRET_ACCESS_KEY) {
1140
+ throw new Error("AWS credentials are not set.");
1141
+ }
1142
+
1143
+ // Initialize AWS Bedrock client
1144
+ const bedrockClient = new BedrockRuntimeClient({
1145
+ region: AWS_REGION,
1146
+ credentials: {
1147
+ accessKeyId: AWS_ACCESS_KEY_ID,
1148
+ secretAccessKey: AWS_SECRET_ACCESS_KEY,
1149
+ },
1150
+ });
1151
+
1152
+ /**
1153
+ * Generates the JSON schema for the SharedSlice TypeScript type.
1154
+ */
1155
+ const getSharedSliceSchema = (): string => {
1156
+ return `
1157
+
1158
+ /**
1159
+ * Represents a Prismic Slice.
1160
+ * @property {string} type - Should always be "SharedSlice".
1161
+ * @property {string} id - Unique identifier for the slice in snake_case.
1162
+ * @property {string} name - Human-readable name in PascalCase.
1163
+ * @property {string} description - Brief explanation of the slice's purpose.
1164
+ * @property {SliceVariation[]} variations - Array of variations for the slice.
1165
+ */
1166
+ type PrismicSlice = {
1167
+ type: "SharedSlice";
1168
+ id: string;
1169
+ name: string;
1170
+ description: string;
1171
+ variations: SliceVariation[];
1172
+ };
1173
+
1174
+ /**
1175
+ * Represents a variation of a Prismic Slice.
1176
+ * @property {string} id - Unique identifier for the variation in snake_case.
1177
+ * @property {string} name - Human-readable name in PascalCase.
1178
+ * @property {string} description - Brief explanation of the variation's purpose.
1179
+ * @property {string} docURL - Legacy property, required with an empty string.
1180
+ * @property {string} version - Legacy property, required with the name property value.
1181
+ * @property {Record<string, PrismicField>} [primary] - Primary fields defining the main content of the slice.
1182
+ */
1183
+ type SliceVariation = {
1184
+ id: string;
1185
+ name: string;
1186
+ description: string;
1187
+ primary: Record<string, PrismicField>;
1188
+ docURL: string;
1189
+ version: string;
1190
+ };
1191
+
1192
+ /**
1193
+ * Union type representing all possible Prismic fields.
1194
+ */
1195
+ type PrismicField =
1196
+ | UIDField
1197
+ | BooleanField
1198
+ | ColorField
1199
+ | DateField
1200
+ | TimestampField
1201
+ | NumberField
1202
+ | KeyTextField
1203
+ | SelectField
1204
+ | StructuredTextField
1205
+ | ImageField
1206
+ | LinkField
1207
+ | GeoPointField
1208
+ | EmbedField
1209
+ | GroupField;
1210
+
1211
+ /**
1212
+ * Represents a UID Field in Prismic.
1213
+ * @property {"UID"} type - Field type.
1214
+ * @property {Object} config - Configuration object.
1215
+ * @property {string} config.label - Label displayed in the editor.
1216
+ * @property {string} [config.placeholder] - Placeholder text.
1217
+ * @property {string} [config.customregex] - Custom regex for validation.
1218
+ * @property {string} [config.errorMessage] - Error message for invalid input.
1219
+ */
1220
+ type UIDField = {
1221
+ type: "UID";
1222
+ config: {
1223
+ label: string;
1224
+ placeholder?: string;
1225
+ customregex?: string;
1226
+ errorMessage?: string;
1227
+ };
1228
+ };
1229
+
1230
+ /**
1231
+ * Represents a Boolean Field in Prismic.
1232
+ * @property {"Boolean"} type - Field type.
1233
+ * @property {Object} config - Configuration object.
1234
+ * @property {string} config.label - Label displayed in the editor.
1235
+ * @property {boolean} [config.default_value] - Default value (true or false).
1236
+ */
1237
+ type BooleanField = {
1238
+ type: "Boolean";
1239
+ config: {
1240
+ label: string;
1241
+ default_value?: boolean;
1242
+ };
1243
+ };
1244
+
1245
+ /**
1246
+ * Represents a Color Field in Prismic.
1247
+ * @property {"Color"} type - Field type.
1248
+ * @property {Object} config - Configuration object.
1249
+ * @property {string} config.label - Label displayed in the editor.
1250
+ */
1251
+ type ColorField = {
1252
+ type: "Color";
1253
+ config: {
1254
+ label: string;
1255
+ };
1256
+ };
1257
+
1258
+ /**
1259
+ * Represents a Date Field in Prismic.
1260
+ * @property {"Date"} type - Field type.
1261
+ * @property {Object} config - Configuration object.
1262
+ * @property {string} config.label - Label displayed in the editor.
1263
+ */
1264
+ type DateField = {
1265
+ type: "Date";
1266
+ config: {
1267
+ label: string;
1268
+ };
1269
+ };
1270
+
1271
+ /**
1272
+ * Represents a Timestamp Field in Prismic.
1273
+ * @property {"Timestamp"} type - Field type.
1274
+ * @property {Object} config - Configuration object.
1275
+ * @property {string} config.label - Label displayed in the editor.
1276
+ */
1277
+ type TimestampField = {
1278
+ type: "Timestamp";
1279
+ config: {
1280
+ label: string;
1281
+ };
1282
+ };
1283
+
1284
+ /**
1285
+ * Represents a Number Field in Prismic.
1286
+ * @property {"Number"} type - Field type.
1287
+ * @property {Object} config - Configuration object.
1288
+ * @property {string} config.label - Label displayed in the editor.
1289
+ * @property {string} [config.placeholder] - Placeholder text.
1290
+ * @property {number} [config.min] - Minimum allowable value.
1291
+ * @property {number} [config.max] - Maximum allowable value.
1292
+ */
1293
+ type NumberField = {
1294
+ type: "Number";
1295
+ config: {
1296
+ label: string;
1297
+ placeholder?: string;
1298
+ min?: number;
1299
+ max?: number;
1300
+ };
1301
+ };
1302
+
1303
+ /**
1304
+ * Represents a Key Text Field in Prismic.
1305
+ * @property {"Text"} type - Field type.
1306
+ * @property {Object} config - Configuration object.
1307
+ * @property {string} config.label - Label displayed in the editor.
1308
+ * @property {string} [config.placeholder] - Placeholder text.
1309
+ */
1310
+ type KeyTextField = {
1311
+ type: "Text";
1312
+ config: {
1313
+ label: string;
1314
+ placeholder?: string;
1315
+ };
1316
+ };
1317
+
1318
+ /**
1319
+ * Represents a Select Field in Prismic.
1320
+ * @property {"Select"} type - Field type.
1321
+ * @property {Object} config - Configuration object.
1322
+ * @property {string} config.label - Label displayed in the editor.
1323
+ * @property {string[]} config.options - Array of options for the select dropdown.
1324
+ */
1325
+ type SelectField = {
1326
+ type: "Select";
1327
+ config: {
1328
+ label: string;
1329
+ options: string[];
1330
+ };
1331
+ };
1332
+
1333
+ /**
1334
+ * Represents a Structured Text Field in Prismic.
1335
+ * @property {"StructuredText"} type - Field type.
1336
+ * @property {Object} config - Configuration object.
1337
+ * @property {string} config.label - Label displayed in the editor.
1338
+ * @property {string} [config.placeholder] - Placeholder text.
1339
+ * @property {string} [config.single] - A comma-separated list of formatting options that does not allow line breaks. Options: paragraph | preformatted | heading1 | heading2 | heading3 | heading4 | heading5 | heading6 | strong | em | hyperlink | image | embed | list-item | o-list-item | rtl.
1340
+ * @property {string} [config.multi] - A comma-separated list of formatting options, with paragraph breaks allowed. Options: paragraph | preformatted | heading1 | heading2 | heading3 | heading4 | heading5 | heading6 | strong | em | hyperlink | image | embed | list-item | o-list-item | rtl.
1341
+ * @property {boolean} [config.allowTargetBlank] - Allows links to open in a new tab.
1342
+ * @property {string[]} [config.labels] - An array of strings to define labels for custom formatting.
1343
+ * @property {ImageConstraint} [config.imageConstraint] - Constraints for images within the rich text field.
1344
+ */
1345
+ type StructuredTextField = {
1346
+ type: "StructuredText";
1347
+ config: {
1348
+ label: string;
1349
+ placeholder?: string;
1350
+ single?: string;
1351
+ multi?: string;
1352
+ allowTargetBlank?: boolean;
1353
+ labels?: string[];
1354
+ imageConstraint?: ImageConstraint;
1355
+ };
1356
+ };
1357
+
1358
+ /**
1359
+ * Represents constraints for images within a rich text field.
1360
+ * @property {number} [width] - Width constraint in pixels.
1361
+ * @property {number
1362
+ * @property {number} [height] - Height constraint in pixels.
1363
+ */
1364
+ type ImageConstraint = {
1365
+ width?: number;
1366
+ height?: number;
1367
+ };
1368
+
1369
+ /**
1370
+ * Represents an Image Field in Prismic.
1371
+ * @property {"Image"} type - Field type.
1372
+ * @property {Object} config - Configuration object.
1373
+ * @property {string} config.label - Label displayed in the editor.
1374
+ * @property {Object} [config.constraint] - Constraints for the image dimensions.
1375
+ * @property {number} [config.constraint.width] - Width constraint.
1376
+ * @property {number} [config.constraint.height] - Height constraint.
1377
+ * @property {Thumbnail[]} [config.thumbnails] - Array of thumbnail configurations.
1378
+ */
1379
+ type ImageField = {
1380
+ type: "Image";
1381
+ config: {
1382
+ label: string;
1383
+ constraint?: {
1384
+ width?: number;
1385
+ height?: number;
1386
+ };
1387
+ thumbnails?: Thumbnail[];
1388
+ };
1389
+ };
1390
+
1391
+ /**
1392
+ * Represents a Thumbnail configuration for an Image field.
1393
+ * @property {string} name - Name of the thumbnail.
1394
+ * @property {number} [width] - Width of the thumbnail in pixels.
1395
+ * @property {number} [height] - Height of the thumbnail in pixels.
1396
+ */
1397
+ type Thumbnail = {
1398
+ name: string;
1399
+ width?: number;
1400
+ height?: number;
1401
+ };
1402
+
1403
+ /**
1404
+ * Represents a Link Field in Prismic.
1405
+ * @property {"Link"} type - Field type.
1406
+ * @property {Object} config - Configuration object.
1407
+ * @property {string} config.label - Label displayed in the editor.
1408
+ * @property {"web" | "document" | "media"} config.select - Defines the type of link allowed.
1409
+ * @property {string[]} [config.customtypes] - Defines which Prismic document types are allowed if select is "document".
1410
+ */
1411
+ type LinkField = {
1412
+ type: "Link";
1413
+ config: {
1414
+ label: string;
1415
+ select: "web" | "document" | "media";
1416
+ customtypes?: string[];
1417
+ allowText: boolean;
1418
+ };
1419
+ };
1420
+
1421
+ /**
1422
+ * Represents an Embed Field in Prismic.
1423
+ * @property {"Embed"} type - Field type.
1424
+ * @property {Object} config - Configuration object.
1425
+ * @property {string} config.label - Label displayed in the editor.
1426
+ */
1427
+ type EmbedField = {
1428
+ type: "Embed";
1429
+ config: {
1430
+ label: string;
1431
+ };
1432
+ };
1433
+
1434
+ /**
1435
+ * Represents a GeoPoint Field in Prismic.
1436
+ * @property {"GeoPoint"} type - Field type.
1437
+ * @property {Object} config - Configuration object.
1438
+ * @property {string} config.label - Label displayed in the editor.
1439
+ */
1440
+ type GeoPointField = {
1441
+ type: "GeoPoint";
1442
+ config: {
1443
+ label: string;
1444
+ };
1445
+ };
1446
+
1447
+ /**
1448
+ * Represents a Group Field (Repeatable Fields) in Prismic.
1449
+ * @property {"Group"} type - Field type.
1450
+ * @property {Object} config - Configuration object.
1451
+ * @property {string} config.label - Label displayed in the editor.
1452
+ * @property {Record<string, PrismicField>} config.fields - Defines the fields inside the group.
1453
+ */
1454
+ type GroupField = {
1455
+ type: "Group";
1456
+ config: {
1457
+ label: string;
1458
+ fields: Record<string, PrismicField>;
1459
+ };
1460
+ };
1461
+ `;
1462
+ };
1463
+
1464
+ /**
1465
+ * Builds the system prompt message using the generated TypeScript schema.
1466
+ */
1467
+ const buildSystemMessage = (
1468
+ schema: string,
1469
+ existingSlice: SharedSlice,
1470
+ ): string => {
1471
+ return `
1472
+ You are a world-class expert in creating Prismic Custom Type models for slices.
1473
+ Your task is to generate a valid Prismic JSON model based solely on the provided description and the TypeScript schema below.
1474
+ The JSON model must adhere strictly to these rules:
1475
+ 1. Include all necessary fields as described.
1476
+ 2. Use the "primary" object for all main content fields.
1477
+ 3. Do NOT use an "items" field. If a field represents a collection, it must be defined inside a Group field within the "primary" object.
1478
+ 4. Ensure that each field has appropriate placeholders, labels, and configurations.
1479
+ 5. If the existing slices contain fields, ensure to understand the user prompt to update the existing slice instead of creating something from scratch.
1480
+ 6. If you detect the user wants to add a variation, always ensure the new variation is not exactly the same as another existing one
1481
+ 7. Always return the full valid slice, as given in existing it should be returned in a valid format.
1482
+ 8. If you detect the user prompt is about creating a totally different slice, do it and discard what was given in the existing slice, BUT only if you detect if nothing related.
1483
+ 9. NEVER generate a Link / Button text field, ONLY the Link / Button field itself is enough. So ONE field just for the Link / Button. ENABLE "allowText" when doing that.
1484
+ 10. AND THE MOST ULTRA IMPORTANT THING! Output ONLY a valid JSON object without any additional commentary or formatting! ONLY JSON, I need to parse it after with JSON.parse!
1485
+
1486
+ ### TypeScript Schema for reference:
1487
+ ${schema}
1488
+
1489
+ ### Existing slice
1490
+ ${JSON.stringify(existingSlice)}
1491
+ `.trim();
1492
+ };
1493
+
1494
+ /**
1495
+ * Sends the prompt to AWS Bedrock and returns the generated Prismic JSON
1496
+ * model.
1497
+ */
1498
+ const generatePrismicModel = async (
1499
+ userPrompt: string,
1500
+ ): Promise<string> => {
1501
+ const schema = getSharedSliceSchema();
1502
+
1503
+ const systemMessage = buildSystemMessage(schema, args.slice);
1504
+
1505
+ const command = new ConverseCommand({
1506
+ modelId: "anthropic.claude-3-5-sonnet-20240620-v1:0",
1507
+ system: [
1508
+ {
1509
+ text:
1510
+ systemMessage +
1511
+ (args.imageFile
1512
+ ? `
1513
+ ### Additional important rules
1514
+ A. SUPER IMPORTANT, you have to check and read the image and generate the model according to what is visible.
1515
+ B. You MUST understand that background image are just a simple image field. Don't try to do anything fancy with it, just a simple image field.
1516
+ C. Even if the background image looks like two image, be smart and detect if it's actually just one simple background that don't need a GROUP!
1517
+ D. NEVER EVER ADD decorative elements as detailled fields
1518
+ `
1519
+ : ``),
1520
+ },
1521
+ ],
1522
+ messages: [
1523
+ args.imageFile
1524
+ ? {
1525
+ role: "user",
1526
+ content: [
1527
+ {
1528
+ image: {
1529
+ format: "png",
1530
+ source: { bytes: args.imageFile } as any,
1531
+ },
1532
+ },
1533
+ ],
1534
+ }
1535
+ : {
1536
+ role: "user",
1537
+ content: [
1538
+ {
1539
+ text: `Generate a valid Prismic JSON model based on the following description:\n\n${userPrompt}`,
1540
+ },
1541
+ ],
1542
+ },
1543
+ ],
1544
+ });
1545
+
1546
+ try {
1547
+ console.log("Before sending command");
1548
+ const response = await bedrockClient.send(command);
1549
+ console.log("After response", JSON.stringify(response));
1550
+
1551
+ const result = response.output?.message?.content?.[0]?.text?.trim();
1552
+ console.log("After sending command");
1553
+ if (!result) {
1554
+ throw new Error("No valid response received.");
1555
+ }
1556
+
1557
+ return result;
1558
+ } catch (error) {
1559
+ console.error("Error generating Prismic model:", error);
1560
+ throw error;
1561
+ }
1562
+ };
1563
+
1564
+ const prismicModel = await generatePrismicModel(args.userPrompt);
1565
+
1566
+ console.log("After saving slice", prismicModel);
1567
+
1568
+ const newSlice = {
1569
+ ...args.slice,
1570
+ variations: JSON.parse(prismicModel).variations,
1571
+ };
1572
+
1573
+ const response = await this.updateSlice({
1574
+ libraryID: args.libraryID,
1575
+ model: newSlice,
1576
+ });
1577
+
1578
+ if (response.errors.length) {
1579
+ return {
1580
+ errors: response.errors,
1581
+ };
1582
+ }
1583
+
1584
+ try {
1585
+ if (args.imageFile) {
1586
+ await this.updateSliceScreenshot({
1587
+ libraryID: args.libraryID,
1588
+ sliceID: newSlice.id,
1589
+ variationID: newSlice.variations[0].id,
1590
+ data: args.imageFile,
1591
+ });
1592
+
1593
+ const extMocks = mockSlice({ model: newSlice });
1594
+ console.log("extMocks", extMocks);
1595
+
1596
+ const command = new ConverseCommand({
1597
+ modelId: "anthropic.claude-3-5-sonnet-20240620-v1:0",
1598
+ system: [
1599
+ {
1600
+ text: `
1601
+ # Task 1
1602
+ You are a world-class expert in creating Prismic Mocks for slices.
1603
+ Your task is to generate a valid Prismic JSON mocks based solely on the provided existing mocks.
1604
+ The goal is for you to take the image from the user input, detect the text and fill ensure the existing mock data is aligned with what is visible.
1605
+ Don't handle images.
1606
+ Only handle text.
1607
+ If you see a repetition with a group, you must create the same number of group items that are visible on the image.
1608
+ KEEP THE EXACT SAME STRUCTURE FOR THE MOCKS DATA, ONLY FILL IN THE TEXT FIELDS!
1609
+ AND ULTRA IMPORTANT! Output ONLY a valid JSON object without any additional commentary or formatting! ONLY JSON with the same existing mock format, I need to parse it after with JSON.parse!
1610
+
1611
+ ### Existing mocks
1612
+ ${JSON.stringify(extMocks)}
1613
+
1614
+ THAT was your FIRST task!
1615
+ # Task 2
1616
+
1617
+ Now you also have a second task, generating the slice code!
1618
+ Generate fully isolated slice mock that don't require any package. The code is in React.
1619
+ You have to ensure the mocks data will be the input of your code.
1620
+ Use the example of a slice fully isolated from bellow to help you know how to code a slice. But use the mocks data as input and the slice name etc.
1621
+ NEVER USE <style jsx> in the final code, just <style> is enough! It's important to not use <style jsx>!
1622
+ Ensure that the color used for the background is the same as the image provide in the user prompt! It's better no background color than a wrong one.
1623
+ Your goal is to make the code visually looks as close as possible to the image from the user input.
1624
+ AND ULTRA IMPORTANT! Output ONLY a valid React code without any additional commentary or formatting! Give me the code so I can just copy paste it into a React component file.
1625
+
1626
+ ### Tips
1627
+ For links just use PrismicNextLink just pass the field, PrismicNextLink will handle the display of the link text.
1628
+ DO NOT TRY TO MANUALLY GO INSIDE THE LINK TO WRITE THE TEXT IT"S DONE AUTOMATICALLY.
1629
+
1630
+ ### Example of a slice fully isolated
1631
+ import { type Content } from "@prismicio/client";
1632
+ import { PrismicNextLink, PrismicNextImage } from "@prismicio/next";
1633
+ import { SliceComponentProps, PrismicRichText } from "@prismicio/react";
1634
+
1635
+ export type HeroProps = SliceComponentProps<Content.HeroSlice>;
1636
+
1637
+ const Hero = ({ slice }: HeroProps): JSX.Element => {
1638
+ return (
1639
+ <section
1640
+ data-slice-type={slice.slice_type}
1641
+ data-slice-variation={slice.variation}
1642
+ className="es-bounded es-fullpage-hero"
1643
+ >
1644
+ <div
1645
+ className="es-fullpage-hero__content"
1646
+ >
1647
+ <div>
1648
+ <PrismicNextImage
1649
+ field={slice.primary.image}
1650
+ className="es-fullpage-hero__image"
1651
+ />
1652
+ </div>
1653
+
1654
+ <div className="es-fullpage-hero__content-right">
1655
+ <div className="es-fullpage-hero__content__intro">
1656
+ <p className="es-fullpage-hero__content__intro__eyebrow">
1657
+ {slice.primary.eyebrowHeadline}
1658
+ </p>
1659
+
1660
+ <div className="es-fullpage-hero__content__intro__headline">
1661
+ <PrismicRichText field={slice.primary.title} />
1662
+ </div>
1663
+
1664
+
1665
+ <div className="es-fullpage-hero__content__intro__description">
1666
+ <PrismicRichText field={slice.primary.description} />
1667
+ </div>
1668
+
1669
+ <PrismicNextLink
1670
+ className="es-call-to-action__link"
1671
+ field={slice.primary.callToActionLink}
1672
+ />
1673
+ </div>
1674
+ </div>
1675
+ </div>
1676
+ <style>
1677
+ {\`
1678
+ .es-bounded {
1679
+ margin: 0px;
1680
+ min-width: 0px;
1681
+ position: relative;
1682
+ }
1683
+
1684
+ .es-fullpage-hero {
1685
+ font-family: system-ui, sans-serif;
1686
+ background-color: #fff;
1687
+ color: #333;
1688
+ }
1689
+
1690
+ .es-fullpage-hero__image {
1691
+ max-width: 100%;
1692
+ height: auto;
1693
+ align-self: center;
1694
+ }
1695
+
1696
+ .es-fullpage-hero__content {
1697
+ display: flex;
1698
+ flex-direction: column;
1699
+ gap: 2rem;
1700
+ }
1701
+
1702
+ .es-fullpage-hero__content-right {
1703
+ display: flex;
1704
+ flex-direction: column;
1705
+ justify-content: space-around;
1706
+ padding: 1.5rem;
1707
+ }
1708
+
1709
+ @media (min-width: 1080px) {
1710
+ .es-fullpage-hero__content {
1711
+ flex-direction: row;
1712
+ }
1713
+
1714
+ .es-fullpage-hero__content > div {
1715
+ width: 50%;
1716
+ }
1717
+ }
1718
+
1719
+ .es-fullpage-hero__content__intro {
1720
+ display: grid;
1721
+ gap: 1rem;
1722
+ }
1723
+
1724
+ .es-fullpage-hero__content__intro__eyebrow {
1725
+ color: #47C1AF;
1726
+ font-size: 1.15rem;
1727
+ font-weight: 500;
1728
+ margin: 0;
1729
+ }
1730
+
1731
+ .es-fullpage-hero__content__intro__headline {
1732
+ font-size: 1.625rem;
1733
+ font-weight: 700;
1734
+ }
1735
+
1736
+ .es-fullpage-hero__content__intro__headline * {
1737
+ margin: 0;
1738
+ }
1739
+
1740
+ @media (min-width: 640px) {
1741
+ .es-fullpage-hero__content__intro__headline {
1742
+ font-size: 2rem;
1743
+ }
1744
+ }
1745
+
1746
+ @media (min-width: 1024px) {
1747
+ .es-fullpage-hero__content__intro__headline {
1748
+ font-size: 2.5rem;
1749
+ }
1750
+ }
1751
+
1752
+ @media (min-width: 1200px) {
1753
+ .es-fullpage-hero__content__intro__headline {
1754
+ font-size: 2.75rem;
1755
+ }
1756
+ }
1757
+
1758
+ .es-fullpage-hero__content__intro__description {
1759
+ font-size: 1.15rem;
1760
+ max-width: 38rem;
1761
+ }
1762
+
1763
+ .es-fullpage-hero__content__intro__description > p {
1764
+ margin: 0;
1765
+ }
1766
+
1767
+ @media (min-width: 1200px) {
1768
+ .es-fullpage-hero__content__intro__description {
1769
+ font-size: 1.4rem;
1770
+ }
1771
+ }
1772
+
1773
+ .es-call-to-action__link {
1774
+ justify-self: flex-start;
1775
+ border-radius: 0.25rem;
1776
+ font-size: 0.875rem;
1777
+ line-height: 1.3;
1778
+ padding: 1rem 2.625rem;
1779
+ transition: background-color 100ms linear;
1780
+ background-color: #16745f;
1781
+ color: #fff;
1782
+ }
1783
+
1784
+ .es-call-to-action__link:hover {
1785
+ background-color: #0d5e4c;
1786
+ }
1787
+ \`}
1788
+ </style>
1789
+ </section>
1790
+ );
1791
+ };
1792
+
1793
+ export default Hero;
1794
+
1795
+
1796
+ # Final output of task 1 and 2
1797
+ Return the task 1 and 2 output in a an object:
1798
+ {
1799
+ task1: <JSON of task 1 for the mocks>,
1800
+ task2: <plain string of the slice code for task 2>
1801
+ }
1802
+ THIS IS THE MOST IMPORTANT THING, YOU NEED A VALID JSON, with task1 and task2 property. And the correct format for each of the two property.
1803
+ `,
1804
+ },
1805
+ ],
1806
+ messages: [
1807
+ {
1808
+ role: "user",
1809
+ content: [
1810
+ {
1811
+ image: {
1812
+ format: "png",
1813
+ source: { bytes: args.imageFile } as any,
1814
+ },
1815
+ },
1816
+ ],
1817
+ },
1818
+ ],
1819
+ });
1820
+
1821
+ console.log("Before sending mock command");
1822
+ const response = await bedrockClient.send(command);
1823
+ console.log("After response", JSON.stringify(response));
1824
+
1825
+ const result = response.output?.message?.content?.[0]?.text?.trim();
1826
+ console.log("After sending mock command");
1827
+
1828
+ if (result) {
1829
+ await this.updateSliceMocks({
1830
+ libraryID: args.libraryID,
1831
+ sliceID: newSlice.id,
1832
+ mocks: JSON.parse(result).task1,
1833
+ });
1834
+
1835
+ await this.sliceMachinePluginRunner.callHook("slice:update-code", {
1836
+ libraryID: args.libraryID,
1837
+ model: newSlice,
1838
+ componentContents: JSON.parse(result).task2,
1839
+ });
1840
+ }
1841
+ }
1842
+ } catch (e) {
1843
+ console.log("Error", e);
1844
+ }
1845
+
1846
+ return {
1847
+ errors: [],
1848
+ slice: newSlice,
1849
+ };
1850
+ }
1113
1851
  }