@orangecatai/adgen-canvas 0.0.15 → 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-EL4HTLYE.js → chunk-4VEZT6GV.js} +2 -2
- package/dist/dev/{chunk-FGSZO5WI.js → chunk-UJP3DIYP.js} +3 -3
- package/dist/dev/data/{image-AVR5GHYZ.js → image-PZBTJSVV.js} +3 -3
- package/dist/dev/index.js +564 -140
- package/dist/dev/index.js.map +3 -3
- package/dist/dev/subset-shared.chunk.js +1 -1
- package/dist/dev/subset-worker.chunk.js +1 -1
- package/dist/prod/{chunk-WLACMVHN.js → chunk-62H5HX6J.js} +1 -1
- package/dist/prod/{chunk-5UTVS66N.js → chunk-VXQSQDGS.js} +2 -2
- package/dist/prod/data/image-REZEAPVS.js +1 -0
- package/dist/prod/index.js +21 -7
- 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/canvasTools.d.ts +8 -5
- package/dist/types/excalidraw/index.d.ts +1 -1
- package/package.json +1 -1
- package/dist/prod/data/image-FOOXCTEO.js +0 -1
- /package/dist/dev/{chunk-EL4HTLYE.js.map → chunk-4VEZT6GV.js.map} +0 -0
- /package/dist/dev/{chunk-FGSZO5WI.js.map → chunk-UJP3DIYP.js.map} +0 -0
- /package/dist/dev/data/{image-AVR5GHYZ.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,14 +26398,19 @@ 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];
|
|
@@ -51045,8 +51316,15 @@ var BANNER_TOOLS = [
|
|
|
51045
51316
|
parameters: {
|
|
51046
51317
|
type: "object",
|
|
51047
51318
|
properties: {
|
|
51048
|
-
query: {
|
|
51049
|
-
|
|
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
|
+
}
|
|
51050
51328
|
},
|
|
51051
51329
|
required: ["query"],
|
|
51052
51330
|
additionalProperties: false
|
|
@@ -51057,11 +51335,29 @@ var BANNER_TOOLS = [
|
|
|
51057
51335
|
type: "function",
|
|
51058
51336
|
function: {
|
|
51059
51337
|
name: "list_brand_templates",
|
|
51060
|
-
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.`,
|
|
51061
51353
|
parameters: {
|
|
51062
51354
|
type: "object",
|
|
51063
51355
|
properties: {
|
|
51064
|
-
|
|
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
|
+
}
|
|
51065
51361
|
},
|
|
51066
51362
|
required: [],
|
|
51067
51363
|
additionalProperties: false
|
|
@@ -51076,7 +51372,10 @@ var BANNER_TOOLS = [
|
|
|
51076
51372
|
parameters: {
|
|
51077
51373
|
type: "object",
|
|
51078
51374
|
properties: {
|
|
51079
|
-
variantId: {
|
|
51375
|
+
variantId: {
|
|
51376
|
+
type: "string",
|
|
51377
|
+
description: "The template ID to fetch"
|
|
51378
|
+
}
|
|
51080
51379
|
},
|
|
51081
51380
|
required: ["variantId"],
|
|
51082
51381
|
additionalProperties: false
|
|
@@ -51091,8 +51390,14 @@ var BANNER_TOOLS = [
|
|
|
51091
51390
|
parameters: {
|
|
51092
51391
|
type: "object",
|
|
51093
51392
|
properties: {
|
|
51094
|
-
frameId: {
|
|
51095
|
-
|
|
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
|
+
}
|
|
51096
51401
|
},
|
|
51097
51402
|
required: ["frameId", "variantId"],
|
|
51098
51403
|
additionalProperties: false
|
|
@@ -51107,18 +51412,45 @@ var BANNER_TOOLS = [
|
|
|
51107
51412
|
parameters: {
|
|
51108
51413
|
type: "object",
|
|
51109
51414
|
properties: {
|
|
51110
|
-
frameId: {
|
|
51111
|
-
|
|
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
|
+
},
|
|
51112
51423
|
subhead: { type: "string", description: "Text for the subhead slot" },
|
|
51113
51424
|
cta: { type: "string", description: "Text for the CTA slot" },
|
|
51114
51425
|
signoff: { type: "string", description: "Text for the signoff slot" },
|
|
51115
|
-
product_image_url: {
|
|
51116
|
-
|
|
51117
|
-
|
|
51118
|
-
|
|
51119
|
-
|
|
51120
|
-
|
|
51121
|
-
|
|
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
|
+
}
|
|
51122
51454
|
},
|
|
51123
51455
|
required: ["frameId"],
|
|
51124
51456
|
additionalProperties: false
|
|
@@ -51953,12 +52285,19 @@ async function execSearchBrandAssets(args, ctx) {
|
|
|
51953
52285
|
const list = assets.map((a) => `- ${a.name} (${a.assetType}) [id:${a.id}]: ${a.blobUrl}`).join("\n");
|
|
51954
52286
|
return {
|
|
51955
52287
|
success: true,
|
|
51956
|
-
data: {
|
|
51957
|
-
|
|
52288
|
+
data: {
|
|
52289
|
+
assets,
|
|
52290
|
+
summary: `Found ${assets.length} brand asset(s):
|
|
52291
|
+
${list}`
|
|
52292
|
+
},
|
|
51958
52293
|
statusMessage: `Found ${assets.length} assets`
|
|
51959
52294
|
};
|
|
51960
52295
|
} catch {
|
|
51961
|
-
return {
|
|
52296
|
+
return {
|
|
52297
|
+
success: false,
|
|
52298
|
+
error: "Failed to search brand assets.",
|
|
52299
|
+
statusMessage: "Asset search failed"
|
|
52300
|
+
};
|
|
51962
52301
|
}
|
|
51963
52302
|
}
|
|
51964
52303
|
async function execFinalizeAd(args, ctx) {
|
|
@@ -51972,14 +52311,23 @@ async function execFinalizeAd(args, ctx) {
|
|
|
51972
52311
|
};
|
|
51973
52312
|
}
|
|
51974
52313
|
async function execListBrandTemplates(args, ctx) {
|
|
51975
|
-
|
|
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
|
+
}
|
|
51976
52320
|
if (!ctx.onListBrandTemplates) {
|
|
51977
52321
|
return { success: true, statusMessage: "No template list configured" };
|
|
51978
52322
|
}
|
|
51979
52323
|
try {
|
|
51980
|
-
const templates = await ctx.onListBrandTemplates(
|
|
52324
|
+
const templates = await ctx.onListBrandTemplates(keywords);
|
|
51981
52325
|
if (templates.length === 0) {
|
|
51982
|
-
return {
|
|
52326
|
+
return {
|
|
52327
|
+
success: true,
|
|
52328
|
+
data: { templates: [] },
|
|
52329
|
+
statusMessage: "No templates found"
|
|
52330
|
+
};
|
|
51983
52331
|
}
|
|
51984
52332
|
const list = templates.map((t2) => {
|
|
51985
52333
|
const dims = t2.width && t2.height ? ` (${t2.width}x${t2.height})` : "";
|
|
@@ -51991,13 +52339,21 @@ async function execListBrandTemplates(args, ctx) {
|
|
|
51991
52339
|
statusMessage: `Found ${templates.length} template(s)`
|
|
51992
52340
|
};
|
|
51993
52341
|
} catch {
|
|
51994
|
-
return {
|
|
52342
|
+
return {
|
|
52343
|
+
success: false,
|
|
52344
|
+
error: "Failed to list brand templates.",
|
|
52345
|
+
statusMessage: "Template list failed"
|
|
52346
|
+
};
|
|
51995
52347
|
}
|
|
51996
52348
|
}
|
|
51997
52349
|
async function execGetTemplateVariant(args, ctx) {
|
|
51998
52350
|
const templateId = args.variantId;
|
|
51999
52351
|
if (!ctx.onGetTemplateVariant) {
|
|
52000
|
-
return {
|
|
52352
|
+
return {
|
|
52353
|
+
success: false,
|
|
52354
|
+
error: "Template fetching not configured.",
|
|
52355
|
+
statusMessage: "No template fetch configured"
|
|
52356
|
+
};
|
|
52001
52357
|
}
|
|
52002
52358
|
try {
|
|
52003
52359
|
const { canvasJson } = await ctx.onGetTemplateVariant(templateId);
|
|
@@ -52011,14 +52367,22 @@ async function execGetTemplateVariant(args, ctx) {
|
|
|
52011
52367
|
statusMessage: "Template fetched"
|
|
52012
52368
|
};
|
|
52013
52369
|
} catch {
|
|
52014
|
-
return {
|
|
52370
|
+
return {
|
|
52371
|
+
success: false,
|
|
52372
|
+
error: "Failed to fetch template.",
|
|
52373
|
+
statusMessage: "Template fetch failed"
|
|
52374
|
+
};
|
|
52015
52375
|
}
|
|
52016
52376
|
}
|
|
52017
52377
|
async function execLoadTemplateIntoFrame(args, ctx) {
|
|
52018
52378
|
const frameId = args.frameId;
|
|
52019
52379
|
const templateId = args.variantId;
|
|
52020
52380
|
if (!ctx.onGetTemplateVariant) {
|
|
52021
|
-
return {
|
|
52381
|
+
return {
|
|
52382
|
+
success: false,
|
|
52383
|
+
error: "Template fetching not configured.",
|
|
52384
|
+
statusMessage: "No template fetch configured"
|
|
52385
|
+
};
|
|
52022
52386
|
}
|
|
52023
52387
|
try {
|
|
52024
52388
|
const cachedJson = ctx._templateJsonCache?.get(templateId);
|
|
@@ -52043,7 +52407,11 @@ async function execLoadTemplateIntoFrame(args, ctx) {
|
|
|
52043
52407
|
const allElements = ctx.excalidrawAPI.getSceneElements();
|
|
52044
52408
|
const targetFrame = allElements.find((el) => el.id === frameId);
|
|
52045
52409
|
if (!targetFrame) {
|
|
52046
|
-
return {
|
|
52410
|
+
return {
|
|
52411
|
+
success: false,
|
|
52412
|
+
error: `Frame ${frameId} not found.`,
|
|
52413
|
+
statusMessage: "Frame not found"
|
|
52414
|
+
};
|
|
52047
52415
|
}
|
|
52048
52416
|
const withoutOldChildren = allElements.filter(
|
|
52049
52417
|
(el) => el.frameId !== frameId
|
|
@@ -52092,7 +52460,11 @@ async function execLoadTemplateIntoFrame(args, ctx) {
|
|
|
52092
52460
|
});
|
|
52093
52461
|
}
|
|
52094
52462
|
}
|
|
52095
|
-
return {
|
|
52463
|
+
return {
|
|
52464
|
+
success: true,
|
|
52465
|
+
data: { frameId },
|
|
52466
|
+
statusMessage: "Template loaded"
|
|
52467
|
+
};
|
|
52096
52468
|
} catch (e) {
|
|
52097
52469
|
return {
|
|
52098
52470
|
success: false,
|
|
@@ -52142,7 +52514,12 @@ function fitFontSize(text, slotEl) {
|
|
|
52142
52514
|
}
|
|
52143
52515
|
}
|
|
52144
52516
|
if (bestFs !== -1) {
|
|
52145
|
-
return {
|
|
52517
|
+
return {
|
|
52518
|
+
fontSize: bestFs,
|
|
52519
|
+
wrappedText: bestWrapped,
|
|
52520
|
+
height: bestHeight,
|
|
52521
|
+
autoResize: false
|
|
52522
|
+
};
|
|
52146
52523
|
}
|
|
52147
52524
|
const minCheck = testFit(MIN_FONT_SIZE3);
|
|
52148
52525
|
return {
|
|
@@ -52182,8 +52559,9 @@ async function execFillTemplateSlots(args, ctx) {
|
|
|
52182
52559
|
const imageJobs = [];
|
|
52183
52560
|
allElements.forEach((el, index) => {
|
|
52184
52561
|
const elAny = el;
|
|
52185
|
-
if (elAny.frameId !== frameId)
|
|
52562
|
+
if (elAny.frameId !== frameId) {
|
|
52186
52563
|
return;
|
|
52564
|
+
}
|
|
52187
52565
|
const slotType = elAny.customData?.slotType;
|
|
52188
52566
|
const url = slotType ? imageUrlBySlotType[slotType] : void 0;
|
|
52189
52567
|
if (url) {
|
|
@@ -52202,8 +52580,9 @@ async function execFillTemplateSlots(args, ctx) {
|
|
|
52202
52580
|
imageJobs.map(async (job) => {
|
|
52203
52581
|
try {
|
|
52204
52582
|
const res = await fetch(job.url);
|
|
52205
|
-
if (!res.ok)
|
|
52583
|
+
if (!res.ok) {
|
|
52206
52584
|
return;
|
|
52585
|
+
}
|
|
52207
52586
|
const blob = await res.blob();
|
|
52208
52587
|
const dataURL = await new Promise((resolve, reject) => {
|
|
52209
52588
|
const reader = new FileReader();
|
|
@@ -52220,8 +52599,9 @@ async function execFillTemplateSlots(args, ctx) {
|
|
|
52220
52599
|
await Promise.all(
|
|
52221
52600
|
imageJobs.map(
|
|
52222
52601
|
(job) => new Promise((resolve) => {
|
|
52223
|
-
if (!job.dataURL)
|
|
52602
|
+
if (!job.dataURL) {
|
|
52224
52603
|
return resolve();
|
|
52604
|
+
}
|
|
52225
52605
|
const img = new Image();
|
|
52226
52606
|
img.onload = () => {
|
|
52227
52607
|
job.naturalWidth = img.naturalWidth;
|
|
@@ -52235,8 +52615,9 @@ async function execFillTemplateSlots(args, ctx) {
|
|
|
52235
52615
|
);
|
|
52236
52616
|
const imageReplacements = /* @__PURE__ */ new Map();
|
|
52237
52617
|
for (const job of imageJobs) {
|
|
52238
|
-
if (!job.fileId)
|
|
52618
|
+
if (!job.fileId) {
|
|
52239
52619
|
continue;
|
|
52620
|
+
}
|
|
52240
52621
|
const { x, y, width, height } = containFit(
|
|
52241
52622
|
job.el.x,
|
|
52242
52623
|
job.el.y,
|
|
@@ -52274,18 +52655,23 @@ async function execFillTemplateSlots(args, ctx) {
|
|
|
52274
52655
|
let filledCount = 0;
|
|
52275
52656
|
const updatedElements = allElements.map((el, index) => {
|
|
52276
52657
|
const elWithFrame = el;
|
|
52277
|
-
if (elWithFrame.frameId !== frameId)
|
|
52658
|
+
if (elWithFrame.frameId !== frameId) {
|
|
52278
52659
|
return el;
|
|
52660
|
+
}
|
|
52279
52661
|
const slotType = elWithFrame.customData?.slotType;
|
|
52280
|
-
if (!slotType)
|
|
52662
|
+
if (!slotType) {
|
|
52281
52663
|
return el;
|
|
52664
|
+
}
|
|
52282
52665
|
if (imageReplacements.has(index)) {
|
|
52283
52666
|
filledCount++;
|
|
52284
52667
|
return imageReplacements.get(index);
|
|
52285
52668
|
}
|
|
52286
52669
|
let mutation = {};
|
|
52287
52670
|
const makeTextMutation = (value, useHeadlineFont = false) => {
|
|
52288
|
-
const { fontSize, wrappedText, height, autoResize } = fitFontSize(
|
|
52671
|
+
const { fontSize, wrappedText, height, autoResize } = fitFontSize(
|
|
52672
|
+
value,
|
|
52673
|
+
el
|
|
52674
|
+
);
|
|
52289
52675
|
const brandFontId = useHeadlineFont ? ctx.brandHeadlineFontId ?? ctx.brandBodyFontId : ctx.brandBodyFontId;
|
|
52290
52676
|
return {
|
|
52291
52677
|
text: wrappedText,
|
|
@@ -52993,7 +53379,10 @@ ${f.textContent}`).join("\n\n")}`;
|
|
|
52993
53379
|
statusMessage: error || "Insufficient credits for image generation"
|
|
52994
53380
|
};
|
|
52995
53381
|
const gatedAction = {
|
|
52996
|
-
result: {
|
|
53382
|
+
result: {
|
|
53383
|
+
success: gatedResult.success,
|
|
53384
|
+
statusMessage: gatedResult.statusMessage
|
|
53385
|
+
}
|
|
52997
53386
|
};
|
|
52998
53387
|
toolActions.push(gatedAction);
|
|
52999
53388
|
onUpdate({
|
|
@@ -53019,7 +53408,10 @@ ${f.textContent}`).join("\n\n")}`;
|
|
|
53019
53408
|
statusMessage: "Blocked: template already provides text slots"
|
|
53020
53409
|
};
|
|
53021
53410
|
const blockedAction = {
|
|
53022
|
-
result: {
|
|
53411
|
+
result: {
|
|
53412
|
+
success: blockedResult.success,
|
|
53413
|
+
statusMessage: blockedResult.statusMessage
|
|
53414
|
+
}
|
|
53023
53415
|
};
|
|
53024
53416
|
toolActions.push(blockedAction);
|
|
53025
53417
|
onUpdate({
|
|
@@ -53030,7 +53422,10 @@ ${f.textContent}`).join("\n\n")}`;
|
|
|
53030
53422
|
messages.push({
|
|
53031
53423
|
role: "tool",
|
|
53032
53424
|
tool_call_id: toolCall.id,
|
|
53033
|
-
content: JSON.stringify({
|
|
53425
|
+
content: JSON.stringify({
|
|
53426
|
+
success: false,
|
|
53427
|
+
error: blockedResult.error
|
|
53428
|
+
})
|
|
53034
53429
|
});
|
|
53035
53430
|
continue;
|
|
53036
53431
|
}
|
|
@@ -53054,7 +53449,10 @@ ${f.textContent}`).join("\n\n")}`;
|
|
|
53054
53449
|
}
|
|
53055
53450
|
}
|
|
53056
53451
|
const action = {
|
|
53057
|
-
result: {
|
|
53452
|
+
result: {
|
|
53453
|
+
success: result.success,
|
|
53454
|
+
statusMessage: result.statusMessage
|
|
53455
|
+
}
|
|
53058
53456
|
};
|
|
53059
53457
|
toolActions.push(action);
|
|
53060
53458
|
onUpdate({
|
|
@@ -54485,7 +54883,12 @@ var AIChatPanel = React63.forwardRef(
|
|
|
54485
54883
|
actions: msg.toolActions
|
|
54486
54884
|
}
|
|
54487
54885
|
),
|
|
54488
|
-
msg.reviewFeedback && /* @__PURE__ */ jsx192(
|
|
54886
|
+
msg.reviewFeedback && /* @__PURE__ */ jsx192(
|
|
54887
|
+
ReviewCritiqueCard,
|
|
54888
|
+
{
|
|
54889
|
+
feedback: msg.reviewFeedback
|
|
54890
|
+
}
|
|
54891
|
+
),
|
|
54489
54892
|
/* @__PURE__ */ jsx192(
|
|
54490
54893
|
MessageContent,
|
|
54491
54894
|
{
|
|
@@ -54779,44 +55182,65 @@ function ToolActionsDisplay({ actions: actions2 }) {
|
|
|
54779
55182
|
function ReviewCritiqueCard({ feedback }) {
|
|
54780
55183
|
const [expanded, setExpanded] = useState55(false);
|
|
54781
55184
|
const severityClass = (severity) => {
|
|
54782
|
-
if (severity === "critical")
|
|
55185
|
+
if (severity === "critical") {
|
|
54783
55186
|
return "acp-review-issue--critical";
|
|
54784
|
-
|
|
55187
|
+
}
|
|
55188
|
+
if (severity === "major") {
|
|
54785
55189
|
return "acp-review-issue--major";
|
|
55190
|
+
}
|
|
54786
55191
|
return "acp-review-issue--minor";
|
|
54787
55192
|
};
|
|
54788
55193
|
const approved = feedback.approved;
|
|
54789
|
-
return /* @__PURE__ */ jsxs106(
|
|
54790
|
-
|
|
54791
|
-
|
|
54792
|
-
{
|
|
54793
|
-
|
|
54794
|
-
|
|
54795
|
-
|
|
54796
|
-
|
|
54797
|
-
|
|
54798
|
-
|
|
54799
|
-
|
|
54800
|
-
|
|
54801
|
-
|
|
54802
|
-
|
|
54803
|
-
|
|
54804
|
-
|
|
54805
|
-
|
|
54806
|
-
|
|
54807
|
-
|
|
54808
|
-
|
|
54809
|
-
|
|
54810
|
-
|
|
54811
|
-
|
|
54812
|
-
|
|
54813
|
-
|
|
54814
|
-
|
|
54815
|
-
|
|
54816
|
-
|
|
54817
|
-
|
|
54818
|
-
|
|
54819
|
-
|
|
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
|
+
);
|
|
54820
55244
|
}
|
|
54821
55245
|
async function callPlainChatAPI(messages, apiKey, signal, opts) {
|
|
54822
55246
|
const baseModel = opts?.chatModel || "google/gemini-3.1-flash-lite-preview";
|