updates UI
This commit is contained in:
@@ -97,6 +97,10 @@ Scenery:
|
|||||||
- in order to decouple the landingpage/dashboard from the studio view (editor) we are going to generate group "shoot" specific html pages. Start by just generate the studio portion of car.html into the group specifc html pages. It does not need to be synchronous, but when data of the group is changing we should update the group specifc data json file too, we copy the goup files to the output folder next to car.html
|
- in order to decouple the landingpage/dashboard from the studio view (editor) we are going to generate group "shoot" specific html pages. Start by just generate the studio portion of car.html into the group specifc html pages. It does not need to be synchronous, but when data of the group is changing we should update the group specifc data json file too, we copy the goup files to the output folder next to car.html
|
||||||
- in /mnt/zim/tour-comfy/output/_turntable we have data regarding orbit generations. We want to store the orbit data in the database, start by adding the corresponding tags and meta info to the images (currently stored in the person table (but actually are images with metadata))
|
- in /mnt/zim/tour-comfy/output/_turntable we have data regarding orbit generations. We want to store the orbit data in the database, start by adding the corresponding tags and meta info to the images (currently stored in the person table (but actually are images with metadata))
|
||||||
- in the ui - studio view we have an orbit filter. Currently the filter is filtering too many files, also references of orbit files are being marked orbit. When an orbit file is used, the metadata should not include the orbit tag.
|
- in the ui - studio view we have an orbit filter. Currently the filter is filtering too many files, also references of orbit files are being marked orbit. When an orbit file is used, the metadata should not include the orbit tag.
|
||||||
|
- pose-prompt has at least three parts, [scenery ,pose, art-form] allow in the ui to compound the prompt with these, scene default = "You are in a black void" art-form= "photo-realistic keep identical person from reference" also allow inherit scenery to as option.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## refine
|
## refine
|
||||||
#file:///mnt/zim/tour-comfy/output/shoot_cg_7ec17537.html
|
#file:///mnt/zim/tour-comfy/output/shoot_cg_7ec17537.html
|
||||||
- when refresh page, we lose track of current jobs running.
|
- when refresh page, we lose track of current jobs running.
|
||||||
|
|||||||
@@ -1330,10 +1330,20 @@
|
|||||||
inset: 0;
|
inset: 0;
|
||||||
background: #0a0a0a;
|
background: #0a0a0a;
|
||||||
z-index: 500;
|
z-index: 500;
|
||||||
flex-direction: column;
|
flex-direction: row; /* row layout to support full height sidebar */
|
||||||
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
.studio.open { display: flex; }
|
.studio.open { display: flex; }
|
||||||
|
|
||||||
|
.studio-left {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
height: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
.studio-topbar {
|
.studio-topbar {
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -1348,10 +1358,6 @@
|
|||||||
.studio-topbar-center{ flex: 1; min-width: 0; display: flex; align-items: center; gap: 10px; overflow: hidden; }
|
.studio-topbar-center{ flex: 1; min-width: 0; display: flex; align-items: center; gap: 10px; overflow: hidden; }
|
||||||
.studio-topbar-right { display: flex; align-items: center; gap: 6px; flex-shrink: 0; }
|
.studio-topbar-right { display: flex; align-items: center; gap: 6px; flex-shrink: 0; }
|
||||||
|
|
||||||
.studio-body {
|
|
||||||
flex: 1; min-height: 0;
|
|
||||||
display: flex; overflow: hidden;
|
|
||||||
}
|
|
||||||
.studio-main {
|
.studio-main {
|
||||||
flex: 1; min-width: 0;
|
flex: 1; min-width: 0;
|
||||||
display: flex; flex-direction: column; overflow: hidden;
|
display: flex; flex-direction: column; overflow: hidden;
|
||||||
@@ -1464,7 +1470,7 @@
|
|||||||
.sidebar-inner {
|
.sidebar-inner {
|
||||||
flex: 1; min-height: 0;
|
flex: 1; min-height: 0;
|
||||||
display: flex; flex-direction: column;
|
display: flex; flex-direction: column;
|
||||||
padding-top: 36px; overflow: hidden;
|
padding-top: 8px; overflow: hidden;
|
||||||
transition: opacity 0.15s;
|
transition: opacity 0.15s;
|
||||||
}
|
}
|
||||||
.studio-sidebar.collapsed .sidebar-inner { opacity: 0; pointer-events: none; }
|
.studio-sidebar.collapsed .sidebar-inner { opacity: 0; pointer-events: none; }
|
||||||
@@ -1936,17 +1942,6 @@
|
|||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<!-- Floating services status container -->
|
|
||||||
<div class="services-status-container" style="position: fixed; bottom: 12px; left: 12px; z-index: 11000; display: flex; align-items: center; gap: 14px; background: rgba(18, 18, 18, 0.9); border: 1px solid #2e2e2e; padding: 6px 12px; border-radius: 20px; font-family: monospace; font-size: 11px; color: #aaa; box-shadow: 0 4px 12px rgba(0,0,0,0.5); backdrop-filter: blur(4px);">
|
|
||||||
<div style="display: flex; align-items: center; gap: 6px; cursor: help;" id="backendStatus" title="Backend: Offline (API server is down)">
|
|
||||||
<span class="status-dot-led offline" id="backendDot"></span>
|
|
||||||
<span>API</span>
|
|
||||||
</div>
|
|
||||||
<div style="display: flex; align-items: center; gap: 6px; cursor: help;" id="modelStatus" title="Model-Engine: Status unknown (API server is down)">
|
|
||||||
<span class="status-dot-led offline" id="modelDot"></span>
|
|
||||||
<span>Model</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="privacyOverlay" class="privacy-overlay" onclick="if(privacyMode)disablePrivacyOverlay()">
|
<div id="privacyOverlay" class="privacy-overlay" onclick="if(privacyMode)disablePrivacyOverlay()">
|
||||||
<div class="priv-topbar">
|
<div class="priv-topbar">
|
||||||
<div class="priv-logo">S</div>
|
<div class="priv-logo">S</div>
|
||||||
@@ -2069,12 +2064,23 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="header">
|
<div class="header">
|
||||||
<div class="controls">
|
<div class="controls" style="display:flex;align-items:center;gap:8px">
|
||||||
<span class="count" id="count">0 images</span>
|
<span class="count" id="count">0 images</span>
|
||||||
<button class="btn" id="archiveViewBtn" onclick="toggleArchiveView()" title="View archived items">📦 Archive</button>
|
<button class="btn" id="archiveViewBtn" onclick="toggleArchiveView()" title="View archived items">📦 Archive</button>
|
||||||
<a href="trash.html" class="btn" title="View database inconsistencies" style="text-decoration:none;display:inline-flex;align-items:center;">🗑️ Trash</a>
|
<a href="trash.html" class="btn" title="View database inconsistencies" style="text-decoration:none;display:inline-flex;align-items:center;">🗑️ Trash</a>
|
||||||
<button class="btn" id="selectBtn" onclick="toggleSelectMode()">Select</button>
|
<button class="btn" id="selectBtn" onclick="toggleSelectMode()">Select</button>
|
||||||
<button class="btn" id="privacyBtn" onclick="togglePrivacyMode()" title="Privacy mode — hides content on focus loss (P)">🔓</button>
|
<button class="btn" id="privacyBtn" onclick="togglePrivacyMode()" title="Privacy mode — hides content on focus loss (P)">🔓</button>
|
||||||
|
<!-- Inline Services LEDs on Dashboard -->
|
||||||
|
<div class="services-status-container" style="display:flex;align-items:center;gap:10px;background:rgba(255,255,255,0.03);border:1px solid rgba(255,255,255,0.06);padding:4px 10px;border-radius:15px;font-family:monospace;font-size:10px;color:#888">
|
||||||
|
<div style="display:flex;align-items:center;gap:4px;cursor:help" id="backendStatus" title="Backend: Offline (API server is down)">
|
||||||
|
<span class="status-dot-led offline" id="backendDot"></span>
|
||||||
|
<span>API</span>
|
||||||
|
</div>
|
||||||
|
<div style="display:flex;align-items:center;gap:4px;cursor:help" id="modelStatus" title="Model-Engine: Status unknown (API server is down)">
|
||||||
|
<span class="status-dot-led offline" id="modelDot"></span>
|
||||||
|
<span>COMFY</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="upload-zone">
|
<div class="upload-zone">
|
||||||
<input type="file" id="uploadInput" multiple onchange="handleUpload(event)" />
|
<input type="file" id="uploadInput" multiple onchange="handleUpload(event)" />
|
||||||
@@ -2103,31 +2109,66 @@
|
|||||||
|
|
||||||
<!-- Studio view (replaces old lightbox + faceswap modal) -->
|
<!-- Studio view (replaces old lightbox + faceswap modal) -->
|
||||||
<div id="studio" class="studio">
|
<div id="studio" class="studio">
|
||||||
|
<!-- Left area: topbar + main viewer + filmstrip -->
|
||||||
|
<div class="studio-left">
|
||||||
<!-- Topbar -->
|
<!-- Topbar -->
|
||||||
<div class="studio-topbar">
|
<div class="studio-topbar">
|
||||||
<div class="studio-topbar-left">
|
<div class="studio-topbar-left">
|
||||||
<button class="btn" onclick="closeStudio()" style="font-size:11px;padding:4px 10px">✕ Gallery</button>
|
<a href="./car.html" id="studioDashboardLink" class="btn" style="font-size:11px;padding:4px 10px;text-decoration:none;display:none;align-items:center;gap:4px">← Dashboard</a>
|
||||||
|
<button class="btn" id="studioGalleryBtn" onclick="closeStudio()" style="font-size:11px;padding:4px 10px">✕ Gallery</button>
|
||||||
<button class="btn" id="lbBackBtn" onclick="jumpToPrevGroup()" style="font-size:11px;padding:4px 10px;display:none" title="Go back to previously opened group">↺ Back</button>
|
<button class="btn" id="lbBackBtn" onclick="jumpToPrevGroup()" style="font-size:11px;padding:4px 10px;display:none" title="Go back to previously opened group">↺ Back</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="studio-topbar-center">
|
<div class="studio-topbar-center" style="display:flex;align-items:center;gap:6px">
|
||||||
<input type="text" id="lbGroupNameInput"
|
<input type="text" id="lbGroupNameInput"
|
||||||
style="background:transparent;border:none;border-bottom:1px solid #2a2a2a;color:#fff;font-size:13px;font-weight:600;padding:2px 5px;min-width:80px;max-width:200px;outline:none"
|
style="background:transparent;border:none;border-bottom:1px solid #2a2a2a;color:#fff;font-size:13px;font-weight:600;padding:2px 5px;min-width:80px;max-width:200px;outline:none"
|
||||||
placeholder="Group name…"
|
placeholder="Group name…"
|
||||||
onblur="updateGroupName()" onkeydown="if(event.key==='Enter')this.blur()"
|
onblur="updateGroupName()" onkeydown="if(event.key==='Enter')this.blur()"
|
||||||
title="Group name (applies to all images in this group)" />
|
title="Group name (applies to all images in this group)" />
|
||||||
|
|
||||||
|
<span style="color:#444;font-size:13px">/</span>
|
||||||
|
|
||||||
|
<input type="text" id="lbTopbarImageNameInput"
|
||||||
|
style="background:transparent;border:none;border-bottom:1px solid #2a2a2a;color:#ccc;font-size:12px;padding:2px 5px;min-width:80px;max-width:180px;outline:none"
|
||||||
|
placeholder="Image name…"
|
||||||
|
onblur="updateTopbarImageName()" onkeydown="if(event.key==='Enter')this.blur()"
|
||||||
|
title="Image name / Character name" />
|
||||||
|
|
||||||
|
<div style="display:flex;gap:4px;margin-left:4px">
|
||||||
|
<button class="sb-btn" onclick="copyRawFilename()" style="padding:2px 6px;font-size:9px;min-width:auto;display:inline-flex;align-items:center;gap:3px;height:20px;border-radius:4px" title="Copy raw filename (ID) to clipboard">
|
||||||
|
<svg width="8" height="8" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||||
|
<rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect>
|
||||||
|
<path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path>
|
||||||
|
</svg>ID
|
||||||
|
</button>
|
||||||
|
<button class="sb-btn" onclick="copyFilepath()" style="padding:2px 6px;font-size:9px;min-width:auto;display:inline-flex;align-items:center;gap:3px;height:20px;border-radius:4px" title="Copy absolute file path to clipboard">
|
||||||
|
<svg width="8" height="8" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||||
|
<rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect>
|
||||||
|
<path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path>
|
||||||
|
</svg>Path
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
<span id="lbPoseTag" style="font-size:11px;color:#f59e0b;display:none"></span>
|
<span id="lbPoseTag" style="font-size:11px;color:#f59e0b;display:none"></span>
|
||||||
<span id="lbImgDims" style="font-size:11px;color:#444;margin:0 8px"></span>
|
<span id="lbImgDims" style="font-size:11px;color:#444;margin:0 8px"></span>
|
||||||
<span id="lbCounter" style="font-size:12px;color:#555"></span>
|
<span id="lbCounter" style="font-size:12px;color:#555"></span>
|
||||||
</div>
|
</div>
|
||||||
<div class="studio-topbar-right" style="display:flex;align-items:center;gap:6px">
|
<div class="studio-topbar-right" style="display:flex;align-items:center;gap:6px">
|
||||||
|
<!-- Inline Services LEDs on Studio Topbar -->
|
||||||
|
<div class="services-status-container" style="display:flex;align-items:center;gap:10px;background:rgba(255,255,255,0.03);border:1px solid rgba(255,255,255,0.06);padding:4px 10px;border-radius:15px;font-family:monospace;font-size:10px;color:#888;margin-right:6px">
|
||||||
|
<div style="display:flex;align-items:center;gap:4px;cursor:help" id="studioBackendStatus" title="Backend: Status unknown">
|
||||||
|
<span class="status-dot-led offline" id="studioBackendDot"></span>
|
||||||
|
<span>API</span>
|
||||||
|
</div>
|
||||||
|
<div style="display:flex;align-items:center;gap:4px;cursor:help" id="studioModelStatus" title="Model-Engine: Status unknown">
|
||||||
|
<span class="status-dot-led offline" id="studioModelDot"></span>
|
||||||
|
<span>COMFY</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<button class="btn" id="studioPrivacyBtn" onclick="togglePrivacyMode()" title="Privacy mode — hides content on focus loss (P)" style="font-size:12px;padding:4px 8px">🔓</button>
|
<button class="btn" id="studioPrivacyBtn" onclick="togglePrivacyMode()" title="Privacy mode — hides content on focus loss (P)" style="font-size:12px;padding:4px 8px">🔓</button>
|
||||||
<button class="btn" id="sidebarInnerToggle" onclick="toggleSidebar()" title="Collapse/expand toolbox">⊟</button>
|
<button class="btn" id="sidebarInnerToggle" onclick="toggleSidebar()" title="Collapse/expand toolbox">⊟</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Body: main viewer + sidebar -->
|
|
||||||
<div class="studio-body">
|
|
||||||
|
|
||||||
<!-- Main area: viewer + filmstrip -->
|
<!-- Main area: viewer + filmstrip -->
|
||||||
<div class="studio-main">
|
<div class="studio-main">
|
||||||
<div class="studio-viewer-row">
|
<div class="studio-viewer-row">
|
||||||
@@ -2179,19 +2220,20 @@
|
|||||||
<option value="15000">15s</option>
|
<option value="15000">15s</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div> <!-- Close .studio-main -->
|
||||||
|
</div> <!-- Close .studio-left -->
|
||||||
|
|
||||||
<!-- Sidebar toolbox -->
|
<!-- Sidebar toolbox -->
|
||||||
<div id="studioSidebar" class="studio-sidebar">
|
<div id="studioSidebar" class="studio-sidebar">
|
||||||
<div id="sidebarInner" class="sidebar-inner">
|
<div id="sidebarInner" class="sidebar-inner">
|
||||||
<div class="sidebar-tabs">
|
<div class="sidebar-tabs">
|
||||||
<button class="sb-tab active" data-tab="info" onclick="switchSidebarTab('info')">Info</button>
|
<button class="sb-tab active" data-tab="info" onclick="switchSidebarTab('info')" title="Info">ℹ️</button>
|
||||||
<button class="sb-tab" data-tab="generate" onclick="switchSidebarTab('generate')">Ceate</button>
|
<button class="sb-tab" data-tab="generate" onclick="switchSidebarTab('generate')" title="Create">🪄</button>
|
||||||
<button class="sb-tab" data-tab="faceswap" onclick="switchSidebarTab('faceswap')">👤</button>
|
<button class="sb-tab" data-tab="faceswap" onclick="switchSidebarTab('faceswap')" title="Faceswap">👤</button>
|
||||||
<button class="sb-tab" data-tab="scenery" onclick="switchSidebarTab('scenery')">🎬</button>
|
<button class="sb-tab" data-tab="scenery" onclick="switchSidebarTab('scenery')" title="Scenery">🎬</button>
|
||||||
<button class="sb-tab" data-tab="segment" onclick="switchSidebarTab('segment')">α</button>
|
<button class="sb-tab" data-tab="segment" onclick="switchSidebarTab('segment')" title="Segment / Background">α</button>
|
||||||
<button class="sb-tab" data-tab="orbit" onclick="switchSidebarTab('orbit')" id="sbTabOrbit">⚛</button>
|
<button class="sb-tab" data-tab="orbit" onclick="switchSidebarTab('orbit')" id="sbTabOrbit" title="Orbit 3D">⚛</button>
|
||||||
<button class="sb-tab" data-tab="designer" onclick="switchSidebarTab('designer')" id="sbTabDesigner">Design</button>
|
<button class="sb-tab" data-tab="designer" onclick="switchSidebarTab('designer')" id="sbTabDesigner" title="Design / Refine">🎨</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="sb-panels">
|
<div class="sb-panels">
|
||||||
<!-- Info panel: static HTML with existing lb* IDs so updateStudio() just works -->
|
<!-- Info panel: static HTML with existing lb* IDs so updateStudio() just works -->
|
||||||
@@ -2355,7 +2397,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Orbit preview modal -->
|
<!-- Orbit preview modal -->
|
||||||
<div id="orbitModal">
|
<div id="orbitModal">
|
||||||
@@ -2503,6 +2544,36 @@
|
|||||||
|
|
||||||
// --- HYDRATION_START ---
|
// --- HYDRATION_START ---
|
||||||
const PRELOADED_IMAGES = [
|
const PRELOADED_IMAGES = [
|
||||||
|
"20260701_051754_image.png",
|
||||||
|
"20260701_051737_image.png",
|
||||||
|
"20260701_051721_image.png",
|
||||||
|
"20260701_051704_image.png",
|
||||||
|
"20260701_051647_image.png",
|
||||||
|
"20260701_051614_image.png",
|
||||||
|
"20260701_051541_image.png",
|
||||||
|
"20260701_051520_image.png",
|
||||||
|
"20260701_050249_image.png",
|
||||||
|
"20260701_050232_image.png",
|
||||||
|
"20260701_050215_image.png",
|
||||||
|
"20260701_050158_image.png",
|
||||||
|
"20260701_050141_image.png",
|
||||||
|
"20260701_050124_image.png",
|
||||||
|
"20260701_050108_image.png",
|
||||||
|
"20260701_050051_image.png",
|
||||||
|
"20260701_050035_image.png",
|
||||||
|
"20260701_050018_image.png",
|
||||||
|
"20260701_050001_image.png",
|
||||||
|
"20260701_045945_image.png",
|
||||||
|
"20260701_045928_image.png",
|
||||||
|
"20260701_045912_image.png",
|
||||||
|
"20260701_045838_image.png",
|
||||||
|
"20260701_045822_image.png",
|
||||||
|
"20260701_045805_image.png",
|
||||||
|
"20260701_045749_image.png",
|
||||||
|
"20260701_045732_image.png",
|
||||||
|
"20260701_045716_image.png",
|
||||||
|
"20260701_045659_1_20260619_202924_image.png",
|
||||||
|
"20260620_014953_image.png",
|
||||||
"20260630_130454_sc_0_20260622_101128_image.nobg.png",
|
"20260630_130454_sc_0_20260622_101128_image.nobg.png",
|
||||||
"20260630_131638_sc_2_20260622_101128_image.nobg.nobg.png",
|
"20260630_131638_sc_2_20260622_101128_image.nobg.nobg.png",
|
||||||
"20260630_151502_sc_0_20260622_101128_image.nobg.png",
|
"20260630_151502_sc_0_20260622_101128_image.nobg.png",
|
||||||
@@ -7232,7 +7303,6 @@
|
|||||||
"20260620_020313_2_20260618_172500_image.png",
|
"20260620_020313_2_20260618_172500_image.png",
|
||||||
"20260620_020302_2_20260618_172500_image.png",
|
"20260620_020302_2_20260618_172500_image.png",
|
||||||
"20260620_020251_2_20260618_172500_image.png",
|
"20260620_020251_2_20260618_172500_image.png",
|
||||||
"20260620_014953_image.png",
|
|
||||||
"20260620_014646_image.png",
|
"20260620_014646_image.png",
|
||||||
"20260620_014349_image.png",
|
"20260620_014349_image.png",
|
||||||
"20260620_014239_img_77.png",
|
"20260620_014239_img_77.png",
|
||||||
@@ -7943,6 +8013,7 @@
|
|||||||
// ============================================
|
// ============================================
|
||||||
|
|
||||||
let autoRefreshTimer = null;
|
let autoRefreshTimer = null;
|
||||||
|
let isInitialLoad = true;
|
||||||
let knownFiles = new Set();
|
let knownFiles = new Set();
|
||||||
let currentFiles = [];
|
let currentFiles = [];
|
||||||
let currentGroups = [];
|
let currentGroups = [];
|
||||||
@@ -8175,6 +8246,7 @@
|
|||||||
|
|
||||||
// --- studio view (replaces lightbox) ---
|
// --- studio view (replaces lightbox) ---
|
||||||
let lbUrls = [], lbNames = [], lbIdx = 0;
|
let lbUrls = [], lbNames = [], lbIdx = 0;
|
||||||
|
let _lastRenderedFilename = null;
|
||||||
let _activeFilmstripTab = 'active'; // 'active', 'group', 'hidden', 'source', 'archived'
|
let _activeFilmstripTab = 'active'; // 'active', 'group', 'hidden', 'source', 'archived'
|
||||||
let _multiSelectModeActive = false;
|
let _multiSelectModeActive = false;
|
||||||
const _selectedFilenames = new Set();
|
const _selectedFilenames = new Set();
|
||||||
@@ -9123,6 +9195,23 @@
|
|||||||
|
|
||||||
function updateStudio() {
|
function updateStudio() {
|
||||||
const fname = lbNames[lbIdx];
|
const fname = lbNames[lbIdx];
|
||||||
|
if (fname && fname !== _lastRenderedFilename) {
|
||||||
|
// Image changed, force cancel any active text areas/edits
|
||||||
|
_lastRenderedFilename = fname;
|
||||||
|
const genPromptEl = document.getElementById('lbGenPrompt');
|
||||||
|
if (genPromptEl) {
|
||||||
|
genPromptEl.innerHTML = '';
|
||||||
|
genPromptEl.onclick = () => editMetadataField('prompt');
|
||||||
|
}
|
||||||
|
const descEl = document.getElementById('lbDescription');
|
||||||
|
if (descEl) {
|
||||||
|
descEl.innerHTML = '';
|
||||||
|
descEl.onclick = () => editMetadataField('description');
|
||||||
|
}
|
||||||
|
} else if (!fname) {
|
||||||
|
_lastRenderedFilename = null;
|
||||||
|
}
|
||||||
|
|
||||||
if (document.getElementById('poseCanvas')) _removePoseOverlay(); // skeleton is per-image
|
if (document.getElementById('poseCanvas')) _removePoseOverlay(); // skeleton is per-image
|
||||||
document.getElementById('poseResults')?.remove();
|
document.getElementById('poseResults')?.remove();
|
||||||
|
|
||||||
@@ -9256,6 +9345,9 @@
|
|||||||
const nameInput = document.getElementById('lbNameInput');
|
const nameInput = document.getElementById('lbNameInput');
|
||||||
if (nameInput) { nameInput.value = imageNames[fname] || ''; nameInput.placeholder = fname; }
|
if (nameInput) { nameInput.value = imageNames[fname] || ''; nameInput.placeholder = fname; }
|
||||||
|
|
||||||
|
const topbarNameInput = document.getElementById('lbTopbarImageNameInput');
|
||||||
|
if (topbarNameInput) { topbarNameInput.value = imageNames[fname] || ''; topbarNameInput.placeholder = fname; }
|
||||||
|
|
||||||
const clipEl = document.getElementById('lbClipDesc');
|
const clipEl = document.getElementById('lbClipDesc');
|
||||||
if (clipEl) clipEl.textContent = clipDescriptions[fname] || '';
|
if (clipEl) clipEl.textContent = clipDescriptions[fname] || '';
|
||||||
|
|
||||||
@@ -9682,6 +9774,8 @@
|
|||||||
});
|
});
|
||||||
if (r.ok) {
|
if (r.ok) {
|
||||||
imageNames[fname] = newName;
|
imageNames[fname] = newName;
|
||||||
|
const topbarNameInput = document.getElementById('lbTopbarImageNameInput');
|
||||||
|
if (topbarNameInput) topbarNameInput.value = newName;
|
||||||
showToast(`Name updated`);
|
showToast(`Name updated`);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -9689,6 +9783,18 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function updateTopbarImageName() {
|
||||||
|
const fname = lbNames[lbIdx];
|
||||||
|
const topbarNameInput = document.getElementById('lbTopbarImageNameInput');
|
||||||
|
if (!topbarNameInput) return;
|
||||||
|
const newName = topbarNameInput.value;
|
||||||
|
|
||||||
|
const nameInput = document.getElementById('lbNameInput');
|
||||||
|
if (nameInput) nameInput.value = newName;
|
||||||
|
|
||||||
|
await updateName();
|
||||||
|
}
|
||||||
|
|
||||||
async function updateGroupName() {
|
async function updateGroupName() {
|
||||||
const gid = lbCurrentGid;
|
const gid = lbCurrentGid;
|
||||||
if (!gid) return;
|
if (!gid) return;
|
||||||
@@ -11375,10 +11481,21 @@
|
|||||||
async function _pollTurntableBadge() {
|
async function _pollTurntableBadge() {
|
||||||
try {
|
try {
|
||||||
let d = null;
|
let d = null;
|
||||||
|
const gid = lbCurrentGid;
|
||||||
|
|
||||||
|
if (gid) {
|
||||||
|
try {
|
||||||
|
const r = await fetch(`${API}/turntable/status/${encodeURIComponent(gid)}`);
|
||||||
|
if (r.ok) d = await r.json();
|
||||||
|
} catch (_) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!d) {
|
||||||
try {
|
try {
|
||||||
const r = await fetch(`${API}/output/_data/turntable_status.json?t=` + Date.now(), { signal: AbortSignal.timeout(2000) });
|
const r = await fetch(`${API}/output/_data/turntable_status.json?t=` + Date.now(), { signal: AbortSignal.timeout(2000) });
|
||||||
if (r.ok) d = await r.json();
|
if (r.ok) d = await r.json();
|
||||||
} catch (_) {}
|
} catch (_) {}
|
||||||
|
}
|
||||||
if (!d) {
|
if (!d) {
|
||||||
const r = await fetch(`${API}/turntable/status`);
|
const r = await fetch(`${API}/turntable/status`);
|
||||||
if (r.ok) d = await r.json();
|
if (r.ok) d = await r.json();
|
||||||
@@ -11389,7 +11506,7 @@
|
|||||||
const tbsDot = document.getElementById('tbsDot');
|
const tbsDot = document.getElementById('tbsDot');
|
||||||
const tbsText = document.getElementById('tbsText');
|
const tbsText = document.getElementById('tbsText');
|
||||||
const total = d.n_total || 0;
|
const total = d.n_total || 0;
|
||||||
const done = d.n_complete || 0;
|
const done = (d.n_complete !== undefined ? d.n_complete : d.n_done) || 0;
|
||||||
if (total === 0) { badge.style.display = 'none'; }
|
if (total === 0) { badge.style.display = 'none'; }
|
||||||
else if (done < total) { badge.textContent = `${done}/${total}`; badge.style.display = ''; }
|
else if (done < total) { badge.textContent = `${done}/${total}`; badge.style.display = ''; }
|
||||||
else { badge.style.display = 'none'; }
|
else { badge.style.display = 'none'; }
|
||||||
@@ -11413,8 +11530,15 @@
|
|||||||
|
|
||||||
// Refresh orbit tab badge on the tab button
|
// Refresh orbit tab badge on the tab button
|
||||||
const tabBtn = document.getElementById('sbTabOrbit');
|
const tabBtn = document.getElementById('sbTabOrbit');
|
||||||
if (tabBtn && done > 0) {
|
if (tabBtn) {
|
||||||
tabBtn.textContent = `Orbit${done < total ? ' (' + done + '/' + total + ')' : ' ✓'}`;
|
tabBtn.title = `Orbit 3D (${done}/${total})`;
|
||||||
|
if (total > 0 && done < total) {
|
||||||
|
tabBtn.innerHTML = `⚛<span style="font-size: 8px; vertical-align: super; background: #fbbf24; color: #1e1b4b; padding: 1px 3px; border-radius: 6px; margin-left: 1px; display: inline-block; line-height: 1; font-weight: bold;">${done}/${total}</span>`;
|
||||||
|
} else if (total > 0 && done === total) {
|
||||||
|
tabBtn.innerHTML = `⚛<span style="font-size: 8px; vertical-align: super; background: #10b981; color: #fff; padding: 1px 3px; border-radius: 6px; margin-left: 1px; display: inline-block; line-height: 1; font-weight: bold;">✓</span>`;
|
||||||
|
} else {
|
||||||
|
tabBtn.innerHTML = `⚛`;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch(_) {}
|
} catch(_) {}
|
||||||
}
|
}
|
||||||
@@ -12155,7 +12279,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
document.getElementById('count').textContent = `${currentGroups.length} group${currentGroups.length !== 1 ? 's' : ''} · ${fileObjects.length} images`;
|
document.getElementById('count').textContent = `${currentGroups.length} group${currentGroups.length !== 1 ? 's' : ''} · ${fileObjects.length} images`;
|
||||||
if (newFileNames.size > 0) showToast(`${newFileNames.size} new image${newFileNames.size !== 1 ? 's' : ''} detected`, 'success');
|
if (newFileNames.size > 0 && !isInitialLoad) showToast(`${newFileNames.size} new image${newFileNames.size !== 1 ? 's' : ''} detected`, 'success');
|
||||||
|
isInitialLoad = false;
|
||||||
|
|
||||||
// If studio is open, sync lbUrls/lbNames from freshly-loaded groupData
|
// If studio is open, sync lbUrls/lbNames from freshly-loaded groupData
|
||||||
const studioEl = document.getElementById('studio');
|
const studioEl = document.getElementById('studio');
|
||||||
@@ -12419,18 +12544,36 @@
|
|||||||
_backendOnline = true;
|
_backendOnline = true;
|
||||||
_modelEngineOnline = data.model_engine.online;
|
_modelEngineOnline = data.model_engine.online;
|
||||||
|
|
||||||
const backendDot = document.getElementById('backendDot');
|
const backendClass = data.backend.busy ? 'status-dot-led busy' : 'status-dot-led online';
|
||||||
if (backendDot) {
|
const backendTitle = data.backend.busy ? 'Backend: Active task running' : 'Backend: Idle (Online)';
|
||||||
backendDot.className = 'status-dot-led ' + (data.backend.busy ? 'busy' : 'online');
|
|
||||||
backendDot.parentElement.title = data.backend.busy ? 'Backend: Active task running' : 'Backend: Idle (Online)';
|
|
||||||
}
|
|
||||||
|
|
||||||
const modelDot = document.getElementById('modelDot');
|
const modelClass = data.model_engine.online ? (data.model_engine.busy ? 'status-dot-led busy' : 'status-dot-led online') : 'status-dot-led offline';
|
||||||
if (modelDot) {
|
const modelTitle = data.model_engine.online
|
||||||
modelDot.className = 'status-dot-led ' + (data.model_engine.online ? (data.model_engine.busy ? 'busy' : 'online') : 'offline');
|
|
||||||
modelDot.parentElement.title = data.model_engine.online
|
|
||||||
? (data.model_engine.busy ? 'Model-Engine: Active inference running' : 'Model-Engine: Idle (Online)')
|
? (data.model_engine.busy ? 'Model-Engine: Active inference running' : 'Model-Engine: Idle (Online)')
|
||||||
: 'Model-Engine: Offline (ComfyUI backend is down)';
|
: 'Model-Engine: Offline (ComfyUI backend is down)';
|
||||||
|
|
||||||
|
// Dashboard dots
|
||||||
|
const backendDot = document.getElementById('backendDot');
|
||||||
|
if (backendDot) {
|
||||||
|
backendDot.className = backendClass;
|
||||||
|
backendDot.parentElement.title = backendTitle;
|
||||||
|
}
|
||||||
|
const modelDot = document.getElementById('modelDot');
|
||||||
|
if (modelDot) {
|
||||||
|
modelDot.className = modelClass;
|
||||||
|
modelDot.parentElement.title = modelTitle;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Studio topbar dots
|
||||||
|
const studioBackendDot = document.getElementById('studioBackendDot');
|
||||||
|
if (studioBackendDot) {
|
||||||
|
studioBackendDot.className = backendClass;
|
||||||
|
studioBackendDot.parentElement.title = backendTitle;
|
||||||
|
}
|
||||||
|
const studioModelDot = document.getElementById('studioModelDot');
|
||||||
|
if (studioModelDot) {
|
||||||
|
studioModelDot.className = modelClass;
|
||||||
|
studioModelDot.parentElement.title = modelTitle;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
throw new Error("API responded with error");
|
throw new Error("API responded with error");
|
||||||
@@ -12439,15 +12582,32 @@
|
|||||||
_backendOnline = false;
|
_backendOnline = false;
|
||||||
_modelEngineOnline = false;
|
_modelEngineOnline = false;
|
||||||
|
|
||||||
|
const offlineClass = 'status-dot-led offline';
|
||||||
|
const backendOfflineTitle = 'Backend: Offline (API server is down)';
|
||||||
|
const modelOfflineTitle = 'Model-Engine: Status unknown (API server is down)';
|
||||||
|
|
||||||
|
// Dashboard dots
|
||||||
const backendDot = document.getElementById('backendDot');
|
const backendDot = document.getElementById('backendDot');
|
||||||
if (backendDot) {
|
if (backendDot) {
|
||||||
backendDot.className = 'status-dot-led offline';
|
backendDot.className = offlineClass;
|
||||||
backendDot.parentElement.title = 'Backend: Offline (API server is down)';
|
backendDot.parentElement.title = backendOfflineTitle;
|
||||||
}
|
}
|
||||||
const modelDot = document.getElementById('modelDot');
|
const modelDot = document.getElementById('modelDot');
|
||||||
if (modelDot) {
|
if (modelDot) {
|
||||||
modelDot.className = 'status-dot-led offline';
|
modelDot.className = offlineClass;
|
||||||
modelDot.parentElement.title = 'Model-Engine: Status unknown (API server is down)';
|
modelDot.parentElement.title = modelOfflineTitle;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Studio topbar dots
|
||||||
|
const studioBackendDot = document.getElementById('studioBackendDot');
|
||||||
|
if (studioBackendDot) {
|
||||||
|
studioBackendDot.className = offlineClass;
|
||||||
|
studioBackendDot.parentElement.title = backendOfflineTitle;
|
||||||
|
}
|
||||||
|
const studioModelDot = document.getElementById('studioModelDot');
|
||||||
|
if (studioModelDot) {
|
||||||
|
studioModelDot.className = offlineClass;
|
||||||
|
studioModelDot.parentElement.title = modelOfflineTitle;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -13007,6 +13167,14 @@
|
|||||||
document.title = PRIV_TITLE;
|
document.title = PRIV_TITLE;
|
||||||
showPrivacyOverlay();
|
showPrivacyOverlay();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Direct-to-dashboard back link for group specific pages
|
||||||
|
if (typeof LOAD_ONLY_GROUP_ID !== 'undefined' && LOAD_ONLY_GROUP_ID) {
|
||||||
|
const dashLink = document.getElementById('studioDashboardLink');
|
||||||
|
const galBtn = document.getElementById('studioGalleryBtn');
|
||||||
|
if (dashLink) dashLink.style.display = 'inline-flex';
|
||||||
|
if (galBtn) galBtn.style.display = 'none';
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
async function toggleTagAction(tagName) {
|
async function toggleTagAction(tagName) {
|
||||||
@@ -13095,7 +13263,7 @@
|
|||||||
fileDescriptions[fname] = newDesc;
|
fileDescriptions[fname] = newDesc;
|
||||||
showToast('Successfully updated both prompt and description!', 'success');
|
showToast('Successfully updated both prompt and description!', 'success');
|
||||||
updateStudio();
|
updateStudio();
|
||||||
refreshNow();
|
refreshNow(true);
|
||||||
} else {
|
} else {
|
||||||
showToast('Failed to update prompt or description', 'error');
|
showToast('Failed to update prompt or description', 'error');
|
||||||
}
|
}
|
||||||
@@ -13120,17 +13288,19 @@
|
|||||||
const el = document.getElementById(contentId);
|
const el = document.getElementById(contentId);
|
||||||
if (!el || el.querySelector('textarea')) return;
|
if (!el || el.querySelector('textarea')) return;
|
||||||
|
|
||||||
|
const buttonLabel = currentVal.trim() === '' ? '✨ Create' : '✨ Refine';
|
||||||
|
|
||||||
el.onclick = null;
|
el.onclick = null;
|
||||||
el.innerHTML = `
|
el.innerHTML = `
|
||||||
<textarea id="editFieldArea" style="width:100%;min-height:80px;background:#0d0d0d;border:1px solid #333;color:#ccc;font-size:11px;font-family:monospace;padding:6px;border-radius:4px;outline:none;resize:vertical;line-height:1.4;margin-bottom:4px">${currentVal}</textarea>
|
<textarea id="editFieldArea_${field}" style="width:100%;min-height:80px;background:#0d0d0d;border:1px solid #333;color:#ccc;font-size:11px;font-family:monospace;padding:6px;border-radius:4px;outline:none;resize:vertical;line-height:1.4;margin-bottom:4px">${currentVal}</textarea>
|
||||||
<div style="display:flex;gap:6px;justify-content:flex-end">
|
<div style="display:flex;gap:6px;justify-content:flex-end">
|
||||||
<button class="sb-btn" style="padding:2px 8px;font-size:10px" onclick="cancelEditField(event, '${field}')">Cancel</button>
|
<button class="sb-btn" style="padding:2px 8px;font-size:10px" onclick="cancelEditField(event, '${field}')">Cancel</button>
|
||||||
<button class="sb-btn" style="padding:2px 8px;font-size:10px" onclick="refineField(event, '${field}')">✨ Refine</button>
|
<button class="sb-btn" style="padding:2px 8px;font-size:10px" onclick="refineField(event, '${field}')">${buttonLabel}</button>
|
||||||
<button class="sb-btn" style="padding:2px 8px;font-size:10px;background:#10b981;color:#fff" onclick="saveEditField(event, '${field}')">Save</button>
|
<button class="sb-btn" style="padding:2px 8px;font-size:10px;background:#10b981;color:#fff" onclick="saveEditField(event, '${field}')">Save</button>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const ta = document.getElementById('editFieldArea');
|
const ta = document.getElementById(`editFieldArea_${field}`);
|
||||||
if (ta) {
|
if (ta) {
|
||||||
ta.focus();
|
ta.focus();
|
||||||
ta.setSelectionRange(ta.value.length, ta.value.length);
|
ta.setSelectionRange(ta.value.length, ta.value.length);
|
||||||
@@ -13151,7 +13321,7 @@
|
|||||||
const fname = lbNames[lbIdx];
|
const fname = lbNames[lbIdx];
|
||||||
if (!fname) return;
|
if (!fname) return;
|
||||||
|
|
||||||
const ta = document.getElementById('editFieldArea');
|
const ta = document.getElementById(`editFieldArea_${field}`);
|
||||||
if (!ta) return;
|
if (!ta) return;
|
||||||
const newVal = ta.value.trim();
|
const newVal = ta.value.trim();
|
||||||
|
|
||||||
@@ -13174,7 +13344,7 @@
|
|||||||
showToast('Character & scenery description updated successfully', 'success');
|
showToast('Character & scenery description updated successfully', 'success');
|
||||||
}
|
}
|
||||||
updateStudio();
|
updateStudio();
|
||||||
refreshNow();
|
refreshNow(true);
|
||||||
} else {
|
} else {
|
||||||
showToast('Failed to save update', 'error');
|
showToast('Failed to save update', 'error');
|
||||||
}
|
}
|
||||||
@@ -13189,24 +13359,30 @@
|
|||||||
const fname = lbNames[lbIdx];
|
const fname = lbNames[lbIdx];
|
||||||
if (!fname) return;
|
if (!fname) return;
|
||||||
|
|
||||||
const ta = document.getElementById('editFieldArea');
|
const ta = document.getElementById(`editFieldArea_${field}`);
|
||||||
if (!ta) return;
|
if (!ta) return;
|
||||||
const currentVal = ta.value.trim();
|
const currentVal = ta.value.trim();
|
||||||
|
|
||||||
const instruction = prompt(`Enter instructions to refine this ${field}:`, "Make it more detailed...");
|
const actionVerb = currentVal === '' ? 'create' : 'refine';
|
||||||
|
const instruction = prompt(`Enter instructions to ${actionVerb} this ${field}:`, actionVerb === 'create' ? "Write a detailed description of..." : "Make it more detailed...");
|
||||||
if (!instruction) return;
|
if (!instruction) return;
|
||||||
|
|
||||||
showToast('AI is refining your text...', 'info');
|
showToast(`AI is generating your ${field}...`, 'info');
|
||||||
try {
|
try {
|
||||||
const r = await fetch(`${API}/refine-prompt`, {
|
const r = await fetch(`${API}/refine-prompt`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
body: JSON.stringify({ prompt: currentVal, user_instruction: instruction })
|
body: JSON.stringify({
|
||||||
|
prompt: currentVal,
|
||||||
|
user_instruction: instruction,
|
||||||
|
filename: fname,
|
||||||
|
field: field
|
||||||
|
})
|
||||||
});
|
});
|
||||||
if (r.ok) {
|
if (r.ok) {
|
||||||
const data = await r.json();
|
const data = await r.json();
|
||||||
ta.value = data.refined;
|
ta.value = data.refined;
|
||||||
showToast('Refined successfully! Click Save to apply.', 'success');
|
showToast('Successfully updated! Click Save to apply.', 'success');
|
||||||
} else {
|
} else {
|
||||||
showToast('Failed to refine field: ' + await r.text(), 'error');
|
showToast('Failed to refine field: ' + await r.text(), 'error');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -422,7 +422,8 @@ def list_persons(include_archived=False):
|
|||||||
SELECT filename, name, group_id, clip_description,
|
SELECT filename, name, group_id, clip_description,
|
||||||
prompt, pose, sort_order, group_name, hidden, has_background, source_refs,
|
prompt, pose, sort_order, group_name, hidden, has_background, source_refs,
|
||||||
has_clothing, content_type, faceswap_source_video, archived, is_source, tags,
|
has_clothing, content_type, faceswap_source_video, archived, is_source, tags,
|
||||||
pose_description, pose_skeleton, people_count, anatomical_completeness, facial_direction, objects, description
|
pose_description, pose_skeleton, people_count, anatomical_completeness, facial_direction, objects, description,
|
||||||
|
filepath
|
||||||
FROM person
|
FROM person
|
||||||
{where}
|
{where}
|
||||||
""")
|
""")
|
||||||
|
|||||||
@@ -1508,6 +1508,8 @@ def _write_all_static() -> None:
|
|||||||
"anatomical_completeness": p[20],
|
"anatomical_completeness": p[20],
|
||||||
"facial_direction": p[21],
|
"facial_direction": p[21],
|
||||||
"objects": obj_list,
|
"objects": obj_list,
|
||||||
|
"description": p[23],
|
||||||
|
"filepath": p[24],
|
||||||
})
|
})
|
||||||
print(f"[static] write_all: {len(db_images)} total images, {archived_count} archived")
|
print(f"[static] write_all: {len(db_images)} total images, {archived_count} archived")
|
||||||
try:
|
try:
|
||||||
@@ -2144,16 +2146,15 @@ def start_multi_ref(req: MultiRefRequest):
|
|||||||
|
|
||||||
|
|
||||||
class RefineRequest(BaseModel):
|
class RefineRequest(BaseModel):
|
||||||
prompt: str
|
prompt: str = ""
|
||||||
filename: str | None = None
|
filename: str | None = None
|
||||||
|
user_instruction: str | None = None
|
||||||
|
field: str | None = None
|
||||||
|
|
||||||
|
|
||||||
@app.post("/refine-prompt")
|
@app.post("/refine-prompt")
|
||||||
def refine_prompt(req: RefineRequest):
|
def refine_prompt(req: RefineRequest):
|
||||||
"""Refine a prompt using the external uncensored chat LLM."""
|
"""Refine or create a prompt/description using the external uncensored chat LLM."""
|
||||||
if not req.prompt:
|
|
||||||
raise HTTPException(400, "Prompt is required")
|
|
||||||
|
|
||||||
context_str = ""
|
context_str = ""
|
||||||
if req.filename:
|
if req.filename:
|
||||||
try:
|
try:
|
||||||
@@ -2197,9 +2198,22 @@ def refine_prompt(req: RefineRequest):
|
|||||||
except Exception as db_err:
|
except Exception as db_err:
|
||||||
print(f"[refine-prompt] database error for {req.filename}: {db_err}")
|
print(f"[refine-prompt] database error for {req.filename}: {db_err}")
|
||||||
|
|
||||||
user_content = f"Refine this pose: {req.prompt}"
|
field_label = req.field if req.field else "text"
|
||||||
|
|
||||||
|
if req.prompt:
|
||||||
|
if req.user_instruction:
|
||||||
|
user_content = f"Refine this {field_label} according to the following instructions:\n{req.user_instruction}\n\nOriginal {field_label}:\n{req.prompt}"
|
||||||
|
else:
|
||||||
|
user_content = f"Refine this {field_label} to make it more descriptive, detailed, and high-quality.\n\nOriginal {field_label}:\n{req.prompt}"
|
||||||
|
else:
|
||||||
|
# Prompt/text is empty, so we are creating one from scratch!
|
||||||
|
if req.user_instruction:
|
||||||
|
user_content = f"Create a new {field_label} from scratch according to these instructions:\n{req.user_instruction}"
|
||||||
|
else:
|
||||||
|
user_content = f"Create a new detailed and high-quality {field_label} from scratch."
|
||||||
|
|
||||||
if context_str:
|
if context_str:
|
||||||
user_content += f"\n\nUse the following image context details to ensure the refined prompt matches the reference characteristics closely:\n{context_str}"
|
user_content += f"\n\nUse the following image context details to ensure the output matches the reference characteristics closely:\n{context_str}"
|
||||||
|
|
||||||
# Use the same API as gen_poses.py
|
# Use the same API as gen_poses.py
|
||||||
llm_api = "http://192.168.1.160:8001/v1/chat/completions"
|
llm_api = "http://192.168.1.160:8001/v1/chat/completions"
|
||||||
@@ -2221,7 +2235,8 @@ def refine_prompt(req: RefineRequest):
|
|||||||
try:
|
try:
|
||||||
database.save_db_prompt("refine", refined, {
|
database.save_db_prompt("refine", refined, {
|
||||||
"original": req.prompt,
|
"original": req.prompt,
|
||||||
"filename": req.filename
|
"filename": req.filename,
|
||||||
|
"field": req.field
|
||||||
})
|
})
|
||||||
except Exception as db_err:
|
except Exception as db_err:
|
||||||
print(f"[refine-prompt] failed to save to prompt table: {db_err}")
|
print(f"[refine-prompt] failed to save to prompt table: {db_err}")
|
||||||
@@ -2712,6 +2727,7 @@ def list_images(archived: bool = False, bypass_static: bool = False):
|
|||||||
"facial_direction": p[21],
|
"facial_direction": p[21],
|
||||||
"objects": obj_list,
|
"objects": obj_list,
|
||||||
"description": p[23] if len(p) > 23 else None,
|
"description": p[23] if len(p) > 23 else None,
|
||||||
|
"filepath": p[24] if len(p) > 24 else None,
|
||||||
})
|
})
|
||||||
db_images.sort(
|
db_images.sort(
|
||||||
key=lambda x: _get_cached_file_meta(x["filename"], output_dir)[1],
|
key=lambda x: _get_cached_file_meta(x["filename"], output_dir)[1],
|
||||||
|
|||||||
@@ -878,6 +878,7 @@ Anatomically precise, hyperrealistic, high detail, keep the characteristics of t
|
|||||||
|
|
||||||
# Lantern:
|
# Lantern:
|
||||||
|
|
||||||
|
you are in a black void.
|
||||||
kneeling, knees apart, sitting back on the heels.
|
kneeling, knees apart, sitting back on the heels.
|
||||||
torso upright, spine long.
|
torso upright, spine long.
|
||||||
arms extended overhead, hands clasped or holding an imaginary object.
|
arms extended overhead, hands clasped or holding an imaginary object.
|
||||||
@@ -889,6 +890,7 @@ Anatomically precise, hyperrealistic, high detail, keep the characteristics of t
|
|||||||
|
|
||||||
# Compass:
|
# Compass:
|
||||||
|
|
||||||
|
you are in a black void.
|
||||||
seated, one leg extended straight forward.
|
seated, one leg extended straight forward.
|
||||||
other leg bent, foot placed on the inner thigh of the extended leg.
|
other leg bent, foot placed on the inner thigh of the extended leg.
|
||||||
torso folded forward over the extended leg.
|
torso folded forward over the extended leg.
|
||||||
@@ -900,6 +902,7 @@ Anatomically precise, hyperrealistic, high detail, keep the characteristics of t
|
|||||||
|
|
||||||
# Vessel (beta):
|
# Vessel (beta):
|
||||||
|
|
||||||
|
you are in a black void.
|
||||||
lying on back, knees bent, feet flat on the ground.
|
lying on back, knees bent, feet flat on the ground.
|
||||||
arms extended overhead, hands clasped.
|
arms extended overhead, hands clasped.
|
||||||
hips lifted slightly, lower back arched.
|
hips lifted slightly, lower back arched.
|
||||||
@@ -911,6 +914,7 @@ Anatomically precise, hyperrealistic, high detail, keep the characteristics of t
|
|||||||
|
|
||||||
# Quiver (beta):
|
# Quiver (beta):
|
||||||
|
|
||||||
|
you are in a black void.
|
||||||
lying on stomach, legs together, arms at the sides.
|
lying on stomach, legs together, arms at the sides.
|
||||||
torso lifted in a backbend, chest and shoulders arching upward.
|
torso lifted in a backbend, chest and shoulders arching upward.
|
||||||
head thrown back, neck stretched.
|
head thrown back, neck stretched.
|
||||||
@@ -922,6 +926,7 @@ Perfect anatomy, hyperrealistic
|
|||||||
|
|
||||||
# Loom:
|
# Loom:
|
||||||
|
|
||||||
|
you are in a black void.
|
||||||
seated, legs extended straight forward, feet flexed.
|
seated, legs extended straight forward, feet flexed.
|
||||||
torso upright, spine long.
|
torso upright, spine long.
|
||||||
arms extended forward, hands reaching toward the feet.
|
arms extended forward, hands reaching toward the feet.
|
||||||
@@ -4637,4 +4642,5 @@ Your gaze is locked onto the viewer, a look of defiance and anticipation. The po
|
|||||||
power, the steel bars creating an asymmetrical silhouette. Perfect anatomy, realistic.
|
power, the steel bars creating an asymmetrical silhouette. Perfect anatomy, realistic.
|
||||||
|
|
||||||
# nice pose
|
# nice pose
|
||||||
|
|
||||||
standing, feet apart, hands on the hips. torso twisted, one shoulder forward, one back. weight shifted to one leg, opposite hip popped. waist compressed, creating a pronounced hourglass silhouette. head turned to look over the shoulder. Looking back into camera. Pinched, exaggerated. Perfect anatomy, realistic
|
standing, feet apart, hands on the hips. torso twisted, one shoulder forward, one back. weight shifted to one leg, opposite hip popped. waist compressed, creating a pronounced hourglass silhouette. head turned to look over the shoulder. Looking back into camera. Pinched, exaggerated. Perfect anatomy, realistic
|
||||||
Reference in New Issue
Block a user