Enhance image processing and error handling in AICore and tasks
- Improved response parsing in AICore to handle both array and dictionary formats, including detailed error logging. - Updated image directory handling in tasks to prioritize web-accessible paths for image storage, with robust fallback mechanisms. - Adjusted image URL generation in serializers and frontend components to support new directory structure and ensure proper accessibility.
This commit is contained in:
@@ -25,6 +25,24 @@ interface ContentImageCellProps {
|
||||
export default function ContentImageCell({ image, maxPromptLength = 100 }: ContentImageCellProps) {
|
||||
const [showFullPrompt, setShowFullPrompt] = useState(false);
|
||||
|
||||
// Convert local file path to web-accessible URL
|
||||
const getLocalImageUrl = (imagePath: string): string => {
|
||||
// If path contains 'ai-images', convert to web URL
|
||||
if (imagePath.includes('ai-images')) {
|
||||
const filename = imagePath.split('ai-images/')[1] || imagePath.split('ai-images\\')[1];
|
||||
if (filename) {
|
||||
return `/images/ai-images/${filename}`;
|
||||
}
|
||||
}
|
||||
// If path is already a web path, return as-is
|
||||
if (imagePath.startsWith('/images/')) {
|
||||
return imagePath;
|
||||
}
|
||||
// Otherwise, try to extract filename and use ai-images path
|
||||
const filename = imagePath.split('/').pop() || imagePath.split('\\').pop();
|
||||
return `/images/ai-images/${filename}`;
|
||||
};
|
||||
|
||||
if (!image) {
|
||||
return (
|
||||
<div className="text-gray-400 dark:text-gray-500 text-sm">-</div>
|
||||
@@ -77,34 +95,69 @@ export default function ContentImageCell({ image, maxPromptLength = 100 }: Conte
|
||||
</div>
|
||||
)}
|
||||
|
||||
{image.status === 'generated' && image.image_url && (
|
||||
<a
|
||||
href={image.image_url}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="block group"
|
||||
>
|
||||
<img
|
||||
src={image.image_url}
|
||||
alt={prompt || 'Generated image'}
|
||||
className="w-full h-24 object-cover rounded border border-gray-300 dark:border-gray-600 group-hover:opacity-80 transition-opacity"
|
||||
onError={(e) => {
|
||||
// Fallback to placeholder if image fails to load
|
||||
const target = e.target as HTMLImageElement;
|
||||
target.style.display = 'none';
|
||||
target.parentElement!.innerHTML = `
|
||||
<div class="w-full h-24 bg-gray-200 dark:bg-gray-700 rounded border-2 border-dashed border-gray-300 dark:border-gray-600 flex items-center justify-center">
|
||||
<p class="text-xs text-gray-500 dark:text-gray-400">Image not available</p>
|
||||
</div>
|
||||
`;
|
||||
}}
|
||||
/>
|
||||
</a>
|
||||
)}
|
||||
|
||||
{image.status === 'generated' && !image.image_url && (
|
||||
<div className="w-full h-24 bg-yellow-100 dark:bg-yellow-900/20 rounded border border-yellow-300 dark:border-yellow-700 flex items-center justify-center">
|
||||
<p className="text-xs text-yellow-700 dark:text-yellow-400">No URL available</p>
|
||||
{image.status === 'generated' && (
|
||||
<div className="space-y-1">
|
||||
{/* Show local image if available, otherwise show original URL */}
|
||||
{image.image_path ? (
|
||||
<>
|
||||
<img
|
||||
src={getLocalImageUrl(image.image_path)}
|
||||
alt={prompt || 'Generated image'}
|
||||
className="w-full h-24 object-cover rounded border border-gray-300 dark:border-gray-600"
|
||||
onError={(e) => {
|
||||
// Fallback to original URL if local image fails
|
||||
const target = e.target as HTMLImageElement;
|
||||
if (image.image_url) {
|
||||
target.src = image.image_url;
|
||||
} else {
|
||||
target.style.display = 'none';
|
||||
target.parentElement!.innerHTML = `
|
||||
<div class="w-full h-24 bg-gray-200 dark:bg-gray-700 rounded border-2 border-dashed border-gray-300 dark:border-gray-600 flex items-center justify-center">
|
||||
<p class="text-xs text-gray-500 dark:text-gray-400">Image not available</p>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
}}
|
||||
/>
|
||||
{image.image_url && (
|
||||
<a
|
||||
href={image.image_url}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="block w-full text-center px-2 py-1 text-xs text-brand-500 hover:text-brand-600 dark:text-brand-400 dark:hover:text-brand-300 border border-brand-300 dark:border-brand-700 rounded hover:bg-brand-50 dark:hover:bg-brand-900/20 transition-colors"
|
||||
>
|
||||
View Original
|
||||
</a>
|
||||
)}
|
||||
</>
|
||||
) : image.image_url ? (
|
||||
<a
|
||||
href={image.image_url}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="block group"
|
||||
>
|
||||
<img
|
||||
src={image.image_url}
|
||||
alt={prompt || 'Generated image'}
|
||||
className="w-full h-24 object-cover rounded border border-gray-300 dark:border-gray-600 group-hover:opacity-80 transition-opacity"
|
||||
onError={(e) => {
|
||||
// Fallback to placeholder if image fails to load
|
||||
const target = e.target as HTMLImageElement;
|
||||
target.style.display = 'none';
|
||||
target.parentElement!.innerHTML = `
|
||||
<div class="w-full h-24 bg-gray-200 dark:bg-gray-700 rounded border-2 border-dashed border-gray-300 dark:border-gray-600 flex items-center justify-center">
|
||||
<p class="text-xs text-gray-500 dark:text-gray-400">Image not available</p>
|
||||
</div>
|
||||
`;
|
||||
}}
|
||||
/>
|
||||
</a>
|
||||
) : (
|
||||
<div className="w-full h-24 bg-yellow-100 dark:bg-yellow-900/20 rounded border border-yellow-300 dark:border-yellow-700 flex items-center justify-center">
|
||||
<p className="text-xs text-yellow-700 dark:text-yellow-400">No URL available</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user