Files
storycove/ASYNC_IMAGE_PROCESSING.md
Stefan Hardegger c291559366 Fix Image Processing
2025-09-28 20:06:52 +02:00

220 lines
6.2 KiB
Markdown

# Async Image Processing Implementation
## Overview
The image processing system has been updated to handle external images asynchronously, preventing timeouts when processing stories with many images. This provides real-time progress updates to users showing which images are being processed.
## Backend Components
### 1. `ImageProcessingProgressService`
- Tracks progress for individual story image processing sessions
- Thread-safe with `ConcurrentHashMap` for multi-user support
- Provides progress information: total images, processed count, current image, status, errors
### 2. `AsyncImageProcessingService`
- Handles asynchronous image processing using Spring's `@Async` annotation
- Counts external images before processing
- Provides progress callbacks during processing
- Updates story content when processing completes
- Automatic cleanup of progress data after completion
### 3. Enhanced `ImageService`
- Added `processContentImagesWithProgress()` method with callback support
- Progress callbacks provide real-time updates during image download/processing
- Maintains compatibility with existing synchronous processing
### 4. Updated `StoryController`
- `POST /api/stories` and `PUT /api/stories/{id}` now trigger async image processing
- `GET /api/stories/{id}/image-processing-progress` endpoint for progress polling
- Processing starts immediately after story save and returns control to user
## Frontend Components
### 1. `ImageProcessingProgressTracker` (Utility Class)
```typescript
const tracker = new ImageProcessingProgressTracker(storyId);
tracker.onProgress((progress) => {
console.log(`Processing ${progress.processedImages}/${progress.totalImages}`);
});
tracker.onComplete(() => console.log('Done!'));
tracker.start();
```
### 2. `ImageProcessingProgressComponent` (React Component)
```tsx
<ImageProcessingProgressComponent
storyId={storyId}
autoStart={true}
onComplete={() => refreshStory()}
/>
```
## User Experience
### Before (Synchronous)
1. User saves story with external images
2. Request hangs for 30+ seconds processing images
3. Browser may timeout
4. No feedback about progress
5. User doesn't know if it's working
### After (Asynchronous)
1. User saves story with external images
2. Save completes immediately
3. Progress indicator appears: "Processing 5 images. Currently image 2 of 5..."
4. User can continue using the application
5. Progress updates every second
6. Story automatically refreshes when processing completes
## API Endpoints
### Progress Endpoint
```
GET /api/stories/{id}/image-processing-progress
```
**Response when processing:**
```json
{
"isProcessing": true,
"totalImages": 5,
"processedImages": 2,
"currentImageUrl": "https://example.com/image.jpg",
"status": "Processing image 3 of 5",
"progressPercentage": 40.0,
"completed": false,
"error": ""
}
```
**Response when completed:**
```json
{
"isProcessing": false,
"totalImages": 5,
"processedImages": 5,
"currentImageUrl": "",
"status": "Completed: 5 images processed",
"progressPercentage": 100.0,
"completed": true,
"error": ""
}
```
**Response when no processing:**
```json
{
"isProcessing": false,
"message": "No active image processing"
}
```
## Integration Examples
### React Hook Usage
```tsx
import { useImageProcessingProgress } from '../utils/imageProcessingProgress';
function StoryEditor({ storyId }) {
const { progress, isTracking, startTracking } = useImageProcessingProgress(storyId);
const handleSave = async () => {
await saveStory();
startTracking(); // Start monitoring progress
};
return (
<div>
{isTracking && progress && (
<div className="progress-indicator">
Processing {progress.processedImages}/{progress.totalImages} images...
</div>
)}
<button onClick={handleSave}>Save Story</button>
</div>
);
}
```
### Manual Progress Tracking
```typescript
// After saving a story with external images
const tracker = new ImageProcessingProgressTracker(storyId);
tracker.onProgress((progress) => {
updateProgressBar(progress.progressPercentage);
showStatus(progress.status);
if (progress.currentImageUrl) {
showCurrentImage(progress.currentImageUrl);
}
});
tracker.onComplete((finalProgress) => {
hideProgressBar();
showNotification('Image processing completed!');
refreshStoryContent(); // Reload story with processed images
});
tracker.onError((error) => {
hideProgressBar();
showError(`Image processing failed: ${error}`);
});
tracker.start();
```
## Configuration
### Polling Interval
Default: 1 second (1000ms)
```typescript
const tracker = new ImageProcessingProgressTracker(storyId, 500); // Poll every 500ms
```
### Timeout
Default: 5 minutes (300000ms)
```typescript
const tracker = new ImageProcessingProgressTracker(storyId, 1000, 600000); // 10 minute timeout
```
### Spring Async Configuration
The backend uses Spring's default async executor. For production, consider configuring a custom thread pool in your application properties:
```yaml
spring:
task:
execution:
pool:
core-size: 4
max-size: 8
queue-capacity: 100
```
## Error Handling
### Backend Errors
- Network timeouts downloading images
- Invalid image formats
- Disk space issues
- All errors are logged and returned in progress status
### Frontend Errors
- Network failures during progress polling
- Timeout if processing takes too long
- Graceful degradation - user can continue working
## Benefits
1. **No More Timeouts**: Large image processing operations won't timeout HTTP requests
2. **Better UX**: Users get real-time feedback about processing progress
3. **Improved Performance**: Users can continue using the app while images process
4. **Error Visibility**: Clear error messages when image processing fails
5. **Scalability**: Multiple users can process images simultaneously without blocking
## Future Enhancements
1. **WebSocket Support**: Replace polling with WebSocket for real-time push updates
2. **Batch Processing**: Queue multiple stories for batch image processing
3. **Retry Logic**: Automatic retry for failed image downloads
4. **Progress Persistence**: Save progress to database for recovery after server restart
5. **Image Optimization**: Automatic resize/compress images during processing