Refactor: enhance API response schemas for pagination; update environment variables for Supabase and Vision API; improve Vite configuration for proxy routing

This commit is contained in:
salirezav
2025-08-12 13:48:17 -04:00
parent 7a939920fa
commit 62dd0d162b
9 changed files with 57 additions and 35 deletions

View File

@@ -71,13 +71,21 @@ class VideoInfoResponse(BaseModel):
class VideoListResponse(BaseModel):
"""Video list response"""
videos: List[VideoInfoResponse] = Field(..., description="List of videos")
total_count: int = Field(..., description="Total number of videos")
total_count: int = Field(..., description="Total number of matching videos (ignores pagination)")
page: Optional[int] = Field(None, description="Current page number (if using page/limit)")
total_pages: Optional[int] = Field(None, description="Total pages (if using page/limit)")
has_next: Optional[bool] = Field(None, description="Is there a next page?")
has_previous: Optional[bool] = Field(None, description="Is there a previous page?")
class Config:
schema_extra = {
"example": {
"videos": [],
"total_count": 0
"total_count": 0,
"page": 1,
"total_pages": 1,
"has_next": False,
"has_previous": False
}
}
@@ -108,8 +116,9 @@ class VideoListRequest(BaseModel):
start_date: Optional[datetime] = Field(None, description="Filter by start date")
end_date: Optional[datetime] = Field(None, description="Filter by end date")
limit: Optional[int] = Field(50, description="Maximum number of results")
include_metadata: bool = Field(False, description="Include video metadata")
offset: Optional[int] = Field(0, description="Number of items to skip (for pagination)")
include_metadata: bool = Field(False, description="Include video metadata for returned items only")
class Config:
schema_extra = {
"example": {
@@ -117,6 +126,7 @@ class VideoListRequest(BaseModel):
"start_date": "2025-08-04T00:00:00",
"end_date": "2025-08-04T23:59:59",
"limit": 50,
"offset": 0,
"include_metadata": True
}
}

View File

@@ -1,5 +1,3 @@
version: "3.9"
services:
api:
build:
@@ -8,11 +6,14 @@ services:
working_dir: /app
volumes:
- ./camera-management-api:/app
- ./camera-management-api/storage:/storage
- /storage:/storage
- /etc/localtime:/etc/localtime:ro
- /etc/timezone:/etc/timezone:ro
environment:
- PYTHONUNBUFFERED=1
- LD_LIBRARY_PATH=/usr/local/lib:/lib:/usr/lib
- PYTHONPATH=/app:/app/camera_sdk
- TZ=America/New_York
command: >
sh -lc "
apt-get update && apt-get install -y libusb-1.0-0-dev;
@@ -39,8 +40,7 @@ services:
# Start the application
python main.py --config config.compose.json
"
ports:
- "8000:8000"
network_mode: host
web:
image: node:20-alpine
@@ -49,13 +49,15 @@ services:
- ./management-dashboard-web-app:/app
environment:
- CHOKIDAR_USEPOLLING=true
- VITE_SUPABASE_URL=${VITE_SUPABASE_URL}
- VITE_SUPABASE_ANON_KEY=${VITE_SUPABASE_ANON_KEY}
- TZ=America/New_York
command: >
sh -lc "
npm ci;
npm run dev -- --host 0.0.0.0 --port 8080
"
# Ensure the web container can resolve host.docker.internal on Linux
extra_hosts:
- "host.docker.internal:host-gateway"
ports:
- "8080:8080"

View File

@@ -1,10 +1,10 @@
# Environment Configuration for Pecan Experiments Application
# USDA Vision Camera System API Configuration
# Default: http://localhost:8000 (current working setup)
# For localhost setup, use: http://localhost:8000
# For remote systems, use: http://192.168.1.100:8000 (replace with actual IP)
VITE_VISION_API_URL=http://localhost:8000
# Recommended default: use a relative path so the dev server proxy routes to the API container
# Leave unset to default to "/api" (see vite.config.ts proxy)
# To override and point directly, set e.g.:
# VITE_VISION_API_URL=http://vm-host-or-ip:8000
# Supabase Configuration (if needed for production)
# VITE_SUPABASE_URL=your_supabase_url

View File

@@ -15,9 +15,8 @@ import {
} from '../types';
import { performanceMonitor } from '../utils/performanceMonitor';
// Configuration - Use environment variable or default to vision container
// The API is accessible at localhost:8000 in the current setup
const API_BASE_URL = import.meta.env.VITE_VISION_API_URL || 'http://localhost:8000';
// Configuration - Prefer env var; default to relative "/api" so Vite proxy can route to the API container
const API_BASE_URL = import.meta.env.VITE_VISION_API_URL || '/api';
/**
* Custom error class for video API errors

View File

@@ -1,8 +1,12 @@
import { createClient } from '@supabase/supabase-js'
// Local development configuration
const supabaseUrl = 'http://127.0.0.1:54321'
const supabaseAnonKey = '[REDACTED]'
// Supabase configuration from environment (Vite)
const supabaseUrl = import.meta.env.VITE_SUPABASE_URL
const supabaseAnonKey = import.meta.env.VITE_SUPABASE_ANON_KEY
if (!supabaseUrl || !supabaseAnonKey) {
throw new Error('Supabase is not configured. Please set VITE_SUPABASE_URL and VITE_SUPABASE_ANON_KEY in your environment (.env)')
}
export const supabase = createClient(supabaseUrl, supabaseAnonKey)

View File

@@ -1,7 +1,6 @@
// Vision System API Client
// Base URL for the vision system API - Use environment variable or default to vision container
// The API is accessible at localhost:8000 in the current setup
const VISION_API_BASE_URL = import.meta.env.VITE_VISION_API_URL || 'http://localhost:8000'
// Base URL for the vision system API - Prefer env var; default to relative "/api" so Vite proxy can route to the API container
const VISION_API_BASE_URL = import.meta.env.VITE_VISION_API_URL || '/api'
// Types based on the API documentation
export interface SystemStatus {
@@ -290,7 +289,7 @@ class VisionApiClient {
private async request<T>(endpoint: string, options: RequestInit = {}): Promise<T> {
const url = `${this.baseUrl}${endpoint}`
const response = await fetch(url, {
headers: {
'Content-Type': 'application/json',
@@ -424,8 +423,8 @@ class VisionApiClient {
} catch (error: any) {
// If the error is related to missing auto-recording fields, try to handle it gracefully
if (error.message?.includes('auto_start_recording_enabled') ||
error.message?.includes('auto_recording_max_retries') ||
error.message?.includes('auto_recording_retry_delay_seconds')) {
error.message?.includes('auto_recording_max_retries') ||
error.message?.includes('auto_recording_retry_delay_seconds')) {
// Try to get the raw camera data and add default auto-recording fields
try {
@@ -540,7 +539,7 @@ export const formatDuration = (seconds: number): string => {
const hours = Math.floor(seconds / 3600)
const minutes = Math.floor((seconds % 3600) / 60)
const secs = Math.floor(seconds % 60)
if (hours > 0) {
return `${hours}h ${minutes}m ${secs}s`
} else if (minutes > 0) {
@@ -554,7 +553,7 @@ export const formatUptime = (seconds: number): string => {
const days = Math.floor(seconds / 86400)
const hours = Math.floor((seconds % 86400) / 3600)
const minutes = Math.floor((seconds % 3600) / 60)
if (days > 0) {
return `${days}d ${hours}h ${minutes}m`
} else if (hours > 0) {

View File

@@ -3,6 +3,7 @@
interface ImportMetaEnv {
readonly VITE_SUPABASE_URL: string;
readonly VITE_SUPABASE_ANON_KEY: string;
readonly VITE_VISION_API_URL?: string; // optional; defaults to "/api" via vite proxy
}
interface ImportMeta {

View File

@@ -1 +1 @@
v2.31.8
v2.33.9

View File

@@ -9,9 +9,16 @@ export default defineConfig({
tailwindcss(),
],
server: {
// Allow connecting via this VM's hostname
allowedHosts: ['exp-dash'],
// host is provided via CLI in docker-compose, but keeping this commented for local use:
// host: true,
// Allow connections from the VM hostname and any other host/IP
allowedHosts: ['exp-dash', 'localhost'],
// Proxy API calls from the browser to the API container via the compose service name
proxy: {
'/api': {
// Route to API via the host so this works whether API is on bridge (via port mapping) or host network
target: 'http://host.docker.internal:8000',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, ''),
},
},
},
})