@goodandready/dsh-image-gen 0.11.25 → 0.11.27
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/lib/attachment-helper.js +25 -0
- package/lib/client.js +179 -39
- package/lib/frontend-assets.js +218 -43
- package/lib/index.js +4 -0
- package/lib/live-progress.js +278 -0
- package/lib/pattern-helpers.js +17 -0
- package/lib/provider-utils.js +77 -15
- package/lib/providers/backends/custom.js +7 -1
- package/lib/providers/backends/fal.js +7 -3
- package/lib/providers/backends/local.js +137 -48
- package/lib/providers/shared-helpers.js +63 -1
- package/lib/providers.js +235 -13
- package/lib/quality-gate.js +6 -5
- package/lib/register-tools.js +19 -1
- package/lib/resolve-image.js +1 -1
- package/lib/tools/editing.js +17 -0
- package/lib/tools/frontend.js +29 -12
- package/lib/tools/generation.js +7 -2
- package/lib/tools/inspect.js +2 -2
- package/lib/tools/pattern.js +9 -5
- package/lib/tools/processing-basic.js +7 -2
- package/lib/tools/style-matrix.js +9 -1
- package/lib/tools/theme-pair.js +19 -1
- package/package.json +2 -2
package/lib/attachment-helper.js
CHANGED
|
@@ -112,3 +112,28 @@ export function renderToolOutput(value) {
|
|
|
112
112
|
}
|
|
113
113
|
return blocks
|
|
114
114
|
}
|
|
115
|
+
|
|
116
|
+
export function buildPresentationMeta(value) {
|
|
117
|
+
if (!value || typeof value !== 'object') return null
|
|
118
|
+
const meta = {
|
|
119
|
+
url: value.url,
|
|
120
|
+
path: value.path,
|
|
121
|
+
width: value.width,
|
|
122
|
+
height: value.height,
|
|
123
|
+
seed: value.seed,
|
|
124
|
+
prompt: value.prompt,
|
|
125
|
+
provider: value.provider,
|
|
126
|
+
model: value.model,
|
|
127
|
+
attachment: value.attachment,
|
|
128
|
+
attachmentId: value.attachment?.attachmentId || value.attachmentId,
|
|
129
|
+
}
|
|
130
|
+
if (value.images) meta.images = value.images
|
|
131
|
+
if (value.cells) meta.cells = value.cells
|
|
132
|
+
if (value.base_prompt) meta.base_prompt = value.base_prompt
|
|
133
|
+
if (value.blind_mode !== undefined) meta.blind_mode = value.blind_mode
|
|
134
|
+
if (value.light) meta.light = value.light
|
|
135
|
+
if (value.dark) meta.dark = value.dark
|
|
136
|
+
if (value.html_snippet) meta.html_snippet = value.html_snippet
|
|
137
|
+
if (value.css_snippet) meta.css_snippet = value.css_snippet
|
|
138
|
+
return meta
|
|
139
|
+
}
|
package/lib/client.js
CHANGED
|
@@ -145,11 +145,15 @@ window.__ModuleLoader__.load({
|
|
|
145
145
|
.ig-progress-meta{display:flex;justify-content:space-between;align-items:center;font-size:11px;color:var(--dsw-alias-label-secondary);font-weight:500}
|
|
146
146
|
.ig-progress-track{height:6px;width:100%;background:var(--dsw-alias-bg-layer-1);border-radius:3px;overflow:hidden;position:relative}
|
|
147
147
|
.ig-progress-fill{height:100%;background:var(--dsw-alias-state-brand);border-radius:3px;transition:width 0.25s ease-in-out}
|
|
148
|
+
.ig-progress-indeterminate{width:40%;animation:ig-indeterminate-slide 1.5s infinite ease-in-out}
|
|
149
|
+
@keyframes ig-indeterminate-slide{0%{transform:translateX(-100%)}50%{transform:translateX(150%)}100%{transform:translateX(300%)}}
|
|
148
150
|
|
|
149
151
|
.ig-draft-overlay{position:absolute;bottom:8px;left:8px;padding:3px 8px;border-radius:4px;background:color-mix(in srgb, var(--dsw-alias-bg-layer-1) 80%, transparent);font-size:11px;font-weight:600;color:var(--dsw-alias-label-primary);display:flex;align-items:center;gap:6px;backdrop-filter:blur(4px)}
|
|
150
152
|
|
|
151
153
|
@media (prefers-reduced-motion: reduce){
|
|
152
154
|
.ig-draft-img,.ig-final-img{transition:none !important}
|
|
155
|
+
.ig-progress-fill{transition:none !important;animation:none !important}
|
|
156
|
+
.ig-progress-indeterminate{animation:none !important;width:100%;opacity:0.6}
|
|
153
157
|
}
|
|
154
158
|
|
|
155
159
|
/* Asset Vault & Studio (#158, #159) */
|
|
@@ -1369,17 +1373,53 @@ window.__ModuleLoader__.load({
|
|
|
1369
1373
|
}
|
|
1370
1374
|
|
|
1371
1375
|
// -------------------------------------------------------------- Toolview Component
|
|
1372
|
-
const
|
|
1376
|
+
const HTTP_IMAGE_URL_RE = /https?:\/\/[^\s)]+\.(png|jpg|jpeg|webp|gif)(\?[^\s)]*)?/i
|
|
1377
|
+
const RELATIVE_IMAGE_URL_RE = /(\/dsh-image-gen\/image\?[^\s)"'<>]+)/i
|
|
1378
|
+
const MARKDOWN_IMAGE_RE = /!\[.*?\]\(((\/|https?:\/\/)[^\s)]+)\)/i
|
|
1379
|
+
const MARKDOWN_LINK_RE = /\[.*?\]\(((\/|https?:\/\/)[^\s)]+)\)/i
|
|
1373
1380
|
|
|
1374
1381
|
function readResult(block) {
|
|
1375
1382
|
if (!block) return { text: '', url: '', attachment: null }
|
|
1376
1383
|
const text = block.output || block.text || ''
|
|
1377
|
-
const
|
|
1378
|
-
|
|
1384
|
+
const meta = block.presentationMeta || block.meta || block.data || block.result || null
|
|
1385
|
+
|
|
1386
|
+
let attachment = block.attachment
|
|
1387
|
+
|| (Array.isArray(block.attachments) && block.attachments[0])
|
|
1388
|
+
|| meta?.attachment
|
|
1389
|
+
|| null
|
|
1390
|
+
|
|
1391
|
+
let url = meta?.url || block.url || ''
|
|
1392
|
+
|
|
1393
|
+
if (!url && attachment) {
|
|
1394
|
+
url = attachmentImageUrl(attachment)
|
|
1395
|
+
}
|
|
1396
|
+
|
|
1397
|
+
let cleanText = text
|
|
1398
|
+
if (!url && text) {
|
|
1399
|
+
const mdImg = text.match(MARKDOWN_IMAGE_RE)
|
|
1400
|
+
const relUrl = text.match(RELATIVE_IMAGE_URL_RE)
|
|
1401
|
+
const httpUrl = text.match(HTTP_IMAGE_URL_RE)
|
|
1402
|
+
const mdLink = text.match(MARKDOWN_LINK_RE)
|
|
1403
|
+
|
|
1404
|
+
if (mdImg) {
|
|
1405
|
+
url = mdImg[1]
|
|
1406
|
+
cleanText = text.replace(mdImg[0], '').trim()
|
|
1407
|
+
} else if (relUrl) {
|
|
1408
|
+
url = relUrl[1]
|
|
1409
|
+
cleanText = text.replace(relUrl[0], '').trim()
|
|
1410
|
+
} else if (httpUrl) {
|
|
1411
|
+
url = httpUrl[0]
|
|
1412
|
+
cleanText = text.replace(httpUrl[0], '').trim()
|
|
1413
|
+
} else if (mdLink) {
|
|
1414
|
+
url = mdLink[1]
|
|
1415
|
+
cleanText = text.replace(mdLink[0], '').trim()
|
|
1416
|
+
}
|
|
1417
|
+
}
|
|
1418
|
+
|
|
1379
1419
|
return {
|
|
1380
1420
|
attachment,
|
|
1381
|
-
url
|
|
1382
|
-
text:
|
|
1421
|
+
url,
|
|
1422
|
+
text: cleanText,
|
|
1383
1423
|
}
|
|
1384
1424
|
}
|
|
1385
1425
|
|
|
@@ -1586,6 +1626,7 @@ window.__ModuleLoader__.load({
|
|
|
1586
1626
|
const draftSrc = block && (block.draftUrl || block.previewUrl || '')
|
|
1587
1627
|
body.push(react.createElement(ProgressiveImagePreview, {
|
|
1588
1628
|
key: 'prog-img',
|
|
1629
|
+
callId: block && (block.id || block.callId || block.toolCallId || ''),
|
|
1589
1630
|
src: displaySrc,
|
|
1590
1631
|
draftSrc,
|
|
1591
1632
|
isRunning: running,
|
|
@@ -1694,8 +1735,9 @@ window.__ModuleLoader__.load({
|
|
|
1694
1735
|
react,
|
|
1695
1736
|
t,
|
|
1696
1737
|
parsed,
|
|
1697
|
-
imgUrl: parsed.
|
|
1698
|
-
targetRef: parsed.
|
|
1738
|
+
imgUrl: parsed.url || (parsed.attachment ? attachmentImageUrl(parsed.attachment) : ''),
|
|
1739
|
+
targetRef: (parsed.attachment && (parsed.attachment.attachmentId || parsed.attachment.id)) || parsed.url || 'latest',
|
|
1740
|
+
sendActionPrompt,
|
|
1699
1741
|
onClose: () => setInpaintOpen(false),
|
|
1700
1742
|
}) : null
|
|
1701
1743
|
|
|
@@ -1761,23 +1803,76 @@ window.__ModuleLoader__.load({
|
|
|
1761
1803
|
current.seed !== undefined ? `seed: ${current.seed}` : (current.timestamp ? new Date(current.timestamp).toLocaleTimeString() : '')
|
|
1762
1804
|
)
|
|
1763
1805
|
)
|
|
1764
|
-
} // -------------------------------------------------------------- Progressive Draft & Live Progress Preview (#147, #329)
|
|
1806
|
+
} // -------------------------------------------------------------- Progressive Draft & Live Progress Preview (#147, #329, #379)
|
|
1765
1807
|
function ProgressiveImagePreview(props) {
|
|
1766
1808
|
const src = props.src
|
|
1767
|
-
const draftSrc = props.draftSrc
|
|
1768
1809
|
const isRunning = props.isRunning
|
|
1769
|
-
const
|
|
1770
|
-
const step = props.step
|
|
1771
|
-
const stage = props.stage || (progress !== undefined && progress < 100 ? 'Rendering...' : 'Complete')
|
|
1810
|
+
const callId = props.callId
|
|
1772
1811
|
const alt = props.alt || 'Generated image'
|
|
1773
1812
|
const t = props.t || ((k) => k)
|
|
1774
1813
|
|
|
1775
1814
|
const [loaded, setLoaded] = react.useState(false)
|
|
1815
|
+
const [liveState, setLiveState] = react.useState({
|
|
1816
|
+
progress: undefined,
|
|
1817
|
+
step: undefined,
|
|
1818
|
+
stage: undefined,
|
|
1819
|
+
draftSrc: '',
|
|
1820
|
+
})
|
|
1776
1821
|
|
|
1777
1822
|
react.useEffect(() => {
|
|
1778
1823
|
setLoaded(false)
|
|
1779
1824
|
}, [src])
|
|
1780
1825
|
|
|
1826
|
+
// Subscribe to live events transport when running and callId is present (#379)
|
|
1827
|
+
react.useEffect(() => {
|
|
1828
|
+
const EventSourceImpl = typeof window !== 'undefined' ? window.EventSource : undefined
|
|
1829
|
+
if (!isRunning || !callId || !EventSourceImpl) {
|
|
1830
|
+
return
|
|
1831
|
+
}
|
|
1832
|
+
let es
|
|
1833
|
+
try {
|
|
1834
|
+
es = new EventSourceImpl('/dsh-image-gen/live-events?callId=' + encodeURIComponent(callId))
|
|
1835
|
+
es.onmessage = (e) => {
|
|
1836
|
+
try {
|
|
1837
|
+
const data = JSON.parse(e.data)
|
|
1838
|
+
if (!data) return
|
|
1839
|
+
setLiveState((prev) => ({
|
|
1840
|
+
progress: typeof data.progress === 'number' ? Math.min(100, Math.max(0, data.progress)) : prev.progress,
|
|
1841
|
+
step: data.step !== undefined ? data.step : prev.step,
|
|
1842
|
+
stage: data.stage !== undefined ? data.stage : prev.stage,
|
|
1843
|
+
draftSrc: data.draftUrl || prev.draftSrc,
|
|
1844
|
+
}))
|
|
1845
|
+
} catch (_err) {
|
|
1846
|
+
// Ignore event parsing errors
|
|
1847
|
+
}
|
|
1848
|
+
}
|
|
1849
|
+
es.onerror = () => {
|
|
1850
|
+
// EventSource handles retries or terminates on close
|
|
1851
|
+
}
|
|
1852
|
+
} catch (_err) {
|
|
1853
|
+
// Ignore EventSource creation errors
|
|
1854
|
+
}
|
|
1855
|
+
|
|
1856
|
+
return () => {
|
|
1857
|
+
if (es) {
|
|
1858
|
+
try {
|
|
1859
|
+
es.close()
|
|
1860
|
+
} catch (_err) {
|
|
1861
|
+
// Ignore EventSource close errors
|
|
1862
|
+
}
|
|
1863
|
+
}
|
|
1864
|
+
}
|
|
1865
|
+
}, [isRunning, callId])
|
|
1866
|
+
|
|
1867
|
+
const draftSrc = liveState.draftSrc || props.draftSrc
|
|
1868
|
+
const progress = liveState.progress !== undefined
|
|
1869
|
+
? liveState.progress
|
|
1870
|
+
: (typeof props.progress === 'number' ? Math.min(100, Math.max(0, props.progress)) : undefined)
|
|
1871
|
+
const step = liveState.step !== undefined ? liveState.step : props.step
|
|
1872
|
+
const stage = liveState.stage
|
|
1873
|
+
|| props.stage
|
|
1874
|
+
|| (progress !== undefined && progress < 100 ? (t('card.rendering') || 'Rendering...') : (isRunning ? (t('card.generating') || 'Generating...') : 'Complete'))
|
|
1875
|
+
|
|
1781
1876
|
const showProgress = isRunning || (progress !== undefined && progress < 100)
|
|
1782
1877
|
|
|
1783
1878
|
const progressElement = showProgress ? react.createElement(
|
|
@@ -1793,8 +1888,8 @@ window.__ModuleLoader__.load({
|
|
|
1793
1888
|
'div',
|
|
1794
1889
|
{ className: 'ig-progress-track' },
|
|
1795
1890
|
react.createElement('div', {
|
|
1796
|
-
className: 'ig-progress-fill',
|
|
1797
|
-
style:
|
|
1891
|
+
className: 'ig-progress-fill' + (progress === undefined ? ' ig-progress-indeterminate' : ''),
|
|
1892
|
+
style: progress !== undefined ? { width: progress + '%' } : undefined,
|
|
1798
1893
|
})
|
|
1799
1894
|
)
|
|
1800
1895
|
) : null
|
|
@@ -1842,10 +1937,17 @@ window.__ModuleLoader__.load({
|
|
|
1842
1937
|
progressElement
|
|
1843
1938
|
)
|
|
1844
1939
|
}
|
|
1845
|
-
// 105-inpaint-canvas.js — Interactive in-chat canvas drawing overlay for inpainting (#285, #301, #328).
|
|
1940
|
+
// 105-inpaint-canvas.js — Interactive in-chat canvas drawing overlay for inpainting (#285, #301, #328, #380).
|
|
1941
|
+
|
|
1942
|
+
function buildEditInstruction(opts) {
|
|
1943
|
+
const p = (opts && opts.prompt ? opts.prompt.trim() : '') || 'inpaint masked region'
|
|
1944
|
+
const img = (opts && opts.image) || 'latest'
|
|
1945
|
+
const m = (opts && opts.mask) || ''
|
|
1946
|
+
return 'Use edit_image with prompt: "' + p + '", image: "' + img + '", mask: "' + m + '"'
|
|
1947
|
+
}
|
|
1846
1948
|
|
|
1847
1949
|
function InpaintCanvas(props) {
|
|
1848
|
-
const { imgUrl, targetRef, parsed, onClose, t } = props
|
|
1950
|
+
const { imgUrl, targetRef, parsed, onClose, sendActionPrompt, t } = props
|
|
1849
1951
|
const canvasRef = react.useRef(null)
|
|
1850
1952
|
const isDrawingRef = react.useRef(false)
|
|
1851
1953
|
const undoStackRef = react.useRef([])
|
|
@@ -1856,8 +1958,12 @@ window.__ModuleLoader__.load({
|
|
|
1856
1958
|
const [inpaintPrompt, setInpaintPrompt] = react.useState('')
|
|
1857
1959
|
const [canvasDims, setCanvasDims] = react.useState({ width: 512, height: 512, ratio: '1/1' })
|
|
1858
1960
|
|
|
1859
|
-
const effectiveImgUrl = imgUrl || parsed?.
|
|
1860
|
-
const effectiveTargetRef = targetRef
|
|
1961
|
+
const effectiveImgUrl = imgUrl || (parsed?.attachment ? attachmentImageUrl(parsed.attachment) : (parsed?.url || ''))
|
|
1962
|
+
const effectiveTargetRef = targetRef
|
|
1963
|
+
|| (parsed?.attachment && (parsed.attachment.attachmentId || parsed.attachment.id))
|
|
1964
|
+
|| parsed?.attachmentId
|
|
1965
|
+
|| parsed?.url
|
|
1966
|
+
|| 'latest'
|
|
1861
1967
|
|
|
1862
1968
|
const initCanvas = react.useCallback(() => {
|
|
1863
1969
|
const canvas = canvasRef.current
|
|
@@ -1877,11 +1983,8 @@ window.__ModuleLoader__.load({
|
|
|
1877
1983
|
if (e.target && e.target.naturalWidth && e.target.naturalHeight) {
|
|
1878
1984
|
const nw = e.target.naturalWidth
|
|
1879
1985
|
const nh = e.target.naturalHeight
|
|
1880
|
-
//
|
|
1881
|
-
|
|
1882
|
-
const cw = Math.round(nw * scale)
|
|
1883
|
-
const ch = Math.round(nh * scale)
|
|
1884
|
-
setCanvasDims({ width: cw, height: ch, ratio: `${cw}/${ch}` })
|
|
1986
|
+
// Preserve 1:1 intrinsic source dimensions for accurate mask generation (#380)
|
|
1987
|
+
setCanvasDims({ width: nw, height: nh, ratio: `${nw}/${nh}` })
|
|
1885
1988
|
}
|
|
1886
1989
|
}
|
|
1887
1990
|
|
|
@@ -1889,11 +1992,12 @@ window.__ModuleLoader__.load({
|
|
|
1889
1992
|
const rect = canvas.getBoundingClientRect()
|
|
1890
1993
|
const clientX = e.touches ? e.touches[0].clientX : e.clientX
|
|
1891
1994
|
const clientY = e.touches ? e.touches[0].clientY : e.clientY
|
|
1892
|
-
const scaleX = canvas.width / rect.width
|
|
1893
|
-
const scaleY = canvas.height / rect.height
|
|
1995
|
+
const scaleX = canvas.width / (rect.width || canvas.width)
|
|
1996
|
+
const scaleY = canvas.height / (rect.height || canvas.height)
|
|
1894
1997
|
return {
|
|
1895
1998
|
x: (clientX - rect.left) * scaleX,
|
|
1896
1999
|
y: (clientY - rect.top) * scaleY,
|
|
2000
|
+
scale: (scaleX + scaleY) / 2,
|
|
1897
2001
|
}
|
|
1898
2002
|
}
|
|
1899
2003
|
|
|
@@ -1905,16 +2009,17 @@ window.__ModuleLoader__.load({
|
|
|
1905
2009
|
if (!ctx) return
|
|
1906
2010
|
isDrawingRef.current = true
|
|
1907
2011
|
const pos = getPos(e, canvas)
|
|
2012
|
+
const actualBrush = brushSize * (pos.scale || 1)
|
|
1908
2013
|
ctx.beginPath()
|
|
1909
2014
|
ctx.moveTo(pos.x, pos.y)
|
|
1910
|
-
ctx.lineWidth =
|
|
2015
|
+
ctx.lineWidth = actualBrush
|
|
1911
2016
|
ctx.lineCap = 'round'
|
|
1912
2017
|
ctx.lineJoin = 'round'
|
|
1913
2018
|
const color = toolMode === 'eraser' ? 'black' : 'white'
|
|
1914
2019
|
ctx.strokeStyle = color
|
|
1915
2020
|
ctx.fillStyle = color
|
|
1916
2021
|
|
|
1917
|
-
ctx.arc(pos.x, pos.y,
|
|
2022
|
+
ctx.arc(pos.x, pos.y, actualBrush / 2, 0, Math.PI * 2)
|
|
1918
2023
|
ctx.fill()
|
|
1919
2024
|
ctx.beginPath()
|
|
1920
2025
|
ctx.moveTo(pos.x, pos.y)
|
|
@@ -1929,25 +2034,26 @@ window.__ModuleLoader__.load({
|
|
|
1929
2034
|
const ctx = canvas.getContext('2d')
|
|
1930
2035
|
if (!ctx) return
|
|
1931
2036
|
const pos = getPos(e, canvas)
|
|
1932
|
-
|
|
2037
|
+
const actualBrush = brushSize * (pos.scale || 1)
|
|
2038
|
+
ctx.lineWidth = actualBrush
|
|
1933
2039
|
ctx.lineCap = 'round'
|
|
1934
2040
|
ctx.lineJoin = 'round'
|
|
1935
2041
|
const color = toolMode === 'eraser' ? 'black' : 'white'
|
|
1936
2042
|
ctx.strokeStyle = color
|
|
1937
2043
|
ctx.lineTo(pos.x, pos.y)
|
|
1938
2044
|
ctx.stroke()
|
|
1939
|
-
|
|
2045
|
+
ctx.beginPath()
|
|
2046
|
+
ctx.moveTo(pos.x, pos.y)
|
|
1940
2047
|
}
|
|
1941
2048
|
|
|
1942
|
-
function stopDraw(
|
|
2049
|
+
function stopDraw() {
|
|
1943
2050
|
if (!isDrawingRef.current) return
|
|
1944
2051
|
isDrawingRef.current = false
|
|
1945
2052
|
const canvas = canvasRef.current
|
|
1946
2053
|
if (!canvas) return
|
|
1947
2054
|
const ctx = canvas.getContext('2d')
|
|
1948
2055
|
if (!ctx) return
|
|
1949
|
-
ctx.
|
|
1950
|
-
|
|
2056
|
+
ctx.beginPath()
|
|
1951
2057
|
if (undoStackRef.current.length >= 15) {
|
|
1952
2058
|
undoStackRef.current.shift()
|
|
1953
2059
|
}
|
|
@@ -2000,7 +2106,15 @@ window.__ModuleLoader__.load({
|
|
|
2000
2106
|
if (!canvas) return
|
|
2001
2107
|
const maskDataUrl = canvas.toDataURL('image/png')
|
|
2002
2108
|
const promptText = inpaintPrompt.trim() || 'inpaint masked region'
|
|
2003
|
-
const instruction =
|
|
2109
|
+
const instruction = buildEditInstruction({
|
|
2110
|
+
prompt: promptText,
|
|
2111
|
+
image: effectiveTargetRef,
|
|
2112
|
+
mask: maskDataUrl,
|
|
2113
|
+
})
|
|
2114
|
+
|
|
2115
|
+
if (typeof sendActionPrompt === 'function') {
|
|
2116
|
+
sendActionPrompt(instruction)
|
|
2117
|
+
}
|
|
2004
2118
|
|
|
2005
2119
|
if (typeof navigator !== 'undefined' && navigator.clipboard) {
|
|
2006
2120
|
navigator.clipboard.writeText(instruction)
|
|
@@ -2188,7 +2302,18 @@ window.__ModuleLoader__.load({
|
|
|
2188
2302
|
const t = props.t || ((k) => k)
|
|
2189
2303
|
const block = props.block || {}
|
|
2190
2304
|
const parsed = react.useMemo(() => {
|
|
2305
|
+
const meta = block.presentationMeta || block.meta || block.data || block.result
|
|
2306
|
+
if (meta && Array.isArray(meta.cells) && meta.cells.length) {
|
|
2307
|
+
return meta
|
|
2308
|
+
}
|
|
2191
2309
|
const raw = block.output || block.text || ''
|
|
2310
|
+
const tagMatch = raw.match(/<dsh-image-gen-matrix>([\s\S]*?)<\/dsh-image-gen-matrix>/)
|
|
2311
|
+
if (tagMatch) {
|
|
2312
|
+
const fromTag = tryParseJsonObject(tagMatch[1])
|
|
2313
|
+
if (fromTag && Array.isArray(fromTag.cells) && fromTag.cells.length) {
|
|
2314
|
+
return fromTag
|
|
2315
|
+
}
|
|
2316
|
+
}
|
|
2192
2317
|
const obj = tryParseJsonObject(raw)
|
|
2193
2318
|
return obj || { base_prompt: '', blind_mode: false, cells: [] }
|
|
2194
2319
|
}, [block])
|
|
@@ -2307,12 +2432,27 @@ window.__ModuleLoader__.load({
|
|
|
2307
2432
|
let args = {}
|
|
2308
2433
|
try { if (raw) args = JSON.parse(raw) } catch (_) { /* invalid json */ }
|
|
2309
2434
|
|
|
2310
|
-
let data =
|
|
2311
|
-
|
|
2312
|
-
const out = block && (block.output || block.
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2435
|
+
let data = block && (block.presentationMeta || block.meta || block.data || block.result)
|
|
2436
|
+
if (!data || (!data.light && !data.dark)) {
|
|
2437
|
+
const out = block && (block.output || block.text || '')
|
|
2438
|
+
const tagMatch = typeof out === 'string' ? out.match(/<dsh-image-gen-theme-pair>([\s\S]*?)<\/dsh-image-gen-theme-pair>/) : null
|
|
2439
|
+
if (tagMatch) {
|
|
2440
|
+
try {
|
|
2441
|
+
data = JSON.parse(tagMatch[1])
|
|
2442
|
+
} catch (_err) {
|
|
2443
|
+
// Malformed XML payload
|
|
2444
|
+
}
|
|
2445
|
+
}
|
|
2446
|
+
if (!data || (!data.light && !data.dark)) {
|
|
2447
|
+
try {
|
|
2448
|
+
if (typeof out === 'object') data = out
|
|
2449
|
+
else if (typeof out === 'string') data = JSON.parse(out)
|
|
2450
|
+
} catch (_err) {
|
|
2451
|
+
// Malformed fallback output
|
|
2452
|
+
}
|
|
2453
|
+
}
|
|
2454
|
+
}
|
|
2455
|
+
data = data || {}
|
|
2316
2456
|
|
|
2317
2457
|
const light = data.light || {}
|
|
2318
2458
|
const dark = data.dark || {}
|