fixed migrations, changed settings to global settings, changed image list to have a "delete all" button instead of "create", fixed printing, added imagick for printing.

This commit is contained in:
2025-08-26 10:39:18 +02:00
parent 44dd0f2867
commit 9b1f6a479f
69 changed files with 17232 additions and 1263 deletions

View File

@@ -19,14 +19,22 @@
</div>
</div>
<ImageContextMenu
v-if="currentOverlayComponent === 'contextMenu'"
:position="contextMenuPosition"
:image="selectedImage"
@close="currentOverlayComponent = null; selectedImage = null"
@print="printImage"
@changeStyle="showStyleSelector"
@styleSelected="applyStyle"
<ImageContextMenu
v-if="currentOverlayComponent === 'contextMenu'"
:position="contextMenuPosition"
:image="selectedImage"
@close="currentOverlayComponent = null; selectedImage = null"
@print="printImage"
@changeStyle="showStyleSelector"
@styleSelected="applyStyle"
/>
<StyleSelector
v-if="currentOverlayComponent === 'styleSelector'"
:image_id="selectedImage.id"
@styleSelected="applyStyle"
@back="goBackToContextMenu"
@close="currentOverlayComponent = null; selectedImage = null"
/>
<div v-if="errorMessage" class="fixed bottom-4 right-4 bg-red-500 text-white p-4 rounded-lg shadow-lg z-50">
@@ -87,7 +95,6 @@ const currentOverlayComponent = ref(null); // null, 'contextMenu', 'styleSelecto
const contextMenuPosition = ref({ x: 0, y: 0 });
const selectedImage = ref(null);
const styledImage = ref(null); // To store the newly styled image
const processingImageUuid = ref(null); // To store the UUID of the image being processed
const processingProgress = ref(0); // To store the progress percentage
const errorMessage = ref(null); // New ref for error messages
const isLoading = ref(false); // New ref for loading state
@@ -168,91 +175,124 @@ const applyStyle = (style, imageId) => {
console.log('Applying style:', style.title, 'to image:', imageId);
currentOverlayComponent.value = null; // Close style selector immediately
isLoading.value = true; // Show loading spinner
processingImageUuid.value = selectedImage.value.uuid; // Set the UUID of the image being processed
processingProgress.value = 0; // Reset progress
axios.get('/api/comfyui-url')
.then(response => {
const comfyUiBaseUrl = response.data.comfyui_url;
const wsUrl = `ws://${new URL(comfyUiBaseUrl).host}/ws`;
const ws = new WebSocket(wsUrl);
// Send style change request to backend first
axios.post('/api/images/style-change', {
image_id: imageId,
style_id: style.id,
})
.then(response => {
console.log('Style change request sent:', response.data);
// Store the prompt_id and plugin from the backend response
const promptId = response.data.prompt_id;
const plugin = response.data.plugin;
ws.onopen = () => {
console.log('WebSocket connected to ComfyUI.');
// Send prompt to ComfyUI via HTTP, then listen for progress via WS
axios.post('/api/images/style-change', {
image_id: imageId,
style_id: style.id,
})
.then(response => {
console.log('Style change request sent:', response.data);
// Store the prompt_id from the backend response
const promptId = response.data.prompt_id;
// Handle different plugins differently
if (plugin === 'ComfyUi') {
// For ComfyUI, use WebSocket for progress monitoring
axios.get(`/api/comfyui-url?style_id=${style.id}`)
.then(comfyResponse => {
const comfyUiBaseUrl = comfyResponse.data.comfyui_url;
const wsUrl = `ws://${new URL(comfyUiBaseUrl).host}/ws`;
const ws = new WebSocket(wsUrl);
ws.onmessage = (event) => {
const message = JSON.parse(event.data);
if (message.type === 'progress') {
console.log('ComfyUI Progress Message:', message);
const { value, max } = message.data;
const progress = (max > 0) ? (value / max) * 100 : 0;
if (message.data.prompt_id === promptId) {
processingProgress.value = progress;
ws.onopen = () => {
console.log('WebSocket connected to ComfyUI.');
if (processingProgress.value >= 100) {
console.log('Frontend: Progress reached 100%. Attempting to fetch final image.', { promptId: promptId });
// Fetch the final styled image from the backend
axios.get(`/api/images/fetch-styled/${promptId}`)
.then(imageResponse => {
console.log('Frontend: Successfully fetched styled image.', imageResponse.data);
styledImage.value = imageResponse.data.styled_image;
currentOverlayComponent.value = 'styledImageDisplay';
fetchImages(); // Refresh gallery
})
.catch(imageError => {
console.error('Frontend: Error fetching styled image:', imageError.response?.data?.error || imageError.message);
showError(imageError.response?.data?.error || 'Failed to fetch styled image.');
})
.finally(() => {
console.log('Frontend: Final fetch process completed.');
isLoading.value = false;
processingImageUuid.value = null;
processingProgress.value = 0;
ws.close();
});
}
}
} else {
console.warn('Received unexpected WebSocket message type:', message.type, message);
}
};
ws.onmessage = (event) => {
const message = JSON.parse(event.data);
if (message.type === 'progress') {
console.log('ComfyUI Progress Message:', message);
const { value, max } = message.data;
const progress = (max > 0) ? (value / max) * 100 : 0;
if (message.data.prompt_id === promptId) {
processingProgress.value = progress;
if (processingProgress.value >= 100) {
console.log('Frontend: Progress reached 100%. Attempting to fetch final image.', { promptId: promptId });
// Fetch the final styled image from the backend
axios.get(`/api/images/fetch-styled/${promptId}`)
.then(imageResponse => {
console.log('Frontend: Successfully fetched styled image.', imageResponse.data);
styledImage.value = imageResponse.data.styled_image;
currentOverlayComponent.value = 'styledImageDisplay';
fetchImages(); // Refresh gallery
})
.catch(imageError => {
console.error('Frontend: Error fetching styled image:', imageError.response?.data?.error || imageError.message);
showError(imageError.response?.data?.error || 'Failed to fetch styled image.');
})
.finally(() => {
console.log('Frontend: Final fetch process completed.');
isLoading.value = false;
processingProgress.value = 0;
ws.close();
});
}
}
} else {
console.warn('Received unexpected WebSocket message type:', message.type, message);
}
};
};
ws.onerror = (error) => {
console.error('WebSocket error:', error);
showError('WebSocket connection error.');
isLoading.value = false;
processingProgress.value = 0;
};
ws.onclose = () => {
console.log('WebSocket closed.');
};
})
.catch(error => {
console.error('Error applying style:', error);
showError(error.response?.data?.error || 'Failed to apply style.');
console.error('Error fetching ComfyUI URL:', error);
showError(error.response?.data?.error || 'Failed to get ComfyUI URL.');
isLoading.value = false;
processingImageUuid.value = null;
processingProgress.value = 0;
ws.close();
});
} else {
// For other plugins, use polling approach
const pollForStyledImage = () => {
axios.get(`/api/images/fetch-styled/${promptId}`)
.then(imageResponse => {
console.log('Frontend: Successfully fetched styled image.', imageResponse.data);
styledImage.value = imageResponse.data.styled_image;
currentOverlayComponent.value = 'styledImageDisplay';
fetchImages(); // Refresh gallery
isLoading.value = false;
processingProgress.value = 0;
})
.catch(imageError => {
console.error('Frontend: Error fetching styled image:', imageError.response?.data?.error || imageError.message);
// If the image is not ready yet, continue polling
if (imageError.response?.status === 404) {
// Update progress if available
if (imageError.response?.data?.progress !== undefined) {
processingProgress.value = imageError.response.data.progress;
}
// Continue polling
setTimeout(pollForStyledImage, 2000); // Poll every 2 seconds
} else {
showError(imageError.response?.data?.error || 'Failed to fetch styled image.');
isLoading.value = false;
processingProgress.value = 0;
}
});
};
ws.onerror = (error) => {
console.error('WebSocket error:', error);
showError('WebSocket connection error.');
isLoading.value = false;
processingImageUuid.value = null;
processingProgress.value = 0;
};
ws.onclose = () => {
console.log('WebSocket closed.');
};
})
.catch(error => {
console.error('Error fetching ComfyUI URL:', error);
showError(error.response?.data?.error || 'Failed to get ComfyUI URL.');
isLoading.value = false;
});
// Start polling for the styled image
pollForStyledImage();
}
})
.catch(error => {
console.error('Error applying style:', error);
showError(error.response?.data?.error || 'Failed to apply style.');
isLoading.value = false;
processingProgress.value = 0;
});
};
const keepStyledImage = (imageToKeep) => {