This commit is contained in:
rUv
2025-06-07 13:55:28 +00:00
parent 6dd89f2ada
commit 7b5df5c077
11 changed files with 713 additions and 141 deletions

267
README.md
View File

@@ -213,8 +213,14 @@ system.stop()
# Start the API server
wifi-densepose start
# Or using Python
python -m wifi_densepose.main
# Start with custom configuration
wifi-densepose -c /path/to/config.yaml start
# Start with verbose logging
wifi-densepose -v start
# Check server status
wifi-densepose status
```
The API will be available at `http://localhost:8000`
@@ -255,180 +261,229 @@ The CLI is automatically installed with the package:
pip install wifi-densepose
# Verify CLI installation
wifi-densepose --version
wifi-densepose --help
wifi-densepose version
```
### Basic Commands
#### Start/Stop System
The WiFi-DensePose CLI provides the following commands:
```bash
# Start the WiFi DensePose system
wifi-densepose [OPTIONS] COMMAND [ARGS]...
Options:
-c, --config PATH Path to configuration file
-v, --verbose Enable verbose logging
--debug Enable debug mode
--help Show this message and exit.
Commands:
config Configuration management commands.
db Database management commands.
start Start the WiFi-DensePose API server.
status Show the status of the WiFi-DensePose API server.
stop Stop the WiFi-DensePose API server.
tasks Background task management commands.
version Show version information.
```
#### Server Management
```bash
# Start the WiFi-DensePose API server
wifi-densepose start
# Start with custom configuration
wifi-densepose start --config /path/to/config.yaml
wifi-densepose -c /path/to/config.yaml start
# Start in development mode
wifi-densepose start --dev
# Start with verbose logging
wifi-densepose -v start
# Stop the system
wifi-densepose stop
# Start with debug mode
wifi-densepose --debug start
# Restart the system
wifi-densepose restart
```
#### System Status
```bash
# Check system status
# Check server status
wifi-densepose status
# Get detailed health information
wifi-densepose health
# Stop the server
wifi-densepose stop
# Show system information
wifi-densepose info
```
#### Pose Data Operations
```bash
# Get latest pose data
wifi-densepose pose latest
# Get pose history
wifi-densepose pose history --hours 24
# Stream pose data to console
wifi-densepose pose stream
# Export pose data
wifi-densepose pose export --format json --output poses.json
# Show version information
wifi-densepose version
```
### Configuration Commands
#### Environment Setup
#### Configuration Management
```bash
# Initialize configuration
wifi-densepose init
# Create configuration from template
wifi-densepose config create --template healthcare
# Validate configuration
wifi-densepose config validate
# Configuration management commands
wifi-densepose config [SUBCOMMAND]
# Examples:
# Show current configuration
wifi-densepose config show
# Validate configuration file
wifi-densepose config validate
# Create default configuration
wifi-densepose config init
# Edit configuration
wifi-densepose config edit
```
#### Hardware Configuration
#### Database Management
```bash
# List available WiFi interfaces
wifi-densepose hardware list-interfaces
# Database management commands
wifi-densepose db [SUBCOMMAND]
# Test hardware connectivity
wifi-densepose hardware test
# Examples:
# Initialize database
wifi-densepose db init
# Calibrate environment
wifi-densepose calibrate --duration 10 --environment room_001
# Run database migrations
wifi-densepose db migrate
# Show hardware status
wifi-densepose hardware status
# Check database status
wifi-densepose db status
# Backup database
wifi-densepose db backup
# Restore database
wifi-densepose db restore
```
### Monitoring Commands
#### Real-time Monitoring
#### Background Tasks
```bash
# Monitor system performance
wifi-densepose monitor
# Background task management commands
wifi-densepose tasks [SUBCOMMAND]
# Monitor pose detection in real-time
wifi-densepose monitor poses
# Examples:
# List running tasks
wifi-densepose tasks list
# Monitor system logs
wifi-densepose logs --follow
# Start background tasks
wifi-densepose tasks start
# Monitor specific component
wifi-densepose monitor --component csi_processor
# Stop background tasks
wifi-densepose tasks stop
# Check task status
wifi-densepose tasks status
```
#### Analytics and Reports
### Command Examples
#### Complete CLI Reference
```bash
# Generate analytics report
wifi-densepose analytics report --period 24h
# Show help for main command
wifi-densepose --help
# Show fall detection events
wifi-densepose analytics falls --since yesterday
# Show help for specific command
wifi-densepose start --help
wifi-densepose config --help
wifi-densepose db --help
# Export system metrics
wifi-densepose metrics export --format csv
# Use global options with commands
wifi-densepose -v status # Verbose status check
wifi-densepose --debug start # Start with debug logging
wifi-densepose -c custom.yaml start # Start with custom config
```
#### Common Usage Patterns
```bash
# Basic server lifecycle
wifi-densepose start # Start the server
wifi-densepose status # Check if running
wifi-densepose stop # Stop the server
# Configuration management
wifi-densepose config show # View current config
wifi-densepose config validate # Check config validity
# Database operations
wifi-densepose db init # Initialize database
wifi-densepose db migrate # Run migrations
wifi-densepose db status # Check database health
# Task management
wifi-densepose tasks list # List background tasks
wifi-densepose tasks status # Check task status
# Version and help
wifi-densepose version # Show version info
wifi-densepose --help # Show help message
```
### CLI Examples
#### Complete Setup Workflow
```bash
# 1. Initialize new environment
wifi-densepose init --environment healthcare
# 1. Check version and help
wifi-densepose version
wifi-densepose --help
# 2. Configure hardware
wifi-densepose hardware setup --interface wlan0
# 2. Initialize configuration
wifi-densepose config init
# 3. Calibrate environment
wifi-densepose calibrate --duration 15
# 3. Initialize database
wifi-densepose db init
# 4. Start system
# 4. Start the server
wifi-densepose start
# 5. Monitor in real-time
wifi-densepose monitor poses
# 5. Check status
wifi-densepose status
```
#### Development Workflow
```bash
# Start in development mode with mock data
wifi-densepose start --dev --mock-hardware
# Start with debug logging
wifi-densepose --debug start
# Run tests
wifi-densepose test
# Use custom configuration
wifi-densepose -c dev-config.yaml start
# Check code quality
wifi-densepose lint
# Check database status
wifi-densepose db status
# Generate documentation
wifi-densepose docs generate
# Manage background tasks
wifi-densepose tasks start
wifi-densepose tasks list
```
#### Production Deployment
#### Production Workflow
```bash
# Deploy to production
wifi-densepose deploy --environment production
# Start with production config
wifi-densepose -c production.yaml start
# Check deployment status
wifi-densepose deploy status
# Check system status
wifi-densepose status
# Scale system
wifi-densepose scale --replicas 3
# Manage database
wifi-densepose db migrate
wifi-densepose db backup
# Update system
wifi-densepose update --version 1.2.0
# Monitor tasks
wifi-densepose tasks status
```
#### Troubleshooting
```bash
# Run system diagnostics
wifi-densepose diagnose
# Enable verbose logging
wifi-densepose -v status
# Check hardware connectivity
wifi-densepose hardware test --verbose
# Check configuration
wifi-densepose config validate
# Validate configuration
wifi-densepose config validate --strict
# Check database health
wifi-densepose db status
# Reset to defaults
wifi-densepose reset --confirm
# Restart services
wifi-densepose stop
wifi-densepose start
```
## 📚 Documentation

206
plans/overview.md Normal file
View File

@@ -0,0 +1,206 @@
# WiFi-DensePose System Implementation Overview
## Project Architecture
```
┌─────────────────────────────────────────────────────────────────┐
│ WiFi-DensePose System │
├─────────────────────────────────────────────────────────────────┤
│ Frontend Layer (React/TypeScript) │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Dashboard │ │ Real-time │ │ Config │ │
│ │ UI │ │ Monitoring │ │ Management │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
├─────────────────────────────────────────────────────────────────┤
│ API & Middleware Layer (FastAPI/Python) │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ REST API │ │ WebSocket │ │ Auth & │ │
│ │ Endpoints │ │ Real-time │ │ Validation │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
├─────────────────────────────────────────────────────────────────┤
│ Neural Network Layer (PyTorch/TensorFlow) │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ DensePose │ │ CSI Signal │ │ Pose │ │
│ │ Model │ │ Processing │ │ Estimation │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
├─────────────────────────────────────────────────────────────────┤
│ CSI Processing Layer (Python/C++) │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Data │ │ Signal │ │ Feature │ │
│ │ Collection │ │ Processing │ │ Extraction │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
├─────────────────────────────────────────────────────────────────┤
│ Infrastructure Layer │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ WiFi Router │ │ Database │ │ Message │ │
│ │ Hardware │ │ (PostgreSQL)│ │ Queue │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
└─────────────────────────────────────────────────────────────────┘
```
## Technology Stack
### Backend Technologies
- **Framework**: FastAPI (Python 3.9+)
- **Neural Networks**: PyTorch 2.0+, TensorFlow 2.x
- **Database**: PostgreSQL 14+, Redis (caching)
- **Message Queue**: RabbitMQ/Celery
- **CSI Processing**: NumPy, SciPy, custom C++ modules
- **Testing**: pytest, pytest-asyncio, pytest-mock
### Frontend Technologies
- **Framework**: React 18+ with TypeScript
- **State Management**: Redux Toolkit
- **UI Components**: Material-UI v5
- **Real-time**: Socket.IO client
- **Testing**: Jest, React Testing Library, Cypress
### Infrastructure
- **Containerization**: Docker, Docker Compose
- **Orchestration**: Kubernetes
- **CI/CD**: GitHub Actions
- **Monitoring**: Prometheus, Grafana
- **Logging**: ELK Stack (Elasticsearch, Logstash, Kibana)
## Phase Dependencies Flowchart
```
Phase 1: Foundation
├─── Phase 2: CSI Processing ──┐
│ │
├─── Phase 3: Neural Networks ─┤
│ │
└─── Phase 4: API Middleware ──┼─── Phase 6: Integration
│ │
Phase 5: UI Frontend ─────┘ │
Phase 7: Deployment
```
## Implementation Timeline
| Phase | Duration | Start Date | End Date | Dependencies |
|-------|----------|------------|----------|--------------|
| Phase 1: Foundation | 2 weeks | Week 1 | Week 2 | None |
| Phase 2: CSI Processing | 3 weeks | Week 2 | Week 4 | Phase 1 |
| Phase 3: Neural Networks | 4 weeks | Week 3 | Week 6 | Phase 1, 2 |
| Phase 4: API Middleware | 3 weeks | Week 4 | Week 6 | Phase 1, 2 |
| Phase 5: UI Frontend | 3 weeks | Week 5 | Week 7 | Phase 4 |
| Phase 6: Integration | 2 weeks | Week 7 | Week 8 | All previous |
| Phase 7: Deployment | 1 week | Week 9 | Week 9 | Phase 6 |
**Total Project Duration**: 9 weeks
## Risk Assessment and Mitigation Strategies
### High-Risk Areas
#### 1. CSI Data Quality and Consistency
- **Risk**: Inconsistent or noisy CSI data affecting model accuracy
- **Mitigation**:
- Implement robust data validation and filtering
- Create comprehensive test datasets
- Develop fallback mechanisms for poor signal conditions
#### 2. Neural Network Performance
- **Risk**: Model accuracy below acceptable thresholds
- **Mitigation**:
- Implement multiple model architectures for comparison
- Use transfer learning from existing DensePose models
- Continuous model validation and retraining pipelines
#### 3. Real-time Processing Requirements
- **Risk**: System unable to meet real-time processing demands
- **Mitigation**:
- Implement efficient data pipelines with streaming
- Use GPU acceleration where possible
- Design scalable microservices architecture
#### 4. Hardware Integration Complexity
- **Risk**: Difficulties integrating with various WiFi router models
- **Mitigation**:
- Create abstraction layer for router interfaces
- Extensive testing with multiple router models
- Fallback to software-based CSI extraction
### Medium-Risk Areas
#### 5. API Performance and Scalability
- **Risk**: API bottlenecks under high load
- **Mitigation**:
- Implement caching strategies
- Use async/await patterns throughout
- Load testing and performance optimization
#### 6. Frontend Complexity
- **Risk**: Complex real-time UI updates causing performance issues
- **Mitigation**:
- Implement efficient state management
- Use React.memo and useMemo for optimization
- Progressive loading and lazy components
### Low-Risk Areas
#### 7. Database Performance
- **Risk**: Database queries becoming slow with large datasets
- **Mitigation**:
- Proper indexing strategy
- Query optimization
- Database connection pooling
## Success Metrics
### Technical Metrics
- **Model Accuracy**: >85% pose estimation accuracy
- **Latency**: <100ms end-to-end processing time
- **Throughput**: Handle 100+ concurrent users
- **Uptime**: 99.9% system availability
- **Test Coverage**: >95% code coverage
### Business Metrics
- **User Adoption**: Successful deployment in test environments
- **Performance**: Real-time pose tracking with minimal lag
- **Scalability**: System handles expected load without degradation
- **Maintainability**: Clean, documented, testable codebase
## Quality Assurance Strategy
### Testing Approach (London School TDD)
- **Unit Tests**: Mock all external dependencies, focus on behavior
- **Integration Tests**: Test component interactions with test doubles
- **End-to-End Tests**: Full system testing with real data
- **Performance Tests**: Load and stress testing
- **Security Tests**: Vulnerability scanning and penetration testing
### Code Quality Standards
- **Code Coverage**: Minimum 95% for all modules
- **Documentation**: Comprehensive API documentation and code comments
- **Code Review**: All code changes require peer review
- **Static Analysis**: Automated linting and security scanning
- **Continuous Integration**: Automated testing on all commits
## Deployment Strategy
### Environment Progression
1. **Development**: Local development with Docker Compose
2. **Testing**: Automated testing environment with CI/CD
3. **Staging**: Production-like environment for final validation
4. **Production**: Kubernetes-based production deployment
### Monitoring and Observability
- **Application Metrics**: Custom metrics for pose estimation accuracy
- **Infrastructure Metrics**: CPU, memory, network, storage
- **Logging**: Structured logging with correlation IDs
- **Alerting**: Proactive alerts for system issues
- **Tracing**: Distributed tracing for performance analysis
## Next Steps
1. **Phase 1**: Begin with foundation setup and core infrastructure
2. **Team Alignment**: Ensure all team members understand the architecture
3. **Environment Setup**: Prepare development and testing environments
4. **Baseline Metrics**: Establish performance and quality baselines
5. **Risk Monitoring**: Regular assessment of identified risks
This overview provides the strategic framework for the WiFi-DensePose system implementation. Each phase plan will detail specific technical requirements, implementation steps, and success criteria.

View File

@@ -42,10 +42,27 @@ class Settings(BaseSettings):
database_pool_size: int = Field(default=10, description="Database connection pool size")
database_max_overflow: int = Field(default=20, description="Database max overflow connections")
# Database connection pool settings (alternative naming for compatibility)
db_pool_size: int = Field(default=10, description="Database connection pool size")
db_max_overflow: int = Field(default=20, description="Database max overflow connections")
db_pool_timeout: int = Field(default=30, description="Database pool timeout in seconds")
db_pool_recycle: int = Field(default=3600, description="Database pool recycle time in seconds")
# Database connection settings
db_host: Optional[str] = Field(default=None, description="Database host")
db_port: int = Field(default=5432, description="Database port")
db_name: Optional[str] = Field(default=None, description="Database name")
db_user: Optional[str] = Field(default=None, description="Database user")
db_password: Optional[str] = Field(default=None, description="Database password")
db_echo: bool = Field(default=False, description="Enable database query logging")
# Redis settings (for caching and rate limiting)
redis_url: Optional[str] = Field(default=None, description="Redis connection URL")
redis_password: Optional[str] = Field(default=None, description="Redis password")
redis_db: int = Field(default=0, description="Redis database number")
redis_enabled: bool = Field(default=True, description="Enable Redis")
redis_host: str = Field(default="localhost", description="Redis host")
redis_port: int = Field(default=6379, description="Redis port")
# Hardware settings
wifi_interface: str = Field(default="wlan0", description="WiFi interface name")
@@ -78,6 +95,9 @@ class Settings(BaseSettings):
metrics_enabled: bool = Field(default=True, description="Enable metrics collection")
health_check_interval: int = Field(default=30, description="Health check interval in seconds")
performance_monitoring: bool = Field(default=True, description="Enable performance monitoring")
monitoring_interval_seconds: int = Field(default=60, description="Monitoring task interval in seconds")
cleanup_interval_seconds: int = Field(default=3600, description="Cleanup task interval in seconds")
backup_interval_seconds: int = Field(default=86400, description="Backup task interval in seconds")
# Storage settings
data_storage_path: str = Field(default="./data", description="Data storage directory")
@@ -160,6 +180,38 @@ class Settings(BaseSettings):
if v < 1:
raise ValueError("Workers must be at least 1")
return v
@field_validator("db_port")
@classmethod
def validate_db_port(cls, v):
"""Validate database port."""
if not 1 <= v <= 65535:
raise ValueError("Database port must be between 1 and 65535")
return v
@field_validator("redis_port")
@classmethod
def validate_redis_port(cls, v):
"""Validate Redis port."""
if not 1 <= v <= 65535:
raise ValueError("Redis port must be between 1 and 65535")
return v
@field_validator("db_pool_size")
@classmethod
def validate_db_pool_size(cls, v):
"""Validate database pool size."""
if v < 1:
raise ValueError("Database pool size must be at least 1")
return v
@field_validator("monitoring_interval_seconds", "cleanup_interval_seconds", "backup_interval_seconds")
@classmethod
def validate_interval_seconds(cls, v):
"""Validate interval settings."""
if v < 0:
raise ValueError("Interval seconds must be non-negative")
return v
@property
def is_development(self) -> bool:
"""Check if running in development environment."""
@@ -180,6 +232,11 @@ class Settings(BaseSettings):
if self.database_url:
return self.database_url
# Build URL from individual components if available
if self.db_host and self.db_name and self.db_user:
password_part = f":{self.db_password}" if self.db_password else ""
return f"postgresql://{self.db_user}{password_part}@{self.db_host}:{self.db_port}/{self.db_name}"
# Default SQLite database for development
if self.is_development:
return f"sqlite:///{self.data_storage_path}/wifi_densepose.db"
@@ -188,14 +245,15 @@ class Settings(BaseSettings):
def get_redis_url(self) -> Optional[str]:
"""Get Redis URL with fallback."""
if not self.redis_enabled:
return None
if self.redis_url:
return self.redis_url
# Default Redis for development
if self.is_development:
return "redis://localhost:6379/0"
return None
# Build URL from individual components
password_part = f":{self.redis_password}@" if self.redis_password else ""
return f"redis://{password_part}{self.redis_host}:{self.redis_port}/{self.redis_db}"
def get_cors_config(self) -> Dict[str, Any]:
"""Get CORS configuration."""
@@ -318,8 +376,8 @@ def validate_settings(settings: Settings) -> List[str]:
if not settings.secret_key or settings.secret_key == "change-me":
issues.append("Secret key must be set for production")
if not settings.database_url:
issues.append("Database URL must be set for production")
if not settings.database_url and not (settings.db_host and settings.db_name and settings.db_user):
issues.append("Database URL or database connection parameters must be set for production")
if settings.debug:
issues.append("Debug mode should be disabled in production")

View File

@@ -34,6 +34,12 @@ ui/
## 🚀 Features
### Smart Backend Detection
- **Automatic Detection**: Automatically detects if your FastAPI backend is running
- **Real Backend Priority**: Always uses the real backend when available
- **Mock Fallback**: Falls back to mock server only when backend is unavailable
- **Testing Mode**: Can force mock mode for testing and development
### Real-time Dashboard
- Live system health monitoring
- Real-time pose detection statistics
@@ -281,6 +287,14 @@ apiService.addResponseInterceptor(async (response, url) => {
## 🚀 Deployment
### Development
**Option 1: Use the startup script**
```bash
cd /workspaces/wifi-densepose/ui
./start-ui.sh
```
**Option 2: Manual setup**
```bash
# First, start your FastAPI backend (runs on port 8000)
wifi-densepose start
@@ -294,9 +308,14 @@ python -m http.server 3000
npx http-server . -p 3000
# Open the UI at http://localhost:3000
# The UI will connect to the FastAPI backend at http://localhost:8000
# The UI will automatically detect and connect to your backend
```
### Backend Detection Behavior
- **Real Backend Available**: UI connects to `http://localhost:8000` and shows ✅ "Connected to real backend"
- **Backend Unavailable**: UI automatically uses mock server and shows ⚠️ "Mock server active - testing mode"
- **Force Mock Mode**: Set `API_CONFIG.MOCK_SERVER.ENABLED = true` for testing
### Production
1. Configure `API_CONFIG.BASE_URL` for your backend
2. Set up HTTPS for WebSocket connections

View File

@@ -7,6 +7,7 @@ import { LiveDemoTab } from './components/LiveDemoTab.js';
import { apiService } from './services/api.service.js';
import { wsService } from './services/websocket.service.js';
import { healthService } from './services/health.service.js';
import { backendDetector } from './utils/backend-detector.js';
class WiFiDensePoseApp {
constructor() {
@@ -51,13 +52,30 @@ class WiFiDensePoseApp {
return response;
});
// Check API availability
try {
const health = await healthService.checkLiveness();
console.log('API is available:', health);
} catch (error) {
console.error('API is not available:', error);
throw new Error('API is not available. Please ensure the backend is running.');
// Detect backend availability and initialize accordingly
const useMock = await backendDetector.shouldUseMockServer();
if (useMock) {
console.log('🧪 Initializing with mock server for testing');
// Import and start mock server only when needed
const { mockServer } = await import('./utils/mock-server.js');
mockServer.start();
// Show notification to user
this.showBackendStatus('Mock server active - testing mode', 'warning');
} else {
console.log('🔌 Initializing with real backend');
// Verify backend is actually working
try {
const health = await healthService.checkLiveness();
console.log('✅ Backend is available and responding:', health);
this.showBackendStatus('Connected to real backend', 'success');
} catch (error) {
console.error('❌ Backend check failed:', error);
this.showBackendStatus('Backend connection failed', 'error');
// Don't throw - let the app continue and retry later
}
}
}
@@ -195,6 +213,28 @@ class WiFiDensePoseApp {
});
}
// Show backend status notification
showBackendStatus(message, type) {
// Create status notification if it doesn't exist
let statusToast = document.getElementById('backendStatusToast');
if (!statusToast) {
statusToast = document.createElement('div');
statusToast.id = 'backendStatusToast';
statusToast.className = 'backend-status-toast';
document.body.appendChild(statusToast);
}
statusToast.textContent = message;
statusToast.className = `backend-status-toast ${type}`;
statusToast.classList.add('show');
// Auto-hide success messages, keep warnings and errors longer
const timeout = type === 'success' ? 3000 : 8000;
setTimeout(() => {
statusToast.classList.remove('show');
}, timeout);
}
// Show global error message
showGlobalError(message) {
// Create error toast if it doesn't exist

View File

@@ -6,6 +6,12 @@ export const API_CONFIG = {
WS_PREFIX: 'ws://',
WSS_PREFIX: 'wss://',
// Mock server configuration (only for testing)
MOCK_SERVER: {
ENABLED: false, // Set to true only for testing without backend
AUTO_DETECT: true, // Automatically detect if backend is available
},
// API Endpoints
ENDPOINTS: {
// Root & Info

View File

@@ -1,6 +1,7 @@
// API Service for WiFi-DensePose UI
import { API_CONFIG, buildApiUrl } from '../config/api.config.js';
import { backendDetector } from '../utils/backend-detector.js';
export class ApiService {
constructor() {
@@ -69,8 +70,15 @@ export class ApiService {
// Process request through interceptors
const processed = await this.processRequest(url, options);
// Determine the correct base URL (real backend vs mock)
let finalUrl = processed.url;
if (processed.url.startsWith(API_CONFIG.BASE_URL)) {
const baseUrl = await backendDetector.getBaseUrl();
finalUrl = processed.url.replace(API_CONFIG.BASE_URL, baseUrl);
}
// Make the request
const response = await fetch(processed.url, {
const response = await fetch(finalUrl, {
...processed.options,
headers: this.getHeaders(processed.options.headers)
});

View File

@@ -1,6 +1,7 @@
// WebSocket Service for WiFi-DensePose UI
import { API_CONFIG, buildWsUrl } from '../config/api.config.js';
import { backendDetector } from '../utils/backend-detector.js';
export class WebSocketService {
constructor() {
@@ -10,8 +11,18 @@ export class WebSocketService {
}
// Connect to WebSocket endpoint
connect(endpoint, params = {}, handlers = {}) {
const url = buildWsUrl(endpoint, params);
async connect(endpoint, params = {}, handlers = {}) {
// Determine if we should use mock WebSockets
const useMock = await backendDetector.shouldUseMockServer();
let url;
if (useMock) {
// Use mock WebSocket URL (served from same origin as UI)
url = buildWsUrl(endpoint, params).replace('localhost:8000', window.location.host);
} else {
// Use real backend WebSocket URL
url = buildWsUrl(endpoint, params);
}
// Check if already connected
if (this.connections.has(url)) {

View File

@@ -1573,6 +1573,42 @@ canvas {
opacity: 1;
}
/* Backend status toast */
.backend-status-toast {
position: fixed;
top: var(--space-24);
right: var(--space-24);
padding: var(--space-12) var(--space-20);
border-radius: var(--radius-base);
box-shadow: var(--shadow-lg);
transform: translateY(-100%);
opacity: 0;
transition: all 0.3s ease;
z-index: 1001;
font-weight: var(--font-weight-medium);
font-size: var(--font-size-sm);
}
.backend-status-toast.show {
transform: translateY(0);
opacity: 1;
}
.backend-status-toast.success {
background: var(--color-success);
color: white;
}
.backend-status-toast.warning {
background: var(--color-warning);
color: white;
}
.backend-status-toast.error {
background: var(--color-error);
color: white;
}
/* Tab badge */
.tab-badge {
display: inline-block;

View File

@@ -95,8 +95,8 @@
<!-- Test Controls Panel -->
<div class="test-controls">
<h3>Integration Tests</h3>
<button class="test-button" onclick="startMockServer()">Start Mock Server</button>
<button class="test-button danger" onclick="stopMockServer()">Stop Mock Server</button>
<button class="test-button" onclick="toggleMockMode()">Toggle Mock Mode</button>
<button class="test-button" onclick="checkBackendStatus()">Check Backend Status</button>
<button class="test-button" onclick="testHealthAPI()">Test Health API</button>
<button class="test-button" onclick="testPoseAPI()">Test Pose API</button>
<button class="test-button" onclick="testWebSocketStream()">Test WebSocket</button>
@@ -376,34 +376,60 @@
<script type="module">
import { mockServer } from '../utils/mock-server.js';
import { WiFiDensePoseApp } from '../app.js';
import { API_CONFIG } from '../config/api.config.js';
import { backendDetector } from '../utils/backend-detector.js';
// Global test functions
window.mockServer = mockServer;
window.app = null;
window.startMockServer = () => {
window.toggleMockMode = async () => {
try {
mockServer.start();
updateMockIndicator(true);
showTestStatus('Mock server started successfully', 'success');
// Toggle mock mode
API_CONFIG.MOCK_SERVER.ENABLED = !API_CONFIG.MOCK_SERVER.ENABLED;
// Initialize app if not already done
// Force backend detector to recheck
backendDetector.forceCheck();
if (API_CONFIG.MOCK_SERVER.ENABLED) {
mockServer.start();
updateMockIndicator(true);
showTestStatus('Mock mode enabled - using test data', 'success');
} else {
mockServer.stop();
updateMockIndicator(false);
showTestStatus('Mock mode disabled - using real backend', 'info');
}
// Reinitialize app with new configuration
if (!window.app) {
window.app = new WiFiDensePoseApp();
window.app.init();
await window.app.init();
}
} catch (error) {
showTestStatus(`Failed to start mock server: ${error.message}`, 'error');
showTestStatus(`Failed to toggle mock mode: ${error.message}`, 'error');
}
};
window.stopMockServer = () => {
window.checkBackendStatus = async () => {
try {
mockServer.stop();
updateMockIndicator(false);
showTestStatus('Mock server stopped', 'info');
showTestStatus('Checking backend status...', 'info');
const isAvailable = await backendDetector.checkBackendAvailability();
const useMock = await backendDetector.shouldUseMockServer();
if (isAvailable && !useMock) {
showTestStatus('✅ Real backend is available and being used', 'success');
updateMockIndicator(false);
} else if (useMock) {
showTestStatus('🧪 Using mock server (testing mode)', 'success');
updateMockIndicator(true);
} else {
showTestStatus('❌ Backend unavailable, mock server available', 'error');
updateMockIndicator(false);
}
} catch (error) {
showTestStatus(`Failed to stop mock server: ${error.message}`, 'error');
showTestStatus(`Backend check failed: ${error.message}`, 'error');
}
};
@@ -537,9 +563,15 @@
}
}
// Auto-start mock server on load
document.addEventListener('DOMContentLoaded', () => {
startMockServer();
// Auto-check backend status on load
document.addEventListener('DOMContentLoaded', async () => {
await checkBackendStatus();
// Initialize app
if (!window.app) {
window.app = new WiFiDensePoseApp();
await window.app.init();
}
});
</script>
</body>

View File

@@ -0,0 +1,101 @@
// Backend Detection Utility
import { API_CONFIG } from '../config/api.config.js';
export class BackendDetector {
constructor() {
this.isBackendAvailable = null;
this.lastCheck = 0;
this.checkInterval = 30000; // Check every 30 seconds
}
// Check if the real backend is available
async checkBackendAvailability() {
const now = Date.now();
// Use cached result if recent
if (this.isBackendAvailable !== null && (now - this.lastCheck) < this.checkInterval) {
return this.isBackendAvailable;
}
try {
console.log('🔍 Checking backend availability...');
// Try to connect to the health endpoint with a short timeout
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 3000); // 3 second timeout
const response = await fetch(`${API_CONFIG.BASE_URL}/health/live`, {
method: 'GET',
signal: controller.signal,
headers: {
'Accept': 'application/json'
}
});
clearTimeout(timeoutId);
if (response.ok) {
this.isBackendAvailable = true;
this.lastCheck = now;
console.log('✅ Real backend is available');
return true;
} else {
throw new Error(`Backend responded with status ${response.status}`);
}
} catch (error) {
this.isBackendAvailable = false;
this.lastCheck = now;
if (error.name === 'AbortError') {
console.log('⏱️ Backend check timed out - assuming unavailable');
} else {
console.log(`❌ Backend unavailable: ${error.message}`);
}
return false;
}
}
// Determine if mock server should be used
async shouldUseMockServer() {
// If mock is explicitly enabled, always use it
if (API_CONFIG.MOCK_SERVER.ENABLED) {
console.log('🧪 Using mock server (explicitly enabled)');
return true;
}
// If auto-detection is disabled, never use mock
if (!API_CONFIG.MOCK_SERVER.AUTO_DETECT) {
console.log('🔌 Using real backend (auto-detection disabled)');
return false;
}
// Check if backend is available
const backendAvailable = await this.checkBackendAvailability();
if (backendAvailable) {
console.log('🔌 Using real backend (detected and available)');
return false;
} else {
console.log('🧪 Using mock server (backend unavailable)');
return true;
}
}
// Get the appropriate base URL
async getBaseUrl() {
const useMock = await this.shouldUseMockServer();
return useMock ? window.location.origin : API_CONFIG.BASE_URL;
}
// Force a fresh check
forceCheck() {
this.isBackendAvailable = null;
this.lastCheck = 0;
}
}
// Create singleton instance
export const backendDetector = new BackendDetector();