checkpoint

This commit is contained in:
Will Miao
2025-03-15 09:53:50 +08:00
parent 09b2fdfc59
commit 5c62ec1177
4 changed files with 254 additions and 61 deletions

View File

@@ -220,12 +220,19 @@ class RecipeRoutes:
# Check if this LoRA exists locally by SHA256 hash
exists_locally = False
local_path = None
if civitai_info and 'files' in civitai_info and civitai_info['files']:
sha256 = civitai_info['files'][0].get('hashes', {}).get('SHA256', '')
if sha256:
sha256 = sha256.lower() # Convert to lowercase for consistency
exists_locally = self.recipe_scanner._lora_scanner.has_lora_hash(sha256)
if civitai_info and 'files' in civitai_info:
# Find the model file (type="Model") in the files list
model_file = next((file for file in civitai_info.get('files', [])
if file.get('type') == 'Model'), None)
if model_file:
sha256 = model_file.get('hashes', {}).get('SHA256', '')
if sha256:
exists_locally = self.recipe_scanner._lora_scanner.has_lora_hash(sha256)
if exists_locally:
local_path = self.recipe_scanner._lora_scanner.get_lora_path_by_hash(sha256)
# Create LoRA entry
lora_entry = {
@@ -235,6 +242,7 @@ class RecipeRoutes:
'type': resource.get('type', 'lora'),
'weight': resource.get('weight', 1.0),
'existsLocally': exists_locally,
'localPath': local_path,
'thumbnailUrl': '',
'baseModel': '',
'size': 0,
@@ -250,9 +258,9 @@ class RecipeRoutes:
# Get base model
lora_entry['baseModel'] = civitai_info.get('baseModel', '')
# Get file size
if 'files' in civitai_info and civitai_info['files']:
lora_entry['size'] = civitai_info['files'][0].get('sizeKB', 0) * 1024
# Get file size from model file
if model_file:
lora_entry['size'] = model_file.get('sizeKB', 0) * 1024
# Get download URL
lora_entry['downloadUrl'] = civitai_info.get('downloadUrl', '')

View File

@@ -1,6 +1,7 @@
/* Import Modal Styles */
.import-step {
margin: var(--space-2) 0;
transition: none !important; /* Disable any transitions that might affect display */
}
/* File Input Styles */
@@ -364,14 +365,6 @@
margin-top: 4px;
}
/* Modal Actions */
.modal-actions {
display: flex;
justify-content: flex-end;
gap: var(--space-2);
margin-top: var(--space-3);
}
/* Dark theme adjustments */
[data-theme="dark"] .lora-item {
background: var(--lora-surface);
@@ -391,3 +384,58 @@
height: 150px;
}
}
/* Size badge for LoRA items */
.size-badge {
background: var(--lora-surface);
padding: 2px 8px;
border-radius: var(--border-radius-xs);
font-size: 0.85em;
color: var(--text-color);
opacity: 0.8;
}
/* Missing LoRAs summary section */
.missing-loras-summary {
margin-bottom: var(--space-3);
padding: var(--space-2);
background: var(--bg-color);
border-radius: var(--border-radius-sm);
border: 1px solid var(--lora-error);
}
.missing-loras-summary h3 {
margin-top: 0;
margin-bottom: var(--space-2);
font-size: 1.1em;
color: var(--text-color);
}
.total-size-info {
margin-bottom: var(--space-2);
font-size: 0.9em;
color: var(--text-color);
}
.missing-lora-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 8px;
border-bottom: 1px solid var(--border-color);
}
.missing-lora-item:last-child {
border-bottom: none;
}
.missing-lora-name {
font-weight: 500;
flex: 1;
}
.missing-lora-size {
font-size: 0.9em;
color: var(--text-color);
opacity: 0.8;
}

View File

@@ -36,14 +36,22 @@ export class ImportManager {
this.initialized = true;
}
// Always reset the state when opening the modal
this.resetSteps();
// Show the modal
modalManager.showModal('importModal', null, () => {
// Cleanup handler when modal closes
this.cleanupFolderBrowser();
// 移除任何强制样式
// Remove any injected styles
this.removeInjectedStyles();
});
this.resetSteps();
// Verify the modal is properly shown
setTimeout(() => {
this.ensureModalVisible();
}, 50);
}
// 添加移除注入样式的方法
@@ -52,12 +60,18 @@ export class ImportManager {
this.injectedStyles.parentNode.removeChild(this.injectedStyles);
this.injectedStyles = null;
}
// Also reset any inline styles that might have been set with !important
document.querySelectorAll('.import-step').forEach(step => {
step.style.cssText = '';
});
}
resetSteps() {
// 移除可能存在的强制样式
// Remove any existing injected styles
this.removeInjectedStyles();
// Show the first step
this.showStep('uploadStep');
// Reset file input
@@ -78,6 +92,18 @@ export class ImportManager {
previewElement.innerHTML = '<div class="placeholder">Image preview will appear here</div>';
}
// Reset recipe name input
const recipeName = document.getElementById('recipeName');
if (recipeName) {
recipeName.value = '';
}
// Reset tags container
const tagsContainer = document.getElementById('tagsContainer');
if (tagsContainer) {
tagsContainer.innerHTML = '<div class="empty-tags">No tags added</div>';
}
// Reset state variables
this.recipeImage = null;
this.recipeData = null;
@@ -92,6 +118,18 @@ export class ImportManager {
folderBrowser.querySelectorAll('.folder-item').forEach(f =>
f.classList.remove('selected'));
}
// Clear missing LoRAs list if it exists
const missingLorasList = document.getElementById('missingLorasList');
if (missingLorasList) {
missingLorasList.innerHTML = '';
}
// Reset total download size
const totalSizeDisplay = document.getElementById('totalDownloadSize');
if (totalSizeDisplay) {
totalSizeDisplay.textContent = 'Calculating...';
}
}
handleImageUpload(event) {
@@ -207,6 +245,10 @@ export class ImportManager {
<i class="fas fa-exclamation-triangle"></i> Not in Library
</div>`;
// Format size if available
const sizeDisplay = lora.size ?
`<div class="size-badge">${this.formatFileSize(lora.size)}</div>` : '';
return `
<div class="lora-item ${existsLocally ? 'exists-locally' : 'missing-locally'}">
<div class="lora-thumbnail">
@@ -220,6 +262,7 @@ export class ImportManager {
${lora.version ? `<div class="lora-version">${lora.version}</div>` : ''}
<div class="lora-info">
${lora.baseModel ? `<div class="base-model">${lora.baseModel}</div>` : ''}
${sizeDisplay}
<div class="weight-badge">Weight: ${lora.weight || 1.0}</div>
</div>
</div>
@@ -291,8 +334,6 @@ export class ImportManager {
return;
}
console.log('Proceeding from details, missing LoRAs:', this.missingLoras.length);
// If we have missing LoRAs, go to location step
if (this.missingLoras.length > 0) {
this.proceedToLocation();
@@ -303,30 +344,61 @@ export class ImportManager {
}
async proceedToLocation() {
// 先移除可能已有的样式
this.removeInjectedStyles();
// 添加强制CSS覆盖
this.injectedStyles = document.createElement('style');
this.injectedStyles.innerHTML = `
#locationStep {
display: block !important;
opacity: 1 !important;
visibility: visible !important;
position: static !important;
z-index: 10000 !important;
width: auto !important;
height: auto !important;
overflow: visible !important;
transform: none !important;
}
`;
document.head.appendChild(this.injectedStyles);
console.log('Added override CSS to force visibility');
// Show the location step with special handling
this.showStep('locationStep');
// Double-check after a short delay to ensure the step is visible
setTimeout(() => {
const locationStep = document.getElementById('locationStep');
if (locationStep.style.display !== 'block' ||
window.getComputedStyle(locationStep).display !== 'block') {
// Force display again
locationStep.style.display = 'block';
// If still not visible, try with injected style
if (window.getComputedStyle(locationStep).display !== 'block') {
this.injectedStyles = document.createElement('style');
this.injectedStyles.innerHTML = `
#locationStep {
display: block !important;
opacity: 1 !important;
visibility: visible !important;
}
`;
document.head.appendChild(this.injectedStyles);
}
}
}, 100);
try {
// Display missing LoRAs that will be downloaded
const missingLorasList = document.getElementById('missingLorasList');
if (missingLorasList && this.missingLoras.length > 0) {
// Calculate total size
const totalSize = this.missingLoras.reduce((sum, lora) => {
return sum + (lora.size ? parseInt(lora.size) : 0);
}, 0);
// Update total size display
const totalSizeDisplay = document.getElementById('totalDownloadSize');
if (totalSizeDisplay) {
totalSizeDisplay.textContent = this.formatFileSize(totalSize);
}
// Generate missing LoRAs list
missingLorasList.innerHTML = this.missingLoras.map(lora => {
const sizeDisplay = lora.size ? this.formatFileSize(lora.size) : 'Unknown size';
return `
<div class="missing-lora-item">
<div class="missing-lora-name">${lora.name}</div>
<div class="missing-lora-size">${sizeDisplay}</div>
</div>
`;
}).join('');
}
// Fetch LoRA roots
const rootsResponse = await fetch('/api/lora-roots');
if (!rootsResponse.ok) {
@@ -365,6 +437,18 @@ export class ImportManager {
backToUpload() {
this.showStep('uploadStep');
// Reset file input to ensure it can trigger change events again
const fileInput = document.getElementById('recipeImageUpload');
if (fileInput) {
fileInput.value = '';
}
// Clear any previous error messages
const errorElement = document.getElementById('uploadError');
if (errorElement) {
errorElement.textContent = '';
}
}
backToDetails() {
@@ -397,7 +481,6 @@ export class ImportManager {
const result = await response.json();
if (result.success) {
// Handle successful save
console.log(`Recipe saved with ID: ${result.recipe_id}`);
// Show success message for recipe save
showToast(`Recipe "${this.recipeName}" saved successfully`, 'success');
@@ -544,7 +627,6 @@ export class ImportManager {
if (loraRoot) loraRoot.addEventListener('change', this.updateTargetPath);
if (newFolder) newFolder.addEventListener('input', this.updateTargetPath);
console.log('Initializing folder browser...');
// Update initial path
this.updateTargetPath();
}
@@ -588,36 +670,80 @@ export class ImportManager {
}
showStep(stepId) {
// 隐藏所有步骤
// First, remove any injected styles to prevent conflicts
this.removeInjectedStyles();
// Hide all steps first
document.querySelectorAll('.import-step').forEach(step => {
step.style.display = 'none';
});
// 显示目标步骤
// Show target step with a monitoring mechanism
const targetStep = document.getElementById(stepId);
if (targetStep) {
// 强制显示目标步骤 - 使用 !important 覆盖任何其他CSS规则
targetStep.setAttribute('style', 'display: block !important');
// Use direct style setting
targetStep.style.display = 'block';
// 调试信息
console.log(`Showing step: ${stepId}`);
const rect = targetStep.getBoundingClientRect();
console.log('Step dimensions:', {
width: rect.width,
height: rect.height,
top: rect.top,
left: rect.left,
visible: rect.width > 0 && rect.height > 0
});
// For the locationStep specifically, we need additional measures
if (stepId === 'locationStep') {
// Create a more persistent style to override any potential conflicts
this.injectedStyles = document.createElement('style');
this.injectedStyles.innerHTML = `
#locationStep {
display: block !important;
opacity: 1 !important;
visibility: visible !important;
}
`;
document.head.appendChild(this.injectedStyles);
// Force layout recalculation
targetStep.offsetHeight;
// Set up a monitor to ensure the step remains visible
setTimeout(() => {
if (targetStep.style.display !== 'block') {
targetStep.style.display = 'block';
}
// Check dimensions again after a short delay
const newRect = targetStep.getBoundingClientRect();
}, 50);
}
// 强制重新计算布局
targetStep.offsetHeight;
// 滚动模态内容到顶部
// Scroll modal content to top
const modalContent = document.querySelector('#importModal .modal-content');
if (modalContent) {
modalContent.scrollTop = 0;
}
}
}
// Add a helper method to format file sizes
formatFileSize(bytes) {
if (!bytes || isNaN(bytes)) return '';
const sizes = ['B', 'KB', 'MB', 'GB'];
const i = Math.floor(Math.log(bytes) / Math.log(1024));
return (bytes / Math.pow(1024, i)).toFixed(2) + ' ' + sizes[i];
}
// Add this method to ensure the modal is fully visible and initialized
ensureModalVisible() {
const importModal = document.getElementById('importModal');
if (!importModal) {
console.error('Import modal element not found');
return false;
}
// Check if modal is actually visible
const modalDisplay = window.getComputedStyle(importModal).display;
if (modalDisplay !== 'block') {
console.error('Import modal is not visible, display: ' + modalDisplay);
return false;
}
return true;
}
}

View File

@@ -68,6 +68,17 @@
<!-- Step 3: Download Location (if needed) -->
<div class="import-step" id="locationStep" style="display: none;">
<div class="location-selection">
<!-- Add missing LoRAs summary section -->
<div class="missing-loras-summary">
<h3>Missing LoRAs to Download</h3>
<div class="total-size-info">
Total download size: <span id="totalDownloadSize">Calculating...</span>
</div>
<div id="missingLorasList" class="missing-loras-list">
<!-- Missing LoRAs will be populated here -->
</div>
</div>
<!-- Move path preview to top -->
<div class="path-preview">
<label>Download Location Preview:</label>