From cef7b6870c84b6f4773c23cc79d77fb06b753466 Mon Sep 17 00:00:00 2001 From: Seyed Yahya Shirazi Date: Mon, 24 Nov 2025 13:06:26 -0800 Subject: [PATCH 1/5] Update frontend to AGI theme and fix image loading - Fix .gitignore to track image-list.json (was causing 404 on deploy) - Update color scheme from purple to AGI brand colors (teal, orange) - Add AGI color palette to tailwind.config.js - Convert to light theme with warm off-white background - Replace Brain icon with AGI logo in header - Update all components (page, ThumbnailRibbon, AnnotationViewer) - Improve accessibility with proper contrast ratios --- .gitignore | 3 +- frontend/app/components/AnnotationViewer.tsx | 76 +- frontend/app/components/ThumbnailRibbon.tsx | 46 +- frontend/app/page.tsx | 88 +- frontend/public/image-list.json | 1002 ++++++++++++++++++ frontend/tailwind.config.js | 41 + 6 files changed, 1151 insertions(+), 105 deletions(-) create mode 100644 frontend/public/image-list.json diff --git a/.gitignore b/.gitignore index d4b1940..c320b3e 100644 --- a/.gitignore +++ b/.gitignore @@ -112,11 +112,12 @@ ehthumbs.db test_outputs/ test_results/ -# Frontend public assets (copied for deployment) +# Frontend public assets (copied for deployment, except essentials) frontend/public/* !frontend/public/AGI-square.svg !frontend/public/AGI-square.png !frontend/public/favicon.ico +!frontend/public/image-list.json # Image files (but keep README, and downsampled) images/original/*.png diff --git a/frontend/app/components/AnnotationViewer.tsx b/frontend/app/components/AnnotationViewer.tsx index 9eb7c89..335db87 100644 --- a/frontend/app/components/AnnotationViewer.tsx +++ b/frontend/app/components/AnnotationViewer.tsx @@ -13,10 +13,10 @@ export default function AnnotationViewer({ annotation }: AnnotationViewerProps) const [viewMode, setViewMode] = useState<'text' | 'json'>('text') const handleCopy = () => { - const textToCopy = viewMode === 'json' + const textToCopy = viewMode === 'json' ? JSON.stringify(annotation.response_data || annotation.response, null, 2) : annotation.response - + navigator.clipboard.writeText(textToCopy) setCopied(true) setTimeout(() => setCopied(false), 2000) @@ -34,8 +34,8 @@ export default function AnnotationViewer({ annotation }: AnnotationViewerProps) return (
{data.map((item, index) => ( -
-
Item {index + 1}
+
+
Item {index + 1}
{renderJsonData(item)}
))} @@ -49,15 +49,15 @@ export default function AnnotationViewer({ annotation }: AnnotationViewerProps)
{Object.entries(data).map(([key, value]) => (
- + {key.replace(/_/g, ' ').replace(/\b\w/g, l => l.toUpperCase())}: {typeof value === 'object' ? ( -
+
{renderJsonData(value)}
) : ( - + {String(value)} )} @@ -68,15 +68,15 @@ export default function AnnotationViewer({ annotation }: AnnotationViewerProps) } // Primitive value - return {String(data)} + return {String(data)} } return (
{/* Prompt Text */} -
-
Prompt
-
+
+
Prompt
+
{annotation.prompt_text}
@@ -88,8 +88,8 @@ export default function AnnotationViewer({ annotation }: AnnotationViewerProps) onClick={() => setViewMode('text')} className={`px-3 py-1.5 rounded-lg text-sm flex items-center gap-1.5 transition-all ${ viewMode === 'text' - ? 'bg-purple-500/20 text-purple-300 border border-purple-500/30' - : 'bg-gray-800/30 text-gray-400 hover:bg-gray-800/50 border border-gray-700/30' + ? 'bg-agi-teal/10 text-agi-teal border border-agi-teal/30' + : 'bg-stone-100 text-agi-teal-600 hover:bg-stone-200 border border-stone-200' }`} > @@ -99,8 +99,8 @@ export default function AnnotationViewer({ annotation }: AnnotationViewerProps) onClick={() => setViewMode('json')} className={`px-3 py-1.5 rounded-lg text-sm flex items-center gap-1.5 transition-all ${ viewMode === 'json' - ? 'bg-purple-500/20 text-purple-300 border border-purple-500/30' - : 'bg-gray-800/30 text-gray-400 hover:bg-gray-800/50 border border-gray-700/30' + ? 'bg-agi-teal/10 text-agi-teal border border-agi-teal/30' + : 'bg-stone-100 text-agi-teal-600 hover:bg-stone-200 border border-stone-200' }`} > @@ -113,19 +113,19 @@ export default function AnnotationViewer({ annotation }: AnnotationViewerProps)
-
+
{viewMode === 'text' ? ( -
+
{annotation.response}
) : hasJsonData ? ( @@ -133,7 +133,7 @@ export default function AnnotationViewer({ annotation }: AnnotationViewerProps) {renderJsonData(annotation.response_data)}
) : ( -
+            
               {JSON.stringify(annotation.response, null, 2)}
             
)} @@ -144,44 +144,44 @@ export default function AnnotationViewer({ annotation }: AnnotationViewerProps) {(annotation.token_metrics || annotation.performance_metrics) && (
{annotation.token_metrics && ( -
+
- - Token Usage + + Token Usage
- Input: - {annotation.token_metrics.input_tokens} + Input: + {annotation.token_metrics.input_tokens}
- Output: - {annotation.token_metrics.output_tokens} + Output: + {annotation.token_metrics.output_tokens}
- Total: - {annotation.token_metrics.total_tokens} + Total: + {annotation.token_metrics.total_tokens}
)} {annotation.performance_metrics && ( -
+
- - Performance + + Performance
- Speed: - + Speed: + {annotation.performance_metrics.tokens_per_second.toFixed(1)} t/s
- Time: - + Time: + {(annotation.performance_metrics.total_duration_ms / 1000).toFixed(2)}s
@@ -192,4 +192,4 @@ export default function AnnotationViewer({ annotation }: AnnotationViewerProps) )}
) -} \ No newline at end of file +} diff --git a/frontend/app/components/ThumbnailRibbon.tsx b/frontend/app/components/ThumbnailRibbon.tsx index 32a79ec..33398a4 100644 --- a/frontend/app/components/ThumbnailRibbon.tsx +++ b/frontend/app/components/ThumbnailRibbon.tsx @@ -19,11 +19,11 @@ export default function ThumbnailRibbon({ images, selectedIndex, onSelect }: Thu if (thumbnailRefs.current[selectedIndex] && scrollContainerRef.current) { const thumbnail = thumbnailRefs.current[selectedIndex] const container = scrollContainerRef.current - + if (thumbnail) { const containerWidth = container.clientWidth const scrollLeft = thumbnail.offsetLeft - containerWidth / 2 + thumbnail.clientWidth / 2 - + container.scrollTo({ left: scrollLeft, behavior: 'smooth' @@ -59,15 +59,15 @@ export default function ThumbnailRibbon({ images, selectedIndex, onSelect }: Thu } return ( -
+
{/* Left scroll button */} {/* Thumbnail container */} @@ -78,13 +78,13 @@ export default function ThumbnailRibbon({ images, selectedIndex, onSelect }: Thu tabIndex={0} style={{ scrollbarWidth: 'thin', - scrollbarColor: 'rgb(147 51 234 / 0.3) transparent' + scrollbarColor: 'rgba(24, 74, 61, 0.3) transparent' }} > {images.map((image, index) => { // Extract the image number for display const imageNumber = image.id.match(/shared(\d+)/)?.[1] || String(index + 1) - + return (
- + {/* Progress indicator */}
@@ -149,16 +149,16 @@ export default function ThumbnailRibbon({ images, selectedIndex, onSelect }: Thu key={i} className={`h-1 rounded-full transition-all ${ Math.floor(selectedIndex / 10) === i - ? 'w-8 bg-gradient-to-r from-purple-400 to-pink-400' - : 'w-2 bg-gray-600' + ? 'w-8 bg-gradient-to-r from-agi-teal to-agi-orange' + : 'w-2 bg-agi-teal/20' }`} /> ))}
- + {selectedIndex + 1} / {images.length}
) -} \ No newline at end of file +} diff --git a/frontend/app/page.tsx b/frontend/app/page.tsx index e4d4a61..fe68d05 100644 --- a/frontend/app/page.tsx +++ b/frontend/app/page.tsx @@ -5,7 +5,7 @@ import Image from 'next/image' import ThumbnailRibbon from './components/ThumbnailRibbon' import AnnotationViewer from './components/AnnotationViewer' import { ImageData, Annotation, PromptAnnotation } from './types' -import { Brain, Sparkles, ChevronDown, Loader2, ExternalLink } from 'lucide-react' +import { Sparkles, ChevronDown, Loader2, ExternalLink } from 'lucide-react' export default function Dashboard() { const [images, setImages] = useState([]) @@ -129,31 +129,33 @@ export default function Dashboard() { if (loading) { return ( -
+
- -
Loading neural interface...
+ +
Loading annotation interface...
) } return ( -
+
{/* Header */} -
+
-
- -
-

- The Annotation Garden Project + AGI Logo +

+ Annotation Garden

-
- - AI-Powered Vision Analysis +
+ + Collaborative Image Annotation
@@ -162,10 +164,10 @@ export default function Dashboard() {
{/* Image Viewer - Full width on mobile, constrained on desktop */}
-
+
{imageLoading && ( -
- +
+
)} {images[selectedImageIndex] && ( @@ -180,15 +182,15 @@ export default function Dashboard() {
{/* Image Info Bar */} -
+
- Image ID: - + Image ID: + {images[selectedImageIndex]?.id || 'Loading...'}
-
+
{selectedImageIndex + 1} / {images.length}
@@ -198,8 +200,8 @@ export default function Dashboard() { {/* Controls and Annotations - Full width on mobile, side panel on desktop */}
{/* Model Selection */} -
-