image generation function implementation
This commit is contained in:
@@ -26,6 +26,7 @@ interface ImageQueueModalProps {
|
||||
onClose: () => void;
|
||||
queue: ImageQueueItem[];
|
||||
totalImages: number;
|
||||
taskId?: string | null;
|
||||
onUpdateQueue?: (queue: ImageQueueItem[]) => void;
|
||||
}
|
||||
|
||||
@@ -34,6 +35,7 @@ export default function ImageQueueModal({
|
||||
onClose,
|
||||
queue,
|
||||
totalImages,
|
||||
taskId,
|
||||
onUpdateQueue,
|
||||
}: ImageQueueModalProps) {
|
||||
const [localQueue, setLocalQueue] = useState<ImageQueueItem[]>(queue);
|
||||
@@ -48,6 +50,101 @@ export default function ImageQueueModal({
|
||||
}
|
||||
}, [localQueue, onUpdateQueue]);
|
||||
|
||||
// Polling for task status updates
|
||||
useEffect(() => {
|
||||
if (!isOpen || !taskId) return;
|
||||
|
||||
const pollInterval = setInterval(async () => {
|
||||
try {
|
||||
const response = await fetch(`/api/v1/system/settings/task_progress/${taskId}/`);
|
||||
if (!response.ok) {
|
||||
console.error('Failed to fetch task status');
|
||||
return;
|
||||
}
|
||||
const data = await response.json();
|
||||
|
||||
// Check state (task_progress returns 'state', not 'status')
|
||||
const taskState = data.state || data.status;
|
||||
|
||||
if (taskState === 'SUCCESS' || taskState === 'FAILURE') {
|
||||
clearInterval(pollInterval);
|
||||
// Update final state
|
||||
if (taskState === 'SUCCESS' && data.result) {
|
||||
updateQueueFromTaskResult(data.result);
|
||||
} else if (taskState === 'SUCCESS' && data.meta && data.meta.result) {
|
||||
// Some responses have result in meta
|
||||
updateQueueFromTaskResult(data.meta.result);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Update progress from task meta
|
||||
if (data.meta) {
|
||||
updateQueueFromTaskMeta(data.meta);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error polling task status:', error);
|
||||
}
|
||||
}, 1000); // Poll every second
|
||||
|
||||
return () => clearInterval(pollInterval);
|
||||
}, [isOpen, taskId]);
|
||||
|
||||
const updateQueueFromTaskMeta = (meta: any) => {
|
||||
const { current_image, total_images, completed, failed, results } = meta;
|
||||
|
||||
setLocalQueue(prevQueue => {
|
||||
return prevQueue.map((item, index) => {
|
||||
const result = results?.find((r: any) => r.image_id === item.imageId);
|
||||
|
||||
if (result) {
|
||||
return {
|
||||
...item,
|
||||
status: result.status === 'completed' ? 'completed' :
|
||||
result.status === 'failed' ? 'failed' : 'processing',
|
||||
progress: result.status === 'completed' ? 100 :
|
||||
result.status === 'failed' ? 0 :
|
||||
index + 1 < current_image ? 100 :
|
||||
index + 1 === current_image ? 50 : 0,
|
||||
imageUrl: result.image_url || item.imageUrl,
|
||||
error: result.error || null
|
||||
};
|
||||
}
|
||||
|
||||
// Update based on current_image index
|
||||
if (index + 1 < current_image) {
|
||||
return { ...item, status: 'completed', progress: 100 };
|
||||
} else if (index + 1 === current_image) {
|
||||
return { ...item, status: 'processing', progress: 50 };
|
||||
}
|
||||
|
||||
return item;
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const updateQueueFromTaskResult = (result: any) => {
|
||||
const { results } = result;
|
||||
|
||||
setLocalQueue(prevQueue => {
|
||||
return prevQueue.map((item) => {
|
||||
const taskResult = results?.find((r: any) => r.image_id === item.imageId);
|
||||
|
||||
if (taskResult) {
|
||||
return {
|
||||
...item,
|
||||
status: taskResult.status === 'completed' ? 'completed' : 'failed',
|
||||
progress: taskResult.status === 'completed' ? 100 : 0,
|
||||
imageUrl: taskResult.image_url || item.imageUrl,
|
||||
error: taskResult.error || null
|
||||
};
|
||||
}
|
||||
|
||||
return item;
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
if (!isOpen) return null;
|
||||
|
||||
const getStatusIcon = (status: string) => {
|
||||
|
||||
@@ -43,6 +43,7 @@ export default function Images() {
|
||||
const [isQueueModalOpen, setIsQueueModalOpen] = useState(false);
|
||||
const [imageQueue, setImageQueue] = useState<ImageQueueItem[]>([]);
|
||||
const [currentContentId, setCurrentContentId] = useState<number | null>(null);
|
||||
const [taskId, setTaskId] = useState<string | null>(null);
|
||||
|
||||
// Load images - wrapped in useCallback
|
||||
const loadImages = useCallback(async () => {
|
||||
@@ -225,7 +226,7 @@ export default function Images() {
|
||||
setCurrentContentId(contentId);
|
||||
setIsQueueModalOpen(true);
|
||||
|
||||
// Collect image IDs for API call (will be used in Stage 2)
|
||||
// Collect image IDs for API call
|
||||
const imageIds: number[] = queue
|
||||
.map(item => item.imageId)
|
||||
.filter((id): id is number => id !== null);
|
||||
@@ -234,8 +235,18 @@ export default function Images() {
|
||||
console.log('[Generate Images] Image IDs to generate:', imageIds);
|
||||
console.log('[Generate Images] Max in-article images from settings:', maxInArticleImages);
|
||||
|
||||
// TODO: Stage 2 - Start actual generation
|
||||
// This will be implemented in Stage 2
|
||||
// STAGE 2: Start actual generation
|
||||
const result = await generateImages(imageIds, contentId);
|
||||
|
||||
if (result.success && result.task_id) {
|
||||
// Task started successfully - polling will be handled by ImageQueueModal
|
||||
setTaskId(result.task_id);
|
||||
console.log('[Generate Images] Stage 2: Task started with ID:', result.task_id);
|
||||
} else {
|
||||
toast.error(result.error || 'Failed to start image generation');
|
||||
setIsQueueModalOpen(false);
|
||||
setTaskId(null);
|
||||
}
|
||||
|
||||
} catch (error: any) {
|
||||
console.error('[Generate Images] Exception:', error);
|
||||
@@ -333,11 +344,13 @@ export default function Images() {
|
||||
setIsQueueModalOpen(false);
|
||||
setImageQueue([]);
|
||||
setCurrentContentId(null);
|
||||
setTaskId(null);
|
||||
// Reload images after closing if generation completed
|
||||
loadImages();
|
||||
}}
|
||||
queue={imageQueue}
|
||||
totalImages={imageQueue.length}
|
||||
taskId={taskId}
|
||||
onUpdateQueue={setImageQueue}
|
||||
/>
|
||||
</>
|
||||
|
||||
@@ -1032,10 +1032,13 @@ export async function fetchContentImages(): Promise<ContentImagesResponse> {
|
||||
return fetchAPI('/v1/writer/images/content_images/');
|
||||
}
|
||||
|
||||
export async function generateImages(imageIds: number[]): Promise<any> {
|
||||
export async function generateImages(imageIds: number[], contentId?: number): Promise<any> {
|
||||
return fetchAPI('/v1/writer/images/generate_images/', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ ids: imageIds }),
|
||||
body: JSON.stringify({
|
||||
ids: imageIds,
|
||||
content_id: contentId
|
||||
}),
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user