@orangecatai/adgen-canvas 0.0.20 → 0.0.21
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-Y6SGUVKW.js → chunk-RD5LX7MN.js} +2 -2
- package/dist/dev/{chunk-ILOOQ6LL.js → chunk-WFKR6OGI.js} +3 -15
- package/dist/dev/{chunk-ILOOQ6LL.js.map → chunk-WFKR6OGI.js.map} +2 -2
- package/dist/dev/data/{image-MFQPU4SU.js → image-DSU2H6P5.js} +3 -3
- package/dist/dev/index.js +132 -494
- 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-SDWSFP7L.js → chunk-OWNL6YOR.js} +1 -1
- package/dist/prod/{chunk-3BUGCS63.js → chunk-RXJEXEKA.js} +3 -3
- package/dist/prod/data/image-I7MZ4QNS.js +1 -0
- package/dist/prod/index.js +56 -56
- 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 +12 -1
- package/dist/types/excalidraw/components/ImageEditToolbar.d.ts +0 -1
- package/dist/types/excalidraw/components/ai-chat/agentLoop.d.ts +1 -1
- package/dist/types/excalidraw/components/ai-chat/audioUtils.d.ts +0 -5
- package/dist/types/excalidraw/components/ai-chat/canvasTools.d.ts +2 -1
- package/dist/types/excalidraw/components/ai-chat/reviewerAgent.d.ts +2 -1
- package/dist/types/excalidraw/components/auto-resize/AutoResizePanel.d.ts +2 -2
- package/dist/types/excalidraw/components/auto-resize/autoResizeEngine.d.ts +1 -1
- package/dist/types/excalidraw/types.d.ts +15 -19
- package/dist/types/excalidraw/utils/imageApi.d.ts +1 -1
- package/package.json +1 -1
- package/dist/prod/data/image-NBDZMG3P.js +0 -1
- package/dist/types/excalidraw/utils/leonardoApiKey.d.ts +0 -1
- /package/dist/dev/{chunk-Y6SGUVKW.js.map → chunk-RD5LX7MN.js.map} +0 -0
- /package/dist/dev/data/{image-MFQPU4SU.js.map → image-DSU2H6P5.js.map} +0 -0
package/dist/dev/index.js
CHANGED
|
@@ -13,7 +13,6 @@ import {
|
|
|
13
13
|
canvasToBlob,
|
|
14
14
|
centerScrollOn,
|
|
15
15
|
createFile,
|
|
16
|
-
dataURLToFile,
|
|
17
16
|
dataURLToString,
|
|
18
17
|
encodePngMetadata,
|
|
19
18
|
exportToCanvas,
|
|
@@ -67,10 +66,10 @@ import {
|
|
|
67
66
|
serializeAsJSON,
|
|
68
67
|
serializeLibraryAsJSON,
|
|
69
68
|
strokeRectWithRotation_simple
|
|
70
|
-
} from "./chunk-
|
|
69
|
+
} from "./chunk-WFKR6OGI.js";
|
|
71
70
|
import {
|
|
72
71
|
define_import_meta_env_default
|
|
73
|
-
} from "./chunk-
|
|
72
|
+
} from "./chunk-RD5LX7MN.js";
|
|
74
73
|
import {
|
|
75
74
|
en_default
|
|
76
75
|
} from "./chunk-4K5LIQQU.js";
|
|
@@ -9771,7 +9770,7 @@ var exportCanvas = async (type, elements, appState, files, {
|
|
|
9771
9770
|
let blob = canvasToBlob(tempCanvas);
|
|
9772
9771
|
if (appState.exportEmbedScene) {
|
|
9773
9772
|
blob = blob.then(
|
|
9774
|
-
(blob2) => import("./data/image-
|
|
9773
|
+
(blob2) => import("./data/image-DSU2H6P5.js").then(
|
|
9775
9774
|
({ encodePngMetadata: encodePngMetadata2 }) => encodePngMetadata2({
|
|
9776
9775
|
blob: blob2,
|
|
9777
9776
|
metadata: serializeAsJSON(elements, appState, files, "local")
|
|
@@ -23049,12 +23048,6 @@ import { useEffect as useEffect32, useRef as useRef26, useState as useState29 }
|
|
|
23049
23048
|
import { sceneCoordsToViewportCoords as sceneCoordsToViewportCoords6 } from "@orangecatai/common";
|
|
23050
23049
|
import { getElementAbsoluteCoords as getElementAbsoluteCoords9 } from "@orangecatai/element";
|
|
23051
23050
|
|
|
23052
|
-
// utils/openRouterApiKey.ts
|
|
23053
|
-
function resolveOpenRouterApiKey(propKey) {
|
|
23054
|
-
const normalizedPropKey = propKey?.trim();
|
|
23055
|
-
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 : "") ?? "";
|
|
23056
|
-
}
|
|
23057
|
-
|
|
23058
23051
|
// components/auto-resize/AutoResizePanel.tsx
|
|
23059
23052
|
import { useCallback as useCallback15, useEffect as useEffect31, useRef as useRef25, useState as useState28 } from "react";
|
|
23060
23053
|
|
|
@@ -23071,7 +23064,7 @@ import {
|
|
|
23071
23064
|
import { FRAME_STYLE as FRAME_STYLE2, arrayToMap as arrayToMap22 } from "@orangecatai/common";
|
|
23072
23065
|
|
|
23073
23066
|
// utils/imageApi.ts
|
|
23074
|
-
async function callOpenRouterImageAPI(prompt, modelId, aspectRatio, imageSize, textOutput,
|
|
23067
|
+
async function callOpenRouterImageAPI(prompt, modelId, aspectRatio, imageSize, textOutput, imageGenUrl, referenceImageDataUrl, signal) {
|
|
23075
23068
|
const contentParts = [];
|
|
23076
23069
|
if (referenceImageDataUrl) {
|
|
23077
23070
|
contentParts.push({
|
|
@@ -23091,18 +23084,14 @@ async function callOpenRouterImageAPI(prompt, modelId, aspectRatio, imageSize, t
|
|
|
23091
23084
|
stream: false,
|
|
23092
23085
|
image_config: imageConfig
|
|
23093
23086
|
};
|
|
23094
|
-
const response = await fetch(
|
|
23095
|
-
"
|
|
23096
|
-
|
|
23097
|
-
|
|
23098
|
-
|
|
23099
|
-
|
|
23100
|
-
|
|
23101
|
-
|
|
23102
|
-
},
|
|
23103
|
-
body: JSON.stringify(body)
|
|
23104
|
-
}
|
|
23105
|
-
);
|
|
23087
|
+
const response = await fetch(imageGenUrl, {
|
|
23088
|
+
method: "POST",
|
|
23089
|
+
signal,
|
|
23090
|
+
headers: {
|
|
23091
|
+
"Content-Type": "application/json"
|
|
23092
|
+
},
|
|
23093
|
+
body: JSON.stringify(body)
|
|
23094
|
+
});
|
|
23106
23095
|
if (!response.ok) {
|
|
23107
23096
|
let message = `OpenRouter API error ${response.status}`;
|
|
23108
23097
|
try {
|
|
@@ -23541,7 +23530,7 @@ async function runReviewerAgent(opts) {
|
|
|
23541
23530
|
imagePlacement,
|
|
23542
23531
|
userBrief,
|
|
23543
23532
|
brandContext,
|
|
23544
|
-
|
|
23533
|
+
chatUrl,
|
|
23545
23534
|
reviewerModel = "qwen/qwen3.7-plus",
|
|
23546
23535
|
signal,
|
|
23547
23536
|
iteration
|
|
@@ -23607,10 +23596,9 @@ async function runReviewerAgent(opts) {
|
|
|
23607
23596
|
};
|
|
23608
23597
|
let response;
|
|
23609
23598
|
try {
|
|
23610
|
-
response = await fetch(
|
|
23599
|
+
response = await fetch(chatUrl, {
|
|
23611
23600
|
method: "POST",
|
|
23612
23601
|
headers: {
|
|
23613
|
-
Authorization: `Bearer ${apiKey}`,
|
|
23614
23602
|
"Content-Type": "application/json",
|
|
23615
23603
|
"HTTP-Referer": "https://dughub.app",
|
|
23616
23604
|
"X-Title": "ADGEN Reviewer"
|
|
@@ -24148,7 +24136,7 @@ Prioritise: (1) readability of text, (2) prominence of the primary CTA, (3) bran
|
|
|
24148
24136
|
return result;
|
|
24149
24137
|
}
|
|
24150
24138
|
var VALID_SLOT_TYPES = /* @__PURE__ */ new Set(["logo", "product", "decoration", "cta"]);
|
|
24151
|
-
async function tagImageElementsWithVision(info, screenshotDataUrl,
|
|
24139
|
+
async function tagImageElementsWithVision(info, screenshotDataUrl, autoResizeUrl, model, signal) {
|
|
24152
24140
|
const imageEls = info.foreground.filter(
|
|
24153
24141
|
(el) => el.kind === "image" && !el.slotType
|
|
24154
24142
|
);
|
|
@@ -24178,12 +24166,11 @@ Assign each element exactly one role:
|
|
|
24178
24166
|
Return ONLY a JSON object mapping the element number (string key) to its role. Example: {"1": "logo", "2": "product"}`;
|
|
24179
24167
|
try {
|
|
24180
24168
|
const response = await fetch(
|
|
24181
|
-
|
|
24169
|
+
autoResizeUrl,
|
|
24182
24170
|
{
|
|
24183
24171
|
method: "POST",
|
|
24184
24172
|
signal,
|
|
24185
24173
|
headers: {
|
|
24186
|
-
Authorization: `Bearer ${openRouterApiKey}`,
|
|
24187
24174
|
"Content-Type": "application/json"
|
|
24188
24175
|
},
|
|
24189
24176
|
body: JSON.stringify({
|
|
@@ -24317,14 +24304,13 @@ Only change positions and sizes.
|
|
|
24317
24304
|
Return ONLY the raw HTML. No markdown, no code fences, no explanation.`;
|
|
24318
24305
|
return { prompt, imagePlaceholders };
|
|
24319
24306
|
}
|
|
24320
|
-
async function callOpenRouterForHtml(prompt,
|
|
24307
|
+
async function callOpenRouterForHtml(prompt, autoResizeUrl, model, signal) {
|
|
24321
24308
|
const response = await fetch(
|
|
24322
|
-
|
|
24309
|
+
autoResizeUrl,
|
|
24323
24310
|
{
|
|
24324
24311
|
method: "POST",
|
|
24325
24312
|
signal,
|
|
24326
24313
|
headers: {
|
|
24327
|
-
Authorization: `Bearer ${apiKey}`,
|
|
24328
24314
|
"Content-Type": "application/json"
|
|
24329
24315
|
},
|
|
24330
24316
|
body: JSON.stringify({
|
|
@@ -24373,7 +24359,7 @@ async function runAutoResizeForDimension(opts) {
|
|
|
24373
24359
|
placementX,
|
|
24374
24360
|
placementY,
|
|
24375
24361
|
app,
|
|
24376
|
-
|
|
24362
|
+
autoResizeUrl,
|
|
24377
24363
|
chatModel,
|
|
24378
24364
|
agentImageModel,
|
|
24379
24365
|
customFontMap = {},
|
|
@@ -24439,7 +24425,7 @@ async function runAutoResizeForDimension(opts) {
|
|
|
24439
24425
|
const compressedBgUrl = await downscaleForGemini(srcBgUrl);
|
|
24440
24426
|
debug(
|
|
24441
24427
|
`[AutoResize] bg-regen starting: ar=${ar}`,
|
|
24442
|
-
`keyLen=${
|
|
24428
|
+
`keyLen=${autoResizeUrl.length}`,
|
|
24443
24429
|
`compressedLen=${compressedBgUrl.length}`,
|
|
24444
24430
|
`model=${agentImageModel || DEFAULT_BG_REGEN_MODEL}`
|
|
24445
24431
|
);
|
|
@@ -24459,7 +24445,7 @@ No new text, logos, watermarks, or unrelated objects added.`,
|
|
|
24459
24445
|
ar,
|
|
24460
24446
|
resolution,
|
|
24461
24447
|
true,
|
|
24462
|
-
|
|
24448
|
+
autoResizeUrl,
|
|
24463
24449
|
compressedBgUrl,
|
|
24464
24450
|
signal
|
|
24465
24451
|
);
|
|
@@ -24533,7 +24519,7 @@ No new text, logos, watermarks, or unrelated objects added.`,
|
|
|
24533
24519
|
);
|
|
24534
24520
|
let html = await callOpenRouterForHtml(
|
|
24535
24521
|
prompt,
|
|
24536
|
-
|
|
24522
|
+
autoResizeUrl,
|
|
24537
24523
|
chatModel,
|
|
24538
24524
|
signal
|
|
24539
24525
|
);
|
|
@@ -24744,7 +24730,7 @@ No new text, logos, watermarks, or unrelated objects added.`,
|
|
|
24744
24730
|
userBrief: `Auto-resize ad from ${Math.round(
|
|
24745
24731
|
srcFrame.width
|
|
24746
24732
|
)}\xD7${Math.round(srcFrame.height)} to ${tgtW}\xD7${tgtH}`,
|
|
24747
|
-
|
|
24733
|
+
chatUrl: autoResizeUrl,
|
|
24748
24734
|
reviewerModel: chatModel,
|
|
24749
24735
|
signal,
|
|
24750
24736
|
iteration: reviewRounds + 1
|
|
@@ -24816,7 +24802,7 @@ async function runAutoResize(opts) {
|
|
|
24816
24802
|
sourceFrameId,
|
|
24817
24803
|
targetDimensions,
|
|
24818
24804
|
app,
|
|
24819
|
-
|
|
24805
|
+
autoResizeUrl,
|
|
24820
24806
|
chatModel = "qwen/qwen3.7-plus",
|
|
24821
24807
|
agentImageModel,
|
|
24822
24808
|
customFontMap = {},
|
|
@@ -24844,7 +24830,7 @@ async function runAutoResize(opts) {
|
|
|
24844
24830
|
await tagImageElementsWithVision(
|
|
24845
24831
|
info,
|
|
24846
24832
|
sourceScreenshot,
|
|
24847
|
-
|
|
24833
|
+
autoResizeUrl,
|
|
24848
24834
|
chatModel,
|
|
24849
24835
|
signal
|
|
24850
24836
|
);
|
|
@@ -24894,7 +24880,7 @@ async function runAutoResize(opts) {
|
|
|
24894
24880
|
placementY: placements[i].y,
|
|
24895
24881
|
existingFrameId: preCreatedFrameInfos?.[i]?.frameId,
|
|
24896
24882
|
app,
|
|
24897
|
-
|
|
24883
|
+
autoResizeUrl,
|
|
24898
24884
|
chatModel,
|
|
24899
24885
|
agentImageModel,
|
|
24900
24886
|
customFontMap,
|
|
@@ -25082,7 +25068,7 @@ var AutoResizePanel = ({
|
|
|
25082
25068
|
onBeforeAutoResize,
|
|
25083
25069
|
onAfterAutoResize,
|
|
25084
25070
|
onRunningChange,
|
|
25085
|
-
|
|
25071
|
+
autoResizeUrl,
|
|
25086
25072
|
chatModel,
|
|
25087
25073
|
agentImageModel
|
|
25088
25074
|
}) => {
|
|
@@ -25185,7 +25171,7 @@ var AutoResizePanel = ({
|
|
|
25185
25171
|
targetDimensions: allDimensions,
|
|
25186
25172
|
preCreatedFrameInfos: preCreatedFrames.length > 0 ? preCreatedFrames : void 0,
|
|
25187
25173
|
app,
|
|
25188
|
-
|
|
25174
|
+
autoResizeUrl,
|
|
25189
25175
|
chatModel,
|
|
25190
25176
|
agentImageModel,
|
|
25191
25177
|
customFontMap,
|
|
@@ -25232,7 +25218,7 @@ var AutoResizePanel = ({
|
|
|
25232
25218
|
cleanupShimmer,
|
|
25233
25219
|
onBeforeAutoResize,
|
|
25234
25220
|
onAfterAutoResize,
|
|
25235
|
-
|
|
25221
|
+
autoResizeUrl,
|
|
25236
25222
|
chatModel,
|
|
25237
25223
|
agentImageModel
|
|
25238
25224
|
]);
|
|
@@ -25503,9 +25489,7 @@ var AutoResizePanelHost = ({ app }) => {
|
|
|
25503
25489
|
onRunningChange: (running) => autoResizePanelStore.setRunning(running),
|
|
25504
25490
|
onBeforeAutoResize: app.props.onBeforeAutoResize,
|
|
25505
25491
|
onAfterAutoResize: app.props.onAfterAutoResize,
|
|
25506
|
-
|
|
25507
|
-
app.props.openRouterApiKey
|
|
25508
|
-
),
|
|
25492
|
+
autoResizeUrl: app.props.autoResizeUrl ?? "",
|
|
25509
25493
|
chatModel: app.props.chatModel ?? "google/gemini-3.1-flash-lite-preview",
|
|
25510
25494
|
agentImageModel: app.props.agentImageModel
|
|
25511
25495
|
}
|
|
@@ -26567,7 +26551,7 @@ var ImageGeneratorPanel = ({
|
|
|
26567
26551
|
};
|
|
26568
26552
|
};
|
|
26569
26553
|
const appState = app.state;
|
|
26570
|
-
const
|
|
26554
|
+
const imageGenUrl = app.props.imageGenUrl;
|
|
26571
26555
|
const [prompt, setPrompt] = useState32(() => getPendingPrompt(element.id));
|
|
26572
26556
|
const [selectedModel, setSelectedModel] = useState32(() => {
|
|
26573
26557
|
const stored = getStoredSettings(element);
|
|
@@ -26787,9 +26771,9 @@ var ImageGeneratorPanel = ({
|
|
|
26787
26771
|
setGenerateError("Please enter a prompt.");
|
|
26788
26772
|
return;
|
|
26789
26773
|
}
|
|
26790
|
-
if (!
|
|
26774
|
+
if (!imageGenUrl) {
|
|
26791
26775
|
setGenerateError(
|
|
26792
|
-
"
|
|
26776
|
+
"Image generation is not configured."
|
|
26793
26777
|
);
|
|
26794
26778
|
return;
|
|
26795
26779
|
}
|
|
@@ -26832,7 +26816,7 @@ var ImageGeneratorPanel = ({
|
|
|
26832
26816
|
selectedRatio,
|
|
26833
26817
|
cfg.supportsImageSize ? selectedResolution : null,
|
|
26834
26818
|
cfg.textOutput,
|
|
26835
|
-
|
|
26819
|
+
imageGenUrl,
|
|
26836
26820
|
referenceImage ?? void 0,
|
|
26837
26821
|
controller.signal
|
|
26838
26822
|
);
|
|
@@ -26861,7 +26845,7 @@ var ImageGeneratorPanel = ({
|
|
|
26861
26845
|
}
|
|
26862
26846
|
}, [
|
|
26863
26847
|
prompt,
|
|
26864
|
-
|
|
26848
|
+
imageGenUrl,
|
|
26865
26849
|
selectedModel,
|
|
26866
26850
|
selectedRatio,
|
|
26867
26851
|
selectedResolution,
|
|
@@ -27085,18 +27069,6 @@ import { useCallback as useCallback18, useState as useState34 } from "react";
|
|
|
27085
27069
|
import { sceneCoordsToViewportCoords as sceneCoordsToViewportCoords9 } from "@orangecatai/common";
|
|
27086
27070
|
import { getElementAbsoluteCoords as getElementAbsoluteCoords12 } from "@orangecatai/element";
|
|
27087
27071
|
|
|
27088
|
-
// utils/leonardoApiKey.ts
|
|
27089
|
-
function resolveLeonardoApiKey(propKey) {
|
|
27090
|
-
const normalizedPropKey = propKey?.trim();
|
|
27091
|
-
return (normalizedPropKey ? normalizedPropKey : void 0) ?? (typeof import.meta !== "undefined" && define_import_meta_env_default?.VITE_APP_LEONARDO_API_KEY ? define_import_meta_env_default.VITE_APP_LEONARDO_API_KEY : "") ?? "";
|
|
27092
|
-
}
|
|
27093
|
-
|
|
27094
|
-
// utils/removeBgApiKey.ts
|
|
27095
|
-
function resolveRemoveBgApiKey(propKey) {
|
|
27096
|
-
const normalizedPropKey = propKey?.trim();
|
|
27097
|
-
return (normalizedPropKey ? normalizedPropKey : void 0) ?? (typeof import.meta !== "undefined" && define_import_meta_env_default?.VITE_APP_REMOVE_BG_API_KEY ? define_import_meta_env_default.VITE_APP_REMOVE_BG_API_KEY : "") ?? "";
|
|
27098
|
-
}
|
|
27099
|
-
|
|
27100
27072
|
// components/ImageQuickEditPanel.tsx
|
|
27101
27073
|
import { useCallback as useCallback17, useEffect as useEffect35, useRef as useRef29, useState as useState33 } from "react";
|
|
27102
27074
|
import { sceneCoordsToViewportCoords as sceneCoordsToViewportCoords8 } from "@orangecatai/common";
|
|
@@ -27264,7 +27236,7 @@ var ImageQuickEditPanel = ({
|
|
|
27264
27236
|
onClose
|
|
27265
27237
|
}) => {
|
|
27266
27238
|
const appState = app.state;
|
|
27267
|
-
const
|
|
27239
|
+
const imageGenUrl = app.props.imageGenUrl;
|
|
27268
27240
|
const [isOpen, setIsOpen] = useState33(
|
|
27269
27241
|
() => forceOpen || hasPendingGeneration(element.id)
|
|
27270
27242
|
);
|
|
@@ -27355,10 +27327,8 @@ var ImageQuickEditPanel = ({
|
|
|
27355
27327
|
setGenerateError("Please enter a prompt.");
|
|
27356
27328
|
return;
|
|
27357
27329
|
}
|
|
27358
|
-
if (!
|
|
27359
|
-
setGenerateError(
|
|
27360
|
-
"No OpenRouter API key found. Set VITE_APP_OPENROUTER_API_KEY in .env or pass openRouterApiKey as a prop."
|
|
27361
|
-
);
|
|
27330
|
+
if (!imageGenUrl) {
|
|
27331
|
+
setGenerateError("Image generation is not configured.");
|
|
27362
27332
|
return;
|
|
27363
27333
|
}
|
|
27364
27334
|
setIsGenerating(true);
|
|
@@ -27401,7 +27371,7 @@ var ImageQuickEditPanel = ({
|
|
|
27401
27371
|
selectedRatio,
|
|
27402
27372
|
cfg.supportsImageSize ? selectedResolution : null,
|
|
27403
27373
|
cfg.textOutput,
|
|
27404
|
-
|
|
27374
|
+
imageGenUrl,
|
|
27405
27375
|
refDataUrl,
|
|
27406
27376
|
controller.signal
|
|
27407
27377
|
);
|
|
@@ -27440,7 +27410,7 @@ var ImageQuickEditPanel = ({
|
|
|
27440
27410
|
}
|
|
27441
27411
|
}, [
|
|
27442
27412
|
prompt,
|
|
27443
|
-
|
|
27413
|
+
imageGenUrl,
|
|
27444
27414
|
selectedModel,
|
|
27445
27415
|
selectedRatio,
|
|
27446
27416
|
selectedResolution,
|
|
@@ -27661,48 +27631,7 @@ var ImageQuickEditPanel = ({
|
|
|
27661
27631
|
|
|
27662
27632
|
// components/ImageEditToolbar.tsx
|
|
27663
27633
|
import { Fragment as Fragment15, jsx as jsx94, jsxs as jsxs52 } from "react/jsx-runtime";
|
|
27664
|
-
var
|
|
27665
|
-
var LEONARDO_POLL_INTERVAL_MS = 1500;
|
|
27666
|
-
var LEONARDO_MAX_POLLS = 40;
|
|
27667
|
-
var getLeonardoHeaders = (apiKey) => ({
|
|
27668
|
-
Authorization: `Bearer ${apiKey}`,
|
|
27669
|
-
"Content-Type": "application/json"
|
|
27670
|
-
});
|
|
27671
|
-
var getImageExtension = (mimeType) => {
|
|
27672
|
-
switch (mimeType) {
|
|
27673
|
-
case "image/jpeg":
|
|
27674
|
-
return "jpeg";
|
|
27675
|
-
case "image/jpg":
|
|
27676
|
-
return "jpg";
|
|
27677
|
-
case "image/webp":
|
|
27678
|
-
return "webp";
|
|
27679
|
-
default:
|
|
27680
|
-
return "png";
|
|
27681
|
-
}
|
|
27682
|
-
};
|
|
27683
|
-
var getOperationLabel = (operation) => operation === "upscale" ? "Upscale" : "Remove background";
|
|
27684
|
-
var getOperationStatus = (operation) => operation === "upscale" ? "Upscaling image..." : "Removing background...";
|
|
27685
|
-
var sleep = (ms) => new Promise((resolve) => {
|
|
27686
|
-
window.setTimeout(resolve, ms);
|
|
27687
|
-
});
|
|
27688
|
-
var readLeonardoError = async (response, fallbackMessage) => {
|
|
27689
|
-
try {
|
|
27690
|
-
const body = await response.json();
|
|
27691
|
-
const message = body?.error?.message ?? body?.message ?? body?.detail ?? body?.errors?.[0]?.message;
|
|
27692
|
-
if (typeof message === "string" && message.trim()) {
|
|
27693
|
-
return message;
|
|
27694
|
-
}
|
|
27695
|
-
} catch {
|
|
27696
|
-
}
|
|
27697
|
-
try {
|
|
27698
|
-
const text = await response.text();
|
|
27699
|
-
if (text.trim()) {
|
|
27700
|
-
return text.trim();
|
|
27701
|
-
}
|
|
27702
|
-
} catch {
|
|
27703
|
-
}
|
|
27704
|
-
return `${fallbackMessage} (${response.status})`;
|
|
27705
|
-
};
|
|
27634
|
+
var getOperationStatus = (_operation) => "Removing background...";
|
|
27706
27635
|
var exportSourceImageDataURL = async (element, sourceDataURL) => {
|
|
27707
27636
|
const crop = element.crop;
|
|
27708
27637
|
if (!crop) {
|
|
@@ -27736,150 +27665,28 @@ var exportSourceImageDataURL = async (element, sourceDataURL) => {
|
|
|
27736
27665
|
img.src = sourceDataURL;
|
|
27737
27666
|
});
|
|
27738
27667
|
};
|
|
27739
|
-
var
|
|
27740
|
-
const
|
|
27741
|
-
const initResponse = await fetch(`${LEONARDO_API_BASE}/init-image`, {
|
|
27668
|
+
var callImageProxy = async (proxyUrl, imageDataUrl) => {
|
|
27669
|
+
const response = await fetch(proxyUrl, {
|
|
27742
27670
|
method: "POST",
|
|
27743
|
-
headers:
|
|
27744
|
-
body: JSON.stringify({
|
|
27745
|
-
});
|
|
27746
|
-
if (!initResponse.ok) {
|
|
27747
|
-
throw new Error(
|
|
27748
|
-
await readLeonardoError(
|
|
27749
|
-
initResponse,
|
|
27750
|
-
"Leonardo init image request failed"
|
|
27751
|
-
)
|
|
27752
|
-
);
|
|
27753
|
-
}
|
|
27754
|
-
const initData = await initResponse.json();
|
|
27755
|
-
const uploadInitImage = initData.uploadInitImage;
|
|
27756
|
-
if (!uploadInitImage?.id || !uploadInitImage.url) {
|
|
27757
|
-
throw new Error("Leonardo init image response was incomplete.");
|
|
27758
|
-
}
|
|
27759
|
-
const rawFields = uploadInitImage.fields ?? {};
|
|
27760
|
-
const fields = typeof rawFields === "string" ? JSON.parse(rawFields) : rawFields;
|
|
27761
|
-
const formData = new FormData();
|
|
27762
|
-
Object.entries(fields).forEach(([key, value]) => {
|
|
27763
|
-
formData.append(key, value);
|
|
27764
|
-
});
|
|
27765
|
-
formData.append(
|
|
27766
|
-
"file",
|
|
27767
|
-
dataURLToFile(sourceDataURL, `image.${extension}`)
|
|
27768
|
-
);
|
|
27769
|
-
await fetch(uploadInitImage.url, {
|
|
27770
|
-
method: "POST",
|
|
27771
|
-
body: formData,
|
|
27772
|
-
mode: "no-cors"
|
|
27773
|
-
});
|
|
27774
|
-
return uploadInitImage.id;
|
|
27775
|
-
};
|
|
27776
|
-
var removeBackgroundWithRemoveBg = async (sourceDataURL, apiKey) => {
|
|
27777
|
-
const mimeType = getMimeTypeFromDataURL(sourceDataURL);
|
|
27778
|
-
const extension = getImageExtension(mimeType);
|
|
27779
|
-
const file2 = dataURLToFile(sourceDataURL, `image.${extension}`);
|
|
27780
|
-
const formData = new FormData();
|
|
27781
|
-
formData.append("size", "auto");
|
|
27782
|
-
formData.append("image_file", file2);
|
|
27783
|
-
const response = await fetch("https://api.remove.bg/v1.0/removebg", {
|
|
27784
|
-
method: "POST",
|
|
27785
|
-
headers: { "X-Api-Key": apiKey },
|
|
27786
|
-
body: formData
|
|
27671
|
+
headers: { "Content-Type": "application/json" },
|
|
27672
|
+
body: JSON.stringify({ imageDataUrl })
|
|
27787
27673
|
});
|
|
27788
27674
|
if (!response.ok) {
|
|
27789
|
-
let
|
|
27675
|
+
let message = `Request failed (${response.status})`;
|
|
27790
27676
|
try {
|
|
27791
27677
|
const body = await response.json();
|
|
27792
|
-
|
|
27793
|
-
|
|
27794
|
-
errorMessage = title;
|
|
27678
|
+
if (body?.error) {
|
|
27679
|
+
message = body.error;
|
|
27795
27680
|
}
|
|
27796
27681
|
} catch {
|
|
27797
27682
|
}
|
|
27798
|
-
throw new Error(
|
|
27799
|
-
}
|
|
27800
|
-
const arrayBuffer = await response.arrayBuffer();
|
|
27801
|
-
return await getDataURL(new Blob([arrayBuffer], { type: "image/png" }));
|
|
27802
|
-
};
|
|
27803
|
-
var createLeonardoVariation = async (imageId, apiKey) => {
|
|
27804
|
-
const response = await fetch(
|
|
27805
|
-
`${LEONARDO_API_BASE}/variations/universal-upscaler`,
|
|
27806
|
-
{
|
|
27807
|
-
method: "POST",
|
|
27808
|
-
headers: getLeonardoHeaders(apiKey),
|
|
27809
|
-
body: JSON.stringify({
|
|
27810
|
-
ultraUpscaleStyle: "ARTISTIC",
|
|
27811
|
-
creativityStrength: 1,
|
|
27812
|
-
// minimum deviation — keeps output faithful to input
|
|
27813
|
-
detailContrast: 5,
|
|
27814
|
-
similarity: 10,
|
|
27815
|
-
// maximum similarity — no structural divergence
|
|
27816
|
-
upscaleMultiplier: 1.5,
|
|
27817
|
-
initImageId: imageId
|
|
27818
|
-
})
|
|
27819
|
-
}
|
|
27820
|
-
);
|
|
27821
|
-
if (!response.ok) {
|
|
27822
|
-
throw new Error(
|
|
27823
|
-
await readLeonardoError(response, "Leonardo upscale request failed")
|
|
27824
|
-
);
|
|
27825
|
-
}
|
|
27826
|
-
const body = await response.json();
|
|
27827
|
-
const variationId = body.universalUpscaler?.id;
|
|
27828
|
-
if (!variationId) {
|
|
27829
|
-
throw new Error("Leonardo variation job id was missing from the response.");
|
|
27830
|
-
}
|
|
27831
|
-
return variationId;
|
|
27832
|
-
};
|
|
27833
|
-
var pollLeonardoVariationURL = async (variationId, apiKey) => {
|
|
27834
|
-
for (let attempt = 0; attempt < LEONARDO_MAX_POLLS; attempt++) {
|
|
27835
|
-
const response = await fetch(
|
|
27836
|
-
`${LEONARDO_API_BASE}/variations/${variationId}`,
|
|
27837
|
-
{
|
|
27838
|
-
method: "GET",
|
|
27839
|
-
headers: { Authorization: `Bearer ${apiKey}` }
|
|
27840
|
-
}
|
|
27841
|
-
);
|
|
27842
|
-
if (!response.ok) {
|
|
27843
|
-
throw new Error(
|
|
27844
|
-
await readLeonardoError(
|
|
27845
|
-
response,
|
|
27846
|
-
"Leonardo variation status check failed"
|
|
27847
|
-
)
|
|
27848
|
-
);
|
|
27849
|
-
}
|
|
27850
|
-
const body = await response.json();
|
|
27851
|
-
const variation = Array.isArray(body.generated_image_variation_generic) ? body.generated_image_variation_generic[0] : body.generated_image_variation_generic;
|
|
27852
|
-
if (!variation) {
|
|
27853
|
-
throw new Error(
|
|
27854
|
-
"Leonardo variation details were missing from the response."
|
|
27855
|
-
);
|
|
27856
|
-
}
|
|
27857
|
-
if (variation.status === "COMPLETE") {
|
|
27858
|
-
if (!variation.url) {
|
|
27859
|
-
throw new Error("Leonardo variation completed without an image URL.");
|
|
27860
|
-
}
|
|
27861
|
-
return variation.url;
|
|
27862
|
-
}
|
|
27863
|
-
if (variation.status === "FAILED") {
|
|
27864
|
-
throw new Error("Leonardo variation failed.");
|
|
27865
|
-
}
|
|
27866
|
-
if (attempt < LEONARDO_MAX_POLLS - 1) {
|
|
27867
|
-
await sleep(LEONARDO_POLL_INTERVAL_MS);
|
|
27868
|
-
}
|
|
27683
|
+
throw new Error(message);
|
|
27869
27684
|
}
|
|
27870
|
-
|
|
27871
|
-
|
|
27872
|
-
|
|
27873
|
-
const response = await fetch(resultURL);
|
|
27874
|
-
if (!response.ok) {
|
|
27875
|
-
throw new Error(
|
|
27876
|
-
await readLeonardoError(
|
|
27877
|
-
response,
|
|
27878
|
-
"Leonardo result image download failed"
|
|
27879
|
-
)
|
|
27880
|
-
);
|
|
27685
|
+
const data = await response.json();
|
|
27686
|
+
if (!data?.imageDataUrl) {
|
|
27687
|
+
throw new Error("No image was returned.");
|
|
27881
27688
|
}
|
|
27882
|
-
return
|
|
27689
|
+
return data.imageDataUrl;
|
|
27883
27690
|
};
|
|
27884
27691
|
var QuickEditIcon = () => /* @__PURE__ */ jsxs52(
|
|
27885
27692
|
"svg",
|
|
@@ -27898,25 +27705,6 @@ var QuickEditIcon = () => /* @__PURE__ */ jsxs52(
|
|
|
27898
27705
|
]
|
|
27899
27706
|
}
|
|
27900
27707
|
);
|
|
27901
|
-
var UpscaleIcon = () => /* @__PURE__ */ jsxs52(
|
|
27902
|
-
"svg",
|
|
27903
|
-
{
|
|
27904
|
-
width: "16",
|
|
27905
|
-
height: "16",
|
|
27906
|
-
viewBox: "0 0 24 24",
|
|
27907
|
-
fill: "none",
|
|
27908
|
-
stroke: "currentColor",
|
|
27909
|
-
strokeWidth: "2",
|
|
27910
|
-
strokeLinecap: "round",
|
|
27911
|
-
strokeLinejoin: "round",
|
|
27912
|
-
children: [
|
|
27913
|
-
/* @__PURE__ */ jsx94("rect", { x: "3", y: "3", width: "18", height: "18", rx: "2" }),
|
|
27914
|
-
/* @__PURE__ */ jsx94("path", { d: "M9 3v18" }),
|
|
27915
|
-
/* @__PURE__ */ jsx94("path", { d: "M14 9l3-3 3 3" }),
|
|
27916
|
-
/* @__PURE__ */ jsx94("path", { d: "M17 6v6" })
|
|
27917
|
-
]
|
|
27918
|
-
}
|
|
27919
|
-
);
|
|
27920
27708
|
var RemoveBGIcon = () => /* @__PURE__ */ jsxs52(
|
|
27921
27709
|
"svg",
|
|
27922
27710
|
{
|
|
@@ -28000,7 +27788,6 @@ var PRIMARY_TOOLS = [
|
|
|
28000
27788
|
label: "Quick Edit",
|
|
28001
27789
|
icon: /* @__PURE__ */ jsx94(QuickEditIcon, {})
|
|
28002
27790
|
},
|
|
28003
|
-
{ id: "upscale", label: "Upscale", icon: /* @__PURE__ */ jsx94(UpscaleIcon, {}) },
|
|
28004
27791
|
{ id: "remove-bg", label: "Remove BG", icon: /* @__PURE__ */ jsx94(RemoveBGIcon, {}) },
|
|
28005
27792
|
{ id: "crop", label: "Crop", icon: /* @__PURE__ */ jsx94(CropIcon, {}) }
|
|
28006
27793
|
];
|
|
@@ -28010,92 +27797,18 @@ var ImageEditToolbar = ({
|
|
|
28010
27797
|
callbacks
|
|
28011
27798
|
}) => {
|
|
28012
27799
|
const appState = app.state;
|
|
28013
|
-
const
|
|
28014
|
-
app.props.leonardoApiKey
|
|
28015
|
-
);
|
|
28016
|
-
const resolvedRemoveBgApiKey = resolveRemoveBgApiKey(
|
|
28017
|
-
app.props.removeBgApiKey
|
|
28018
|
-
);
|
|
27800
|
+
const removeBgUrl = app.props.removeBgUrl;
|
|
28019
27801
|
const [quickEditOpen, setQuickEditOpen] = useState34(
|
|
28020
27802
|
() => hasPendingGeneration(element.id)
|
|
28021
27803
|
);
|
|
28022
|
-
const [activeOperation, setActiveOperation] = useState34(
|
|
27804
|
+
const [activeOperation, setActiveOperation] = useState34(
|
|
27805
|
+
null
|
|
27806
|
+
);
|
|
28023
27807
|
const [operationError, setOperationError] = useState34(null);
|
|
28024
27808
|
const isToolbarBusy = activeOperation !== null;
|
|
28025
|
-
const runLeonardoAction = useCallback18(
|
|
28026
|
-
async (operation) => {
|
|
28027
|
-
if (!resolvedLeonardoApiKey) {
|
|
28028
|
-
setOperationError(
|
|
28029
|
-
"No Leonardo API key found. Set VITE_APP_LEONARDO_API_KEY in .env or pass leonardoApiKey as a prop."
|
|
28030
|
-
);
|
|
28031
|
-
return;
|
|
28032
|
-
}
|
|
28033
|
-
const fileId = element.fileId;
|
|
28034
|
-
if (!fileId) {
|
|
28035
|
-
setOperationError("The selected image is missing its file reference.");
|
|
28036
|
-
return;
|
|
28037
|
-
}
|
|
28038
|
-
const sourceDataURL = app.files[fileId]?.dataURL;
|
|
28039
|
-
if (!sourceDataURL) {
|
|
28040
|
-
setOperationError("The selected image file could not be found.");
|
|
28041
|
-
return;
|
|
28042
|
-
}
|
|
28043
|
-
const onBefore = app.props.onBeforeUpscale;
|
|
28044
|
-
const onAfter = app.props.onAfterUpscale;
|
|
28045
|
-
if (onBefore) {
|
|
28046
|
-
try {
|
|
28047
|
-
const { allowed, error } = await onBefore();
|
|
28048
|
-
if (!allowed) {
|
|
28049
|
-
setOperationError(error || "Insufficient credits for upscale");
|
|
28050
|
-
return;
|
|
28051
|
-
}
|
|
28052
|
-
} catch {
|
|
28053
|
-
setOperationError("Credit check failed");
|
|
28054
|
-
return;
|
|
28055
|
-
}
|
|
28056
|
-
}
|
|
28057
|
-
setActiveOperation(operation);
|
|
28058
|
-
setOperationError(null);
|
|
28059
|
-
try {
|
|
28060
|
-
const exportedSourceDataURL = await exportSourceImageDataURL(
|
|
28061
|
-
element,
|
|
28062
|
-
sourceDataURL
|
|
28063
|
-
);
|
|
28064
|
-
const imageId = await uploadImageToLeonardo(
|
|
28065
|
-
exportedSourceDataURL,
|
|
28066
|
-
resolvedLeonardoApiKey
|
|
28067
|
-
);
|
|
28068
|
-
const variationId = await createLeonardoVariation(
|
|
28069
|
-
imageId,
|
|
28070
|
-
resolvedLeonardoApiKey
|
|
28071
|
-
);
|
|
28072
|
-
const resultURL = await pollLeonardoVariationURL(
|
|
28073
|
-
variationId,
|
|
28074
|
-
resolvedLeonardoApiKey
|
|
28075
|
-
);
|
|
28076
|
-
const resultDataURL = await fetchLeonardoResultDataURL(resultURL);
|
|
28077
|
-
await app.insertGeneratedImageNearElement(
|
|
28078
|
-
resultDataURL,
|
|
28079
|
-
element,
|
|
28080
|
-
element.width,
|
|
28081
|
-
element.height
|
|
28082
|
-
);
|
|
28083
|
-
onAfter?.();
|
|
28084
|
-
} catch (error) {
|
|
28085
|
-
setOperationError(
|
|
28086
|
-
error instanceof Error ? error.message : `${getOperationLabel(operation)} failed.`
|
|
28087
|
-
);
|
|
28088
|
-
} finally {
|
|
28089
|
-
setActiveOperation(null);
|
|
28090
|
-
}
|
|
28091
|
-
},
|
|
28092
|
-
[app, element, resolvedLeonardoApiKey]
|
|
28093
|
-
);
|
|
28094
27809
|
const runRemoveBgAction = useCallback18(async () => {
|
|
28095
|
-
if (!
|
|
28096
|
-
setOperationError(
|
|
28097
|
-
"No remove.bg API key found. Set VITE_APP_REMOVE_BG_API_KEY in .env or pass removeBgApiKey as a prop."
|
|
28098
|
-
);
|
|
27810
|
+
if (!removeBgUrl) {
|
|
27811
|
+
setOperationError("Remove background is not configured.");
|
|
28099
27812
|
return;
|
|
28100
27813
|
}
|
|
28101
27814
|
const fileId = element.fileId;
|
|
@@ -28131,9 +27844,9 @@ var ImageEditToolbar = ({
|
|
|
28131
27844
|
element,
|
|
28132
27845
|
sourceDataURL
|
|
28133
27846
|
);
|
|
28134
|
-
const resultDataURL = await
|
|
28135
|
-
|
|
28136
|
-
|
|
27847
|
+
const resultDataURL = await callImageProxy(
|
|
27848
|
+
removeBgUrl,
|
|
27849
|
+
exportedSourceDataURL
|
|
28137
27850
|
);
|
|
28138
27851
|
await app.insertGeneratedImageNearElement(
|
|
28139
27852
|
resultDataURL,
|
|
@@ -28149,7 +27862,7 @@ var ImageEditToolbar = ({
|
|
|
28149
27862
|
} finally {
|
|
28150
27863
|
setActiveOperation(null);
|
|
28151
27864
|
}
|
|
28152
|
-
}, [app, element,
|
|
27865
|
+
}, [app, element, removeBgUrl]);
|
|
28153
27866
|
const handleAction = useCallback18(
|
|
28154
27867
|
(id) => {
|
|
28155
27868
|
setOperationError(null);
|
|
@@ -28169,21 +27882,15 @@ var ImageEditToolbar = ({
|
|
|
28169
27882
|
}
|
|
28170
27883
|
return;
|
|
28171
27884
|
}
|
|
28172
|
-
|
|
28173
|
-
|
|
28174
|
-
|
|
28175
|
-
|
|
28176
|
-
|
|
28177
|
-
|
|
28178
|
-
return;
|
|
28179
|
-
}
|
|
28180
|
-
if (id === "upscale") {
|
|
28181
|
-
void runLeonardoAction(id);
|
|
28182
|
-
} else if (id === "remove-bg") {
|
|
28183
|
-
void runRemoveBgAction();
|
|
27885
|
+
if (id === "remove-bg") {
|
|
27886
|
+
if (callbacks?.onRemoveBG) {
|
|
27887
|
+
callbacks.onRemoveBG();
|
|
27888
|
+
} else {
|
|
27889
|
+
void runRemoveBgAction();
|
|
27890
|
+
}
|
|
28184
27891
|
}
|
|
28185
27892
|
},
|
|
28186
|
-
[callbacks, app.actionManager,
|
|
27893
|
+
[callbacks, app.actionManager, runRemoveBgAction]
|
|
28187
27894
|
);
|
|
28188
27895
|
const handleDownload = useCallback18(() => {
|
|
28189
27896
|
if (callbacks?.onDownload) {
|
|
@@ -52951,11 +52658,11 @@ async function execGenerateImage(args, ctx) {
|
|
|
52951
52658
|
statusMessage: "Failed: missing required parameters"
|
|
52952
52659
|
};
|
|
52953
52660
|
}
|
|
52954
|
-
if (!ctx.
|
|
52661
|
+
if (!ctx.imageGenUrl) {
|
|
52955
52662
|
return {
|
|
52956
52663
|
success: false,
|
|
52957
|
-
error: "
|
|
52958
|
-
statusMessage: "Failed:
|
|
52664
|
+
error: "Image generation is not configured.",
|
|
52665
|
+
statusMessage: "Failed: image generation not configured"
|
|
52959
52666
|
};
|
|
52960
52667
|
}
|
|
52961
52668
|
const elements = ctx.excalidrawAPI.getSceneElements();
|
|
@@ -52979,7 +52686,7 @@ async function execGenerateImage(args, ctx) {
|
|
|
52979
52686
|
aspectRatio,
|
|
52980
52687
|
null,
|
|
52981
52688
|
true,
|
|
52982
|
-
ctx.
|
|
52689
|
+
ctx.imageGenUrl,
|
|
52983
52690
|
referenceImageDataUrl,
|
|
52984
52691
|
ctx.signal
|
|
52985
52692
|
);
|
|
@@ -54172,7 +53879,7 @@ Never write full sentences or long phrases for any text slot. Tight, punchy copy
|
|
|
54172
53879
|
|
|
54173
53880
|
FINALIZING THE AD: When ALL elements are placed \u2014 brand assets, generated images, and the HTML text overlay \u2014 call finalize_ad(frameId) to signal completion. Do not call it before all assets are in place. This triggers the final quality review.`;
|
|
54174
53881
|
var MAX_ITERATIONS = 15;
|
|
54175
|
-
async function callOpenRouter(messages,
|
|
53882
|
+
async function callOpenRouter(messages, chatUrl, signal, webSearchEnabled, chatModel, onContentChunk, tools = CANVAS_TOOLS) {
|
|
54176
53883
|
const baseModel = chatModel || "minimax/minimax-m3";
|
|
54177
53884
|
const model = webSearchEnabled ? `${baseModel}:online` : baseModel;
|
|
54178
53885
|
const body = {
|
|
@@ -54208,18 +53915,14 @@ async function callOpenRouter(messages, apiKey, signal, webSearchEnabled, chatMo
|
|
|
54208
53915
|
plugins.push({ id: "file-parser", pdf: { engine: "cloudflare-ai" } });
|
|
54209
53916
|
if (plugins.length > 0)
|
|
54210
53917
|
body.plugins = plugins;
|
|
54211
|
-
const response = await fetch(
|
|
54212
|
-
"
|
|
54213
|
-
|
|
54214
|
-
|
|
54215
|
-
|
|
54216
|
-
|
|
54217
|
-
|
|
54218
|
-
|
|
54219
|
-
},
|
|
54220
|
-
body: JSON.stringify(body)
|
|
54221
|
-
}
|
|
54222
|
-
);
|
|
53918
|
+
const response = await fetch(chatUrl, {
|
|
53919
|
+
method: "POST",
|
|
53920
|
+
signal,
|
|
53921
|
+
headers: {
|
|
53922
|
+
"Content-Type": "application/json"
|
|
53923
|
+
},
|
|
53924
|
+
body: JSON.stringify(body)
|
|
53925
|
+
});
|
|
54223
53926
|
if (!response.ok) {
|
|
54224
53927
|
let message = `OpenRouter error ${response.status}`;
|
|
54225
53928
|
try {
|
|
@@ -54353,7 +54056,7 @@ async function runAgentLoop(opts) {
|
|
|
54353
54056
|
frameScreenshot,
|
|
54354
54057
|
fileAttachments,
|
|
54355
54058
|
webSearchEnabled,
|
|
54356
|
-
|
|
54059
|
+
chatUrl,
|
|
54357
54060
|
chatModel,
|
|
54358
54061
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
54359
54062
|
agentImageModel: _agentImageModel,
|
|
@@ -54491,7 +54194,7 @@ ${f.textContent}`).join("\n\n")}`;
|
|
|
54491
54194
|
});
|
|
54492
54195
|
const response = await callOpenRouter(
|
|
54493
54196
|
messages,
|
|
54494
|
-
|
|
54197
|
+
chatUrl,
|
|
54495
54198
|
signal,
|
|
54496
54199
|
webSearchEnabled,
|
|
54497
54200
|
chatModel,
|
|
@@ -54719,7 +54422,7 @@ Use the frameId="${imageGenData.frameId}" for all elements. Keep all elements wi
|
|
|
54719
54422
|
} : void 0,
|
|
54720
54423
|
userBrief: typeof userMessages[0]?.content === "string" ? userMessages[0].content : "",
|
|
54721
54424
|
brandContext,
|
|
54722
|
-
|
|
54425
|
+
chatUrl,
|
|
54723
54426
|
reviewerModel: reviewerModel ?? chatModel,
|
|
54724
54427
|
signal,
|
|
54725
54428
|
iteration: reviewRounds
|
|
@@ -54897,50 +54600,6 @@ async function blobToWavBase64(blob) {
|
|
|
54897
54600
|
}
|
|
54898
54601
|
return btoa(binary);
|
|
54899
54602
|
}
|
|
54900
|
-
async function transcribeAudio(base64Audio, format, apiKey, voiceModel) {
|
|
54901
|
-
const model = voiceModel || "mistralai/voxtral-mini-transcribe";
|
|
54902
|
-
const response = await fetch(
|
|
54903
|
-
"https://openrouter.ai/api/v1/chat/completions",
|
|
54904
|
-
{
|
|
54905
|
-
method: "POST",
|
|
54906
|
-
headers: {
|
|
54907
|
-
Authorization: `Bearer ${apiKey}`,
|
|
54908
|
-
"Content-Type": "application/json"
|
|
54909
|
-
},
|
|
54910
|
-
body: JSON.stringify({
|
|
54911
|
-
model,
|
|
54912
|
-
messages: [
|
|
54913
|
-
{
|
|
54914
|
-
role: "user",
|
|
54915
|
-
content: [
|
|
54916
|
-
{
|
|
54917
|
-
type: "text",
|
|
54918
|
-
text: "Transcribe this audio. Return only the transcription text, nothing else."
|
|
54919
|
-
},
|
|
54920
|
-
{
|
|
54921
|
-
type: "input_audio",
|
|
54922
|
-
input_audio: { data: base64Audio, format }
|
|
54923
|
-
}
|
|
54924
|
-
]
|
|
54925
|
-
}
|
|
54926
|
-
]
|
|
54927
|
-
})
|
|
54928
|
-
}
|
|
54929
|
-
);
|
|
54930
|
-
if (!response.ok) {
|
|
54931
|
-
let message = `Transcription error ${response.status}`;
|
|
54932
|
-
try {
|
|
54933
|
-
const err = await response.json();
|
|
54934
|
-
if (err?.error?.message) {
|
|
54935
|
-
message = err.error.message;
|
|
54936
|
-
}
|
|
54937
|
-
} catch {
|
|
54938
|
-
}
|
|
54939
|
-
throw new Error(message);
|
|
54940
|
-
}
|
|
54941
|
-
const data = await response.json();
|
|
54942
|
-
return data?.choices?.[0]?.message?.content || "";
|
|
54943
|
-
}
|
|
54944
54603
|
|
|
54945
54604
|
// components/ui/chat-container.tsx
|
|
54946
54605
|
import { StickToBottom } from "use-stick-to-bottom";
|
|
@@ -55289,7 +54948,8 @@ var AIChatPanel = React64.forwardRef(
|
|
|
55289
54948
|
({
|
|
55290
54949
|
isOpen,
|
|
55291
54950
|
onClose,
|
|
55292
|
-
|
|
54951
|
+
chatUrl,
|
|
54952
|
+
imageGenUrl,
|
|
55293
54953
|
excalidrawAPI,
|
|
55294
54954
|
initialMessages,
|
|
55295
54955
|
initialSessionId,
|
|
@@ -55303,7 +54963,6 @@ var AIChatPanel = React64.forwardRef(
|
|
|
55303
54963
|
onBeforeImageGen,
|
|
55304
54964
|
onAfterImageGen,
|
|
55305
54965
|
chatModel,
|
|
55306
|
-
voiceModel,
|
|
55307
54966
|
transcribeUrl,
|
|
55308
54967
|
agentImageModel,
|
|
55309
54968
|
brandContext,
|
|
@@ -55587,40 +55246,29 @@ var AIChatPanel = React64.forwardRef(
|
|
|
55587
55246
|
setStatusText("Transcribing\u2026");
|
|
55588
55247
|
try {
|
|
55589
55248
|
const wavBase64 = await blobToWavBase64(audioBlob);
|
|
55590
|
-
|
|
55591
|
-
|
|
55592
|
-
|
|
55593
|
-
|
|
55594
|
-
|
|
55595
|
-
|
|
55596
|
-
|
|
55597
|
-
|
|
55598
|
-
|
|
55599
|
-
|
|
55600
|
-
|
|
55601
|
-
|
|
55602
|
-
|
|
55603
|
-
|
|
55604
|
-
|
|
55605
|
-
|
|
55606
|
-
|
|
55607
|
-
|
|
55608
|
-
transcription = data?.text ?? "";
|
|
55609
|
-
} else {
|
|
55610
|
-
const normalizedKey = resolveOpenRouterApiKey(apiKey);
|
|
55611
|
-
if (!normalizedKey) {
|
|
55612
|
-
setError("No API key for voice transcription.");
|
|
55613
|
-
setIsTranscribing(false);
|
|
55614
|
-
setStatusText("");
|
|
55615
|
-
return;
|
|
55249
|
+
if (!transcribeUrl) {
|
|
55250
|
+
setError("Voice transcription is not configured.");
|
|
55251
|
+
setIsTranscribing(false);
|
|
55252
|
+
setStatusText("");
|
|
55253
|
+
return;
|
|
55254
|
+
}
|
|
55255
|
+
const res = await fetch(transcribeUrl, {
|
|
55256
|
+
method: "POST",
|
|
55257
|
+
headers: { "Content-Type": "application/json" },
|
|
55258
|
+
body: JSON.stringify({ audio: wavBase64, format: "wav" })
|
|
55259
|
+
});
|
|
55260
|
+
if (!res.ok) {
|
|
55261
|
+
let msg = `Transcription error ${res.status}`;
|
|
55262
|
+
try {
|
|
55263
|
+
const err = await res.json();
|
|
55264
|
+
if (err?.error)
|
|
55265
|
+
msg = err.error;
|
|
55266
|
+
} catch {
|
|
55616
55267
|
}
|
|
55617
|
-
|
|
55618
|
-
wavBase64,
|
|
55619
|
-
"wav",
|
|
55620
|
-
normalizedKey,
|
|
55621
|
-
voiceModel
|
|
55622
|
-
);
|
|
55268
|
+
throw new Error(msg);
|
|
55623
55269
|
}
|
|
55270
|
+
const data = await res.json();
|
|
55271
|
+
const transcription = data?.text ?? "";
|
|
55624
55272
|
const updated = (prevPromptRef.current ? `${prevPromptRef.current} ` : "") + transcription;
|
|
55625
55273
|
prevPromptRef.current = updated;
|
|
55626
55274
|
setPrompt(updated);
|
|
@@ -55640,7 +55288,7 @@ var AIChatPanel = React64.forwardRef(
|
|
|
55640
55288
|
stream?.getTracks().forEach((t2) => t2.stop());
|
|
55641
55289
|
setError("Could not access microphone. Check browser permissions.");
|
|
55642
55290
|
}
|
|
55643
|
-
}, [isRecording,
|
|
55291
|
+
}, [isRecording, transcribeUrl]);
|
|
55644
55292
|
const handleCopy = useCallback29((msgId, content) => {
|
|
55645
55293
|
navigator.clipboard.writeText(content).then(
|
|
55646
55294
|
() => {
|
|
@@ -55655,16 +55303,13 @@ var AIChatPanel = React64.forwardRef(
|
|
|
55655
55303
|
const handleSend = useCallback29(
|
|
55656
55304
|
async (textOverride) => {
|
|
55657
55305
|
const text = (textOverride ?? prompt).trim();
|
|
55658
|
-
const normalizedKey = resolveOpenRouterApiKey(apiKey);
|
|
55659
55306
|
if (!text || isLoading) {
|
|
55660
55307
|
voiceUsedRef.current = false;
|
|
55661
55308
|
return;
|
|
55662
55309
|
}
|
|
55663
|
-
if (!
|
|
55310
|
+
if (!chatUrl) {
|
|
55664
55311
|
voiceUsedRef.current = false;
|
|
55665
|
-
setError(
|
|
55666
|
-
"No OpenRouter API key. Set VITE_APP_OPENROUTER_API_KEY in .env or pass the key via the `apiKey` prop."
|
|
55667
|
-
);
|
|
55312
|
+
setError("Chat is not configured.");
|
|
55668
55313
|
return;
|
|
55669
55314
|
}
|
|
55670
55315
|
const capturedFiles = [...attachedFiles];
|
|
@@ -55747,7 +55392,7 @@ var AIChatPanel = React64.forwardRef(
|
|
|
55747
55392
|
try {
|
|
55748
55393
|
const reply = await callPlainChatAPI(
|
|
55749
55394
|
nextMessages,
|
|
55750
|
-
|
|
55395
|
+
chatUrl,
|
|
55751
55396
|
controller.signal,
|
|
55752
55397
|
{
|
|
55753
55398
|
webSearchEnabled: capturedWebSearch,
|
|
@@ -55841,14 +55486,14 @@ var AIChatPanel = React64.forwardRef(
|
|
|
55841
55486
|
textContent: f.textContent
|
|
55842
55487
|
})) : void 0,
|
|
55843
55488
|
webSearchEnabled: capturedWebSearch,
|
|
55844
|
-
|
|
55489
|
+
chatUrl,
|
|
55845
55490
|
chatModel,
|
|
55846
55491
|
agentImageModel,
|
|
55847
55492
|
brandContext,
|
|
55848
55493
|
customFontIds,
|
|
55849
55494
|
toolCtx: {
|
|
55850
55495
|
excalidrawAPI,
|
|
55851
|
-
|
|
55496
|
+
imageGenUrl: imageGenUrl ?? chatUrl,
|
|
55852
55497
|
signal: controller.signal,
|
|
55853
55498
|
agentImageModel,
|
|
55854
55499
|
onSearchBrandAssets,
|
|
@@ -55961,7 +55606,8 @@ var AIChatPanel = React64.forwardRef(
|
|
|
55961
55606
|
prompt,
|
|
55962
55607
|
isLoading,
|
|
55963
55608
|
messages,
|
|
55964
|
-
|
|
55609
|
+
chatUrl,
|
|
55610
|
+
imageGenUrl,
|
|
55965
55611
|
excalidrawAPI,
|
|
55966
55612
|
frameRef,
|
|
55967
55613
|
attachedFiles,
|
|
@@ -56496,7 +56142,7 @@ function ReviewCritiqueCard({ feedback }) {
|
|
|
56496
56142
|
}
|
|
56497
56143
|
);
|
|
56498
56144
|
}
|
|
56499
|
-
async function callPlainChatAPI(messages,
|
|
56145
|
+
async function callPlainChatAPI(messages, chatUrl, signal, opts) {
|
|
56500
56146
|
const baseModel = opts?.chatModel || "minimax/minimax-m3";
|
|
56501
56147
|
const model = opts?.webSearchEnabled ? `${baseModel}:online` : baseModel;
|
|
56502
56148
|
const systemMessages = [];
|
|
@@ -56545,18 +56191,14 @@ ${f.textContent}`).join("\n\n")}`;
|
|
|
56545
56191
|
if (opts?.onChunk) {
|
|
56546
56192
|
body.stream = true;
|
|
56547
56193
|
}
|
|
56548
|
-
const response = await fetch(
|
|
56549
|
-
"
|
|
56550
|
-
|
|
56551
|
-
|
|
56552
|
-
|
|
56553
|
-
|
|
56554
|
-
|
|
56555
|
-
|
|
56556
|
-
},
|
|
56557
|
-
body: JSON.stringify(body)
|
|
56558
|
-
}
|
|
56559
|
-
);
|
|
56194
|
+
const response = await fetch(chatUrl, {
|
|
56195
|
+
method: "POST",
|
|
56196
|
+
signal,
|
|
56197
|
+
headers: {
|
|
56198
|
+
"Content-Type": "application/json"
|
|
56199
|
+
},
|
|
56200
|
+
body: JSON.stringify(body)
|
|
56201
|
+
});
|
|
56560
56202
|
if (!response.ok) {
|
|
56561
56203
|
let message = `OpenRouter error ${response.status}`;
|
|
56562
56204
|
try {
|
|
@@ -56696,14 +56338,12 @@ var ExcalidrawBase = (props) => {
|
|
|
56696
56338
|
renderEmbeddable,
|
|
56697
56339
|
aiEnabled,
|
|
56698
56340
|
showDeprecatedFonts,
|
|
56699
|
-
|
|
56700
|
-
|
|
56701
|
-
|
|
56341
|
+
imageGenUrl,
|
|
56342
|
+
autoResizeUrl,
|
|
56343
|
+
removeBgUrl,
|
|
56702
56344
|
renderScrollbars,
|
|
56703
56345
|
onBeforeImageGen,
|
|
56704
56346
|
onAfterImageGen,
|
|
56705
|
-
onBeforeUpscale,
|
|
56706
|
-
onAfterUpscale,
|
|
56707
56347
|
onBeforeRemoveBg,
|
|
56708
56348
|
onAfterRemoveBg,
|
|
56709
56349
|
onBeforeAutoResize,
|
|
@@ -56794,14 +56434,12 @@ var ExcalidrawBase = (props) => {
|
|
|
56794
56434
|
renderEmbeddable,
|
|
56795
56435
|
aiEnabled: aiEnabled !== false,
|
|
56796
56436
|
showDeprecatedFonts,
|
|
56797
|
-
|
|
56798
|
-
|
|
56799
|
-
|
|
56437
|
+
imageGenUrl,
|
|
56438
|
+
autoResizeUrl,
|
|
56439
|
+
removeBgUrl,
|
|
56800
56440
|
renderScrollbars,
|
|
56801
56441
|
onBeforeImageGen,
|
|
56802
56442
|
onAfterImageGen,
|
|
56803
|
-
onBeforeUpscale,
|
|
56804
|
-
onAfterUpscale,
|
|
56805
56443
|
onBeforeRemoveBg,
|
|
56806
56444
|
onAfterRemoveBg,
|
|
56807
56445
|
onBeforeAutoResize,
|