502 lines
16 KiB
Markdown
502 lines
16 KiB
Markdown
# Image Generation Implementation Changelog
|
|
|
|
## Stage 1: Pre-Queue Modal Display - Completed ✅
|
|
|
|
**Date:** 2025-01-XX
|
|
**Status:** Completed
|
|
**Goal:** Open modal immediately showing all progress bars before any API calls
|
|
|
|
---
|
|
|
|
## Changes Made
|
|
|
|
### 1. Frontend Components
|
|
|
|
#### Created: `frontend/src/components/common/ImageQueueModal.tsx`
|
|
- **Purpose:** Display image generation queue with individual progress bars
|
|
- **Features:**
|
|
- Shows all images that will be generated with individual progress bars
|
|
- Displays queue number, label, content title, status, and progress percentage
|
|
- Includes thumbnail placeholder for generated images
|
|
- Supports 4 states: `pending`, `processing`, `completed`, `failed`
|
|
- Styled similar to WP plugin's image-queue-processor.js modal
|
|
- Responsive design with dark mode support
|
|
- Prevents closing while processing
|
|
- Shows completion summary in footer
|
|
|
|
**Key Props:**
|
|
- `isOpen`: Boolean to control modal visibility
|
|
- `onClose`: Callback when modal is closed
|
|
- `queue`: Array of `ImageQueueItem` objects
|
|
- `totalImages`: Total number of images in queue
|
|
- `onUpdateQueue`: Optional callback to update queue state
|
|
|
|
**ImageQueueItem Interface:**
|
|
```typescript
|
|
{
|
|
imageId: number | null;
|
|
index: number;
|
|
label: string;
|
|
type: 'featured' | 'in_article';
|
|
position?: number;
|
|
contentTitle: string;
|
|
status: 'pending' | 'processing' | 'completed' | 'failed';
|
|
progress: number; // 0-100
|
|
imageUrl: string | null;
|
|
error: string | null;
|
|
}
|
|
```
|
|
|
|
#### Updated: `frontend/src/pages/Writer/Images.tsx`
|
|
- **Added Imports:**
|
|
- `fetchImageGenerationSettings` from `../../services/api`
|
|
- `ImageQueueModal` and `ImageQueueItem` from `../../components/common/ImageQueueModal`
|
|
|
|
- **Added State:**
|
|
```typescript
|
|
const [isQueueModalOpen, setIsQueueModalOpen] = useState(false);
|
|
const [imageQueue, setImageQueue] = useState<ImageQueueItem[]>([]);
|
|
const [currentContentId, setCurrentContentId] = useState<number | null>(null);
|
|
```
|
|
|
|
- **Added Function: `buildImageQueue()`**
|
|
- Builds image queue structure from content images
|
|
- Includes featured image (if pending and has prompt)
|
|
- Includes in-article images (up to `max_in_article_images` from settings)
|
|
- Sorts in-article images by position
|
|
- Returns array of `ImageQueueItem` objects
|
|
|
|
- **Updated Function: `handleGenerateImages()`**
|
|
- **Stage 1 Implementation:**
|
|
1. Fetches image generation settings to get `max_in_article_images`
|
|
2. Builds image queue using `buildImageQueue()`
|
|
3. Opens modal immediately with all progress bars at 0%
|
|
4. Collects image IDs for future API call (Stage 2)
|
|
5. Logs Stage 1 completion
|
|
|
|
- **Added Modal Component:**
|
|
- Renders `ImageQueueModal` at end of component
|
|
- Handles modal close with image reload
|
|
- Passes queue state and update callback
|
|
|
|
### 2. API Services
|
|
|
|
#### Updated: `frontend/src/services/api.ts`
|
|
- **Added Interface: `ImageGenerationSettings`**
|
|
```typescript
|
|
{
|
|
success: boolean;
|
|
config: {
|
|
provider: string;
|
|
model: string;
|
|
image_type: string;
|
|
max_in_article_images: number;
|
|
image_format: string;
|
|
desktop_enabled: boolean;
|
|
mobile_enabled: boolean;
|
|
};
|
|
}
|
|
```
|
|
|
|
- **Added Function: `fetchImageGenerationSettings()`**
|
|
- Fetches image generation settings from backend
|
|
- Endpoint: `/v1/system/integrations/image_generation/`
|
|
- Returns settings including `max_in_article_images`
|
|
|
|
### 3. Backend API
|
|
|
|
#### Updated: `backend/igny8_core/modules/system/integration_views.py`
|
|
- **Added Method: `get_image_generation_settings()`**
|
|
- Action decorator: `@action(detail=False, methods=['get'], url_path='image_generation')`
|
|
- Gets account from request (with fallbacks)
|
|
- Retrieves `IntegrationSettings` for `image_generation` type
|
|
- Returns formatted config with defaults if not found
|
|
- Default values:
|
|
- `provider`: 'openai'
|
|
- `model`: 'dall-e-3'
|
|
- `image_type`: 'realistic'
|
|
- `max_in_article_images`: 2
|
|
- `image_format`: 'webp'
|
|
- `desktop_enabled`: True
|
|
- `mobile_enabled`: True
|
|
|
|
#### Updated: `backend/igny8_core/modules/system/urls.py`
|
|
- **Added URL Route:**
|
|
```python
|
|
path('integrations/image_generation/', integration_image_gen_settings_viewset, name='integration-image-gen-settings')
|
|
```
|
|
- **Added ViewSet:**
|
|
```python
|
|
integration_image_gen_settings_viewset = IntegrationSettingsViewSet.as_view({
|
|
'get': 'get_image_generation_settings',
|
|
})
|
|
```
|
|
|
|
---
|
|
|
|
## How It Works
|
|
|
|
### User Flow:
|
|
1. User clicks "Generate Images" button on Images page
|
|
2. System fetches `max_in_article_images` from IntegrationSettings
|
|
3. System builds queue:
|
|
- 1 Featured Image (if pending and has prompt)
|
|
- N In-Article Images (up to `max_in_article_images`, if pending and have prompts)
|
|
4. **Modal opens immediately** showing all progress bars at 0%
|
|
5. Each progress bar displays:
|
|
- Queue number (1, 2, 3...)
|
|
- Label (Featured Image, In-Article Image 1, etc.)
|
|
- Content title
|
|
- Status: "⏳ Pending"
|
|
- Progress: 0%
|
|
- Thumbnail placeholder: "No image"
|
|
|
|
### Queue Calculation:
|
|
```
|
|
Total Images = 1 (featured) + min(pending_in_article_count, max_in_article_images)
|
|
```
|
|
|
|
Example:
|
|
- Settings: `max_in_article_images = 3`
|
|
- Content has: 1 featured (pending), 5 in-article (pending)
|
|
- Queue: 1 featured + 3 in-article = **4 total progress bars**
|
|
|
|
---
|
|
|
|
## Files Modified
|
|
|
|
### Frontend:
|
|
1. ✅ `frontend/src/components/common/ImageQueueModal.tsx` (NEW)
|
|
2. ✅ `frontend/src/pages/Writer/Images.tsx` (UPDATED)
|
|
3. ✅ `frontend/src/services/api.ts` (UPDATED)
|
|
|
|
### Backend:
|
|
1. ✅ `backend/igny8_core/modules/system/integration_views.py` (UPDATED)
|
|
2. ✅ `backend/igny8_core/modules/system/urls.py` (UPDATED)
|
|
|
|
---
|
|
|
|
## Testing Checklist
|
|
|
|
- [x] Modal opens immediately when "Generate Images" button is clicked
|
|
- [x] Modal shows correct number of progress bars (1 featured + N in-article)
|
|
- [x] Progress bars display correct labels and content titles
|
|
- [x] All progress bars start at 0% with "Pending" status
|
|
- [x] Modal can be closed (when not processing)
|
|
- [x] API endpoint returns correct `max_in_article_images` value
|
|
- [x] Queue respects `max_in_article_images` setting
|
|
- [x] Only pending images with prompts are included in queue
|
|
|
|
---
|
|
|
|
## Next Steps (Stage 2)
|
|
|
|
### Planned Features:
|
|
1. **Start Actual Generation**
|
|
- Call `generateImages()` API with image IDs
|
|
- Handle async task response with `task_id`
|
|
|
|
2. **Real-Time Progress Updates**
|
|
- Poll task progress or use WebSocket
|
|
- Update individual progress bars as images are generated
|
|
- Implement progressive loading (0-50% in 7s, 50-75% in 5s, etc.)
|
|
|
|
3. **Sequential Processing**
|
|
- Process images one at a time (sequential)
|
|
- Update status: pending → processing → completed/failed
|
|
- Update progress percentage for each image
|
|
|
|
4. **Error Handling**
|
|
- Mark failed images with error message
|
|
- Continue processing other images if one fails
|
|
- Display error in queue item
|
|
|
|
5. **Completion Handling**
|
|
- Show generated image thumbnails
|
|
- Update all statuses to completed/failed
|
|
- Reload images list on modal close
|
|
|
|
---
|
|
|
|
## Notes
|
|
|
|
- Stage 1 focuses on **immediate visual feedback** - modal opens instantly
|
|
- No API calls are made in Stage 1 (only settings fetch)
|
|
- Queue structure is built client-side from existing image data
|
|
- Modal is ready to receive progress updates in Stage 2
|
|
- Design matches WP plugin's image-queue-processor.js modal
|
|
|
|
---
|
|
|
|
## Related Files
|
|
|
|
- **Reference Implementation:** `igny8-ai-seo-wp-plugin/assets/js/image-queue-processor.js`
|
|
- **Implementation Plan:** `docs/IMAGE_GENERATION_IMPLEMENTATION_PLAN.md`
|
|
- **Backend Function:** `backend/igny8_core/ai/functions/generate_images_from_prompts.py`
|
|
|
|
---
|
|
|
|
---
|
|
|
|
## Stage 1 Updates: Modal Styling Improvements
|
|
|
|
**Date:** 2025-01-XX
|
|
**Status:** Completed
|
|
|
|
### Changes Made:
|
|
|
|
1. **Updated Modal Background**
|
|
- Changed from `bg-black bg-opacity-50` to standard modal backdrop
|
|
- Now uses `Modal` component with `bg-gray-400/50 backdrop-blur-[32px]` (standard glass effect)
|
|
- Matches all other modals in the system
|
|
|
|
2. **Replaced Emojis with React Icons**
|
|
- Header: Replaced 🎨 emoji with `FileIcon` component
|
|
- Pending status: Replaced ⏳ emoji with `TimeIcon` component
|
|
- Processing status: Added spinning SVG icon
|
|
- Completed status: Uses `CheckCircleIcon` component
|
|
- Failed status: Uses `ErrorIcon` component
|
|
|
|
3. **Standard Modal Width**
|
|
- Changed from custom width to `max-w-4xl` (standard modal width)
|
|
- Uses `Modal` component which provides consistent styling across system
|
|
|
|
### Files Modified:
|
|
- ✅ `frontend/src/components/common/ImageQueueModal.tsx` (UPDATED)
|
|
|
|
### Visual Improvements:
|
|
- Modal now has proper blur/glass backdrop effect
|
|
- Icons are consistent with system design
|
|
- Modal width matches other modals in the system
|
|
- Better visual hierarchy with icon in header
|
|
|
|
---
|
|
|
|
**End of Stage 1 Changelog**
|
|
|
|
---
|
|
|
|
## Stage 2 & 3: Image Generation Execution & Real-Time Progress - Completed ✅
|
|
|
|
**Date:** 2025-01-XX
|
|
**Status:** Completed
|
|
**Goal:** Execute image generation sequentially and update progress in real-time
|
|
|
|
---
|
|
|
|
## Changes Made
|
|
|
|
### 1. Backend API
|
|
|
|
#### Updated: `backend/igny8_core/modules/writer/views.py`
|
|
- **Added Method: `generate_images()`**
|
|
- Action decorator: `@action(detail=False, methods=['post'], url_path='generate_images')`
|
|
- Accepts `ids` (image IDs array) and `content_id` (optional)
|
|
- Queues `process_image_generation_queue` Celery task
|
|
- Returns `task_id` for progress tracking
|
|
- Handles validation errors and execution errors
|
|
|
|
### 2. Celery Task
|
|
|
|
#### Updated: `backend/igny8_core/ai/tasks.py`
|
|
- **Added Task: `process_image_generation_queue()`**
|
|
- Decorator: `@shared_task(bind=True, name='igny8_core.ai.tasks.process_image_generation_queue')`
|
|
- Parameters: `image_ids`, `account_id`, `content_id`
|
|
- Loads account from `account_id`
|
|
- Gets image generation settings from `IntegrationSettings` (provider, model, image_type, etc.)
|
|
- Gets provider API key from `IntegrationSettings` (OpenAI or Runware)
|
|
- Gets prompt templates from `PromptRegistry`
|
|
- Processes images sequentially (one at a time)
|
|
- For each image:
|
|
- Updates task meta with current progress
|
|
- Loads image record from database
|
|
- Validates prompt exists
|
|
- Gets content for prompt formatting
|
|
- Formats prompt using template
|
|
- Calls `AICore.generate_image()`
|
|
- Updates `Images` model: `image_url`, `status`
|
|
- Handles errors per image (continues on failure)
|
|
- Returns final result with counts and per-image results
|
|
|
|
### 3. Frontend API
|
|
|
|
#### Updated: `frontend/src/services/api.ts`
|
|
- **Updated Function: `generateImages()`**
|
|
- Added `contentId` parameter (optional)
|
|
- Sends both `ids` and `content_id` to backend
|
|
- Returns task response with `task_id`
|
|
|
|
### 4. Frontend Components
|
|
|
|
#### Updated: `frontend/src/pages/Writer/Images.tsx`
|
|
- **Added State:**
|
|
- `taskId`: Stores Celery task ID for polling
|
|
- **Updated Function: `handleGenerateImages()`**
|
|
- Stage 2: Calls `generateImages()` API after opening modal
|
|
- Stores `task_id` in state
|
|
- Handles API errors
|
|
- **Updated Modal Props:**
|
|
- Passes `taskId` to `ImageQueueModal`
|
|
|
|
#### Updated: `frontend/src/components/common/ImageQueueModal.tsx`
|
|
- **Added Prop: `taskId`**
|
|
- Optional string for Celery task ID
|
|
- **Added Polling Mechanism:**
|
|
- `useEffect` hook polls task status every 1 second
|
|
- Endpoint: `/api/v1/system/settings/task_progress/{taskId}/`
|
|
- Stops polling when task completes (SUCCESS/FAILURE)
|
|
- **Added Function: `updateQueueFromTaskMeta()`**
|
|
- Updates queue items from task meta data
|
|
- Maps `current_image`, `completed`, `failed`, `results` to queue items
|
|
- Updates status, progress, imageUrl, error for each item
|
|
- **Added Function: `updateQueueFromTaskResult()`**
|
|
- Updates queue items from final task result
|
|
- Sets final status and image URLs
|
|
- Handles completion state
|
|
|
|
### 5. Backend Task Status Endpoint
|
|
|
|
#### Existing: `backend/igny8_core/modules/system/integration_views.py`
|
|
- **Method: `task_progress()`**
|
|
- Already exists and handles Celery task status polling
|
|
- Returns task state (PENDING, PROGRESS, SUCCESS, FAILURE)
|
|
- Returns task meta for progress updates
|
|
- Returns task result on completion
|
|
|
|
---
|
|
|
|
## How It Works
|
|
|
|
### User Flow:
|
|
1. User clicks "Generate Images" button
|
|
2. **Stage 1:** Modal opens immediately with all progress bars
|
|
3. **Stage 2:** Frontend calls `generate_images()` API
|
|
4. Backend queues `process_image_generation_queue` Celery task
|
|
5. **Stage 3:** Frontend polls task status every 1 second
|
|
6. Celery task processes images sequentially:
|
|
- Image 1: Load → Format Prompt → Generate → Save
|
|
- Image 2: Load → Format Prompt → Generate → Save
|
|
- ... (continues for all images)
|
|
7. Task updates meta with progress after each image
|
|
8. Frontend receives updates and updates modal progress bars
|
|
9. On completion, modal shows final status for all images
|
|
10. User closes modal → Images list reloads
|
|
|
|
### Data Flow:
|
|
```
|
|
Frontend (Images.tsx)
|
|
↓ handleGenerateImages()
|
|
↓ generateImages() API call
|
|
Backend (ImagesViewSet.generate_images)
|
|
↓ process_image_generation_queue.delay()
|
|
Celery Task (process_image_generation_queue)
|
|
↓ For each image:
|
|
↓ Load from DB
|
|
↓ Get settings (IntegrationSettings)
|
|
↓ Format prompt (PromptRegistry)
|
|
↓ AICore.generate_image()
|
|
↓ Update Images model (image_url, status)
|
|
↓ Update task meta
|
|
Frontend (ImageQueueModal)
|
|
↓ Poll task_progress endpoint
|
|
↓ Update queue from meta/result
|
|
↓ Display progress bars
|
|
```
|
|
|
|
### Progress Updates:
|
|
- **Task Meta Structure:**
|
|
- `current_image`: Index of image being processed
|
|
- `total_images`: Total images in queue
|
|
- `completed`: Number of completed images
|
|
- `failed`: Number of failed images
|
|
- `results`: Array of per-image results
|
|
- **Per-Image Result:**
|
|
- `image_id`: Image record ID
|
|
- `status`: 'completed' or 'failed'
|
|
- `image_url`: Generated image URL (if successful)
|
|
- `error`: Error message (if failed)
|
|
|
|
---
|
|
|
|
## Files Modified
|
|
|
|
### Backend:
|
|
1. ✅ `backend/igny8_core/modules/writer/views.py` (UPDATED)
|
|
- `generate_images()` method
|
|
|
|
2. ✅ `backend/igny8_core/ai/tasks.py` (UPDATED)
|
|
- `process_image_generation_queue()` task
|
|
|
|
### Frontend:
|
|
1. ✅ `frontend/src/services/api.ts` (UPDATED)
|
|
- `generateImages()` function
|
|
|
|
2. ✅ `frontend/src/pages/Writer/Images.tsx` (UPDATED)
|
|
- `handleGenerateImages()` function
|
|
- `taskId` state
|
|
- Modal props
|
|
|
|
3. ✅ `frontend/src/components/common/ImageQueueModal.tsx` (UPDATED)
|
|
- `taskId` prop
|
|
- Polling mechanism
|
|
- `updateQueueFromTaskMeta()` function
|
|
- `updateQueueFromTaskResult()` function
|
|
|
|
---
|
|
|
|
## Integration Points
|
|
|
|
### Settings Integration:
|
|
- **IntegrationSettings Model:**
|
|
- `image_generation` type: Provider, model, image_type, max_in_article_images, etc.
|
|
- `openai` type: API key, model
|
|
- `runware` type: API key, model
|
|
|
|
### Prompt Templates:
|
|
- **PromptRegistry:**
|
|
- `get_image_prompt_template()`: Formats prompt with post_title, image_prompt, image_type
|
|
- `get_negative_prompt()`: Returns negative prompt for Runware
|
|
|
|
### Image Storage:
|
|
- **Images Model:**
|
|
- `image_url`: Updated with generated image URL
|
|
- `status`: Updated to 'generated' or 'failed'
|
|
- `prompt`: Used for generation (already set)
|
|
|
|
---
|
|
|
|
## Testing Checklist
|
|
|
|
- [x] API endpoint accepts image IDs and content ID
|
|
- [x] Celery task queues successfully
|
|
- [x] Task processes images sequentially
|
|
- [x] Task reads settings from IntegrationSettings
|
|
- [x] Task formats prompts using PromptRegistry
|
|
- [x] Task calls AICore.generate_image() correctly
|
|
- [x] Task updates Images model with URLs and status
|
|
- [x] Task updates meta with progress
|
|
- [x] Frontend polls task status correctly
|
|
- [x] Modal updates progress bars in real-time
|
|
- [x] Modal shows generated image thumbnails
|
|
- [x] Modal handles errors per image
|
|
- [x] Modal shows completion summary
|
|
- [x] Images list reloads after modal close
|
|
|
|
---
|
|
|
|
## Notes
|
|
|
|
- Images are processed **sequentially** (one at a time) to respect API rate limits
|
|
- Each image failure is handled independently (doesn't stop other images)
|
|
- Progress updates are sent via Celery task meta (polled every 1 second)
|
|
- Task status endpoint already exists and is reused
|
|
- Integration settings are read from database (not hardcoded)
|
|
- Prompt templates support fallback if formatting fails
|
|
- Image URLs are saved directly to Images model
|
|
- Status is updated to 'generated' or 'failed' per image
|
|
|
|
---
|
|
|
|
**End of Stage 2 & 3 Changelog**
|
|
|