diff --git a/static/js/components/shared/ModelCard.js b/static/js/components/shared/ModelCard.js index 9e63bfb2..f309be77 100644 --- a/static/js/components/shared/ModelCard.js +++ b/static/js/components/shared/ModelCard.js @@ -214,7 +214,7 @@ function handleCardClick(card, modelType) { } } -function showModelModalFromCard(card, modelType) { +async function showModelModalFromCard(card, modelType) { // Get the appropriate preview versions map const previewVersionsKey = modelType; const previewVersions = state.pages[previewVersionsKey]?.previewVersions || new Map(); @@ -246,7 +246,7 @@ function showModelModalFromCard(card, modelType) { }) }; - showModelModal(modelMeta, modelType); + await showModelModal(modelMeta, modelType); } // Function to show the example access modal (generalized for lora and checkpoint) @@ -306,7 +306,7 @@ function showExampleAccessModal(card, modelType) { // Set up import button const importBtn = modal.querySelector('#importExamplesBtn'); if (importBtn) { - importBtn.onclick = () => { + importBtn.onclick = async () => { modalManager.closeModal('exampleAccessModal'); // Get the model data from card dataset (works for both lora and checkpoint) @@ -333,7 +333,7 @@ function showExampleAccessModal(card, modelType) { } // Show the model modal - showModelModal(modelMeta, modelType); + await showModelModal(modelMeta, modelType); // Scroll to import area after modal is visible setTimeout(() => { diff --git a/static/js/components/shared/ModelModal.js b/static/js/components/shared/ModelModal.js index 4e264bbc..27a9f573 100644 --- a/static/js/components/shared/ModelModal.js +++ b/static/js/components/shared/ModelModal.js @@ -6,7 +6,7 @@ import { scrollToTop, loadExampleImages } from './showcase/ShowcaseView.js'; -import { setupTabSwitching, setupModelDescriptionEditing } from './ModelDescription.js'; +import { setupTabSwitching } from './ModelDescription.js'; import { setupModelNameEditing, setupBaseModelEditing, @@ -24,31 +24,49 @@ import { loadRecipesForLora } from './RecipeTab.js'; * @param {Object} model - Model data object * @param {string} modelType - Type of model ('lora' or 'checkpoint') */ -export function showModelModal(model, modelType) { +export async function showModelModal(model, modelType) { const modalId = 'modelModal'; const modalTitle = model.model_name; + + // Fetch complete civitai metadata + let completeCivitaiData = model.civitai || {}; + if (model.file_path) { + try { + const fullMetadata = await getModelApiClient().fetchModelMetadata(model.file_path); + completeCivitaiData = fullMetadata || model.civitai || {}; + } catch (error) { + console.warn('Failed to fetch complete metadata, using existing data:', error); + // Continue with existing data if fetch fails + } + } - // Prepare LoRA specific data - const escapedWords = (modelType === 'loras' || modelType === 'embeddings') && model.civitai?.trainedWords?.length ? - model.civitai.trainedWords.map(word => word.replace(/'/g, '\\\'')) : []; + // Update model with complete civitai data + const modelWithFullData = { + ...model, + civitai: completeCivitaiData + }; + // Prepare LoRA specific data with complete civitai data + const escapedWords = (modelType === 'loras' || modelType === 'embeddings') && modelWithFullData.civitai?.trainedWords?.length ? + modelWithFullData.civitai.trainedWords.map(word => word.replace(/'/g, '\\\'')) : []; + // Generate model type specific content let typeSpecificContent; if (modelType === 'loras') { - typeSpecificContent = renderLoraSpecificContent(model, escapedWords); + typeSpecificContent = renderLoraSpecificContent(modelWithFullData, escapedWords); } else if (modelType === 'embeddings') { - typeSpecificContent = renderEmbeddingSpecificContent(model, escapedWords); + typeSpecificContent = renderEmbeddingSpecificContent(modelWithFullData, escapedWords); } else { typeSpecificContent = ''; } - + // Generate tabs based on model type const tabsContent = modelType === 'loras' ? ` - - ` : + + ` : ` - `; + `; const tabPanesContent = modelType === 'loras' ? `
@@ -100,26 +118,26 @@ export function showModelModal(model, modelType) {
- ${model.from_civitai ? ` -
+ ${modelWithFullData.from_civitai ? ` +
View on Civitai
` : ''} - ${model.civitai?.creator ? ` -
- ${model.civitai.creator.image ? + ${modelWithFullData.civitai?.creator ? ` +
+ ${modelWithFullData.civitai.creator.image ? `
- ${model.civitai.creator.username} + ${modelWithFullData.civitai.creator.username}
` : `
` } - ${model.civitai.creator.username} + ${modelWithFullData.civitai.creator.username}
` : ''}
- ${renderCompactTags(model.tags || [], model.file_path)} + ${renderCompactTags(modelWithFullData.tags || [], modelWithFullData.file_path)}