@orangecatai/adgen-canvas 0.0.14 → 0.0.16
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/dev/{chunk-3OPVOEOA.js → chunk-4VEZT6GV.js} +2 -2
- package/dist/dev/{chunk-W3WRQE6Q.js → chunk-UJP3DIYP.js} +3 -3
- package/dist/dev/data/{image-NKXZX2BO.js → image-PZBTJSVV.js} +3 -3
- package/dist/dev/index.js +618 -160
- package/dist/dev/index.js.map +4 -4
- package/dist/dev/subset-shared.chunk.js +1 -1
- package/dist/dev/subset-worker.chunk.js +1 -1
- package/dist/prod/{chunk-4NRCN4F5.js → chunk-62H5HX6J.js} +1 -1
- package/dist/prod/{chunk-4DCJIUJX.js → chunk-VXQSQDGS.js} +2 -2
- package/dist/prod/data/image-REZEAPVS.js +1 -0
- package/dist/prod/index.js +68 -48
- package/dist/prod/subset-shared.chunk.js +1 -1
- package/dist/prod/subset-worker.chunk.js +1 -1
- package/dist/types/excalidraw/components/AIChatPanel.d.ts +5 -8
- package/dist/types/excalidraw/components/ai-chat/agentLoop.d.ts +5 -4
- package/dist/types/excalidraw/components/ai-chat/canvasTools.d.ts +20 -5
- package/dist/types/excalidraw/index.d.ts +1 -1
- package/package.json +1 -1
- package/dist/prod/data/image-PEXWAOBP.js +0 -1
- /package/dist/dev/{chunk-3OPVOEOA.js.map → chunk-4VEZT6GV.js.map} +0 -0
- /package/dist/dev/{chunk-W3WRQE6Q.js.map → chunk-UJP3DIYP.js.map} +0 -0
- /package/dist/dev/data/{image-NKXZX2BO.js.map → image-PZBTJSVV.js.map} +0 -0
package/dist/dev/index.js
CHANGED
|
@@ -67,10 +67,10 @@ import {
|
|
|
67
67
|
serializeAsJSON,
|
|
68
68
|
serializeLibraryAsJSON,
|
|
69
69
|
strokeRectWithRotation_simple
|
|
70
|
-
} from "./chunk-
|
|
70
|
+
} from "./chunk-UJP3DIYP.js";
|
|
71
71
|
import {
|
|
72
72
|
define_import_meta_env_default
|
|
73
|
-
} from "./chunk-
|
|
73
|
+
} from "./chunk-4VEZT6GV.js";
|
|
74
74
|
import {
|
|
75
75
|
en_default
|
|
76
76
|
} from "./chunk-IFMURN5W.js";
|
|
@@ -9770,7 +9770,7 @@ var exportCanvas = async (type, elements, appState, files, {
|
|
|
9770
9770
|
let blob = canvasToBlob(tempCanvas);
|
|
9771
9771
|
if (appState.exportEmbedScene) {
|
|
9772
9772
|
blob = blob.then(
|
|
9773
|
-
(blob2) => import("./data/image-
|
|
9773
|
+
(blob2) => import("./data/image-PZBTJSVV.js").then(
|
|
9774
9774
|
({ encodePngMetadata: encodePngMetadata2 }) => encodePngMetadata2({
|
|
9775
9775
|
blob: blob2,
|
|
9776
9776
|
metadata: serializeAsJSON(elements, appState, files, "local")
|
|
@@ -22300,7 +22300,13 @@ function notify2() {
|
|
|
22300
22300
|
}
|
|
22301
22301
|
var templateBuilderStore = {
|
|
22302
22302
|
open(sourceFrameId) {
|
|
22303
|
-
state2 = {
|
|
22303
|
+
state2 = {
|
|
22304
|
+
...state2,
|
|
22305
|
+
isOpen: true,
|
|
22306
|
+
templateName: "",
|
|
22307
|
+
campaignTag: "",
|
|
22308
|
+
sourceFrameId: sourceFrameId ?? null
|
|
22309
|
+
};
|
|
22304
22310
|
notify2();
|
|
22305
22311
|
},
|
|
22306
22312
|
close() {
|
|
@@ -22493,10 +22499,54 @@ var CheckIcon = () => /* @__PURE__ */ jsx83(
|
|
|
22493
22499
|
}
|
|
22494
22500
|
);
|
|
22495
22501
|
var TemplateIcon = () => /* @__PURE__ */ jsxs45("svg", { width: "14", height: "14", viewBox: "0 0 14 14", fill: "none", children: [
|
|
22496
|
-
/* @__PURE__ */ jsx83(
|
|
22497
|
-
|
|
22498
|
-
|
|
22499
|
-
|
|
22502
|
+
/* @__PURE__ */ jsx83(
|
|
22503
|
+
"rect",
|
|
22504
|
+
{
|
|
22505
|
+
x: "1",
|
|
22506
|
+
y: "1",
|
|
22507
|
+
width: "5",
|
|
22508
|
+
height: "5",
|
|
22509
|
+
rx: "1",
|
|
22510
|
+
stroke: "currentColor",
|
|
22511
|
+
strokeWidth: "1.4"
|
|
22512
|
+
}
|
|
22513
|
+
),
|
|
22514
|
+
/* @__PURE__ */ jsx83(
|
|
22515
|
+
"rect",
|
|
22516
|
+
{
|
|
22517
|
+
x: "8",
|
|
22518
|
+
y: "1",
|
|
22519
|
+
width: "5",
|
|
22520
|
+
height: "5",
|
|
22521
|
+
rx: "1",
|
|
22522
|
+
stroke: "currentColor",
|
|
22523
|
+
strokeWidth: "1.4"
|
|
22524
|
+
}
|
|
22525
|
+
),
|
|
22526
|
+
/* @__PURE__ */ jsx83(
|
|
22527
|
+
"rect",
|
|
22528
|
+
{
|
|
22529
|
+
x: "1",
|
|
22530
|
+
y: "8",
|
|
22531
|
+
width: "5",
|
|
22532
|
+
height: "5",
|
|
22533
|
+
rx: "1",
|
|
22534
|
+
stroke: "currentColor",
|
|
22535
|
+
strokeWidth: "1.4"
|
|
22536
|
+
}
|
|
22537
|
+
),
|
|
22538
|
+
/* @__PURE__ */ jsx83(
|
|
22539
|
+
"rect",
|
|
22540
|
+
{
|
|
22541
|
+
x: "8",
|
|
22542
|
+
y: "8",
|
|
22543
|
+
width: "5",
|
|
22544
|
+
height: "5",
|
|
22545
|
+
rx: "1",
|
|
22546
|
+
stroke: "currentColor",
|
|
22547
|
+
strokeWidth: "1.4"
|
|
22548
|
+
}
|
|
22549
|
+
)
|
|
22500
22550
|
] });
|
|
22501
22551
|
var AutoResizeIcon = () => /* @__PURE__ */ jsxs45("svg", { width: "14", height: "14", viewBox: "0 0 16 16", fill: "none", children: [
|
|
22502
22552
|
/* @__PURE__ */ jsx83(
|
|
@@ -22549,7 +22599,9 @@ var FrameToolbar = ({
|
|
|
22549
22599
|
const [localWidth, setLocalWidth] = useState27(Math.round(element.width));
|
|
22550
22600
|
const [localHeight, setLocalHeight] = useState27(Math.round(element.height));
|
|
22551
22601
|
const [panelState, setPanelState] = useState27(autoResizePanelStore.getState());
|
|
22552
|
-
const [builderState, setBuilderState] = useState27(
|
|
22602
|
+
const [builderState, setBuilderState] = useState27(
|
|
22603
|
+
templateBuilderStore.getState()
|
|
22604
|
+
);
|
|
22553
22605
|
const dropdownRef = useRef24(null);
|
|
22554
22606
|
useEffect29(() => {
|
|
22555
22607
|
return autoResizePanelStore.subscribe(setPanelState);
|
|
@@ -22882,6 +22934,12 @@ import { useEffect as useEffect33, useRef as useRef28, useState as useState31 }
|
|
|
22882
22934
|
import { sceneCoordsToViewportCoords as sceneCoordsToViewportCoords7 } from "@orangecatai/common";
|
|
22883
22935
|
import { getElementAbsoluteCoords as getElementAbsoluteCoords10 } from "@orangecatai/element";
|
|
22884
22936
|
|
|
22937
|
+
// utils/openRouterApiKey.ts
|
|
22938
|
+
function resolveOpenRouterApiKey(propKey) {
|
|
22939
|
+
const normalizedPropKey = propKey?.trim();
|
|
22940
|
+
return (normalizedPropKey ? normalizedPropKey : void 0) ?? (typeof import.meta !== "undefined" && define_import_meta_env_default?.VITE_APP_OPENROUTER_API_KEY ? define_import_meta_env_default.VITE_APP_OPENROUTER_API_KEY : "") ?? "";
|
|
22941
|
+
}
|
|
22942
|
+
|
|
22885
22943
|
// components/auto-resize/AutoResizePanel.tsx
|
|
22886
22944
|
import { useCallback as useCallback16, useEffect as useEffect32, useRef as useRef27, useState as useState30 } from "react";
|
|
22887
22945
|
|
|
@@ -24674,11 +24732,19 @@ function extractFrameInfo(elements, frame, files) {
|
|
|
24674
24732
|
if (el.type === "image") {
|
|
24675
24733
|
const fileData = files[el.fileId];
|
|
24676
24734
|
if (fileData?.dataURL) {
|
|
24677
|
-
background = {
|
|
24735
|
+
background = {
|
|
24736
|
+
type: "image",
|
|
24737
|
+
dataUrl: fileData.dataURL,
|
|
24738
|
+
elementId: el.id
|
|
24739
|
+
};
|
|
24678
24740
|
continue;
|
|
24679
24741
|
}
|
|
24680
24742
|
} else if (el.type === "rectangle" && el.backgroundColor && el.backgroundColor !== "transparent") {
|
|
24681
|
-
background = {
|
|
24743
|
+
background = {
|
|
24744
|
+
type: "solid",
|
|
24745
|
+
color: el.backgroundColor,
|
|
24746
|
+
elementId: el.id
|
|
24747
|
+
};
|
|
24682
24748
|
continue;
|
|
24683
24749
|
}
|
|
24684
24750
|
}
|
|
@@ -24797,8 +24863,9 @@ function containImageInBbox(imgW, imgH, bboxW, bboxH) {
|
|
|
24797
24863
|
async function captureFrameScreenshotFromApp(app, frameId) {
|
|
24798
24864
|
const elements = app.getSceneElements();
|
|
24799
24865
|
const frame = elements.find((el) => el.id === frameId);
|
|
24800
|
-
if (!frame)
|
|
24866
|
+
if (!frame) {
|
|
24801
24867
|
return null;
|
|
24868
|
+
}
|
|
24802
24869
|
const children = getFrameChildren4(elements, frameId);
|
|
24803
24870
|
try {
|
|
24804
24871
|
const canvas = await exportToCanvas(
|
|
@@ -24910,8 +24977,9 @@ async function tagImageElementsWithVision(info, screenshotDataUrl, openRouterApi
|
|
|
24910
24977
|
const imageEls = info.foreground.filter(
|
|
24911
24978
|
(el) => el.kind === "image" && !el.slotType
|
|
24912
24979
|
);
|
|
24913
|
-
if (imageEls.length === 0)
|
|
24980
|
+
if (imageEls.length === 0) {
|
|
24914
24981
|
return;
|
|
24982
|
+
}
|
|
24915
24983
|
const srcW = info.frame.width;
|
|
24916
24984
|
const srcH = info.frame.height;
|
|
24917
24985
|
const elementList = imageEls.map((el, i) => {
|
|
@@ -24960,8 +25028,9 @@ Return ONLY a JSON object mapping the element number (string key) to its role. E
|
|
|
24960
25028
|
})
|
|
24961
25029
|
}
|
|
24962
25030
|
);
|
|
24963
|
-
if (!response.ok)
|
|
25031
|
+
if (!response.ok) {
|
|
24964
25032
|
return;
|
|
25033
|
+
}
|
|
24965
25034
|
const data = await response.json();
|
|
24966
25035
|
const raw = data?.choices?.[0]?.message?.content ?? "";
|
|
24967
25036
|
const parsed = JSON.parse(raw);
|
|
@@ -25325,13 +25394,15 @@ async function runAutoResizeForDimension(opts) {
|
|
|
25325
25394
|
newEls.push({ ...el, frameId });
|
|
25326
25395
|
} else if (pel.kind === "image") {
|
|
25327
25396
|
const fileId2 = nanoid();
|
|
25328
|
-
const { width: natW, height: natH } = await getImageNaturalDimensions(
|
|
25329
|
-
|
|
25330
|
-
natW,
|
|
25331
|
-
natH,
|
|
25332
|
-
pel.width,
|
|
25333
|
-
pel.height
|
|
25397
|
+
const { width: natW, height: natH } = await getImageNaturalDimensions(
|
|
25398
|
+
pel.dataUrl
|
|
25334
25399
|
);
|
|
25400
|
+
const {
|
|
25401
|
+
relX,
|
|
25402
|
+
relY,
|
|
25403
|
+
width: imgW,
|
|
25404
|
+
height: imgH
|
|
25405
|
+
} = containImageInBbox(natW, natH, pel.width, pel.height);
|
|
25335
25406
|
const el = newImageElement({
|
|
25336
25407
|
type: "image",
|
|
25337
25408
|
x: pel.x + relX,
|
|
@@ -25401,7 +25472,9 @@ async function runAutoResizeForDimension(opts) {
|
|
|
25401
25472
|
}
|
|
25402
25473
|
const screenshot = await captureFrameScreenshotFromApp(app, frameId);
|
|
25403
25474
|
if (!screenshot) {
|
|
25404
|
-
debug(
|
|
25475
|
+
debug(
|
|
25476
|
+
`[AutoResize] ${debugLabel} \u2014 screenshot unavailable, skipping reviewer`
|
|
25477
|
+
);
|
|
25405
25478
|
break;
|
|
25406
25479
|
}
|
|
25407
25480
|
onProgress?.("Reviewing layout\u2026");
|
|
@@ -25410,7 +25483,9 @@ async function runAutoResizeForDimension(opts) {
|
|
|
25410
25483
|
screenshotDataUrl: screenshot,
|
|
25411
25484
|
htmlSource: html,
|
|
25412
25485
|
frame: { id: frameId, width: tgtW, height: tgtH },
|
|
25413
|
-
userBrief: `Auto-resize ad from ${Math.round(
|
|
25486
|
+
userBrief: `Auto-resize ad from ${Math.round(
|
|
25487
|
+
srcFrame.width
|
|
25488
|
+
)}\xD7${Math.round(srcFrame.height)} to ${tgtW}\xD7${tgtH}`,
|
|
25414
25489
|
apiKey: openRouterApiKey,
|
|
25415
25490
|
reviewerModel: chatModel,
|
|
25416
25491
|
signal,
|
|
@@ -25418,7 +25493,9 @@ async function runAutoResizeForDimension(opts) {
|
|
|
25418
25493
|
});
|
|
25419
25494
|
reviewRounds++;
|
|
25420
25495
|
if (feedback.approved) {
|
|
25421
|
-
debug(
|
|
25496
|
+
debug(
|
|
25497
|
+
`[AutoResize] ${debugLabel} \u2014 reviewer approved (round ${reviewRounds})`
|
|
25498
|
+
);
|
|
25422
25499
|
break;
|
|
25423
25500
|
}
|
|
25424
25501
|
debug(
|
|
@@ -25494,7 +25571,10 @@ async function runAutoResize(opts) {
|
|
|
25494
25571
|
}));
|
|
25495
25572
|
}
|
|
25496
25573
|
const info = extractFrameInfo(elements, sourceFrame, app.files);
|
|
25497
|
-
const sourceScreenshot = await captureFrameScreenshotFromApp(
|
|
25574
|
+
const sourceScreenshot = await captureFrameScreenshotFromApp(
|
|
25575
|
+
app,
|
|
25576
|
+
sourceFrameId
|
|
25577
|
+
);
|
|
25498
25578
|
if (sourceScreenshot) {
|
|
25499
25579
|
await tagImageElementsWithVision(
|
|
25500
25580
|
info,
|
|
@@ -25590,16 +25670,95 @@ var PRESETS = [
|
|
|
25590
25670
|
{ label: "160\xD7600", width: 160, height: 600, desc: "Wide Skyscraper" }
|
|
25591
25671
|
];
|
|
25592
25672
|
var ResizeIcon = () => /* @__PURE__ */ jsxs48("svg", { width: "14", height: "14", viewBox: "0 0 16 16", fill: "none", children: [
|
|
25593
|
-
/* @__PURE__ */ jsx89(
|
|
25594
|
-
|
|
25595
|
-
|
|
25673
|
+
/* @__PURE__ */ jsx89(
|
|
25674
|
+
"rect",
|
|
25675
|
+
{
|
|
25676
|
+
x: "1.5",
|
|
25677
|
+
y: "1.5",
|
|
25678
|
+
width: "7",
|
|
25679
|
+
height: "7",
|
|
25680
|
+
rx: "1",
|
|
25681
|
+
stroke: "currentColor",
|
|
25682
|
+
strokeWidth: "1.4"
|
|
25683
|
+
}
|
|
25684
|
+
),
|
|
25685
|
+
/* @__PURE__ */ jsx89(
|
|
25686
|
+
"rect",
|
|
25687
|
+
{
|
|
25688
|
+
x: "7.5",
|
|
25689
|
+
y: "7.5",
|
|
25690
|
+
width: "7",
|
|
25691
|
+
height: "7",
|
|
25692
|
+
rx: "1",
|
|
25693
|
+
stroke: "currentColor",
|
|
25694
|
+
strokeWidth: "1.4",
|
|
25695
|
+
strokeDasharray: "2 1",
|
|
25696
|
+
opacity: "0.6"
|
|
25697
|
+
}
|
|
25698
|
+
),
|
|
25699
|
+
/* @__PURE__ */ jsx89(
|
|
25700
|
+
"path",
|
|
25701
|
+
{
|
|
25702
|
+
d: "M9.5 6.5L13.5 6.5M13.5 6.5L13.5 2.5M13.5 2.5L9.5 2.5",
|
|
25703
|
+
stroke: "currentColor",
|
|
25704
|
+
strokeWidth: "1.3",
|
|
25705
|
+
strokeLinecap: "round",
|
|
25706
|
+
strokeLinejoin: "round"
|
|
25707
|
+
}
|
|
25708
|
+
)
|
|
25596
25709
|
] });
|
|
25597
|
-
var CloseIcon2 = () => /* @__PURE__ */ jsx89("svg", { width: "12", height: "12", viewBox: "0 0 12 12", fill: "none", children: /* @__PURE__ */ jsx89(
|
|
25598
|
-
|
|
25599
|
-
|
|
25710
|
+
var CloseIcon2 = () => /* @__PURE__ */ jsx89("svg", { width: "12", height: "12", viewBox: "0 0 12 12", fill: "none", children: /* @__PURE__ */ jsx89(
|
|
25711
|
+
"path",
|
|
25712
|
+
{
|
|
25713
|
+
d: "M1.5 1.5L10.5 10.5M10.5 1.5L1.5 10.5",
|
|
25714
|
+
stroke: "currentColor",
|
|
25715
|
+
strokeWidth: "1.5",
|
|
25716
|
+
strokeLinecap: "round"
|
|
25717
|
+
}
|
|
25718
|
+
) });
|
|
25719
|
+
var CheckIcon3 = () => /* @__PURE__ */ jsx89("svg", { width: "11", height: "11", viewBox: "0 0 12 12", fill: "none", children: /* @__PURE__ */ jsx89(
|
|
25720
|
+
"path",
|
|
25721
|
+
{
|
|
25722
|
+
d: "M2 6.5L4.5 9L10 3",
|
|
25723
|
+
stroke: "currentColor",
|
|
25724
|
+
strokeWidth: "1.6",
|
|
25725
|
+
strokeLinecap: "round",
|
|
25726
|
+
strokeLinejoin: "round"
|
|
25727
|
+
}
|
|
25728
|
+
) });
|
|
25729
|
+
var SpinnerIcon2 = () => /* @__PURE__ */ jsx89(
|
|
25730
|
+
"svg",
|
|
25731
|
+
{
|
|
25732
|
+
className: "arp-spinner",
|
|
25733
|
+
width: "13",
|
|
25734
|
+
height: "13",
|
|
25735
|
+
viewBox: "0 0 14 14",
|
|
25736
|
+
fill: "none",
|
|
25737
|
+
children: /* @__PURE__ */ jsx89(
|
|
25738
|
+
"circle",
|
|
25739
|
+
{
|
|
25740
|
+
cx: "7",
|
|
25741
|
+
cy: "7",
|
|
25742
|
+
r: "5.5",
|
|
25743
|
+
stroke: "currentColor",
|
|
25744
|
+
strokeWidth: "1.5",
|
|
25745
|
+
strokeLinecap: "round",
|
|
25746
|
+
strokeDasharray: "20 14"
|
|
25747
|
+
}
|
|
25748
|
+
)
|
|
25749
|
+
}
|
|
25750
|
+
);
|
|
25600
25751
|
var ErrorIcon = () => /* @__PURE__ */ jsxs48("svg", { width: "11", height: "11", viewBox: "0 0 12 12", fill: "none", children: [
|
|
25601
25752
|
/* @__PURE__ */ jsx89("circle", { cx: "6", cy: "6", r: "4.5", stroke: "currentColor", strokeWidth: "1.3" }),
|
|
25602
|
-
/* @__PURE__ */ jsx89(
|
|
25753
|
+
/* @__PURE__ */ jsx89(
|
|
25754
|
+
"path",
|
|
25755
|
+
{
|
|
25756
|
+
d: "M6 3.5V6.5",
|
|
25757
|
+
stroke: "currentColor",
|
|
25758
|
+
strokeWidth: "1.4",
|
|
25759
|
+
strokeLinecap: "round"
|
|
25760
|
+
}
|
|
25761
|
+
),
|
|
25603
25762
|
/* @__PURE__ */ jsx89("circle", { cx: "6", cy: "8.5", r: "0.65", fill: "currentColor" })
|
|
25604
25763
|
] });
|
|
25605
25764
|
var CustomDimInput = ({ onAdd }) => {
|
|
@@ -25615,10 +25774,41 @@ var CustomDimInput = ({ onAdd }) => {
|
|
|
25615
25774
|
}
|
|
25616
25775
|
};
|
|
25617
25776
|
return /* @__PURE__ */ jsxs48("div", { className: "arp-custom-row", children: [
|
|
25618
|
-
/* @__PURE__ */ jsx89(
|
|
25777
|
+
/* @__PURE__ */ jsx89(
|
|
25778
|
+
"input",
|
|
25779
|
+
{
|
|
25780
|
+
className: "arp-custom-input",
|
|
25781
|
+
type: "number",
|
|
25782
|
+
placeholder: "W",
|
|
25783
|
+
value: w,
|
|
25784
|
+
min: 1,
|
|
25785
|
+
onChange: (e) => setW(e.target.value),
|
|
25786
|
+
onPointerDown: (e) => e.stopPropagation()
|
|
25787
|
+
}
|
|
25788
|
+
),
|
|
25619
25789
|
/* @__PURE__ */ jsx89("span", { className: "arp-custom-x", children: "\xD7" }),
|
|
25620
|
-
/* @__PURE__ */ jsx89(
|
|
25621
|
-
|
|
25790
|
+
/* @__PURE__ */ jsx89(
|
|
25791
|
+
"input",
|
|
25792
|
+
{
|
|
25793
|
+
className: "arp-custom-input",
|
|
25794
|
+
type: "number",
|
|
25795
|
+
placeholder: "H",
|
|
25796
|
+
value: h,
|
|
25797
|
+
min: 1,
|
|
25798
|
+
onChange: (e) => setH(e.target.value),
|
|
25799
|
+
onPointerDown: (e) => e.stopPropagation()
|
|
25800
|
+
}
|
|
25801
|
+
),
|
|
25802
|
+
/* @__PURE__ */ jsx89(
|
|
25803
|
+
"button",
|
|
25804
|
+
{
|
|
25805
|
+
className: "arp-custom-add",
|
|
25806
|
+
onClick: handleAdd,
|
|
25807
|
+
disabled: !w || !h,
|
|
25808
|
+
title: "Add custom dimension",
|
|
25809
|
+
children: "+ Add"
|
|
25810
|
+
}
|
|
25811
|
+
)
|
|
25622
25812
|
] });
|
|
25623
25813
|
};
|
|
25624
25814
|
var AutoResizePanel = ({
|
|
@@ -25649,17 +25839,19 @@ var AutoResizePanel = ({
|
|
|
25649
25839
|
const togglePreset = (label) => {
|
|
25650
25840
|
setSelected((prev) => {
|
|
25651
25841
|
const next = new Set(prev);
|
|
25652
|
-
if (next.has(label))
|
|
25842
|
+
if (next.has(label)) {
|
|
25653
25843
|
next.delete(label);
|
|
25654
|
-
else
|
|
25844
|
+
} else {
|
|
25655
25845
|
next.add(label);
|
|
25846
|
+
}
|
|
25656
25847
|
return next;
|
|
25657
25848
|
});
|
|
25658
25849
|
};
|
|
25659
25850
|
const addCustom = (dim) => {
|
|
25660
25851
|
const key = dim.label;
|
|
25661
|
-
if (selected.has(key))
|
|
25852
|
+
if (selected.has(key)) {
|
|
25662
25853
|
return;
|
|
25854
|
+
}
|
|
25663
25855
|
setExtras((prev) => [...prev, dim]);
|
|
25664
25856
|
setSelected((prev) => /* @__PURE__ */ new Set([...prev, key]));
|
|
25665
25857
|
};
|
|
@@ -25671,9 +25863,15 @@ var AutoResizePanel = ({
|
|
|
25671
25863
|
return next;
|
|
25672
25864
|
});
|
|
25673
25865
|
};
|
|
25674
|
-
const updateDimState = useCallback16(
|
|
25675
|
-
|
|
25676
|
-
|
|
25866
|
+
const updateDimState = useCallback16(
|
|
25867
|
+
(label, update) => {
|
|
25868
|
+
setDimStates((prev) => ({
|
|
25869
|
+
...prev,
|
|
25870
|
+
[label]: { ...prev[label], ...update }
|
|
25871
|
+
}));
|
|
25872
|
+
},
|
|
25873
|
+
[]
|
|
25874
|
+
);
|
|
25677
25875
|
const cleanupShimmer = useCallback16(() => {
|
|
25678
25876
|
autoResizeStore.clear();
|
|
25679
25877
|
}, []);
|
|
@@ -25684,8 +25882,9 @@ var AutoResizePanel = ({
|
|
|
25684
25882
|
};
|
|
25685
25883
|
}, []);
|
|
25686
25884
|
const handleGenerate = useCallback16(async () => {
|
|
25687
|
-
if (allDimensions.length === 0)
|
|
25885
|
+
if (allDimensions.length === 0) {
|
|
25688
25886
|
return;
|
|
25887
|
+
}
|
|
25689
25888
|
setRunning(true);
|
|
25690
25889
|
onRunningChange?.(true);
|
|
25691
25890
|
setGlobalError(null);
|
|
@@ -25734,12 +25933,14 @@ var AutoResizePanel = ({
|
|
|
25734
25933
|
const dimLabel = allDimensions[idx]?.label ?? label;
|
|
25735
25934
|
if (phase === "done") {
|
|
25736
25935
|
updateDimState(dimLabel, { status: "done" });
|
|
25737
|
-
if (preCreatedFrames[idx])
|
|
25936
|
+
if (preCreatedFrames[idx]) {
|
|
25738
25937
|
autoResizeStore.markComplete(preCreatedFrames[idx].frameId);
|
|
25938
|
+
}
|
|
25739
25939
|
} else if (phase === "error") {
|
|
25740
25940
|
updateDimState(dimLabel, { status: "error", error: label });
|
|
25741
|
-
if (preCreatedFrames[idx])
|
|
25941
|
+
if (preCreatedFrames[idx]) {
|
|
25742
25942
|
autoResizeStore.markComplete(preCreatedFrames[idx].frameId);
|
|
25943
|
+
}
|
|
25743
25944
|
} else if (phase === "bg-regen") {
|
|
25744
25945
|
updateDimState(dimLabel, { status: "bg-regen" });
|
|
25745
25946
|
} else {
|
|
@@ -25751,7 +25952,9 @@ var AutoResizePanel = ({
|
|
|
25751
25952
|
} catch (err) {
|
|
25752
25953
|
if (err instanceof DOMException && err.name === "AbortError" || controller.signal.aborted) {
|
|
25753
25954
|
} else {
|
|
25754
|
-
setGlobalError(
|
|
25955
|
+
setGlobalError(
|
|
25956
|
+
err instanceof Error ? err.message : "An unexpected error occurred"
|
|
25957
|
+
);
|
|
25755
25958
|
}
|
|
25756
25959
|
} finally {
|
|
25757
25960
|
setRunning(false);
|
|
@@ -25777,7 +25980,9 @@ var AutoResizePanel = ({
|
|
|
25777
25980
|
onRunningChange?.(false);
|
|
25778
25981
|
cleanupShimmer();
|
|
25779
25982
|
};
|
|
25780
|
-
const doneCount = Object.values(dimStates).filter(
|
|
25983
|
+
const doneCount = Object.values(dimStates).filter(
|
|
25984
|
+
(s) => s.status === "done"
|
|
25985
|
+
).length;
|
|
25781
25986
|
const totalCount = allDimensions.length;
|
|
25782
25987
|
const hasResults = doneCount > 0;
|
|
25783
25988
|
return /* @__PURE__ */ jsx89(Fragment13, { children: /* @__PURE__ */ jsxs48(
|
|
@@ -25798,7 +26003,9 @@ var AutoResizePanel = ({
|
|
|
25798
26003
|
className: "arp-header__close",
|
|
25799
26004
|
onClick: () => {
|
|
25800
26005
|
if (running) {
|
|
25801
|
-
if (window.confirm(
|
|
26006
|
+
if (window.confirm(
|
|
26007
|
+
"This will cancel the generation. Are you sure?"
|
|
26008
|
+
)) {
|
|
25802
26009
|
handleCancel();
|
|
25803
26010
|
onClose();
|
|
25804
26011
|
}
|
|
@@ -25835,7 +26042,14 @@ var AutoResizePanel = ({
|
|
|
25835
26042
|
state3.status === "waiting" && /* @__PURE__ */ jsx89("span", { className: "arp-status arp-status--waiting", children: "\u2026" }),
|
|
25836
26043
|
(state3.status === "bg-regen" || state3.status === "layout" || state3.status === "inserting") && /* @__PURE__ */ jsx89("span", { className: "arp-status arp-status--running", children: /* @__PURE__ */ jsx89(SpinnerIcon2, {}) }),
|
|
25837
26044
|
state3.status === "done" && /* @__PURE__ */ jsx89("span", { className: "arp-status arp-status--done", children: /* @__PURE__ */ jsx89(CheckIcon3, {}) }),
|
|
25838
|
-
state3.status === "error" && /* @__PURE__ */ jsx89(
|
|
26045
|
+
state3.status === "error" && /* @__PURE__ */ jsx89(
|
|
26046
|
+
"span",
|
|
26047
|
+
{
|
|
26048
|
+
className: "arp-status arp-status--error",
|
|
26049
|
+
title: state3.error,
|
|
26050
|
+
children: /* @__PURE__ */ jsx89(ErrorIcon, {})
|
|
26051
|
+
}
|
|
26052
|
+
)
|
|
25839
26053
|
] })
|
|
25840
26054
|
]
|
|
25841
26055
|
},
|
|
@@ -25847,9 +26061,23 @@ var AutoResizePanel = ({
|
|
|
25847
26061
|
return /* @__PURE__ */ jsxs48("div", { className: "arp-extra-tag", children: [
|
|
25848
26062
|
/* @__PURE__ */ jsx89("span", { children: d.label }),
|
|
25849
26063
|
state3?.status === "done" && /* @__PURE__ */ jsx89("span", { className: "arp-status arp-status--done", children: /* @__PURE__ */ jsx89(CheckIcon3, {}) }),
|
|
25850
|
-
state3?.status === "error" && /* @__PURE__ */ jsx89(
|
|
26064
|
+
state3?.status === "error" && /* @__PURE__ */ jsx89(
|
|
26065
|
+
"span",
|
|
26066
|
+
{
|
|
26067
|
+
className: "arp-status arp-status--error",
|
|
26068
|
+
title: state3.error,
|
|
26069
|
+
children: /* @__PURE__ */ jsx89(ErrorIcon, {})
|
|
26070
|
+
}
|
|
26071
|
+
),
|
|
25851
26072
|
(state3?.status === "bg-regen" || state3?.status === "layout") && /* @__PURE__ */ jsx89("span", { className: "arp-status arp-status--running", children: /* @__PURE__ */ jsx89(SpinnerIcon2, {}) }),
|
|
25852
|
-
!running && /* @__PURE__ */ jsx89(
|
|
26073
|
+
!running && /* @__PURE__ */ jsx89(
|
|
26074
|
+
"button",
|
|
26075
|
+
{
|
|
26076
|
+
className: "arp-extra-tag__remove",
|
|
26077
|
+
onClick: () => removeExtra(d.label),
|
|
26078
|
+
children: "\xD7"
|
|
26079
|
+
}
|
|
26080
|
+
)
|
|
25853
26081
|
] }, d.label);
|
|
25854
26082
|
}) }),
|
|
25855
26083
|
!running && /* @__PURE__ */ jsxs48(Fragment13, { children: [
|
|
@@ -25858,7 +26086,13 @@ var AutoResizePanel = ({
|
|
|
25858
26086
|
] }),
|
|
25859
26087
|
globalError && /* @__PURE__ */ jsx89("div", { className: "arp-error", children: globalError }),
|
|
25860
26088
|
running && totalCount > 0 && /* @__PURE__ */ jsxs48("div", { className: "arp-progress", children: [
|
|
25861
|
-
/* @__PURE__ */ jsx89("div", { className: "arp-progress__bar-bg", children: /* @__PURE__ */ jsx89(
|
|
26089
|
+
/* @__PURE__ */ jsx89("div", { className: "arp-progress__bar-bg", children: /* @__PURE__ */ jsx89(
|
|
26090
|
+
"div",
|
|
26091
|
+
{
|
|
26092
|
+
className: "arp-progress__bar-fill",
|
|
26093
|
+
style: { width: `${doneCount / totalCount * 100}%` }
|
|
26094
|
+
}
|
|
26095
|
+
) }),
|
|
25862
26096
|
/* @__PURE__ */ jsxs48("span", { className: "arp-progress__text", children: [
|
|
25863
26097
|
doneCount,
|
|
25864
26098
|
"/",
|
|
@@ -25867,20 +26101,30 @@ var AutoResizePanel = ({
|
|
|
25867
26101
|
] })
|
|
25868
26102
|
] }),
|
|
25869
26103
|
/* @__PURE__ */ jsx89("div", { className: "arp-actions", children: running ? /* @__PURE__ */ jsx89("button", { className: "arp-btn arp-btn--cancel", onClick: handleCancel, children: "Cancel" }) : hasResults ? /* @__PURE__ */ jsxs48(Fragment13, { children: [
|
|
25870
|
-
/* @__PURE__ */ jsx89(
|
|
26104
|
+
/* @__PURE__ */ jsx89(
|
|
26105
|
+
"button",
|
|
26106
|
+
{
|
|
26107
|
+
className: "arp-btn arp-btn--primary",
|
|
26108
|
+
onClick: handleGenerate,
|
|
26109
|
+
disabled: allDimensions.length === 0,
|
|
26110
|
+
children: "Generate more"
|
|
26111
|
+
}
|
|
26112
|
+
),
|
|
25871
26113
|
/* @__PURE__ */ jsx89("button", { className: "arp-btn arp-btn--ghost", onClick: onClose, children: "Done" })
|
|
25872
|
-
] }) : /* @__PURE__ */ jsx89(
|
|
26114
|
+
] }) : /* @__PURE__ */ jsx89(
|
|
26115
|
+
"button",
|
|
26116
|
+
{
|
|
26117
|
+
className: "arp-btn arp-btn--primary",
|
|
26118
|
+
onClick: handleGenerate,
|
|
26119
|
+
disabled: allDimensions.length === 0,
|
|
26120
|
+
children: allDimensions.length === 0 ? "Select sizes above" : `Generate ${allDimensions.length} size${allDimensions.length !== 1 ? "s" : ""}`
|
|
26121
|
+
}
|
|
26122
|
+
) })
|
|
25873
26123
|
]
|
|
25874
26124
|
}
|
|
25875
26125
|
) });
|
|
25876
26126
|
};
|
|
25877
26127
|
|
|
25878
|
-
// utils/openRouterApiKey.ts
|
|
25879
|
-
function resolveOpenRouterApiKey(propKey) {
|
|
25880
|
-
const normalizedPropKey = propKey?.trim();
|
|
25881
|
-
return (normalizedPropKey ? normalizedPropKey : void 0) ?? (typeof import.meta !== "undefined" && define_import_meta_env_default?.VITE_APP_OPENROUTER_API_KEY ? define_import_meta_env_default.VITE_APP_OPENROUTER_API_KEY : "") ?? "";
|
|
25882
|
-
}
|
|
25883
|
-
|
|
25884
26128
|
// components/auto-resize/AutoResizePanelHost.tsx
|
|
25885
26129
|
import { jsx as jsx90 } from "react/jsx-runtime";
|
|
25886
26130
|
var AutoResizePanelHost = ({ app }) => {
|
|
@@ -25970,12 +26214,22 @@ import { arrayToMap as arrayToMap23 } from "@orangecatai/common";
|
|
|
25970
26214
|
var SLOT_TYPES = [
|
|
25971
26215
|
{ id: "background", label: "Background", color: "#94a3b8", kind: "rect" },
|
|
25972
26216
|
{ id: "logo", label: "Logo", color: "#f97316", kind: "image" },
|
|
25973
|
-
{
|
|
26217
|
+
{
|
|
26218
|
+
id: "product_image",
|
|
26219
|
+
label: "Product Image",
|
|
26220
|
+
color: "#22c55e",
|
|
26221
|
+
kind: "image"
|
|
26222
|
+
},
|
|
25974
26223
|
{ id: "headline", label: "Headline", color: "#3b82f6", kind: "text" },
|
|
25975
26224
|
{ id: "subhead", label: "Subhead", color: "#8b5cf6", kind: "text" },
|
|
25976
26225
|
{ id: "cta", label: "CTA", color: "#ef4444", kind: "text" },
|
|
25977
26226
|
{ id: "signoff", label: "Signoff", color: "#64748b", kind: "text" },
|
|
25978
|
-
{
|
|
26227
|
+
{
|
|
26228
|
+
id: "auxiliary_image",
|
|
26229
|
+
label: "Aux Image",
|
|
26230
|
+
color: "#14b8a6",
|
|
26231
|
+
kind: "image"
|
|
26232
|
+
}
|
|
25979
26233
|
];
|
|
25980
26234
|
|
|
25981
26235
|
// components/template-builder/TemplateBuilderTray.tsx
|
|
@@ -26004,7 +26258,11 @@ var TemplateBuilderTray = ({ app }) => {
|
|
|
26004
26258
|
strokeColor: "transparent",
|
|
26005
26259
|
opacity: 60
|
|
26006
26260
|
});
|
|
26007
|
-
newEl = {
|
|
26261
|
+
newEl = {
|
|
26262
|
+
...base,
|
|
26263
|
+
frameId: frame.id,
|
|
26264
|
+
customData: { slotType: slot.id, isSlot: true }
|
|
26265
|
+
};
|
|
26008
26266
|
} else if (slot.kind === "text") {
|
|
26009
26267
|
const base = newTextElement3({
|
|
26010
26268
|
text: slot.label,
|
|
@@ -26013,7 +26271,11 @@ var TemplateBuilderTray = ({ app }) => {
|
|
|
26013
26271
|
fontSize: 32,
|
|
26014
26272
|
strokeColor: slot.color
|
|
26015
26273
|
});
|
|
26016
|
-
newEl = {
|
|
26274
|
+
newEl = {
|
|
26275
|
+
...base,
|
|
26276
|
+
frameId: frame.id,
|
|
26277
|
+
customData: { slotType: slot.id, isSlot: true }
|
|
26278
|
+
};
|
|
26017
26279
|
} else {
|
|
26018
26280
|
const base = newElement5({
|
|
26019
26281
|
type: "rectangle",
|
|
@@ -26026,7 +26288,11 @@ var TemplateBuilderTray = ({ app }) => {
|
|
|
26026
26288
|
strokeColor: slot.color,
|
|
26027
26289
|
opacity: 40
|
|
26028
26290
|
});
|
|
26029
|
-
newEl = {
|
|
26291
|
+
newEl = {
|
|
26292
|
+
...base,
|
|
26293
|
+
frameId: frame.id,
|
|
26294
|
+
customData: { slotType: slot.id, isSlot: true }
|
|
26295
|
+
};
|
|
26030
26296
|
}
|
|
26031
26297
|
const elements = app.getSceneElements();
|
|
26032
26298
|
const newElements = [...elements, newEl];
|
|
@@ -26132,25 +26398,48 @@ var TemplateBuilderPanelHost = ({
|
|
|
26132
26398
|
}
|
|
26133
26399
|
if (framesToSave.length === 0) {
|
|
26134
26400
|
framesToSave = allElements.filter((el) => {
|
|
26135
|
-
if (el.isDeleted || !isFrameLikeElement11(el))
|
|
26401
|
+
if (el.isDeleted || !isFrameLikeElement11(el)) {
|
|
26136
26402
|
return false;
|
|
26403
|
+
}
|
|
26137
26404
|
const children = getFrameChildren5(allElements, el.id);
|
|
26138
|
-
return children.some(
|
|
26405
|
+
return children.some(
|
|
26406
|
+
(child) => child.customData?.isSlot === true
|
|
26407
|
+
);
|
|
26139
26408
|
});
|
|
26140
26409
|
}
|
|
26141
26410
|
if (framesToSave.length === 0) {
|
|
26142
|
-
alert(
|
|
26411
|
+
alert(
|
|
26412
|
+
"No frame found to save. Please select a frame on the canvas first."
|
|
26413
|
+
);
|
|
26143
26414
|
return;
|
|
26144
26415
|
}
|
|
26145
26416
|
const frame = framesToSave[0];
|
|
26146
26417
|
const frameChildren = getFrameChildren5(allElements, frame.id);
|
|
26418
|
+
const files = app.files;
|
|
26419
|
+
const templateFiles = {};
|
|
26420
|
+
for (const el of frameChildren) {
|
|
26421
|
+
const imgEl = el;
|
|
26422
|
+
if (el.type === "image" && imgEl.fileId) {
|
|
26423
|
+
const file2 = files[imgEl.fileId];
|
|
26424
|
+
if (file2?.dataURL) {
|
|
26425
|
+
templateFiles[imgEl.fileId] = {
|
|
26426
|
+
dataURL: file2.dataURL,
|
|
26427
|
+
mimeType: file2.mimeType
|
|
26428
|
+
};
|
|
26429
|
+
}
|
|
26430
|
+
}
|
|
26431
|
+
}
|
|
26147
26432
|
onSaveTemplate({
|
|
26148
26433
|
name: panelState.templateName,
|
|
26149
26434
|
campaignTag: panelState.campaignTag || void 0,
|
|
26150
26435
|
label: `${Math.round(frame.width)}x${Math.round(frame.height)}`,
|
|
26151
26436
|
width: Math.round(frame.width),
|
|
26152
26437
|
height: Math.round(frame.height),
|
|
26153
|
-
canvasJson: JSON.stringify({
|
|
26438
|
+
canvasJson: JSON.stringify({
|
|
26439
|
+
frame: { ...frame },
|
|
26440
|
+
elements: frameChildren,
|
|
26441
|
+
...Object.keys(templateFiles).length > 0 ? { files: templateFiles } : {}
|
|
26442
|
+
})
|
|
26154
26443
|
});
|
|
26155
26444
|
templateBuilderStore.close();
|
|
26156
26445
|
};
|
|
@@ -51027,8 +51316,15 @@ var BANNER_TOOLS = [
|
|
|
51027
51316
|
parameters: {
|
|
51028
51317
|
type: "object",
|
|
51029
51318
|
properties: {
|
|
51030
|
-
query: {
|
|
51031
|
-
|
|
51319
|
+
query: {
|
|
51320
|
+
type: "string",
|
|
51321
|
+
description: "Search query \u2014 name or tag keywords"
|
|
51322
|
+
},
|
|
51323
|
+
type: {
|
|
51324
|
+
type: "string",
|
|
51325
|
+
enum: ["product", "logo", "lifestyle", "auxiliary"],
|
|
51326
|
+
description: "Optional filter by asset type"
|
|
51327
|
+
}
|
|
51032
51328
|
},
|
|
51033
51329
|
required: ["query"],
|
|
51034
51330
|
additionalProperties: false
|
|
@@ -51039,11 +51335,29 @@ var BANNER_TOOLS = [
|
|
|
51039
51335
|
type: "function",
|
|
51040
51336
|
function: {
|
|
51041
51337
|
name: "list_brand_templates",
|
|
51042
|
-
description:
|
|
51338
|
+
description: `List available brand templates by keyword search across template names, campaign tags, and labels.
|
|
51339
|
+
|
|
51340
|
+
MANDATORY SEARCH PROTOCOL \u2014 follow exactly, no shortcuts:
|
|
51341
|
+
|
|
51342
|
+
ATTEMPT 1: Generate TWO sets of 10 keywords each from the user's request:
|
|
51343
|
+
- Set A (campaign tag variations): 10 synonyms/abbreviations/phrasings of the campaign topic (e.g. for "noida datacenter": ["datacenter", "data center", "dc", "noida dc", "noida datacenter", "data centre", "server farm", "cloud infra", "hyperscale", "colocation"])
|
|
51344
|
+
- Set B (template name variations): 10 different name keywords the template might have (e.g. ["noida", "datacenter campaign", "new datacenter", "dc launch", "infrastructure", "cloud", "enterprise", "b2b", "tech", "facility"])
|
|
51345
|
+
Merge all 20 into the keywords array. Call list_brand_templates with all 20.
|
|
51346
|
+
|
|
51347
|
+
IF templates returned is empty \u2192 ATTEMPT 2 (MANDATORY \u2014 do NOT skip):
|
|
51348
|
+
Generate a completely DIFFERENT set of 20 keywords \u2014 do not reuse any from attempt 1. Think laterally: different synonyms, related industry terms, the city name, brand-adjacent words, seasonal terms. Call list_brand_templates again with the new 20.
|
|
51349
|
+
|
|
51350
|
+
ONLY after both attempts return empty \u2192 tell the user no matching template was found.
|
|
51351
|
+
|
|
51352
|
+
If no search context exists, call with an empty keywords array to list all templates.`,
|
|
51043
51353
|
parameters: {
|
|
51044
51354
|
type: "object",
|
|
51045
51355
|
properties: {
|
|
51046
|
-
|
|
51356
|
+
keywords: {
|
|
51357
|
+
type: "array",
|
|
51358
|
+
items: { type: "string" },
|
|
51359
|
+
description: "Up to 20 keyword variations to search across template names, campaign tags, and labels. All are OR-matched case-insensitively. Generate 10 tag synonyms + 10 name variations from the user's request."
|
|
51360
|
+
}
|
|
51047
51361
|
},
|
|
51048
51362
|
required: [],
|
|
51049
51363
|
additionalProperties: false
|
|
@@ -51058,7 +51372,10 @@ var BANNER_TOOLS = [
|
|
|
51058
51372
|
parameters: {
|
|
51059
51373
|
type: "object",
|
|
51060
51374
|
properties: {
|
|
51061
|
-
variantId: {
|
|
51375
|
+
variantId: {
|
|
51376
|
+
type: "string",
|
|
51377
|
+
description: "The template ID to fetch"
|
|
51378
|
+
}
|
|
51062
51379
|
},
|
|
51063
51380
|
required: ["variantId"],
|
|
51064
51381
|
additionalProperties: false
|
|
@@ -51073,8 +51390,14 @@ var BANNER_TOOLS = [
|
|
|
51073
51390
|
parameters: {
|
|
51074
51391
|
type: "object",
|
|
51075
51392
|
properties: {
|
|
51076
|
-
frameId: {
|
|
51077
|
-
|
|
51393
|
+
frameId: {
|
|
51394
|
+
type: "string",
|
|
51395
|
+
description: "The frame ID to load the template into"
|
|
51396
|
+
},
|
|
51397
|
+
variantId: {
|
|
51398
|
+
type: "string",
|
|
51399
|
+
description: "The template ID to load (from list_brand_templates)"
|
|
51400
|
+
}
|
|
51078
51401
|
},
|
|
51079
51402
|
required: ["frameId", "variantId"],
|
|
51080
51403
|
additionalProperties: false
|
|
@@ -51089,18 +51412,45 @@ var BANNER_TOOLS = [
|
|
|
51089
51412
|
parameters: {
|
|
51090
51413
|
type: "object",
|
|
51091
51414
|
properties: {
|
|
51092
|
-
frameId: {
|
|
51093
|
-
|
|
51415
|
+
frameId: {
|
|
51416
|
+
type: "string",
|
|
51417
|
+
description: "The frame ID containing slot elements"
|
|
51418
|
+
},
|
|
51419
|
+
headline: {
|
|
51420
|
+
type: "string",
|
|
51421
|
+
description: "Text for the headline slot"
|
|
51422
|
+
},
|
|
51094
51423
|
subhead: { type: "string", description: "Text for the subhead slot" },
|
|
51095
51424
|
cta: { type: "string", description: "Text for the CTA slot" },
|
|
51096
51425
|
signoff: { type: "string", description: "Text for the signoff slot" },
|
|
51097
|
-
product_image_url: {
|
|
51098
|
-
|
|
51099
|
-
|
|
51100
|
-
|
|
51101
|
-
|
|
51102
|
-
|
|
51103
|
-
|
|
51426
|
+
product_image_url: {
|
|
51427
|
+
type: "string",
|
|
51428
|
+
description: "URL for the product image slot (from search_brand_assets blobUrl, or a generated image data URL)"
|
|
51429
|
+
},
|
|
51430
|
+
product_image_asset_id: {
|
|
51431
|
+
type: "string",
|
|
51432
|
+
description: "Asset ID for the product image (from search_brand_assets [id:...] field). Required when using a brand asset so the image can be swapped later."
|
|
51433
|
+
},
|
|
51434
|
+
logo_url: {
|
|
51435
|
+
type: "string",
|
|
51436
|
+
description: "URL for the logo slot (from search_brand_assets blobUrl)"
|
|
51437
|
+
},
|
|
51438
|
+
logo_asset_id: {
|
|
51439
|
+
type: "string",
|
|
51440
|
+
description: "Asset ID for the logo (from search_brand_assets [id:...] field). Required when using a brand asset."
|
|
51441
|
+
},
|
|
51442
|
+
auxiliary_image_url: {
|
|
51443
|
+
type: "string",
|
|
51444
|
+
description: "URL for the auxiliary image slot"
|
|
51445
|
+
},
|
|
51446
|
+
auxiliary_image_asset_id: {
|
|
51447
|
+
type: "string",
|
|
51448
|
+
description: "Asset ID for the auxiliary image (from search_brand_assets [id:...] field). Required when using a brand asset."
|
|
51449
|
+
},
|
|
51450
|
+
background_color: {
|
|
51451
|
+
type: "string",
|
|
51452
|
+
description: "Hex color (e.g. #000000) for the background slot"
|
|
51453
|
+
}
|
|
51104
51454
|
},
|
|
51105
51455
|
required: ["frameId"],
|
|
51106
51456
|
additionalProperties: false
|
|
@@ -51432,12 +51782,13 @@ function execAddText(args, ctx) {
|
|
|
51432
51782
|
statusMessage: "Failed: missing frameId"
|
|
51433
51783
|
};
|
|
51434
51784
|
}
|
|
51785
|
+
const resolvedFontFamily = ctx.brandBodyFontId ?? ctx.brandHeadlineFontId ?? args.fontFamily ?? 2;
|
|
51435
51786
|
const textEl = newTextElement6({
|
|
51436
51787
|
x: args.x,
|
|
51437
51788
|
y: args.y,
|
|
51438
51789
|
text: args.text,
|
|
51439
51790
|
fontSize: args.fontSize || 20,
|
|
51440
|
-
fontFamily:
|
|
51791
|
+
fontFamily: resolvedFontFamily,
|
|
51441
51792
|
strokeColor: args.strokeColor || "#000000",
|
|
51442
51793
|
textAlign: args.textAlign || "left",
|
|
51443
51794
|
width: args.width,
|
|
@@ -51910,8 +52261,7 @@ async function execGenerateHtmlBanner(args, ctx) {
|
|
|
51910
52261
|
y: Math.round(frameY),
|
|
51911
52262
|
width: frameW,
|
|
51912
52263
|
height: frameH,
|
|
51913
|
-
elementCount: newEls.length
|
|
51914
|
-
screenshot: screenshot ?? void 0
|
|
52264
|
+
elementCount: newEls.length
|
|
51915
52265
|
},
|
|
51916
52266
|
statusMessage: `Banner updated: ${newEls.length} elements in frame "${args.name || "Banner"}" (${frameW}\xD7${frameH})`,
|
|
51917
52267
|
screenshot: screenshot ?? void 0
|
|
@@ -51935,12 +52285,19 @@ async function execSearchBrandAssets(args, ctx) {
|
|
|
51935
52285
|
const list = assets.map((a) => `- ${a.name} (${a.assetType}) [id:${a.id}]: ${a.blobUrl}`).join("\n");
|
|
51936
52286
|
return {
|
|
51937
52287
|
success: true,
|
|
51938
|
-
data: {
|
|
51939
|
-
|
|
52288
|
+
data: {
|
|
52289
|
+
assets,
|
|
52290
|
+
summary: `Found ${assets.length} brand asset(s):
|
|
52291
|
+
${list}`
|
|
52292
|
+
},
|
|
51940
52293
|
statusMessage: `Found ${assets.length} assets`
|
|
51941
52294
|
};
|
|
51942
52295
|
} catch {
|
|
51943
|
-
return {
|
|
52296
|
+
return {
|
|
52297
|
+
success: false,
|
|
52298
|
+
error: "Failed to search brand assets.",
|
|
52299
|
+
statusMessage: "Asset search failed"
|
|
52300
|
+
};
|
|
51944
52301
|
}
|
|
51945
52302
|
}
|
|
51946
52303
|
async function execFinalizeAd(args, ctx) {
|
|
@@ -51948,20 +52305,29 @@ async function execFinalizeAd(args, ctx) {
|
|
|
51948
52305
|
const screenshot = await captureFrameScreenshot(ctx.excalidrawAPI, frameId);
|
|
51949
52306
|
return {
|
|
51950
52307
|
success: true,
|
|
51951
|
-
data: { frameId
|
|
52308
|
+
data: { frameId },
|
|
51952
52309
|
statusMessage: "Ad finalized, ready for review",
|
|
51953
52310
|
screenshot: screenshot ?? void 0
|
|
51954
52311
|
};
|
|
51955
52312
|
}
|
|
51956
52313
|
async function execListBrandTemplates(args, ctx) {
|
|
51957
|
-
|
|
52314
|
+
let keywords;
|
|
52315
|
+
if (Array.isArray(args.keywords) && args.keywords.length > 0) {
|
|
52316
|
+
keywords = args.keywords;
|
|
52317
|
+
} else if (args.query || args.campaignTag) {
|
|
52318
|
+
keywords = [args.query ?? args.campaignTag];
|
|
52319
|
+
}
|
|
51958
52320
|
if (!ctx.onListBrandTemplates) {
|
|
51959
52321
|
return { success: true, statusMessage: "No template list configured" };
|
|
51960
52322
|
}
|
|
51961
52323
|
try {
|
|
51962
|
-
const templates = await ctx.onListBrandTemplates(
|
|
52324
|
+
const templates = await ctx.onListBrandTemplates(keywords);
|
|
51963
52325
|
if (templates.length === 0) {
|
|
51964
|
-
return {
|
|
52326
|
+
return {
|
|
52327
|
+
success: true,
|
|
52328
|
+
data: { templates: [] },
|
|
52329
|
+
statusMessage: "No templates found"
|
|
52330
|
+
};
|
|
51965
52331
|
}
|
|
51966
52332
|
const list = templates.map((t2) => {
|
|
51967
52333
|
const dims = t2.width && t2.height ? ` (${t2.width}x${t2.height})` : "";
|
|
@@ -51973,13 +52339,21 @@ async function execListBrandTemplates(args, ctx) {
|
|
|
51973
52339
|
statusMessage: `Found ${templates.length} template(s)`
|
|
51974
52340
|
};
|
|
51975
52341
|
} catch {
|
|
51976
|
-
return {
|
|
52342
|
+
return {
|
|
52343
|
+
success: false,
|
|
52344
|
+
error: "Failed to list brand templates.",
|
|
52345
|
+
statusMessage: "Template list failed"
|
|
52346
|
+
};
|
|
51977
52347
|
}
|
|
51978
52348
|
}
|
|
51979
52349
|
async function execGetTemplateVariant(args, ctx) {
|
|
51980
52350
|
const templateId = args.variantId;
|
|
51981
52351
|
if (!ctx.onGetTemplateVariant) {
|
|
51982
|
-
return {
|
|
52352
|
+
return {
|
|
52353
|
+
success: false,
|
|
52354
|
+
error: "Template fetching not configured.",
|
|
52355
|
+
statusMessage: "No template fetch configured"
|
|
52356
|
+
};
|
|
51983
52357
|
}
|
|
51984
52358
|
try {
|
|
51985
52359
|
const { canvasJson } = await ctx.onGetTemplateVariant(templateId);
|
|
@@ -51993,14 +52367,22 @@ async function execGetTemplateVariant(args, ctx) {
|
|
|
51993
52367
|
statusMessage: "Template fetched"
|
|
51994
52368
|
};
|
|
51995
52369
|
} catch {
|
|
51996
|
-
return {
|
|
52370
|
+
return {
|
|
52371
|
+
success: false,
|
|
52372
|
+
error: "Failed to fetch template.",
|
|
52373
|
+
statusMessage: "Template fetch failed"
|
|
52374
|
+
};
|
|
51997
52375
|
}
|
|
51998
52376
|
}
|
|
51999
52377
|
async function execLoadTemplateIntoFrame(args, ctx) {
|
|
52000
52378
|
const frameId = args.frameId;
|
|
52001
52379
|
const templateId = args.variantId;
|
|
52002
52380
|
if (!ctx.onGetTemplateVariant) {
|
|
52003
|
-
return {
|
|
52381
|
+
return {
|
|
52382
|
+
success: false,
|
|
52383
|
+
error: "Template fetching not configured.",
|
|
52384
|
+
statusMessage: "No template fetch configured"
|
|
52385
|
+
};
|
|
52004
52386
|
}
|
|
52005
52387
|
try {
|
|
52006
52388
|
const cachedJson = ctx._templateJsonCache?.get(templateId);
|
|
@@ -52025,7 +52407,11 @@ async function execLoadTemplateIntoFrame(args, ctx) {
|
|
|
52025
52407
|
const allElements = ctx.excalidrawAPI.getSceneElements();
|
|
52026
52408
|
const targetFrame = allElements.find((el) => el.id === frameId);
|
|
52027
52409
|
if (!targetFrame) {
|
|
52028
|
-
return {
|
|
52410
|
+
return {
|
|
52411
|
+
success: false,
|
|
52412
|
+
error: `Frame ${frameId} not found.`,
|
|
52413
|
+
statusMessage: "Frame not found"
|
|
52414
|
+
};
|
|
52029
52415
|
}
|
|
52030
52416
|
const withoutOldChildren = allElements.filter(
|
|
52031
52417
|
(el) => el.frameId !== frameId
|
|
@@ -52051,6 +52437,18 @@ async function execLoadTemplateIntoFrame(args, ctx) {
|
|
|
52051
52437
|
];
|
|
52052
52438
|
const merged = syncMovedIndices7(mergedArr, arrayToMap30(mergedArr));
|
|
52053
52439
|
ctx.excalidrawAPI.updateScene({ elements: merged });
|
|
52440
|
+
const templateFiles = parsed.files;
|
|
52441
|
+
if (templateFiles && Object.keys(templateFiles).length > 0) {
|
|
52442
|
+
ctx.excalidrawAPI.addFiles(
|
|
52443
|
+
Object.entries(templateFiles).map(([fileId, file2]) => ({
|
|
52444
|
+
id: fileId,
|
|
52445
|
+
dataURL: file2.dataURL,
|
|
52446
|
+
mimeType: file2.mimeType,
|
|
52447
|
+
created: Date.now(),
|
|
52448
|
+
lastRetrieved: Date.now()
|
|
52449
|
+
}))
|
|
52450
|
+
);
|
|
52451
|
+
}
|
|
52054
52452
|
if (templateId) {
|
|
52055
52453
|
const frameEl = ctx.excalidrawAPI.getSceneElements().find((el) => el.id === frameId);
|
|
52056
52454
|
if (frameEl) {
|
|
@@ -52062,7 +52460,11 @@ async function execLoadTemplateIntoFrame(args, ctx) {
|
|
|
52062
52460
|
});
|
|
52063
52461
|
}
|
|
52064
52462
|
}
|
|
52065
|
-
return {
|
|
52463
|
+
return {
|
|
52464
|
+
success: true,
|
|
52465
|
+
data: { frameId },
|
|
52466
|
+
statusMessage: "Template loaded"
|
|
52467
|
+
};
|
|
52066
52468
|
} catch (e) {
|
|
52067
52469
|
return {
|
|
52068
52470
|
success: false,
|
|
@@ -52112,7 +52514,12 @@ function fitFontSize(text, slotEl) {
|
|
|
52112
52514
|
}
|
|
52113
52515
|
}
|
|
52114
52516
|
if (bestFs !== -1) {
|
|
52115
|
-
return {
|
|
52517
|
+
return {
|
|
52518
|
+
fontSize: bestFs,
|
|
52519
|
+
wrappedText: bestWrapped,
|
|
52520
|
+
height: bestHeight,
|
|
52521
|
+
autoResize: false
|
|
52522
|
+
};
|
|
52116
52523
|
}
|
|
52117
52524
|
const minCheck = testFit(MIN_FONT_SIZE3);
|
|
52118
52525
|
return {
|
|
@@ -52152,8 +52559,9 @@ async function execFillTemplateSlots(args, ctx) {
|
|
|
52152
52559
|
const imageJobs = [];
|
|
52153
52560
|
allElements.forEach((el, index) => {
|
|
52154
52561
|
const elAny = el;
|
|
52155
|
-
if (elAny.frameId !== frameId)
|
|
52562
|
+
if (elAny.frameId !== frameId) {
|
|
52156
52563
|
return;
|
|
52564
|
+
}
|
|
52157
52565
|
const slotType = elAny.customData?.slotType;
|
|
52158
52566
|
const url = slotType ? imageUrlBySlotType[slotType] : void 0;
|
|
52159
52567
|
if (url) {
|
|
@@ -52172,8 +52580,9 @@ async function execFillTemplateSlots(args, ctx) {
|
|
|
52172
52580
|
imageJobs.map(async (job) => {
|
|
52173
52581
|
try {
|
|
52174
52582
|
const res = await fetch(job.url);
|
|
52175
|
-
if (!res.ok)
|
|
52583
|
+
if (!res.ok) {
|
|
52176
52584
|
return;
|
|
52585
|
+
}
|
|
52177
52586
|
const blob = await res.blob();
|
|
52178
52587
|
const dataURL = await new Promise((resolve, reject) => {
|
|
52179
52588
|
const reader = new FileReader();
|
|
@@ -52190,8 +52599,9 @@ async function execFillTemplateSlots(args, ctx) {
|
|
|
52190
52599
|
await Promise.all(
|
|
52191
52600
|
imageJobs.map(
|
|
52192
52601
|
(job) => new Promise((resolve) => {
|
|
52193
|
-
if (!job.dataURL)
|
|
52602
|
+
if (!job.dataURL) {
|
|
52194
52603
|
return resolve();
|
|
52604
|
+
}
|
|
52195
52605
|
const img = new Image();
|
|
52196
52606
|
img.onload = () => {
|
|
52197
52607
|
job.naturalWidth = img.naturalWidth;
|
|
@@ -52205,8 +52615,9 @@ async function execFillTemplateSlots(args, ctx) {
|
|
|
52205
52615
|
);
|
|
52206
52616
|
const imageReplacements = /* @__PURE__ */ new Map();
|
|
52207
52617
|
for (const job of imageJobs) {
|
|
52208
|
-
if (!job.fileId)
|
|
52618
|
+
if (!job.fileId) {
|
|
52209
52619
|
continue;
|
|
52620
|
+
}
|
|
52210
52621
|
const { x, y, width, height } = containFit(
|
|
52211
52622
|
job.el.x,
|
|
52212
52623
|
job.el.y,
|
|
@@ -52244,28 +52655,35 @@ async function execFillTemplateSlots(args, ctx) {
|
|
|
52244
52655
|
let filledCount = 0;
|
|
52245
52656
|
const updatedElements = allElements.map((el, index) => {
|
|
52246
52657
|
const elWithFrame = el;
|
|
52247
|
-
if (elWithFrame.frameId !== frameId)
|
|
52658
|
+
if (elWithFrame.frameId !== frameId) {
|
|
52248
52659
|
return el;
|
|
52660
|
+
}
|
|
52249
52661
|
const slotType = elWithFrame.customData?.slotType;
|
|
52250
|
-
if (!slotType)
|
|
52662
|
+
if (!slotType) {
|
|
52251
52663
|
return el;
|
|
52664
|
+
}
|
|
52252
52665
|
if (imageReplacements.has(index)) {
|
|
52253
52666
|
filledCount++;
|
|
52254
52667
|
return imageReplacements.get(index);
|
|
52255
52668
|
}
|
|
52256
52669
|
let mutation = {};
|
|
52257
|
-
const makeTextMutation = (value) => {
|
|
52258
|
-
const { fontSize, wrappedText, height, autoResize } = fitFontSize(
|
|
52670
|
+
const makeTextMutation = (value, useHeadlineFont = false) => {
|
|
52671
|
+
const { fontSize, wrappedText, height, autoResize } = fitFontSize(
|
|
52672
|
+
value,
|
|
52673
|
+
el
|
|
52674
|
+
);
|
|
52675
|
+
const brandFontId = useHeadlineFont ? ctx.brandHeadlineFontId ?? ctx.brandBodyFontId : ctx.brandBodyFontId;
|
|
52259
52676
|
return {
|
|
52260
52677
|
text: wrappedText,
|
|
52261
52678
|
originalText: value,
|
|
52262
52679
|
fontSize,
|
|
52263
52680
|
height,
|
|
52264
|
-
autoResize
|
|
52681
|
+
autoResize,
|
|
52682
|
+
...brandFontId !== void 0 ? { fontFamily: brandFontId } : {}
|
|
52265
52683
|
};
|
|
52266
52684
|
};
|
|
52267
52685
|
if (slotType === "headline" && args.headline) {
|
|
52268
|
-
mutation = makeTextMutation(args.headline);
|
|
52686
|
+
mutation = makeTextMutation(args.headline, true);
|
|
52269
52687
|
} else if (slotType === "subhead" && args.subhead) {
|
|
52270
52688
|
mutation = makeTextMutation(args.subhead);
|
|
52271
52689
|
} else if (slotType === "cta" && args.cta) {
|
|
@@ -52491,7 +52909,11 @@ When the design needs a full-frame photorealistic background (a scene, landscape
|
|
|
52491
52909
|
Use hex (\`#rrggbb\`) or \`rgba(r,g,b,a)\`. No named colors (no \`red\`, \`blue\`). CSS gradients (\`linear-gradient\`, \`radial-gradient\`) are allowed.
|
|
52492
52910
|
|
|
52493
52911
|
### 7. Fonts
|
|
52494
|
-
|
|
52912
|
+
**MANDATORY \u2014 Brand font enforcement:**
|
|
52913
|
+
- If the Brand Identity context specifies fonts with a registered fontFamilyId, you MUST use those fonts everywhere. Do NOT use any other font \u2014 no Arial, no Helvetica, no web-safe fallbacks as primary fonts.
|
|
52914
|
+
- In HTML \`<style>\` blocks: use the exact brand font-family name (e.g. \`font-family: "Brand Font Name", sans-serif\`). The canvas renderer maps this name to the registered font automatically.
|
|
52915
|
+
- For \`add_text\` calls: the system enforces the brand fontFamilyId automatically \u2014 you do not need to pass a fontFamily param.
|
|
52916
|
+
- Only fall back to web-safe fonts (\`Arial\`, \`"Helvetica Neue"\`, \`sans-serif\`) when the Brand Identity context has no font specified at all.
|
|
52495
52917
|
|
|
52496
52918
|
### 9. No unsupported features
|
|
52497
52919
|
No \`transform\`, \`animation\`, \`transition\`, \`filter\`, \`clip-path\`, \`<img>\` tags, or JavaScript. No \`box-shadow\`.
|
|
@@ -52590,8 +53012,10 @@ ASSET USE MANDATE: If search_brand_assets() returns any results, you MUST incorp
|
|
|
52590
53012
|
|
|
52591
53013
|
IMAGE GENERATION SCOPE: generate_image is only for supplementary content images (backgrounds, lifestyle photography) where no brand asset matches AND the brief explicitly requires a photo or illustration. For solid-color backgrounds or brand-asset-only ads, skip generate_image entirely.
|
|
52592
53014
|
|
|
52593
|
-
TEMPLATE BANK:
|
|
52594
|
-
|
|
53015
|
+
TEMPLATE BANK: Whenever the user asks to create, make, or build an ad \u2014 even without mentioning templates \u2014 call \`list_brand_templates()\` as your very first action before asking any clarifying questions. Use the returned catalog to ask smarter, more specific questions (e.g. "I see you have a Noida Campaign template \u2014 should I use that, or build from scratch?"). If multiple templates could match, ask which one to use. If none match or the user prefers no template, proceed with HTML generation. Only skip this tool call for messages that are clearly not ad-creation requests (greetings, questions, edits to existing canvas elements, etc.).
|
|
53016
|
+
|
|
53017
|
+
Template workflow once you know which template to use:
|
|
53018
|
+
1. Call \`list_brand_templates()\` to see available templates (already done above)
|
|
52595
53019
|
2. Call \`load_template_into_frame(frameId, variantId)\` to insert the template
|
|
52596
53020
|
3. Call \`get_frame_elements(frameId)\` to inspect which slot types exist (headline, subhead, cta, background, product_image, logo, etc.)
|
|
52597
53021
|
4. For each **image slot** found (product_image, logo): call \`search_brand_assets()\` to look up the asset. Pass the returned \`blobUrl\` as \`product_image_url\` or \`logo_url\` to \`fill_template_slots\`. Only call \`generate_image\` if no matching asset exists in the bank.
|
|
@@ -52714,7 +53138,7 @@ function buildBrandContextMessage(ctx) {
|
|
|
52714
53138
|
const { headline, body } = ctx.typography;
|
|
52715
53139
|
if (headline?.family) {
|
|
52716
53140
|
const sizeHint = headline.sizeScale ? ` (suggested size: ${SIZE_SCALE_MAP[headline.sizeScale] ?? headline.sizeScale})` : "";
|
|
52717
|
-
const idNote = headline.fontFamilyId ? ` \u2014
|
|
53141
|
+
const idNote = headline.fontFamilyId ? ` \u2014 MANDATORY: use \`font-family: "${headline.family}", sans-serif\` in ALL HTML CSS for headlines. Do NOT use any other font.` : ` \u2014 no custom font file loaded; use \`font-family: "${headline.family}", Arial, sans-serif\` in your HTML CSS (will render as Arial on canvas)`;
|
|
52718
53142
|
const fileNote = headline.fontName ? ` [file: ${headline.fontName}]` : "";
|
|
52719
53143
|
lines.push(
|
|
52720
53144
|
`**Headline font**: ${headline.family}${headline.weight ? ` weight ${headline.weight}` : ""}${sizeHint}${idNote}${fileNote}`
|
|
@@ -52722,7 +53146,7 @@ function buildBrandContextMessage(ctx) {
|
|
|
52722
53146
|
}
|
|
52723
53147
|
if (body?.family) {
|
|
52724
53148
|
const sizeHint = body.sizeScale ? ` (suggested size: ${SIZE_SCALE_MAP[body.sizeScale] ?? body.sizeScale})` : "";
|
|
52725
|
-
const idNote = body.fontFamilyId ? ` \u2014
|
|
53149
|
+
const idNote = body.fontFamilyId ? ` \u2014 MANDATORY: use \`font-family: "${body.family}", sans-serif\` in ALL HTML CSS for body copy, subheads, CTAs, and any other text. Do NOT use any other font.` : ` \u2014 no custom font file loaded; use \`font-family: "${body.family}", Arial, sans-serif\` in your HTML CSS (will render as Arial on canvas)`;
|
|
52726
53150
|
const fileNote = body.fontName ? ` [file: ${body.fontName}]` : "";
|
|
52727
53151
|
lines.push(
|
|
52728
53152
|
`**Body font**: ${body.family}${body.weight ? ` weight ${body.weight}` : ""}${sizeHint}${idNote}${fileNote}`
|
|
@@ -52826,7 +53250,9 @@ async function runAgentLoop(opts) {
|
|
|
52826
53250
|
...Object.keys(customFontMap).length ? { customFontMap } : {},
|
|
52827
53251
|
...allImageAttachments.length ? { fileAttachments: allImageAttachments } : {},
|
|
52828
53252
|
...brandContext?.typography?.headline?.fontName ? { brandHeadlineFontName: brandContext.typography.headline.fontName } : {},
|
|
52829
|
-
...brandContext?.typography?.body?.fontName ? { brandBodyFontName: brandContext.typography.body.fontName } : {}
|
|
53253
|
+
...brandContext?.typography?.body?.fontName ? { brandBodyFontName: brandContext.typography.body.fontName } : {},
|
|
53254
|
+
...brandContext?.typography?.headline?.fontFamilyId ? { brandHeadlineFontId: brandContext.typography.headline.fontFamilyId } : {},
|
|
53255
|
+
...brandContext?.typography?.body?.fontFamilyId ? { brandBodyFontId: brandContext.typography.body.fontFamilyId } : {}
|
|
52830
53256
|
};
|
|
52831
53257
|
const messages = [{ role: "system", content: SYSTEM_PROMPT }];
|
|
52832
53258
|
if (brandContext) {
|
|
@@ -52953,9 +53379,10 @@ ${f.textContent}`).join("\n\n")}`;
|
|
|
52953
53379
|
statusMessage: error || "Insufficient credits for image generation"
|
|
52954
53380
|
};
|
|
52955
53381
|
const gatedAction = {
|
|
52956
|
-
|
|
52957
|
-
|
|
52958
|
-
|
|
53382
|
+
result: {
|
|
53383
|
+
success: gatedResult.success,
|
|
53384
|
+
statusMessage: gatedResult.statusMessage
|
|
53385
|
+
}
|
|
52959
53386
|
};
|
|
52960
53387
|
toolActions.push(gatedAction);
|
|
52961
53388
|
onUpdate({
|
|
@@ -52981,9 +53408,10 @@ ${f.textContent}`).join("\n\n")}`;
|
|
|
52981
53408
|
statusMessage: "Blocked: template already provides text slots"
|
|
52982
53409
|
};
|
|
52983
53410
|
const blockedAction = {
|
|
52984
|
-
|
|
52985
|
-
|
|
52986
|
-
|
|
53411
|
+
result: {
|
|
53412
|
+
success: blockedResult.success,
|
|
53413
|
+
statusMessage: blockedResult.statusMessage
|
|
53414
|
+
}
|
|
52987
53415
|
};
|
|
52988
53416
|
toolActions.push(blockedAction);
|
|
52989
53417
|
onUpdate({
|
|
@@ -52994,7 +53422,10 @@ ${f.textContent}`).join("\n\n")}`;
|
|
|
52994
53422
|
messages.push({
|
|
52995
53423
|
role: "tool",
|
|
52996
53424
|
tool_call_id: toolCall.id,
|
|
52997
|
-
content: JSON.stringify({
|
|
53425
|
+
content: JSON.stringify({
|
|
53426
|
+
success: false,
|
|
53427
|
+
error: blockedResult.error
|
|
53428
|
+
})
|
|
52998
53429
|
});
|
|
52999
53430
|
continue;
|
|
53000
53431
|
}
|
|
@@ -53018,9 +53449,10 @@ ${f.textContent}`).join("\n\n")}`;
|
|
|
53018
53449
|
}
|
|
53019
53450
|
}
|
|
53020
53451
|
const action = {
|
|
53021
|
-
|
|
53022
|
-
|
|
53023
|
-
|
|
53452
|
+
result: {
|
|
53453
|
+
success: result.success,
|
|
53454
|
+
statusMessage: result.statusMessage
|
|
53455
|
+
}
|
|
53024
53456
|
};
|
|
53025
53457
|
toolActions.push(action);
|
|
53026
53458
|
onUpdate({
|
|
@@ -54451,7 +54883,12 @@ var AIChatPanel = React63.forwardRef(
|
|
|
54451
54883
|
actions: msg.toolActions
|
|
54452
54884
|
}
|
|
54453
54885
|
),
|
|
54454
|
-
msg.reviewFeedback && /* @__PURE__ */ jsx192(
|
|
54886
|
+
msg.reviewFeedback && /* @__PURE__ */ jsx192(
|
|
54887
|
+
ReviewCritiqueCard,
|
|
54888
|
+
{
|
|
54889
|
+
feedback: msg.reviewFeedback
|
|
54890
|
+
}
|
|
54891
|
+
),
|
|
54455
54892
|
/* @__PURE__ */ jsx192(
|
|
54456
54893
|
MessageContent,
|
|
54457
54894
|
{
|
|
@@ -54745,44 +55182,65 @@ function ToolActionsDisplay({ actions: actions2 }) {
|
|
|
54745
55182
|
function ReviewCritiqueCard({ feedback }) {
|
|
54746
55183
|
const [expanded, setExpanded] = useState55(false);
|
|
54747
55184
|
const severityClass = (severity) => {
|
|
54748
|
-
if (severity === "critical")
|
|
55185
|
+
if (severity === "critical") {
|
|
54749
55186
|
return "acp-review-issue--critical";
|
|
54750
|
-
|
|
55187
|
+
}
|
|
55188
|
+
if (severity === "major") {
|
|
54751
55189
|
return "acp-review-issue--major";
|
|
55190
|
+
}
|
|
54752
55191
|
return "acp-review-issue--minor";
|
|
54753
55192
|
};
|
|
54754
55193
|
const approved = feedback.approved;
|
|
54755
|
-
return /* @__PURE__ */ jsxs106(
|
|
54756
|
-
|
|
54757
|
-
|
|
54758
|
-
{
|
|
54759
|
-
|
|
54760
|
-
|
|
54761
|
-
|
|
54762
|
-
|
|
54763
|
-
|
|
54764
|
-
|
|
54765
|
-
|
|
54766
|
-
|
|
54767
|
-
|
|
54768
|
-
|
|
54769
|
-
|
|
54770
|
-
|
|
54771
|
-
|
|
54772
|
-
|
|
54773
|
-
|
|
54774
|
-
|
|
54775
|
-
|
|
54776
|
-
|
|
54777
|
-
|
|
54778
|
-
|
|
54779
|
-
|
|
54780
|
-
|
|
54781
|
-
|
|
54782
|
-
|
|
54783
|
-
|
|
54784
|
-
|
|
54785
|
-
|
|
55194
|
+
return /* @__PURE__ */ jsxs106(
|
|
55195
|
+
"div",
|
|
55196
|
+
{
|
|
55197
|
+
className: `acp-review-card ${approved ? "acp-review-card--ok" : "acp-review-card--issues"}`,
|
|
55198
|
+
children: [
|
|
55199
|
+
/* @__PURE__ */ jsxs106(
|
|
55200
|
+
"button",
|
|
55201
|
+
{
|
|
55202
|
+
className: "acp-review-toggle",
|
|
55203
|
+
onClick: () => setExpanded((v) => !v),
|
|
55204
|
+
children: [
|
|
55205
|
+
/* @__PURE__ */ jsx192(
|
|
55206
|
+
"span",
|
|
55207
|
+
{
|
|
55208
|
+
className: `acp-review-badge ${approved ? "acp-review-badge--ok" : "acp-review-badge--issues"}`,
|
|
55209
|
+
children: approved ? "\u2713 Design approved" : `${feedback.issues.length} issue${feedback.issues.length !== 1 ? "s" : ""} found`
|
|
55210
|
+
}
|
|
55211
|
+
),
|
|
55212
|
+
/* @__PURE__ */ jsx192("span", { className: "acp-review-summary", children: feedback.summary }),
|
|
55213
|
+
!approved && feedback.issues.length > 0 && /* @__PURE__ */ jsx192(
|
|
55214
|
+
ChevronRight,
|
|
55215
|
+
{
|
|
55216
|
+
size: 12,
|
|
55217
|
+
className: `acp-tool-chevron ${expanded ? "acp-tool-chevron--open" : ""}`
|
|
55218
|
+
}
|
|
55219
|
+
)
|
|
55220
|
+
]
|
|
55221
|
+
}
|
|
55222
|
+
),
|
|
55223
|
+
expanded && !approved && feedback.issues.length > 0 && /* @__PURE__ */ jsx192("div", { className: "acp-review-issues", children: feedback.issues.map((iss, i) => /* @__PURE__ */ jsxs106(
|
|
55224
|
+
"div",
|
|
55225
|
+
{
|
|
55226
|
+
className: `acp-review-issue ${severityClass(iss.severity)}`,
|
|
55227
|
+
children: [
|
|
55228
|
+
/* @__PURE__ */ jsxs106("div", { className: "acp-review-issue-header", children: [
|
|
55229
|
+
/* @__PURE__ */ jsx192("span", { className: "acp-review-issue-severity", children: iss.severity }),
|
|
55230
|
+
/* @__PURE__ */ jsx192("span", { className: "acp-review-issue-element", children: iss.element }),
|
|
55231
|
+
/* @__PURE__ */ jsx192("span", { className: "acp-review-issue-problem", children: iss.problem })
|
|
55232
|
+
] }),
|
|
55233
|
+
/* @__PURE__ */ jsxs106("div", { className: "acp-review-issue-fix", children: [
|
|
55234
|
+
"\u2192 ",
|
|
55235
|
+
iss.preciseInstruction
|
|
55236
|
+
] })
|
|
55237
|
+
]
|
|
55238
|
+
},
|
|
55239
|
+
i
|
|
55240
|
+
)) })
|
|
55241
|
+
]
|
|
55242
|
+
}
|
|
55243
|
+
);
|
|
54786
55244
|
}
|
|
54787
55245
|
async function callPlainChatAPI(messages, apiKey, signal, opts) {
|
|
54788
55246
|
const baseModel = opts?.chatModel || "google/gemini-3.1-flash-lite-preview";
|