Add extra prompts, endless generation, random character default, and small fixes
- Add extra positive/negative prompt textareas to all 9 detail pages with session persistence - Add Endless generation button to all detail pages (continuous preview generation until stopped) - Default character selector to "Random Character" on all secondary detail pages - Fix queue clear endpoint (remove spurious auth check) - Refactor app.py into routes/ and services/ modules - Update CLAUDE.md with new architecture documentation - Various data file updates and cleanup Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -29,17 +29,6 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Image Modal -->
|
||||
<div class="modal fade" id="imageModal" tabindex="-1" aria-hidden="true">
|
||||
<div class="modal-dialog modal-xl modal-dialog-centered">
|
||||
<div class="modal-content bg-transparent border-0">
|
||||
<div class="modal-body p-0 text-center">
|
||||
<img id="modalImage" src="" alt="Enlarged Image" class="img-fluid" style="max-height: 90vh;">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||
<div>
|
||||
<a href="{{ url_for('presets_index') }}" class="btn btn-sm btn-outline-secondary me-2">Back to Library</a>
|
||||
@@ -59,8 +48,7 @@
|
||||
<div class="col-md-4">
|
||||
<div class="card mb-3">
|
||||
<div class="img-container" style="height:auto;min-height:400px;cursor:pointer;"
|
||||
data-bs-toggle="modal" data-bs-target="#imageModal"
|
||||
onclick="showImage(this.querySelector('img') ? this.querySelector('img').src : '')">
|
||||
onclick="openGallery([this.querySelector('img') ? this.querySelector('img').src : this.src || ''], 0)">
|
||||
{% if preset.image_path %}
|
||||
<img src="{{ url_for('static', filename='uploads/' + preset.image_path) }}"
|
||||
alt="{{ preset.name }}" class="img-fluid"
|
||||
@@ -72,18 +60,28 @@
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form action="{{ url_for('upload_preset_image', slug=preset.slug) }}" method="post" enctype="multipart/form-data" class="mb-3">
|
||||
<label class="form-label text-muted small">Update Cover Image</label>
|
||||
<div class="input-group input-group-sm">
|
||||
<input class="form-control" type="file" name="image" required>
|
||||
<button type="submit" class="btn btn-outline-primary">Upload</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<form id="generate-form" action="{{ url_for('generate_preset_image', slug=preset.slug) }}" method="post">
|
||||
{# Additional Prompts #}
|
||||
<div class="mb-2">
|
||||
<label for="extra_positive" class="form-label">Additional Positive</label>
|
||||
<textarea class="form-control form-control-sm font-monospace" id="extra_positive" name="extra_positive" rows="2" placeholder="e.g. masterpiece, best quality">{{ extra_positive or '' }}</textarea>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="extra_negative" class="form-label">Additional Negative</label>
|
||||
<textarea class="form-control form-control-sm font-monospace" id="extra_negative" name="extra_negative" rows="2" placeholder="e.g. blurry, low quality">{{ extra_negative or '' }}</textarea>
|
||||
</div>
|
||||
|
||||
<div class="d-grid gap-2">
|
||||
<button type="submit" name="action" value="preview" class="btn btn-success">Generate Preview</button>
|
||||
<button type="submit" name="action" value="replace" class="btn btn-outline-warning btn-sm">Generate & Set Cover</button>
|
||||
<div class="input-group input-group-sm mb-1">
|
||||
<span class="input-group-text">Seed</span>
|
||||
<input type="number" class="form-control" id="seed-input" name="seed" placeholder="Random" min="1" step="1">
|
||||
<button type="button" class="btn btn-outline-secondary" id="seed-clear-btn" title="Clear (random)">×</button>
|
||||
</div>
|
||||
<button type="submit" name="action" value="preview" class="btn btn-success" data-requires="comfyui">Generate Preview</button>
|
||||
<button type="button" id="endless-btn" class="btn btn-outline-success" onclick="window._endlessStart()" data-requires="comfyui">Endless</button>
|
||||
<button type="button" id="endless-stop-btn" class="btn btn-danger d-none" onclick="window._endlessStop()">Stop</button>
|
||||
<small id="endless-counter" class="text-muted d-none"></small>
|
||||
<button type="submit" name="action" value="replace" class="btn btn-outline-warning btn-sm" data-requires="comfyui">Generate & Set Cover</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
@@ -280,7 +278,7 @@ document.getElementById('generate-form').addEventListener('submit', function(e)
|
||||
btn.disabled = true;
|
||||
btn.textContent = 'Generating...';
|
||||
|
||||
fetch(this.action, {
|
||||
fetch(this.getAttribute('action'), {
|
||||
method: 'POST',
|
||||
headers: {'X-Requested-With': 'XMLHttpRequest'},
|
||||
body: formData
|
||||
@@ -319,6 +317,7 @@ function pollJob(jobId, btn, actionVal) {
|
||||
document.getElementById('generated-images').prepend(col);
|
||||
document.getElementById('no-images-msg')?.classList.add('d-none');
|
||||
selectPreview(data.result.relative_path, data.result.image_url);
|
||||
updateSeedFromResult(data.result);
|
||||
} else if (data.status === 'failed') {
|
||||
btn.disabled = false;
|
||||
btn.textContent = 'Generate Preview';
|
||||
@@ -346,6 +345,23 @@ document.addEventListener('click', function(e) {
|
||||
if (img) selectPreview(img.dataset.previewPath, img.src);
|
||||
});
|
||||
|
||||
window._onEndlessResult = function(jobResult) {
|
||||
if (jobResult.result?.image_url) {
|
||||
selectPreview(jobResult.result.relative_path, jobResult.result.image_url);
|
||||
const img = document.createElement('img');
|
||||
img.src = jobResult.result.image_url;
|
||||
img.className = 'img-fluid rounded';
|
||||
img.style.cursor = 'pointer';
|
||||
img.dataset.previewPath = jobResult.result.relative_path;
|
||||
img.addEventListener('click', () => selectPreview(jobResult.result.relative_path, img.src));
|
||||
const col = document.createElement('div');
|
||||
col.className = 'col-4 col-md-3';
|
||||
col.appendChild(img);
|
||||
document.getElementById('generated-images').prepend(col);
|
||||
document.getElementById('no-images-msg')?.classList.add('d-none');
|
||||
}
|
||||
};
|
||||
|
||||
// JSON editor
|
||||
initJsonEditor("{{ url_for('save_preset_json', slug=preset.slug) }}");
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user