Spaces:
Paused
Paused
File size: 11,932 Bytes
b5f60e1 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 | <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Structured Prompt Studio</title>
<style>
%%CSS%%
</style>
</head>
<body data-generated="%%GENERATION_TIME%%">
<div class="app">
<!-- ==================== History Bar ==================== -->
<div class="history-bar">
<div class="history-title">History</div>
<div class="history-scroll" id="historyScroll">
<div class="history-empty" id="historyEmpty">No history yet</div>
</div>
<button class="tool-btn history-clear-btn" id="historyClearBtn" onclick="clearHistory()" title="Clear history" style="display:none;">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="3 6 5 6 21 6"/><path d="M19 6v14a2 2 0 01-2 2H7a2 2 0 01-2-2V6m3 0V4a2 2 0 012-2h4a2 2 0 012 2v2"/></svg>
</button>
</div>
<!-- ==================== Workspace (CSS Grid) ==================== -->
<div class="workspace">
<!-- Image Panel (row 1, col 1) -->
<div class="panel image-panel" id="imagePanel">
<div class="panel-toolbar">
<span class="panel-label">Image</span>
<div class="panel-actions">
<button class="tool-btn" onclick="triggerImageUpload()" title="Import image">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4"/><polyline points="17 8 12 3 7 8"/><line x1="12" y1="3" x2="12" y2="15"/></svg>
</button>
<button class="tool-btn" id="btnBboxShow" onclick="showAllBboxes()" title="Show all bboxes" style="display:none;">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><circle cx="12" cy="12" r="3"/></svg>
</button>
<button class="tool-btn" id="btnBboxHide" onclick="hideAllBboxes()" title="Hide all bboxes" style="display:none;">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M17.94 17.94A10.07 10.07 0 0112 20c-7 0-11-8-11-8a18.45 18.45 0 015.06-5.94M9.9 4.24A9.12 9.12 0 0112 4c7 0 11 8 11 8a18.5 18.5 0 01-2.16 3.19m-6.72-1.07a3 3 0 11-4.24-4.24"/><line x1="1" y1="1" x2="23" y2="23"/></svg>
</button>
<button class="tool-btn" id="btnImageZoom" onclick="handleImageEnlarge()" title="Zoom" style="display:none;">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/><line x1="11" y1="8" x2="11" y2="14"/><line x1="8" y1="11" x2="14" y2="11"/></svg>
</button>
<button class="tool-btn" id="btnImageDelete" onclick="handleImageDelete()" title="Delete image" style="display:none;">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="3 6 5 6 21 6"/><path d="M19 6v14a2 2 0 01-2 2H7a2 2 0 01-2-2V6m3 0V4a2 2 0 012-2h4a2 2 0 012 2v2"/></svg>
</button>
</div>
</div>
<div class="image-area" id="imageArea">
<div class="dropzone" id="dropzone" onclick="triggerImageUpload()">
<div class="dropzone-icon">πΌοΈ</div>
<div class="dropzone-text">Drop an image here or click to upload</div>
</div>
<div class="image-display" id="imageDisplay" style="display:none;">
<img id="displayImage" onclick="handleImageClick(event)" title="Click to select a bbox" />
<div class="bbox-container" id="bboxContainer"></div>
</div>
</div>
<input type="file" id="imageFileInput" accept="image/*" onchange="handleImageFileSelected(event)" style="display:none;">
</div>
<!-- Structured Prompt Panel (row 1, col 2) -->
<div class="panel sp-panel" id="spPanel">
<div class="panel-toolbar">
<span class="panel-label">Structured Prompt</span>
<div class="panel-actions">
<button class="tool-btn" id="btnSPRaw" onclick="toggleSPRawMode()" title="Toggle raw JSON">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="16 18 22 12 16 6"/><polyline points="8 6 2 12 8 18"/></svg>
</button>
<button class="tool-btn" onclick="triggerSPImport()" title="Import JSON">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4"/><polyline points="17 8 12 3 7 8"/><line x1="12" y1="3" x2="12" y2="15"/></svg>
</button>
<button class="tool-btn" id="btnSPUndo" onclick="handleSPUndo()" title="Undo" style="display:none;">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="1 4 1 10 7 10"/><path d="M3.51 15a9 9 0 102.13-9.36L1 10"/></svg>
</button>
<button class="tool-btn" id="btnSPDelete" onclick="handleSPDelete()" title="Clear" style="display:none;">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="3 6 5 6 21 6"/><path d="M19 6v14a2 2 0 01-2 2H7a2 2 0 01-2-2V6m3 0V4a2 2 0 012-2h4a2 2 0 012 2v2"/></svg>
</button>
</div>
</div>
<div class="sp-area" id="spArea">
<div class="sp-empty" id="spEmpty">
<div class="sp-empty-icon">π</div>
<div>Structured Prompt is empty</div>
<div class="sp-empty-hint">Generate one with the button, or paste / import JSON</div>
</div>
<div class="sp-structured" id="spStructured" style="display:none;"></div>
<textarea id="spTextarea" style="display:none;" spellcheck="false"
placeholder="Paste Structured Prompt JSON here..."></textarea>
</div>
<input type="file" id="spFileInput" accept=".json,.txt" onchange="handleSPFileSelected(event)" style="display:none;">
</div>
<!-- Params Bar (row 2, col 1) -->
<div class="panel params-bar">
<div class="params-label">Params</div>
<div class="params-group">
<label>CFG</label>
<input type="number" id="paramCfgScale" value="4.0" min="0" max="20" step="0.1">
</div>
<div class="params-group">
<label>Steps</label>
<input type="number" id="paramSteps" value="25" min="1" max="100" step="1">
</div>
<div class="params-spacer"></div>
<div class="params-group">
<label>H</label>
<input type="number" id="paramHeight" value="1024" min="64" max="4096" step="32">
</div>
<div class="params-group">
<label>W</label>
<input type="number" id="paramWidth" value="1024" min="64" max="4096" step="32">
</div>
<div class="params-group">
<label>Seed</label>
<input type="number" id="paramSeed" value="42" min="-1" max="999999">
</div>
</div>
<!-- Generate SP Button (row 2, col 2) -->
<button class="action-btn gen-sp-btn" id="genSPBtn" onclick="handleGenerateSP()">
Generate SP
</button>
<!-- User Prompt Bar (row 3, col 1) -->
<div class="panel prompt-bar">
<div class="prompt-label">User Prompt</div>
<textarea id="userPromptInput" placeholder="Describe the image you want..." rows="1"></textarea>
</div>
<!-- Generate Image Button (row 3, col 2) -->
<button class="action-btn gen-image-btn" id="genImageBtn" onclick="handleGenerateImage()">
Generate Image
</button>
</div>
</div>
<!-- ==================== Image Enlarge Modal ==================== -->
<div class="modal-overlay" id="imageModal" onclick="closeImageModal()">
<div class="modal-image-container" id="modalImageContainer" onclick="event.stopPropagation()">
<img id="modalImage" class="modal-image" />
</div>
<button class="modal-close-btn" onclick="closeImageModal()">β</button>
</div>
<!-- ==================== Diff Confirmation Dialog ==================== -->
<div class="modal-overlay" id="diffModal">
<div class="diff-dialog" onclick="event.stopPropagation()">
<div class="diff-header">
<span>Review changes</span>
<button class="modal-close-btn-sm" onclick="cancelGeneration()">β</button>
</div>
<div class="diff-content" id="diffContent"></div>
<div class="diff-actions">
<button class="action-btn cancel-btn" onclick="cancelGeneration()">Cancel</button>
<button class="action-btn confirm-btn" onclick="confirmGeneration()">Confirm & generate</button>
</div>
</div>
</div>
<!-- ==================== History Detail Modal ==================== -->
<div class="modal-overlay" id="historyModal" onclick="closeHistoryModal()">
<div class="history-detail" onclick="event.stopPropagation()">
<div class="history-detail-header">
<span>History entry</span>
<button class="modal-close-btn-sm" onclick="closeHistoryModal()">β</button>
</div>
<div class="history-detail-body" id="historyDetailBody"></div>
<div class="history-detail-footer">
<button class="action-btn restore-part-btn" onclick="restoreImageFromHistory()" title="Restore image only">πΌοΈ Image</button>
<button class="action-btn restore-part-btn" onclick="restorePromptFromHistory()" title="Restore User Prompt & SP">π Prompt</button>
<button class="action-btn restore-part-btn" onclick="restoreParamsFromHistory()" title="Restore params only">βοΈ Params</button>
<button class="action-btn restore-btn" onclick="restoreFromHistory()">Restore all</button>
</div>
</div>
</div>
<!-- ==================== Toast Container ==================== -->
<div class="toast-container" id="toastContainer"></div>
<!-- ==================== Add Field Dropdown ==================== -->
<div class="sp-add-dropdown" id="spAddDropdown" style="display:none;"></div>
<!-- ==================== Scripts ==================== -->
<script src="https://cdn.jsdelivr.net/npm/jsonrepair@3/lib/umd/jsonrepair.min.js"></script>
<script>
%%SCRIPT%%
</script>
</body>
</html>
|