Spaces:
Sleeping
Sleeping
| import { useState, useEffect } from 'react'; | |
| import { UploadSection } from './components/UploadSection'; | |
| import { DashboardHeader } from './components/DashboardHeader'; | |
| import { AnalyzingAnimation } from './components/AnalyzingAnimation'; | |
| import { Footer } from './components/Footer'; | |
| import { AnalysisResults } from './components/AnalysisResults'; | |
| import { ModelExplorer } from './components/ModelExplorer'; | |
| import { MarketPrices } from './components/MarketPrices'; | |
| import { AnalysisData } from './types/analysis'; | |
| import { API_BASE_URL } from './config'; | |
| function App() { | |
| const [activeTab, setActiveTab] = useState<'auditor' | 'market' | 'explorer'>('auditor'); | |
| const [isDarkMode, setIsDarkMode] = useState(true); // default to dark theme | |
| const [analysisData, setAnalysisData] = useState<AnalysisData | null>(null); | |
| const [isAnalyzing, setIsAnalyzing] = useState(false); | |
| const [error, setError] = useState<string | null>(null); | |
| // Sync dark mode class | |
| useEffect(() => { | |
| if (isDarkMode) { | |
| document.documentElement.classList.add('dark'); | |
| } else { | |
| document.documentElement.classList.remove('dark'); | |
| } | |
| }, [isDarkMode]); | |
| const handleAnalyze = async (imageUrl: string) => { | |
| setIsAnalyzing(true); | |
| setError(null); | |
| setAnalysisData(null); | |
| try { | |
| // Direct call to local Python AI endpoint | |
| const response = await fetch(`${API_BASE_URL}/api/analyze`, { | |
| method: 'POST', | |
| headers: { 'Content-Type': 'application/json' }, | |
| body: JSON.stringify({ imageUrl }) | |
| }); | |
| if (!response.ok) { | |
| throw new Error(`Server returned status: ${response.status}`); | |
| } | |
| const data = await response.json(); | |
| if (data.error) throw new Error(data.error); | |
| setAnalysisData(data); | |
| } catch (err: any) { | |
| console.error(err); | |
| setError(err.message || 'Failed to connect to Python backend.'); | |
| } finally { | |
| setIsAnalyzing(false); | |
| } | |
| }; | |
| return ( | |
| <div className="min-h-screen bg-background text-foreground pb-12 font-sans flex flex-col justify-between transition-colors duration-300"> | |
| <div> | |
| {/* Unified Dashboard Header with Tab Switcher & Theme Toggle */} | |
| <DashboardHeader | |
| activeTab={activeTab} | |
| setActiveTab={(tab: any) => setActiveTab(tab)} | |
| isDarkMode={isDarkMode} | |
| setIsDarkMode={setIsDarkMode} | |
| /> | |
| <main className="container mx-auto px-6 py-8 max-w-7xl"> | |
| {activeTab === 'auditor' && ( | |
| <div className="space-y-8"> | |
| {/* Uploader Section */} | |
| <UploadSection onAnalyze={handleAnalyze} isAnalyzing={isAnalyzing} /> | |
| {/* Error logs */} | |
| {error && ( | |
| <div className="p-4 rounded-xl text-rose-500 bg-rose-500/10 border border-rose-500/25 text-xs font-semibold"> | |
| <strong>Audit Failed:</strong> {error} | |
| </div> | |
| )} | |
| {/* AI Processing animation */} | |
| {isAnalyzing && ( | |
| <div className="bg-card/40 backdrop-blur-md p-16 rounded-2xl border border-border flex flex-col items-center justify-center"> | |
| <AnalyzingAnimation /> | |
| <p className="text-muted-foreground mt-6 font-mono text-xs animate-pulse uppercase tracking-widest font-bold"> | |
| Running OCR Boundary & NLP Vector Models... | |
| </p> | |
| </div> | |
| )} | |
| {/* Audit Diagnostic Results */} | |
| {analysisData && !isAnalyzing && ( | |
| <AnalysisResults data={analysisData} /> | |
| )} | |
| </div> | |
| )} | |
| {activeTab === 'market' && ( | |
| <MarketPrices /> | |
| )} | |
| {activeTab === 'explorer' && ( | |
| <ModelExplorer /> | |
| )} | |
| </main> | |
| </div> | |
| <Footer /> | |
| </div> | |
| ); | |
| } | |
| export default App; | |