feat(recipes): add toggle to strip <lora:> tags when copying prompt/negative_prompt

Adds a compact inline toggle in the Generation Parameters section of the
Recipe Modal that, when enabled, strips <lora:name:weight> tags and
cleans up residual punctuation before copying to clipboard. The setting
persists across sessions via localStorage.
This commit is contained in:
Will Miao
2026-05-13 11:47:02 +08:00
parent 60cfb3b8e0
commit 3bf396d003
4 changed files with 102 additions and 8 deletions

View File

@@ -396,14 +396,54 @@
flex-direction: column;
}
.recipe-gen-params h3 {
margin-top: 0;
.gen-params-header-row {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: var(--space-2);
font-size: 1.2em;
color: var(--text-color);
padding-bottom: var(--space-1);
border-bottom: 1px solid var(--border-color);
flex-shrink: 0;
gap: 8px;
}
.gen-params-header-row h3 {
margin: 0;
font-size: 1.2em;
color: var(--text-color);
}
/* Inline toggle for lora strip setting */
.lora-strip-toggle {
flex-shrink: 0;
gap: 6px;
}
.lora-strip-toggle .inline-toggle-label {
font-size: 0.78em;
white-space: nowrap;
opacity: 0.7;
transition: opacity 0.2s;
}
.lora-strip-toggle:hover .inline-toggle-label {
opacity: 1;
}
.lora-strip-toggle .toggle-switch {
width: 32px;
height: 16px;
}
.lora-strip-toggle .toggle-slider:before {
height: 10px;
width: 10px;
left: 3px;
bottom: 3px;
}
.lora-strip-toggle .toggle-switch input:checked + .toggle-slider:before {
transform: translateX(16px);
}
.gen-params-container {

View File

@@ -2,7 +2,7 @@
import { showToast, copyToClipboard, sendLoraToWorkflow, sendModelPathToWorkflow, openCivitaiByMetadata } from '../utils/uiHelpers.js';
import { translate } from '../utils/i18nHelpers.js';
import { state } from '../state/index.js';
import { setSessionItem, removeSessionItem } from '../utils/storageHelpers.js';
import { setSessionItem, removeSessionItem, getStorageItem, setStorageItem } from '../utils/storageHelpers.js';
import { fetchRecipeDetails, updateRecipeMetadata } from '../api/recipeApi.js';
import { downloadManager } from '../managers/DownloadManager.js';
import { MODEL_TYPES } from '../api/apiConfig.js';
@@ -105,6 +105,7 @@ class RecipeModal {
init() {
this.setupCopyButtons();
this.setupStripLoraToggle();
this.setupPromptEditors();
// Set up tooltip positioning handlers after DOM is ready
document.addEventListener('DOMContentLoaded', () => {
@@ -1350,14 +1351,20 @@ class RecipeModal {
if (copyPromptBtn) {
copyPromptBtn.addEventListener('click', () => {
const promptText = this.currentRecipe?.gen_params?.prompt || '';
let promptText = this.currentRecipe?.gen_params?.prompt || '';
if (this.shouldStripLoraOnCopy()) {
promptText = RecipeModal.stripLoraTags(promptText);
}
this.copyToClipboard(promptText, 'Prompt copied to clipboard');
});
}
if (copyNegativePromptBtn) {
copyNegativePromptBtn.addEventListener('click', () => {
const negativePromptText = this.currentRecipe?.gen_params?.negative_prompt || '';
let negativePromptText = this.currentRecipe?.gen_params?.negative_prompt || '';
if (this.shouldStripLoraOnCopy()) {
negativePromptText = RecipeModal.stripLoraTags(negativePromptText);
}
this.copyToClipboard(negativePromptText, 'Negative prompt copied to clipboard');
});
}
@@ -1377,6 +1384,43 @@ class RecipeModal {
}
}
/**
* Strip <lora:...> tags from prompt text and clean up residual punctuation/whitespace.
* Handles both unescaped (<lora:...>) and HTML-escaped (&lt;lora:...&gt;) variants.
* Cleans up artifacts like leading ", ", double commas, and extra whitespace.
*/
static stripLoraTags(text) {
return text
.replace(/<lora:[^>]*>/gi, '')
.replace(/&lt;lora:[^&]*&gt;/gi, '')
.replace(/,(\s*,)+/g, ',')
.replace(/^,\s*/, '')
.replace(/,\s*$/, '')
.replace(/\s{2,}/g, ' ')
.trim();
}
shouldStripLoraOnCopy() {
const toggle = document.getElementById('stripLoraOnCopyToggle');
return toggle ? toggle.checked : false;
}
setupStripLoraToggle() {
const toggle = document.getElementById('stripLoraOnCopyToggle');
if (!toggle) return;
const stored = getStorageItem('strip_lora_on_copy');
if (stored !== null) {
toggle.checked = stored === true;
}
toggle.addEventListener('change', () => {
const checked = toggle.checked;
setStorageItem('strip_lora_on_copy', checked);
state.global.settings.strip_lora_on_copy = checked;
});
}
// Fetch recipe syntax from backend and copy to clipboard
async fetchAndCopyRecipeSyntax() {
if (!this.recipeId) {

View File

@@ -50,6 +50,7 @@ const DEFAULT_SETTINGS_BASE = Object.freeze({
download_skip_base_models: [],
backup_auto_enabled: true,
backup_retention_count: 5,
strip_lora_on_copy: false,
});
export function createDefaultSettings() {

View File

@@ -22,7 +22,16 @@
</div>
<div class="info-section recipe-gen-params">
<h3>Generation Parameters</h3>
<div class="gen-params-header-row">
<h3>Generation Parameters</h3>
<label class="inline-toggle-container lora-strip-toggle" title="When enabled, &lt;lora:...&gt; tags are removed from prompt text when copying">
<span class="inline-toggle-label">Strip &lt;lora:&gt;</span>
<div class="toggle-switch">
<input type="checkbox" id="stripLoraOnCopyToggle">
<span class="toggle-slider"></span>
</div>
</label>
</div>
<div class="gen-params-container">
<!-- Prompt -->