auto-image-generation
This commit is contained in:
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"permissions": {
|
||||||
|
"allow": [
|
||||||
|
"mcp__plugin_context7_context7__resolve-library-id",
|
||||||
|
"mcp__plugin_context7_context7__get-library-docs",
|
||||||
|
"Bash(find:*)"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -402,6 +402,22 @@ async function initUI() {
|
|||||||
toggleAnimations();
|
toggleAnimations();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Auto avatar generation settings
|
||||||
|
$('#rpg-toggle-auto-avatars').on('change', function() {
|
||||||
|
extensionSettings.autoGenerateAvatars = $(this).prop('checked');
|
||||||
|
saveSettings();
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#rpg-avatar-style-select').on('change', function() {
|
||||||
|
extensionSettings.avatarGenerationStyle = String($(this).val());
|
||||||
|
saveSettings();
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#rpg-avatar-custom-prompt').on('input', function() {
|
||||||
|
extensionSettings.avatarGenerationPrompt = $(this).val().trim();
|
||||||
|
saveSettings();
|
||||||
|
});
|
||||||
|
|
||||||
$('#rpg-manual-update').on('click', async function() {
|
$('#rpg-manual-update').on('click', async function() {
|
||||||
if (!extensionSettings.enabled) {
|
if (!extensionSettings.enabled) {
|
||||||
// console.log('[RPG Companion] Extension is disabled. Please enable it in the Extensions tab.');
|
// console.log('[RPG Companion] Extension is disabled. Please enable it in the Extensions tab.');
|
||||||
@@ -493,6 +509,9 @@ async function initUI() {
|
|||||||
|
|
||||||
$('#rpg-toggle-plot-buttons').prop('checked', extensionSettings.enablePlotButtons); $('#rpg-toggle-plot-buttons').prop('checked', extensionSettings.enablePlotButtons); $('#rpg-toggle-plot-buttons').prop('checked', extensionSettings.enablePlotButtons);
|
$('#rpg-toggle-plot-buttons').prop('checked', extensionSettings.enablePlotButtons); $('#rpg-toggle-plot-buttons').prop('checked', extensionSettings.enablePlotButtons); $('#rpg-toggle-plot-buttons').prop('checked', extensionSettings.enablePlotButtons);
|
||||||
$('#rpg-toggle-animations').prop('checked', extensionSettings.enableAnimations);
|
$('#rpg-toggle-animations').prop('checked', extensionSettings.enableAnimations);
|
||||||
|
$('#rpg-toggle-auto-avatars').prop('checked', extensionSettings.autoGenerateAvatars || false);
|
||||||
|
$('#rpg-avatar-style-select').val(extensionSettings.avatarGenerationStyle || 'auto');
|
||||||
|
$('#rpg-avatar-custom-prompt').val(extensionSettings.avatarGenerationPrompt || '');
|
||||||
$('#rpg-stat-bar-color-low').val(extensionSettings.statBarColorLow);
|
$('#rpg-stat-bar-color-low').val(extensionSettings.statBarColorLow);
|
||||||
$('#rpg-stat-bar-color-high').val(extensionSettings.statBarColorHigh);
|
$('#rpg-stat-bar-color-high').val(extensionSettings.statBarColorHigh);
|
||||||
$('#rpg-theme-select').val(extensionSettings.theme);
|
$('#rpg-theme-select').val(extensionSettings.theme);
|
||||||
|
|||||||
+5
-1
@@ -166,7 +166,11 @@ export let extensionSettings = {
|
|||||||
},
|
},
|
||||||
debugMode: false, // Enable debug logging visible in UI (for mobile debugging)
|
debugMode: false, // Enable debug logging visible in UI (for mobile debugging)
|
||||||
memoryMessagesToProcess: 16, // Number of messages to process per batch in memory recollection
|
memoryMessagesToProcess: 16, // Number of messages to process per batch in memory recollection
|
||||||
npcAvatars: {} // Store custom avatar images for NPCs (key: character name, value: base64 data URI)
|
npcAvatars: {}, // Store custom avatar images for NPCs (key: character name, value: base64 data URI)
|
||||||
|
// Auto avatar generation settings
|
||||||
|
autoGenerateAvatars: false, // Master toggle for auto-generating avatars
|
||||||
|
avatarGenerationPrompt: 'portrait, fantasy character, RPG style', // Default prompt template
|
||||||
|
avatarGenerationStyle: 'auto', // Style preset: auto, fantasy, sci-fi, anime, realistic
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -41,6 +41,16 @@
|
|||||||
"template.settingsModal.display.showPlotProgressionButtonsNote": "Display buttons above chat input for plot progression prompts",
|
"template.settingsModal.display.showPlotProgressionButtonsNote": "Display buttons above chat input for plot progression prompts",
|
||||||
"template.settingsModal.display.enableDebugMode": "Enable Debug Mode",
|
"template.settingsModal.display.enableDebugMode": "Enable Debug Mode",
|
||||||
"template.settingsModal.display.enableDebugModeNote": "Shows parser logs in a mobile-friendly UI panel. Useful for troubleshooting. Look for the red bug button.",
|
"template.settingsModal.display.enableDebugModeNote": "Shows parser logs in a mobile-friendly UI panel. Useful for troubleshooting. Look for the red bug button.",
|
||||||
|
"template.settingsModal.display.autoGenerateAvatars": "Auto-generate Missing Avatars",
|
||||||
|
"template.settingsModal.display.autoGenerateAvatarsNote": "Automatically generate avatars for characters without custom images using Stable Diffusion",
|
||||||
|
"template.settingsModal.display.avatarPromptStyle": "Avatar Generation Style:",
|
||||||
|
"template.settingsModal.display.avatarPromptStyleOptions.auto": "Auto (Fantasy)",
|
||||||
|
"template.settingsModal.display.avatarPromptStyleOptions.fantasy": "Fantasy",
|
||||||
|
"template.settingsModal.display.avatarPromptStyleOptions.scifi": "Sci-Fi",
|
||||||
|
"template.settingsModal.display.avatarPromptStyleOptions.anime": "Anime",
|
||||||
|
"template.settingsModal.display.avatarPromptStyleOptions.realistic": "Realistic",
|
||||||
|
"template.settingsModal.display.avatarCustomPrompt": "Custom Avatar Prompt:",
|
||||||
|
"template.settingsModal.display.avatarCustomPromptNote": "Additional prompt modifiers for avatar generation",
|
||||||
"template.settingsModal.advancedTitle": "Advanced",
|
"template.settingsModal.advancedTitle": "Advanced",
|
||||||
"template.settingsModal.advanced.generationMode": "Generation Mode:",
|
"template.settingsModal.advanced.generationMode": "Generation Mode:",
|
||||||
"template.settingsModal.advanced.generationModeOptions.together": "Together with Main Generation",
|
"template.settingsModal.advanced.generationModeOptions.together": "Together with Main Generation",
|
||||||
|
|||||||
@@ -0,0 +1,136 @@
|
|||||||
|
/**
|
||||||
|
* Avatar Generator Module
|
||||||
|
* Handles automatic avatar generation for characters without images
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { executeSlashCommandsOnChatInput } from '../../../../../../../scripts/slash-commands.js';
|
||||||
|
import { extensionSettings } from '../../core/state.js';
|
||||||
|
import { saveSettings } from '../../core/persistence.js';
|
||||||
|
|
||||||
|
// Track pending avatar generations to avoid duplicate requests
|
||||||
|
const pendingGenerations = new Set();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Style presets for avatar generation prompts
|
||||||
|
*/
|
||||||
|
const STYLE_PRESETS = {
|
||||||
|
'auto': 'portrait, fantasy character, RPG style',
|
||||||
|
'fantasy': 'portrait, fantasy character, medieval RPG style, detailed face',
|
||||||
|
'scifi': 'portrait, sci-fi character, futuristic, cyberpunk style, detailed face',
|
||||||
|
'anime': 'portrait, anime character, manga style, detailed face',
|
||||||
|
'realistic': 'portrait, realistic character, detailed face, photorealistic'
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds the generation prompt for a character
|
||||||
|
* @param {string} characterName - Name of the character
|
||||||
|
* @returns {string} Full prompt for /sd command
|
||||||
|
*/
|
||||||
|
function buildGenerationPrompt(characterName) {
|
||||||
|
const style = STYLE_PRESETS[extensionSettings.avatarGenerationStyle] || STYLE_PRESETS.auto;
|
||||||
|
const custom = extensionSettings.avatarGenerationPrompt || '';
|
||||||
|
return `${style}, ${characterName}, ${custom}`.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates an avatar for a character using /sd command
|
||||||
|
* @param {string} characterName - Name of the character to generate avatar for
|
||||||
|
* @returns {Promise<string|null>} Avatar URL or null if failed
|
||||||
|
*/
|
||||||
|
export async function generateAvatar(characterName) {
|
||||||
|
// Skip if already generating
|
||||||
|
if (pendingGenerations.has(characterName)) {
|
||||||
|
console.log(`[RPG Avatar] Already generating avatar for: ${characterName}`);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip if disabled
|
||||||
|
if (!extensionSettings.autoGenerateAvatars) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip if custom avatar already exists
|
||||||
|
if (extensionSettings.npcAvatars && extensionSettings.npcAvatars[characterName]) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
pendingGenerations.add(characterName);
|
||||||
|
console.log(`[RPG Avatar] Starting generation for: ${characterName}`);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const prompt = buildGenerationPrompt(characterName);
|
||||||
|
|
||||||
|
// Execute /sd command with quiet=true
|
||||||
|
// This saves to gallery without posting to chat
|
||||||
|
const result = await executeSlashCommandsOnChatInput(
|
||||||
|
`/sd ${prompt} quiet=true`,
|
||||||
|
{ clearChatInput: false }
|
||||||
|
);
|
||||||
|
|
||||||
|
// The result might be an object with various properties
|
||||||
|
// We need to extract the actual image URL if available
|
||||||
|
let imageUrl = null;
|
||||||
|
|
||||||
|
if (result) {
|
||||||
|
// Handle different result formats
|
||||||
|
if (typeof result === 'string') {
|
||||||
|
imageUrl = result;
|
||||||
|
} else if (result.pipe) {
|
||||||
|
imageUrl = result.pipe;
|
||||||
|
} else if (result.output || result.image || result.url) {
|
||||||
|
imageUrl = result.output || result.image || result.url;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only store if we got a valid string URL
|
||||||
|
if (imageUrl && typeof imageUrl === 'string') {
|
||||||
|
if (!extensionSettings.npcAvatars) {
|
||||||
|
extensionSettings.npcAvatars = {};
|
||||||
|
}
|
||||||
|
extensionSettings.npcAvatars[characterName] = imageUrl;
|
||||||
|
saveSettings();
|
||||||
|
|
||||||
|
console.log(`[RPG Avatar] Generation complete for: ${characterName}`);
|
||||||
|
return imageUrl;
|
||||||
|
} else {
|
||||||
|
console.warn(`[RPG Avatar] Generation result for ${characterName} was not a valid URL:`, result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`[RPG Avatar] Generation failed for ${characterName}:`, error);
|
||||||
|
return null;
|
||||||
|
} finally {
|
||||||
|
pendingGenerations.delete(characterName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a character needs an avatar and triggers generation
|
||||||
|
* @param {string} characterName - Name of the character to check
|
||||||
|
* @param {boolean} hasAvatar - Whether the character already has an avatar
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
|
export function checkAndGenerateAvatar(characterName, hasAvatar) {
|
||||||
|
// Only generate if no avatar exists and feature is enabled
|
||||||
|
if (hasAvatar || !extensionSettings.autoGenerateAvatars) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if we already have a custom NPC avatar
|
||||||
|
if (extensionSettings.npcAvatars && extensionSettings.npcAvatars[characterName]) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Trigger generation (non-blocking)
|
||||||
|
generateAvatar(characterName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if an avatar is currently being generated for a character
|
||||||
|
* @param {string} characterName - Name of the character to check
|
||||||
|
* @returns {boolean} True if generation is in progress
|
||||||
|
*/
|
||||||
|
export function isGenerating(characterName) {
|
||||||
|
return pendingGenerations.has(characterName);
|
||||||
|
}
|
||||||
@@ -17,6 +17,7 @@ import {
|
|||||||
import { saveChatData } from '../../core/persistence.js';
|
import { saveChatData } from '../../core/persistence.js';
|
||||||
import { getSafeThumbnailUrl } from '../../utils/avatars.js';
|
import { getSafeThumbnailUrl } from '../../utils/avatars.js';
|
||||||
import { saveSettings } from '../../core/persistence.js';
|
import { saveSettings } from '../../core/persistence.js';
|
||||||
|
import { checkAndGenerateAvatar, isGenerating } from '../features/avatarGenerator.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper to log to both console and debug logs array
|
* Helper to log to both console and debug logs array
|
||||||
@@ -110,12 +111,21 @@ function namesMatch(cardName, aiName) {
|
|||||||
function getCharacterAvatar(characterName) {
|
function getCharacterAvatar(characterName) {
|
||||||
// First, check if there's a custom NPC avatar
|
// First, check if there's a custom NPC avatar
|
||||||
if (extensionSettings.npcAvatars && extensionSettings.npcAvatars[characterName]) {
|
if (extensionSettings.npcAvatars && extensionSettings.npcAvatars[characterName]) {
|
||||||
debugLog(`[RPG Thoughts] Found custom NPC avatar for: ${characterName}`);
|
const avatar = extensionSettings.npcAvatars[characterName];
|
||||||
return extensionSettings.npcAvatars[characterName];
|
// Skip if not a valid string (e.g., if it's an object from a previous bug)
|
||||||
|
if (typeof avatar === 'string' && avatar) {
|
||||||
|
debugLog(`[RPG Thoughts] Found custom NPC avatar for: ${characterName}`);
|
||||||
|
return avatar;
|
||||||
|
} else {
|
||||||
|
// Clear invalid avatar data
|
||||||
|
console.warn(`[RPG Thoughts] Invalid avatar data for ${characterName}, clearing...`);
|
||||||
|
delete extensionSettings.npcAvatars[characterName];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use the existing avatar lookup logic
|
// Use the existing avatar lookup logic
|
||||||
let characterPortrait = FALLBACK_AVATAR_DATA_URI;
|
let characterPortrait = FALLBACK_AVATAR_DATA_URI;
|
||||||
|
let hasAvatar = false;
|
||||||
|
|
||||||
// For group chats, search through group members first
|
// For group chats, search through group members first
|
||||||
if (selected_group) {
|
if (selected_group) {
|
||||||
@@ -129,6 +139,7 @@ function getCharacterAvatar(characterName) {
|
|||||||
if (matchingMember && matchingMember.avatar && matchingMember.avatar !== 'none') {
|
if (matchingMember && matchingMember.avatar && matchingMember.avatar !== 'none') {
|
||||||
const thumbnailUrl = getSafeThumbnailUrl('avatar', matchingMember.avatar);
|
const thumbnailUrl = getSafeThumbnailUrl('avatar', matchingMember.avatar);
|
||||||
if (thumbnailUrl) {
|
if (thumbnailUrl) {
|
||||||
|
hasAvatar = true;
|
||||||
return thumbnailUrl;
|
return thumbnailUrl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -147,6 +158,7 @@ function getCharacterAvatar(characterName) {
|
|||||||
if (matchingCharacter && matchingCharacter.avatar && matchingCharacter.avatar !== 'none') {
|
if (matchingCharacter && matchingCharacter.avatar && matchingCharacter.avatar !== 'none') {
|
||||||
const thumbnailUrl = getSafeThumbnailUrl('avatar', matchingCharacter.avatar);
|
const thumbnailUrl = getSafeThumbnailUrl('avatar', matchingCharacter.avatar);
|
||||||
if (thumbnailUrl) {
|
if (thumbnailUrl) {
|
||||||
|
hasAvatar = true;
|
||||||
return thumbnailUrl;
|
return thumbnailUrl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -157,10 +169,16 @@ function getCharacterAvatar(characterName) {
|
|||||||
characters[this_chid].name && namesMatch(characters[this_chid].name, characterName)) {
|
characters[this_chid].name && namesMatch(characters[this_chid].name, characterName)) {
|
||||||
const thumbnailUrl = getSafeThumbnailUrl('avatar', characters[this_chid].avatar);
|
const thumbnailUrl = getSafeThumbnailUrl('avatar', characters[this_chid].avatar);
|
||||||
if (thumbnailUrl) {
|
if (thumbnailUrl) {
|
||||||
|
hasAvatar = true;
|
||||||
return thumbnailUrl;
|
return thumbnailUrl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Trigger auto-generation if no avatar was found
|
||||||
|
if (!hasAvatar) {
|
||||||
|
checkAndGenerateAvatar(characterName, false);
|
||||||
|
}
|
||||||
|
|
||||||
return characterPortrait;
|
return characterPortrait;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -500,7 +518,7 @@ export function renderThoughts() {
|
|||||||
// Find character portrait using the new helper function
|
// Find character portrait using the new helper function
|
||||||
const characterPortrait = getCharacterAvatar(char.name);
|
const characterPortrait = getCharacterAvatar(char.name);
|
||||||
|
|
||||||
debugLog(`[RPG Thoughts] Final avatar for ${char.name}:`, characterPortrait.substring(0, 50) + '...');
|
debugLog(`[RPG Thoughts] Final avatar for ${char.name}:`, typeof characterPortrait === 'string' ? characterPortrait.substring(0, 50) + '...' : characterPortrait);
|
||||||
|
|
||||||
// Get relationship badge - only if relationships are enabled in config
|
// Get relationship badge - only if relationships are enabled in config
|
||||||
let relationshipBadge = '⚖️'; // Default
|
let relationshipBadge = '⚖️'; // Default
|
||||||
@@ -519,10 +537,14 @@ export function renderThoughts() {
|
|||||||
// Escape character name for use in HTML attributes
|
// Escape character name for use in HTML attributes
|
||||||
const escapedName = escapeHtmlAttr(char.name);
|
const escapedName = escapeHtmlAttr(char.name);
|
||||||
|
|
||||||
|
// Check if avatar is being generated
|
||||||
|
const isCurrentlyGenerating = isGenerating(char.name);
|
||||||
|
|
||||||
html += `
|
html += `
|
||||||
<div class="rpg-character-card" data-character-name="${escapedName}">
|
<div class="rpg-character-card" data-character-name="${escapedName}">
|
||||||
<div class="rpg-character-avatar rpg-avatar-upload" data-character="${escapedName}" title="Click to upload custom avatar Right-click to remove custom avatar">
|
<div class="rpg-character-avatar rpg-avatar-upload ${isCurrentlyGenerating ? 'rpg-avatar-generating' : ''}" data-character="${escapedName}" title="Click to upload custom avatar Right-click to remove custom avatar">
|
||||||
<img src="${characterPortrait}" alt="${escapedName}" onerror="this.style.opacity='0.5';this.onerror=null;" />
|
<img src="${characterPortrait}" alt="${escapedName}" onerror="this.style.opacity='0.5';this.onerror=null;" />
|
||||||
|
${isCurrentlyGenerating ? '<div class="rpg-generating-overlay"><i class="fa-solid fa-spinner fa-spin"></i></div>' : ''}
|
||||||
${hasRelationshipEnabled ? `<div class="rpg-relationship-badge rpg-editable" contenteditable="true" data-character="${escapedName}" data-field="${relationshipFieldName}" title="Click to edit (use emoji: ⚔️ ⚖️ ⭐ ❤️)">${relationshipBadge}</div>` : ''}
|
${hasRelationshipEnabled ? `<div class="rpg-relationship-badge rpg-editable" contenteditable="true" data-character="${escapedName}" data-field="${relationshipFieldName}" title="Click to edit (use emoji: ⚔️ ⚖️ ⭐ ❤️)">${relationshipBadge}</div>` : ''}
|
||||||
</div>
|
</div>
|
||||||
<div class="rpg-character-content">
|
<div class="rpg-character-content">
|
||||||
|
|||||||
@@ -6767,3 +6767,23 @@ body:has(.rpg-panel.rpg-position-left) #sheld {
|
|||||||
background: linear-gradient(180deg, #4a9eff 0%, transparent 100%);
|
background: linear-gradient(180deg, #4a9eff 0%, transparent 100%);
|
||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Avatar generation loading overlay */
|
||||||
|
.rpg-avatar-generating {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rpg-generating-overlay {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background: rgba(0, 0, 0, 0.5);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
color: white;
|
||||||
|
font-size: 24px;
|
||||||
|
border-radius: 8px;
|
||||||
|
}
|
||||||
|
|||||||
@@ -229,6 +229,35 @@
|
|||||||
<small style="display: block; margin-left: 24px; margin-top: -8px; color: #888; font-size: 11px;" data-i18n-key="template.settingsModal.display.enableDebugModeNote">
|
<small style="display: block; margin-left: 24px; margin-top: -8px; color: #888; font-size: 11px;" data-i18n-key="template.settingsModal.display.enableDebugModeNote">
|
||||||
Shows parser logs in a mobile-friendly UI panel. Useful for troubleshooting. Look for the red bug button.
|
Shows parser logs in a mobile-friendly UI panel. Useful for troubleshooting. Look for the red bug button.
|
||||||
</small>
|
</small>
|
||||||
|
|
||||||
|
<label class="checkbox_label">
|
||||||
|
<input type="checkbox" id="rpg-toggle-auto-avatars" />
|
||||||
|
<span data-i18n-key="template.settingsModal.display.autoGenerateAvatars">Auto-generate Missing Avatars</span>
|
||||||
|
</label>
|
||||||
|
<small style="display: block; margin-left: 24px; margin-top: -8px; color: #888; font-size: 11px;" data-i18n-key="template.settingsModal.display.autoGenerateAvatarsNote">
|
||||||
|
Automatically generate avatars for characters without custom images using Stable Diffusion
|
||||||
|
</small>
|
||||||
|
|
||||||
|
<div class="rpg-setting-row" style="margin-top: 12px;">
|
||||||
|
<label for="rpg-avatar-style-select" data-i18n-key="template.settingsModal.display.avatarPromptStyle">Avatar Generation Style:</label>
|
||||||
|
<select id="rpg-avatar-style-select" class="rpg-select">
|
||||||
|
<option value="auto" data-i18n-key="template.settingsModal.display.avatarPromptStyleOptions.auto">Auto (Fantasy)</option>
|
||||||
|
<option value="fantasy" data-i18n-key="template.settingsModal.display.avatarPromptStyleOptions.fantasy">Fantasy</option>
|
||||||
|
<option value="scifi" data-i18n-key="template.settingsModal.display.avatarPromptStyleOptions.scifi">Sci-Fi</option>
|
||||||
|
<option value="anime" data-i18n-key="template.settingsModal.display.avatarPromptStyleOptions.anime">Anime</option>
|
||||||
|
<option value="realistic" data-i18n-key="template.settingsModal.display.avatarPromptStyleOptions.realistic">Realistic</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="rpg-setting-row" style="margin-top: 12px;">
|
||||||
|
<label for="rpg-avatar-custom-prompt" style="display: block; margin-bottom: 8px;" data-i18n-key="template.settingsModal.display.avatarCustomPrompt">
|
||||||
|
Custom Avatar Prompt:
|
||||||
|
</label>
|
||||||
|
<input type="text" id="rpg-avatar-custom-prompt" class="rpg-input" placeholder="portrait, fantasy character, RPG style" />
|
||||||
|
<small style="display: block; margin-top: 4px; color: #888; font-size: 11px;" data-i18n-key="template.settingsModal.display.avatarCustomPromptNote">
|
||||||
|
Additional prompt modifiers for avatar generation
|
||||||
|
</small>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="rpg-settings-group">
|
<div class="rpg-settings-group">
|
||||||
|
|||||||
Reference in New Issue
Block a user