import React, { useState, useEffect } from 'react'; import { Header } from './Header'; import { JobForm } from './JobForm'; import { StatusDisplay } from './StatusDisplay'; import { TokenUsage } from './TokenUsage'; import { DecisionLog } from './DecisionLog'; import { ScreenshotGallery } from './ScreenshotGallery'; import { StreamingViewer } from './StreamingViewer'; import { ProxyStats } from './ProxyStats'; import { WebSocketManager } from '../services/WebSocketManager'; export const BrowserPilotDashboard: React.FC = () => { const [wsManager] = useState(() => new WebSocketManager()); const [status, setStatus] = useState<{ message: string; type: 'success' | 'error' | 'info'; } | null>(null); const [tokenUsage, setTokenUsage] = useState({ prompt_tokens: 0, response_tokens: 0, total_tokens: 0, api_calls: 0 }); const [proxyStats, setProxyStats] = useState({ available: 0, healthy: 0, blocked: 0, retry_count: 0 }); const [decisions, setDecisions] = useState([]); const [screenshots, setScreenshots] = useState([]); const [currentJobId, setCurrentJobId] = useState(null); const [isLoading, setIsLoading] = useState(false); const [streamingEnabled, setStreamingEnabled] = useState(false); useEffect(() => { // Set up WebSocket event listeners wsManager.on('connected', () => { setStatus({ message: 'Connected to BrowserPilot server', type: 'success' }); setIsLoading(false); }); wsManager.on('decision', (data: any) => { const decision = data.decision || data; setDecisions(prev => [...prev, decision]); if (decision.token_usage) { updateTokenUsage(decision.token_usage); } }); wsManager.on('screenshot', (data: any) => { const screenshot = data.screenshot || data; if (typeof screenshot === 'string') { setScreenshots(prev => [...prev, screenshot]); } }); wsManager.on('proxy_stats', (data: any) => { setProxyStats(data.stats || data); }); wsManager.on('token_usage', (data: any) => { updateTokenUsage(data.token_usage || data); }); wsManager.on('page_info', (data: any) => { setStatus({ message: `Navigating: ${data.url} • Found ${data.interactive_elements} interactive elements`, type: 'info' }); }); wsManager.on('extraction', (data: any) => { if (data.status === 'completed') { setStatus({ message: `Extraction completed successfully in ${data.format?.toUpperCase()} format`, type: 'success' }); } }); wsManager.on('error', (data: any) => { setStatus({ message: data.message || data.error || 'An unexpected error occurred', type: 'error' }); setIsLoading(false); }); return () => { wsManager.disconnect(); wsManager.disconnectStream(); }; }, [wsManager]); const updateTokenUsage = (usage: any) => { setTokenUsage(prev => ({ prompt_tokens: prev.prompt_tokens + (usage.prompt_tokens || 0), response_tokens: prev.response_tokens + (usage.response_tokens || 0), total_tokens: prev.total_tokens + (usage.total_tokens || 0), api_calls: prev.api_calls + 1 })); }; const handleJobCreated = (jobData: { jobId: string; streaming: boolean; format: string }) => { console.log('Job created:', jobData); setCurrentJobId(jobData.jobId); setIsLoading(true); setStreamingEnabled(jobData.streaming); wsManager.connect(jobData.jobId); }; const clearDecisions = () => setDecisions([]); const clearScreenshots = () => setScreenshots([]); return (
{/* Welcome Animation */}

Welcome to BrowserPilot

Open-source alternative to Perplexity Comet and director.ai. Describe what you need, and watch as your browser comes to life.

{/* Control Panel */}
{/* Status Display */} {status && (
setStatus(null)} />
)} {/* Loading State */} {isLoading && (

BrowserPilot is working...

)} {/* Browser Streaming */}
{/* Decision Log */}
{/* Screenshot Gallery */}
{/* Floating Action Button */}
); };