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

@@ -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() {