Refactor camera management to conditionally import SDK and handle mock mode; update API base URL references to localhost in documentation and code.

This commit is contained in:
salirezav
2025-08-08 13:20:31 -04:00
parent fc2da16728
commit 20907509b1
17 changed files with 404 additions and 121 deletions

1
.gitignore vendored
View File

@@ -29,3 +29,4 @@ camera-management-api/usda_vision_system.log
# Docker # Docker
*.pid *.pid
camera-management-api/camera_sdk/

View File

@@ -7,14 +7,14 @@ This guide is specifically designed for AI assistants to understand and implemen
The USDA Vision Camera system provides live video streaming through REST API endpoints. The streaming uses MJPEG format which is natively supported by HTML `<img>` tags and can be easily integrated into React components. The USDA Vision Camera system provides live video streaming through REST API endpoints. The streaming uses MJPEG format which is natively supported by HTML `<img>` tags and can be easily integrated into React components.
### Key Characteristics: ### Key Characteristics:
- **Base URL**: `http://vision:8000` (production) or `http://localhost:8000` (development) - **Base URL**: `http://localhost:8000` (production) or `http://localhost:8000` (development)
- **Stream Format**: MJPEG (Motion JPEG) - **Stream Format**: MJPEG (Motion JPEG)
- **Content-Type**: `multipart/x-mixed-replace; boundary=frame` - **Content-Type**: `multipart/x-mixed-replace; boundary=frame`
- **Authentication**: None (add if needed for production) - **Authentication**: None (add if needed for production)
- **CORS**: Enabled for all origins (configure for production) - **CORS**: Enabled for all origins (configure for production)
### Base URL Configuration: ### Base URL Configuration:
- **Production**: `http://vision:8000` (requires hostname setup) - **Production**: `http://localhost:8000` (requires hostname setup)
- **Development**: `http://localhost:8000` (local testing) - **Development**: `http://localhost:8000` (local testing)
- **Custom IP**: `http://192.168.1.100:8000` (replace with actual IP) - **Custom IP**: `http://192.168.1.100:8000` (replace with actual IP)
- **Custom hostname**: Configure DNS or /etc/hosts as needed - **Custom hostname**: Configure DNS or /etc/hosts as needed
@@ -77,7 +77,7 @@ GET /cameras/{camera_name}/stream
```jsx ```jsx
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect } from 'react';
const CameraStream = ({ cameraName, apiBaseUrl = 'http://vision:8000' }) => { const CameraStream = ({ cameraName, apiBaseUrl = 'http://localhost:8000' }) => {
const [isStreaming, setIsStreaming] = useState(false); const [isStreaming, setIsStreaming] = useState(false);
const [error, setError] = useState(null); const [error, setError] = useState(null);
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
@@ -227,7 +227,7 @@ export default CameraStream;
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect } from 'react';
import CameraStream from './CameraStream'; import CameraStream from './CameraStream';
const CameraDashboard = ({ apiBaseUrl = 'http://vision:8000' }) => { const CameraDashboard = ({ apiBaseUrl = 'http://localhost:8000' }) => {
const [cameras, setCameras] = useState({}); const [cameras, setCameras] = useState({});
const [loading, setLoading] = useState(true); const [loading, setLoading] = useState(true);
const [error, setError] = useState(null); const [error, setError] = useState(null);
@@ -315,7 +315,7 @@ export default CameraDashboard;
```jsx ```jsx
import { useState, useEffect, useCallback } from 'react'; import { useState, useEffect, useCallback } from 'react';
const useCameraStream = (cameraName, apiBaseUrl = 'http://vision:8000') => { const useCameraStream = (cameraName, apiBaseUrl = 'http://localhost:8000') => {
const [isStreaming, setIsStreaming] = useState(false); const [isStreaming, setIsStreaming] = useState(false);
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const [error, setError] = useState(null); const [error, setError] = useState(null);
@@ -451,7 +451,7 @@ const CameraStreamTailwind = ({ cameraName }) => {
### Environment Variables (.env) ### Environment Variables (.env)
```env ```env
# Production configuration (using 'vision' hostname) # Production configuration (using 'vision' hostname)
REACT_APP_CAMERA_API_URL=http://vision:8000 REACT_APP_CAMERA_API_URL=http://localhost:8000
REACT_APP_STREAM_REFRESH_INTERVAL=30000 REACT_APP_STREAM_REFRESH_INTERVAL=30000
REACT_APP_STREAM_TIMEOUT=10000 REACT_APP_STREAM_TIMEOUT=10000
@@ -465,7 +465,7 @@ REACT_APP_STREAM_TIMEOUT=10000
### API Configuration ### API Configuration
```javascript ```javascript
const apiConfig = { const apiConfig = {
baseUrl: process.env.REACT_APP_CAMERA_API_URL || 'http://vision:8000', baseUrl: process.env.REACT_APP_CAMERA_API_URL || 'http://localhost:8000',
timeout: parseInt(process.env.REACT_APP_STREAM_TIMEOUT) || 10000, timeout: parseInt(process.env.REACT_APP_STREAM_TIMEOUT) || 10000,
refreshInterval: parseInt(process.env.REACT_APP_STREAM_REFRESH_INTERVAL) || 30000, refreshInterval: parseInt(process.env.REACT_APP_STREAM_REFRESH_INTERVAL) || 30000,
}; };

View File

@@ -3,18 +3,18 @@
# #
# CONFIGURATION: # CONFIGURATION:
# - Default Base URL: http://localhost:8000 (local development) # - Default Base URL: http://localhost:8000 (local development)
# - Production Base URL: http://vision:8000 (when using hostname 'vision') # - Production Base URL: http://localhost:8000 (when using hostname 'vision')
# - Custom hostname: Update @baseUrl variable below # - Custom hostname: Update @baseUrl variable below
# #
# HOSTNAME SETUP: # HOSTNAME SETUP:
# To use 'vision' hostname instead of 'localhost': # To use 'vision' hostname instead of 'localhost':
# 1. Add to /etc/hosts: 127.0.0.1 vision # 1. Add to /etc/hosts: 127.0.0.1 vision
# 2. Or configure DNS to point 'vision' to the server IP # 2. Or configure DNS to point 'vision' to the server IP
# 3. Update camera_preview.html: API_BASE = 'http://vision:8000' # 3. Update camera_preview.html: API_BASE = 'http://localhost:8000'
############################################################################### ###############################################################################
# Base URL Configuration - Change this to match your setup # Base URL Configuration - Change this to match your setup
@baseUrl = http://vision:8000 @baseUrl = http://localhost:8000
# Alternative configurations: # Alternative configurations:
# @baseUrl = http://localhost:8000 # Local development # @baseUrl = http://localhost:8000 # Local development
# @baseUrl = http://192.168.1.100:8000 # Specific IP address # @baseUrl = http://192.168.1.100:8000 # Specific IP address
@@ -30,8 +30,8 @@
# - Requires hostname resolution setup # - Requires hostname resolution setup
# - Add to /etc/hosts: 127.0.0.1 vision # - Add to /etc/hosts: 127.0.0.1 vision
# - Or configure DNS: vision -> server IP address # - Or configure DNS: vision -> server IP address
# - Update camera_preview.html: API_BASE = 'http://vision:8000' # - Update camera_preview.html: API_BASE = 'http://localhost:8000'
# - Set @baseUrl = http://vision:8000 # - Set @baseUrl = http://localhost:8000
# Option 2: Using localhost (development) # Option 2: Using localhost (development)
# - Works immediately on local machine # - Works immediately on local machine

View File

@@ -16,7 +16,7 @@ export interface ApiConfig {
} }
export const defaultApiConfig: ApiConfig = { export const defaultApiConfig: ApiConfig = {
baseUrl: 'http://vision:8000', // Production default, change to 'http://localhost:8000' for development baseUrl: 'http://localhost:8000', // Production default, change to 'http://localhost:8000' for development
timeout: 10000, timeout: 10000,
refreshInterval: 30000, refreshInterval: 30000,
}; };

View File

@@ -1,7 +1,7 @@
### USDA Vision Camera Streaming API ### USDA Vision Camera Streaming API
### ###
### CONFIGURATION: ### CONFIGURATION:
### - Production: http://vision:8000 (requires hostname setup) ### - Production: http://localhost:8000 (requires hostname setup)
### - Development: http://localhost:8000 ### - Development: http://localhost:8000
### - Custom: Update @baseUrl below to match your setup ### - Custom: Update @baseUrl below to match your setup
### ###
@@ -9,7 +9,7 @@
### Use with VS Code REST Client extension or similar tools. ### Use with VS Code REST Client extension or similar tools.
# Base URL - Update to match your configuration # Base URL - Update to match your configuration
@baseUrl = http://vision:8000 @baseUrl = http://localhost:8000
# Alternative: @baseUrl = http://localhost:8000 # Alternative: @baseUrl = http://localhost:8000
### ============================================================================= ### =============================================================================

View File

@@ -1,5 +1,6 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
@@ -18,7 +19,7 @@
background-color: white; background-color: white;
padding: 20px; padding: 20px;
border-radius: 8px; border-radius: 8px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1); box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
} }
h1 { h1 {
@@ -155,6 +156,7 @@
} }
</style> </style>
</head> </head>
<body> <body>
<div class="container"> <div class="container">
<h1>🎥 USDA Vision Camera Live Preview</h1> <h1>🎥 USDA Vision Camera Live Preview</h1>
@@ -178,7 +180,7 @@
</div> </div>
<script> <script>
const API_BASE = 'http://vision:8000'; const API_BASE = 'http://localhost:8000';
let cameras = {}; let cameras = {};
// Initialize the page // Initialize the page
@@ -333,4 +335,5 @@
document.addEventListener('DOMContentLoaded', init); document.addEventListener('DOMContentLoaded', init);
</script> </script>
</body> </body>
</html> </html>

View File

@@ -1,5 +1,9 @@
# This file was autogenerated by uv via the following command: # This file was autogenerated by uv via the following command:
# uv export --format requirements-txt # uv export --format requirements-txt
aiofiles==24.1.0 \
--hash=sha256:22a075c9e5a3810f0c2e48f3008c94d68c65d763b9b03857924c99e57355166c \
--hash=sha256:b4ec55f4195e3eb5d7abd1bf7e061763e864dd4954231fb8539a0ef8bb8260e5
# via usda-vision-cameras
annotated-types==0.7.0 \ annotated-types==0.7.0 \
--hash=sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53 \ --hash=sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53 \
--hash=sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89 --hash=sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89
@@ -7,11 +11,61 @@ annotated-types==0.7.0 \
anyio==4.9.0 \ anyio==4.9.0 \
--hash=sha256:673c0c244e15788651a4ff38710fea9675823028a6f08a5eda409e0c9840a028 \ --hash=sha256:673c0c244e15788651a4ff38710fea9675823028a6f08a5eda409e0c9840a028 \
--hash=sha256:9f76d541cad6e36af7beb62e978876f3b41e3e04f2c1fbf0884604c0a9c4d93c --hash=sha256:9f76d541cad6e36af7beb62e978876f3b41e3e04f2c1fbf0884604c0a9c4d93c
# via starlette # via
# httpx
# starlette
appnope==0.1.4 ; sys_platform == 'darwin' \
--hash=sha256:1de3860566df9caf38f01f86f65e0e13e379af54f9e4bee1e66b48f2efffd1ee \
--hash=sha256:502575ee11cd7a28c0205f379b525beefebab9d161b7c964670864014ed7213c
# via ipykernel
asttokens==3.0.0 \
--hash=sha256:0dcd8baa8d62b0c1d118b399b2ddba3c4aff271d0d7a9e0d4c1681c79035bbc7 \
--hash=sha256:e3078351a059199dd5138cb1c706e6430c05eff2ff136af5eb4790f9d28932e2
# via stack-data
certifi==2025.7.14 \ certifi==2025.7.14 \
--hash=sha256:6b31f564a415d79ee77df69d757bb49a5bb53bd9f756cbbe24394ffd6fc1f4b2 \ --hash=sha256:6b31f564a415d79ee77df69d757bb49a5bb53bd9f756cbbe24394ffd6fc1f4b2 \
--hash=sha256:8ea99dbdfaaf2ba2f9bac77b9249ef62ec5218e7c2b2e903378ed5fccf765995 --hash=sha256:8ea99dbdfaaf2ba2f9bac77b9249ef62ec5218e7c2b2e903378ed5fccf765995
# via requests # via
# httpcore
# httpx
# requests
cffi==1.17.1 ; implementation_name == 'pypy' \
--hash=sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2 \
--hash=sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36 \
--hash=sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824 \
--hash=sha256:30c5e0cb5ae493c04c8b42916e52ca38079f1b235c2f8ae5f4527b963c401caf \
--hash=sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3 \
--hash=sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed \
--hash=sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1 \
--hash=sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8 \
--hash=sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903 \
--hash=sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d \
--hash=sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683 \
--hash=sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9 \
--hash=sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c \
--hash=sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4 \
--hash=sha256:85a950a4ac9c359340d5963966e3e0a94a676bd6245a4b55bc43949eee26a655 \
--hash=sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65 \
--hash=sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41 \
--hash=sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6 \
--hash=sha256:a45e3c6913c5b87b3ff120dcdc03f6131fa0065027d0ed7ee6190736a74cd401 \
--hash=sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6 \
--hash=sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93 \
--hash=sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4 \
--hash=sha256:caaf0640ef5f5517f49bc275eca1406b0ffa6aa184892812030f04c2abf589a0 \
--hash=sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3 \
--hash=sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff \
--hash=sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5 \
--hash=sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd \
--hash=sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f \
--hash=sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5 \
--hash=sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d \
--hash=sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e \
--hash=sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a \
--hash=sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4 \
--hash=sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99 \
--hash=sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b
# via pyzmq
charset-normalizer==3.4.2 \ charset-normalizer==3.4.2 \
--hash=sha256:0c29de6a1a95f24b9a1aa7aefd27d2487263f00dfd55a77719b530788f75cff7 \ --hash=sha256:0c29de6a1a95f24b9a1aa7aefd27d2487263f00dfd55a77719b530788f75cff7 \
--hash=sha256:0c8c57f84ccfc871a48a47321cfa49ae1df56cd1d965a09abe84066f6853b9c0 \ --hash=sha256:0c8c57f84ccfc871a48a47321cfa49ae1df56cd1d965a09abe84066f6853b9c0 \
@@ -64,7 +118,12 @@ colorama==0.4.6 ; sys_platform == 'win32' \
--hash=sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6 --hash=sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6
# via # via
# click # click
# ipython
# tqdm # tqdm
comm==0.2.3 \
--hash=sha256:2dc8048c10962d55d7ad693be1e7045d891b7ce8d999c97963a5e3e99c055971 \
--hash=sha256:c615d91d75f7f04f095b30d1c1711babd43bdc6419c1be9886a85f2f4e489417
# via ipykernel
contourpy==1.3.2 \ contourpy==1.3.2 \
--hash=sha256:0475b1f6604896bc7c53bb070e355e9321e1bc0d381735421a2d2068ec56531f \ --hash=sha256:0475b1f6604896bc7c53bb070e355e9321e1bc0d381735421a2d2068ec56531f \
--hash=sha256:106fab697af11456fcba3e352ad50effe493a90f893fca6c2ca5c033820cea92 \ --hash=sha256:106fab697af11456fcba3e352ad50effe493a90f893fca6c2ca5c033820cea92 \
@@ -115,6 +174,30 @@ cycler==0.12.1 \
--hash=sha256:85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30 \ --hash=sha256:85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30 \
--hash=sha256:88bb128f02ba341da8ef447245a9e138fae777f6a23943da4540077d3601eb1c --hash=sha256:88bb128f02ba341da8ef447245a9e138fae777f6a23943da4540077d3601eb1c
# via matplotlib # via matplotlib
debugpy==1.8.15 \
--hash=sha256:047a493ca93c85ccede1dbbaf4e66816794bdc214213dde41a9a61e42d27f8fc \
--hash=sha256:3dcc7225cb317469721ab5136cda9ff9c8b6e6fb43e87c9e15d5b108b99d01ba \
--hash=sha256:58d7a20b7773ab5ee6bdfb2e6cf622fdf1e40c9d5aef2857d85391526719ac00 \
--hash=sha256:62954fb904bec463e2b5a415777f6d1926c97febb08ef1694da0e5d1463c5c3b \
--hash=sha256:73c943776cb83e36baf95e8f7f8da765896fd94b05991e7bc162456d25500683 \
--hash=sha256:94dc0f0d00e528d915e0ce1c78e771475b2335b376c49afcc7382ee0b146bab6 \
--hash=sha256:b08e9b0bc260cf324c890626961dad4ffd973f7568fbf57feb3c3a65ab6b6327 \
--hash=sha256:babc4fb1962dd6a37e94d611280e3d0d11a1f5e6c72ac9b3d87a08212c4b6dd3 \
--hash=sha256:bce2e6c5ff4f2e00b98d45e7e01a49c7b489ff6df5f12d881c67d2f1ac635f3d \
--hash=sha256:e2a4fe357c92334272eb2845fcfcdbec3ef9f22c16cf613c388ac0887aed15fa \
--hash=sha256:f5e01291ad7d6649aed5773256c5bba7a1a556196300232de1474c3c372592bf \
--hash=sha256:f778e68f2986a58479d0ac4f643e0b8c82fdd97c2e200d4d61e7c2d13838eb53 \
--hash=sha256:f9d1b5abd75cd965e2deabb1a06b0e93a1546f31f9f621d2705e78104377c702 \
--hash=sha256:fcf0748d4f6e25f89dc5e013d1129ca6f26ad4da405e0723a4f704583896a709
# via ipykernel
decorator==5.2.1 \
--hash=sha256:65f266143752f734b0a7cc83c46f4618af75b8c5911b00ccb61d0ac9b6da0360 \
--hash=sha256:d316bb415a2d9e2d2b3abcc4084c6502fc09240e292cd76a76afc106a1c8e04a
# via ipython
executing==2.2.0 \
--hash=sha256:11387150cad388d62750327a53d3339fad4888b39a6fe233c3afbb54ecffd3aa \
--hash=sha256:5d108c028108fe2551d1a7b2e8b713341e2cb4fc0aa7dcf966fa4327a5226755
# via stack-data
fastapi==0.116.1 \ fastapi==0.116.1 \
--hash=sha256:c46ac7c312df840f0c9e220f7964bada936781bc4e2e6eb71f1c4d7553786565 \ --hash=sha256:c46ac7c312df840f0c9e220f7964bada936781bc4e2e6eb71f1c4d7553786565 \
--hash=sha256:ed52cbf946abfd70c5a0dccb24673f0670deeb517a88b3544d03c2a6bf283143 --hash=sha256:ed52cbf946abfd70c5a0dccb24673f0670deeb517a88b3544d03c2a6bf283143
@@ -150,17 +233,54 @@ fonttools==4.59.0 \
h11==0.16.0 \ h11==0.16.0 \
--hash=sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1 \ --hash=sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1 \
--hash=sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86 --hash=sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86
# via uvicorn # via
# httpcore
# uvicorn
httpcore==1.0.9 \
--hash=sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55 \
--hash=sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8
# via httpx
httpx==0.28.1 \
--hash=sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc \
--hash=sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad
# via usda-vision-cameras
idna==3.10 \ idna==3.10 \
--hash=sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9 \ --hash=sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9 \
--hash=sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3 --hash=sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3
# via # via
# anyio # anyio
# httpx
# requests # requests
imageio==2.37.0 \ imageio==2.37.0 \
--hash=sha256:11efa15b87bc7871b61590326b2d635439acc321cf7f8ce996f812543ce10eed \ --hash=sha256:11efa15b87bc7871b61590326b2d635439acc321cf7f8ce996f812543ce10eed \
--hash=sha256:71b57b3669666272c818497aebba2b4c5f20d5b37c81720e5e1a56d59c492996 --hash=sha256:71b57b3669666272c818497aebba2b4c5f20d5b37c81720e5e1a56d59c492996
# via usda-vision-cameras # via usda-vision-cameras
ipykernel==6.30.0 \
--hash=sha256:b7b808ddb2d261aae2df3a26ff3ff810046e6de3dfbc6f7de8c98ea0a6cb632c \
--hash=sha256:fd2936e55c4a1c2ee8b1e5fa6a372b8eecc0ab1338750dee76f48fa5cca1301e
# via usda-vision-cameras
ipython==9.4.0 \
--hash=sha256:25850f025a446d9b359e8d296ba175a36aedd32e83ca9b5060430fe16801f066 \
--hash=sha256:c033c6d4e7914c3d9768aabe76bbe87ba1dc66a92a05db6bfa1125d81f2ee270
# via ipykernel
ipython-pygments-lexers==1.1.1 \
--hash=sha256:09c0138009e56b6854f9535736f4171d855c8c08a563a0dcd8022f78355c7e81 \
--hash=sha256:a9462224a505ade19a605f71f8fa63c2048833ce50abc86768a0d81d876dc81c
# via ipython
jedi==0.19.2 \
--hash=sha256:4770dc3de41bde3966b02eb84fbcf557fb33cce26ad23da12c742fb50ecb11f0 \
--hash=sha256:a8ef22bde8490f57fe5c7681a3c83cb58874daf72b4784de3cce5b6ef6edb5b9
# via ipython
jupyter-client==8.6.3 \
--hash=sha256:35b3a0947c4a6e9d589eb97d7d4cd5e90f910ee73101611f01283732bd6d9419 \
--hash=sha256:e8a19cc986cc45905ac3362915f410f3af85424b4c0905e94fa5f2cb08e8f23f
# via ipykernel
jupyter-core==5.8.1 \
--hash=sha256:0a5f9706f70e64786b75acba995988915ebd4601c8a52e534a40b51c95f59941 \
--hash=sha256:c28d268fc90fb53f1338ded2eb410704c5449a358406e8a948b75706e24863d0
# via
# ipykernel
# jupyter-client
kiwisolver==1.4.8 \ kiwisolver==1.4.8 \
--hash=sha256:01c3d31902c7db5fb6182832713d3b4122ad9317c2c5877d0539227d96bb2e50 \ --hash=sha256:01c3d31902c7db5fb6182832713d3b4122ad9317c2c5877d0539227d96bb2e50 \
--hash=sha256:085940635c62697391baafaaeabdf3dd7a6c3643577dde337f4d66eba021b2b8 \ --hash=sha256:085940635c62697391baafaaeabdf3dd7a6c3643577dde337f4d66eba021b2b8 \
@@ -249,6 +369,16 @@ matplotlib==3.10.3 \
--hash=sha256:f6929fc618cb6db9cb75086f73b3219bbb25920cb24cee2ea7a12b04971a4158 \ --hash=sha256:f6929fc618cb6db9cb75086f73b3219bbb25920cb24cee2ea7a12b04971a4158 \
--hash=sha256:fdfa07c0ec58035242bc8b2c8aae37037c9a886370eef6850703d7583e19964b --hash=sha256:fdfa07c0ec58035242bc8b2c8aae37037c9a886370eef6850703d7583e19964b
# via usda-vision-cameras # via usda-vision-cameras
matplotlib-inline==0.1.7 \
--hash=sha256:8423b23ec666be3d16e16b60bdd8ac4e86e840ebd1dd11a30b9f117f2fa0ab90 \
--hash=sha256:df192d39a4ff8f21b1895d72e6a13f5fcc5099f00fa84384e0ea28c2cc0653ca
# via
# ipykernel
# ipython
nest-asyncio==1.6.0 \
--hash=sha256:6f172d5449aca15afd6c646851f4e31e02c598d553a667e38cafa997cfec55fe \
--hash=sha256:87af6efd6b5e897c81050477ef65c62e2b2f35d51703cae01aff2905b1852e1c
# via ipykernel
numpy==2.3.2 \ numpy==2.3.2 \
--hash=sha256:07b62978075b67eee4065b166d000d457c82a1efe726cce608b9db9dd66a73a5 \ --hash=sha256:07b62978075b67eee4065b166d000d457c82a1efe726cce608b9db9dd66a73a5 \
--hash=sha256:087ffc25890d89a43536f75c5fe8770922008758e8eeeef61733957041ed2f9b \ --hash=sha256:087ffc25890d89a43536f75c5fe8770922008758e8eeeef61733957041ed2f9b \
@@ -342,11 +472,21 @@ opencv-python==4.11.0.86 \
packaging==25.0 \ packaging==25.0 \
--hash=sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484 \ --hash=sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484 \
--hash=sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f --hash=sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f
# via matplotlib # via
# ipykernel
# matplotlib
paho-mqtt==2.1.0 \ paho-mqtt==2.1.0 \
--hash=sha256:12d6e7511d4137555a3f6ea167ae846af2c7357b10bc6fa4f7c3968fc1723834 \ --hash=sha256:12d6e7511d4137555a3f6ea167ae846af2c7357b10bc6fa4f7c3968fc1723834 \
--hash=sha256:6db9ba9b34ed5bc6b6e3812718c7e06e2fd7444540df2455d2c51bd58808feee --hash=sha256:6db9ba9b34ed5bc6b6e3812718c7e06e2fd7444540df2455d2c51bd58808feee
# via usda-vision-cameras # via usda-vision-cameras
parso==0.8.4 \
--hash=sha256:a418670a20291dacd2dddc80c377c5c3791378ee1e8d12bffc35420643d43f18 \
--hash=sha256:eb3a7b58240fb99099a345571deecc0f9540ea5f4dd2fe14c2a99d6b281ab92d
# via jedi
pexpect==4.9.0 ; sys_platform != 'emscripten' and sys_platform != 'win32' \
--hash=sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523 \
--hash=sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f
# via ipython
pillow==11.3.0 \ pillow==11.3.0 \
--hash=sha256:023f6d2d11784a465f09fd09a34b150ea4672e85fb3d05931d89f373ab14abb2 \ --hash=sha256:023f6d2d11784a465f09fd09a34b150ea4672e85fb3d05931d89f373ab14abb2 \
--hash=sha256:02a723e6bf909e7cea0dac1b0e0310be9d7650cd66222a5f1c571455c0a45214 \ --hash=sha256:02a723e6bf909e7cea0dac1b0e0310be9d7650cd66222a5f1c571455c0a45214 \
@@ -429,6 +569,36 @@ pillow==11.3.0 \
# imageio # imageio
# matplotlib # matplotlib
# usda-vision-cameras # usda-vision-cameras
platformdirs==4.3.8 \
--hash=sha256:3d512d96e16bcb959a814c9f348431070822a6496326a4be0911c40b5a74c2bc \
--hash=sha256:ff7059bb7eb1179e2685604f4aaf157cfd9535242bd23742eadc3c13542139b4
# via jupyter-core
prompt-toolkit==3.0.51 \
--hash=sha256:52742911fde84e2d423e2f9a4cf1de7d7ac4e51958f648d9540e0fb8db077b07 \
--hash=sha256:931a162e3b27fc90c86f1b48bb1fb2c528c2761475e57c9c06de13311c7b54ed
# via ipython
psutil==7.0.0 \
--hash=sha256:101d71dc322e3cffd7cea0650b09b3d08b8e7c4109dd6809fe452dfd00e58b25 \
--hash=sha256:1fcee592b4c6f146991ca55919ea3d1f8926497a713ed7faaf8225e174581e91 \
--hash=sha256:39db632f6bb862eeccf56660871433e111b6ea58f2caea825571951d4b6aa3da \
--hash=sha256:4b1388a4f6875d7e2aff5c4ca1cc16c545ed41dd8bb596cefea80111db353a34 \
--hash=sha256:4cf3d4eb1aa9b348dec30105c55cd9b7d4629285735a102beb4441e38db90553 \
--hash=sha256:7be9c3eba38beccb6495ea33afd982a44074b78f28c434a1f51cc07fd315c456 \
--hash=sha256:a5f098451abc2828f7dc6b58d44b532b22f2088f4999a937557b603ce72b1993 \
--hash=sha256:ba3fcef7523064a6c9da440fc4d6bd07da93ac726b5733c29027d7dc95b39d99
# via ipykernel
ptyprocess==0.7.0 ; sys_platform != 'emscripten' and sys_platform != 'win32' \
--hash=sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35 \
--hash=sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220
# via pexpect
pure-eval==0.2.3 \
--hash=sha256:1db8e35b67b3d218d818ae653e27f06c3aa420901fa7b081ca98cbedc874e0d0 \
--hash=sha256:5f4e983f40564c576c7c8635ae88db5956bb2229d7e9237d03b3c0b0190eaf42
# via stack-data
pycparser==2.22 ; implementation_name == 'pypy' \
--hash=sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6 \
--hash=sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc
# via cffi
pydantic==2.11.7 \ pydantic==2.11.7 \
--hash=sha256:d989c3c6cb79469287b1569f7447a17848c998458d49ebe294e975b9baf0f0db \ --hash=sha256:d989c3c6cb79469287b1569f7447a17848c998458d49ebe294e975b9baf0f0db \
--hash=sha256:dde5df002701f6de26248661f6835bbe296a47bf73990135c7d07ce741b9623b --hash=sha256:dde5df002701f6de26248661f6835bbe296a47bf73990135c7d07ce741b9623b
@@ -490,6 +660,12 @@ pydantic-core==2.33.2 \
--hash=sha256:fa854f5cf7e33842a892e5c73f45327760bc7bc516339fda888c75ae60edaeb6 \ --hash=sha256:fa854f5cf7e33842a892e5c73f45327760bc7bc516339fda888c75ae60edaeb6 \
--hash=sha256:fe5b32187cbc0c862ee201ad66c30cf218e5ed468ec8dc1cf49dec66e160cc4d --hash=sha256:fe5b32187cbc0c862ee201ad66c30cf218e5ed468ec8dc1cf49dec66e160cc4d
# via pydantic # via pydantic
pygments==2.19.2 \
--hash=sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887 \
--hash=sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b
# via
# ipython
# ipython-pygments-lexers
pyparsing==3.2.3 \ pyparsing==3.2.3 \
--hash=sha256:a749938e02d6fd0b59b356ca504a24982314bb090c383e3cf201c95ef7e2bfcf \ --hash=sha256:a749938e02d6fd0b59b356ca504a24982314bb090c383e3cf201c95ef7e2bfcf \
--hash=sha256:b9c13f1ab8b3b542f72e28f634bad4de758ab3ce4546e4301970ad6fa77c38be --hash=sha256:b9c13f1ab8b3b542f72e28f634bad4de758ab3ce4546e4301970ad6fa77c38be
@@ -497,11 +673,66 @@ pyparsing==3.2.3 \
python-dateutil==2.9.0.post0 \ python-dateutil==2.9.0.post0 \
--hash=sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3 \ --hash=sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3 \
--hash=sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427 --hash=sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427
# via matplotlib # via
# jupyter-client
# matplotlib
pytz==2025.2 \ pytz==2025.2 \
--hash=sha256:360b9e3dbb49a209c21ad61809c7fb453643e048b38924c765813546746e81c3 \ --hash=sha256:360b9e3dbb49a209c21ad61809c7fb453643e048b38924c765813546746e81c3 \
--hash=sha256:5ddf76296dd8c44c26eb8f4b6f35488f3ccbf6fbbd7adee0b7262d43f0ec2f00 --hash=sha256:5ddf76296dd8c44c26eb8f4b6f35488f3ccbf6fbbd7adee0b7262d43f0ec2f00
# via usda-vision-cameras # via usda-vision-cameras
pywin32==311 ; platform_python_implementation != 'PyPy' and sys_platform == 'win32' \
--hash=sha256:184eb5e436dea364dcd3d2316d577d625c0351bf237c4e9a5fabbcfa5a58b151 \
--hash=sha256:3aca44c046bd2ed8c90de9cb8427f581c479e594e99b5c0bb19b29c10fd6cb87 \
--hash=sha256:3ce80b34b22b17ccbd937a6e78e7225d80c52f5ab9940fe0506a1a16f3dab503 \
--hash=sha256:718a38f7e5b058e76aee1c56ddd06908116d35147e133427e59a3983f703a20d \
--hash=sha256:750ec6e621af2b948540032557b10a2d43b0cee2ae9758c54154d711cc852d31 \
--hash=sha256:7b4075d959648406202d92a2310cb990fea19b535c7f4a78d3f5e10b926eeb8a \
--hash=sha256:a508e2d9025764a8270f93111a970e1d0fbfc33f4153b388bb649b7eec4f9b42 \
--hash=sha256:a733f1388e1a842abb67ffa8e7aad0e70ac519e09b0f6a784e65a136ec7cefd2 \
--hash=sha256:b7a2c10b93f8986666d0c803ee19b5990885872a7de910fc460f9b0c2fbf92ee \
--hash=sha256:b8c095edad5c211ff31c05223658e71bf7116daa0ecf3ad85f3201ea3190d067 \
--hash=sha256:e286f46a9a39c4a18b319c28f59b61de793654af2f395c102b4f819e584b5852 \
--hash=sha256:f95ba5a847cba10dd8c4d8fefa9f2a6cf283b8b88ed6178fa8a6c1ab16054d0d
# via jupyter-core
pyzmq==27.0.0 \
--hash=sha256:0546a720c1f407b2172cb04b6b094a78773491497e3644863cf5c96c42df8cff \
--hash=sha256:111db5f395e09f7e775f759d598f43cb815fc58e0147623c4816486e1a39dc22 \
--hash=sha256:14fe7aaac86e4e93ea779a821967360c781d7ac5115b3f1a171ced77065a0174 \
--hash=sha256:15f39d50bd6c9091c67315ceb878a4f531957b121d2a05ebd077eb35ddc5efed \
--hash=sha256:1958947983fef513e6e98eff9cb487b60bf14f588dc0e6bf35fa13751d2c8251 \
--hash=sha256:20d5cb29e8c5f76a127c75b6e7a77e846bc4b655c373baa098c26a61b7ecd0ef \
--hash=sha256:21457825249b2a53834fa969c69713f8b5a79583689387a5e7aed880963ac564 \
--hash=sha256:2c386339d7e3f064213aede5d03d054b237937fbca6dd2197ac8cf3b25a6b14e \
--hash=sha256:53a48f0228eab6cbf69fde3aa3c03cbe04e50e623ef92ae395fce47ef8a76152 \
--hash=sha256:56e46bbb85d52c1072b3f809cc1ce77251d560bc036d3a312b96db1afe76db2e \
--hash=sha256:5cd11d46d7b7e5958121b3eaf4cd8638eff3a720ec527692132f05a57f14341d \
--hash=sha256:60e8cc82d968174650c1860d7b716366caab9973787a1c060cf8043130f7d0f7 \
--hash=sha256:67855c14173aec36395d7777aaba3cc527b393821f30143fd20b98e1ff31fd38 \
--hash=sha256:67bfbcbd0a04c575e8103a6061d03e393d9f80ffdb9beb3189261e9e9bc5d5e9 \
--hash=sha256:6ad0562d4e6abb785be3e4dd68599c41be821b521da38c402bc9ab2a8e7ebc7e \
--hash=sha256:7011ade88c8e535cf140f8d1a59428676fbbce7c6e54fefce58bf117aefb6667 \
--hash=sha256:8617c7d43cd8ccdb62aebe984bfed77ca8f036e6c3e46dd3dddda64b10f0ab7a \
--hash=sha256:88b4e43cab04c3c0f0d55df3b1eef62df2b629a1a369b5289a58f6fa8b07c4f4 \
--hash=sha256:9df43a2459cd3a3563404c1456b2c4c69564daa7dbaf15724c09821a3329ce46 \
--hash=sha256:a20528da85c7ac7a19b7384e8c3f8fa707841fd85afc4ed56eda59d93e3d98ad \
--hash=sha256:b1f08eeb9ce1510e6939b6e5dcd46a17765e2333daae78ecf4606808442e52cf \
--hash=sha256:b801c2e40c5aa6072c2f4876de8dccd100af6d9918d4d0d7aa54a1d982fd4f44 \
--hash=sha256:c0dc628b5493f9a8cd9844b8bee9732ef587ab00002157c9329e4fc0ef4d3afa \
--hash=sha256:c0ed2c1f335ba55b5fdc964622254917d6b782311c50e138863eda409fbb3b6d \
--hash=sha256:c36ad534c0c29b4afa088dc53543c525b23c0797e01b69fef59b1a9c0e38b688 \
--hash=sha256:c5817641eebb391a2268c27fecd4162448e03538387093cdbd8bf3510c316b38 \
--hash=sha256:c8878011653dcdc27cc2c57e04ff96f0471e797f5c19ac3d7813a245bcb24371 \
--hash=sha256:cb0ac5179cba4b2f94f1aa208fbb77b62c4c9bf24dd446278b8b602cf85fcda3 \
--hash=sha256:cbabc59dcfaac66655c040dfcb8118f133fb5dde185e5fc152628354c1598e52 \
--hash=sha256:cd1dc59763effd1576f8368047c9c31468fce0af89d76b5067641137506792ae \
--hash=sha256:d8229f2efece6a660ee211d74d91dbc2a76b95544d46c74c615e491900dc107f \
--hash=sha256:dc1091f59143b471d19eb64f54bae4f54bcf2a466ffb66fe45d94d8d734eb495 \
--hash=sha256:dce4199bf5f648a902ce37e7b3afa286f305cd2ef7a8b6ec907470ccb6c8b371 \
--hash=sha256:e918d70862d4cfd4b1c187310015646a14e1f5917922ab45b29f28f345eeb6be \
--hash=sha256:f7bbe9e1ed2c8d3da736a15694d87c12493e54cc9dc9790796f0321794bbc91f
# via
# ipykernel
# jupyter-client
requests==2.32.4 \ requests==2.32.4 \
--hash=sha256:27babd3cda2a6d50b30443204ee89830707d396671944c998b5975b031ac2b2c \ --hash=sha256:27babd3cda2a6d50b30443204ee89830707d396671944c998b5975b031ac2b2c \
--hash=sha256:27d0316682c8a29834d3264820024b62a36942083d52caf2f14c0591336d3422 --hash=sha256:27d0316682c8a29834d3264820024b62a36942083d52caf2f14c0591336d3422
@@ -514,20 +745,50 @@ sniffio==1.3.1 \
--hash=sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2 \ --hash=sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2 \
--hash=sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc --hash=sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc
# via anyio # via anyio
stack-data==0.6.3 \
--hash=sha256:836a778de4fec4dcd1dcd89ed8abff8a221f58308462e1c4aa2a3cf30148f0b9 \
--hash=sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695
# via ipython
starlette==0.47.2 \ starlette==0.47.2 \
--hash=sha256:6ae9aa5db235e4846decc1e7b79c4f346adf41e9777aebeb49dfd09bbd7023d8 \ --hash=sha256:6ae9aa5db235e4846decc1e7b79c4f346adf41e9777aebeb49dfd09bbd7023d8 \
--hash=sha256:c5847e96134e5c5371ee9fac6fdf1a67336d5815e09eb2a01fdb57a351ef915b --hash=sha256:c5847e96134e5c5371ee9fac6fdf1a67336d5815e09eb2a01fdb57a351ef915b
# via fastapi # via fastapi
tornado==6.5.1 \
--hash=sha256:02420a0eb7bf617257b9935e2b754d1b63897525d8a289c9d65690d580b4dcf7 \
--hash=sha256:13ce6e3396c24e2808774741331638ee6c2f50b114b97a55c5b442df65fd9692 \
--hash=sha256:253b76040ee3bab8bcf7ba9feb136436a3787208717a1fb9f2c16b744fba7331 \
--hash=sha256:308473f4cc5a76227157cdf904de33ac268af770b2c5f05ca6c1161d82fdd95e \
--hash=sha256:5cae6145f4cdf5ab24744526cc0f55a17d76f02c98f4cff9daa08ae9a217448a \
--hash=sha256:84ceece391e8eb9b2b95578db65e920d2a61070260594819589609ba9bc6308c \
--hash=sha256:908e7d64567cecd4c2b458075589a775063453aeb1d2a1853eedb806922f568b \
--hash=sha256:9e9ca370f717997cb85606d074b0e5b247282cf5e2e1611568b8821afe0342d6 \
--hash=sha256:b77e9dfa7ed69754a54c89d82ef746398be82f749df69c4d3abe75c4d1ff4888 \
--hash=sha256:caec6314ce8a81cf69bd89909f4b633b9f523834dc1a352021775d45e51d9401 \
--hash=sha256:d50065ba7fd11d3bd41bcad0825227cc9a95154bad83239357094c36708001f7 \
--hash=sha256:e0a36e1bc684dca10b1aa75a31df8bdfed656831489bc1e6a6ebed05dc1ec365
# via
# ipykernel
# jupyter-client
tqdm==4.67.1 \ tqdm==4.67.1 \
--hash=sha256:26445eca388f82e72884e0d580d5464cd801a3ea01e63e5601bdff9ba6a48de2 \ --hash=sha256:26445eca388f82e72884e0d580d5464cd801a3ea01e63e5601bdff9ba6a48de2 \
--hash=sha256:f8aef9c52c08c13a65f30ea34f4e5aac3fd1a34959879d7e59e63027286627f2 --hash=sha256:f8aef9c52c08c13a65f30ea34f4e5aac3fd1a34959879d7e59e63027286627f2
# via usda-vision-cameras # via usda-vision-cameras
traitlets==5.14.3 \
--hash=sha256:9ed0579d3502c94b4b3732ac120375cda96f923114522847de4b3bb98b96b6b7 \
--hash=sha256:b74e89e397b1ed28cc831db7aea759ba6640cb3de13090ca145426688ff1ac4f
# via
# ipykernel
# ipython
# jupyter-client
# jupyter-core
# matplotlib-inline
typing-extensions==4.14.1 \ typing-extensions==4.14.1 \
--hash=sha256:38b39f4aeeab64884ce9f74c94263ef78f3c22467c8724005483154c26648d36 \ --hash=sha256:38b39f4aeeab64884ce9f74c94263ef78f3c22467c8724005483154c26648d36 \
--hash=sha256:d1e1e3b58374dc93031d6eda2420a48ea44a36c2b4766a4fdeb3710755731d76 --hash=sha256:d1e1e3b58374dc93031d6eda2420a48ea44a36c2b4766a4fdeb3710755731d76
# via # via
# anyio # anyio
# fastapi # fastapi
# ipython
# pydantic # pydantic
# pydantic-core # pydantic-core
# starlette # starlette
@@ -544,6 +805,10 @@ uvicorn==0.35.0 \
--hash=sha256:197535216b25ff9b785e29a0b79199f55222193d47f820816e7da751e9bc8d4a \ --hash=sha256:197535216b25ff9b785e29a0b79199f55222193d47f820816e7da751e9bc8d4a \
--hash=sha256:bc662f087f7cf2ce11a1d7fd70b90c9f98ef2e2831556dd078d131b96cc94a01 --hash=sha256:bc662f087f7cf2ce11a1d7fd70b90c9f98ef2e2831556dd078d131b96cc94a01
# via usda-vision-cameras # via usda-vision-cameras
wcwidth==0.2.13 \
--hash=sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859 \
--hash=sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5
# via prompt-toolkit
websockets==15.0.1 \ websockets==15.0.1 \
--hash=sha256:0701bc3cfcb9164d04a14b149fd74be7347a530ad3bbf15ab2c678a2cd3dd9a2 \ --hash=sha256:0701bc3cfcb9164d04a14b149fd74be7347a530ad3bbf15ab2c678a2cd3dd9a2 \
--hash=sha256:0af68c55afbd5f07986df82831c7bff04846928ea8d1fd7f30052638788bc9b5 \ --hash=sha256:0af68c55afbd5f07986df82831c7bff04846928ea8d1fd7f30052638788bc9b5 \

View File

@@ -12,9 +12,15 @@ import logging
from typing import Dict, List, Optional, Tuple, Any from typing import Dict, List, Optional, Tuple, Any
from datetime import datetime from datetime import datetime
# Add camera SDK to path # Add camera SDK to path and import conditionally
sys.path.append(os.path.join(os.path.dirname(__file__), "..", "..", "camera_sdk")) sys.path.append(os.path.join(os.path.dirname(__file__), "..", "..", "camera_sdk"))
import mvsdk try:
import mvsdk
CAMERA_SDK_AVAILABLE = True
except (ImportError, OSError) as e:
# Camera SDK not available - system will run in mock mode
mvsdk = None
CAMERA_SDK_AVAILABLE = False
from ..core.config import Config, CameraConfig from ..core.config import Config, CameraConfig
from ..core.state_manager import StateManager, CameraStatus from ..core.state_manager import StateManager, CameraStatus
@@ -35,8 +41,11 @@ class CameraManager:
self.event_system = event_system self.event_system = event_system
self.logger = logging.getLogger(__name__) self.logger = logging.getLogger(__name__)
# Initialize SDK early to suppress error messages # Initialize SDK early to suppress error messages (if available)
if CAMERA_SDK_AVAILABLE:
initialize_sdk_with_suppression() initialize_sdk_with_suppression()
else:
self.logger.warning("Camera SDK not available - running in mock mode")
# Camera management # Camera management
self.available_cameras: List[Any] = [] # mvsdk camera device info self.available_cameras: List[Any] = [] # mvsdk camera device info
@@ -111,6 +120,11 @@ class CameraManager:
try: try:
self.logger.info("Discovering GigE cameras...") self.logger.info("Discovering GigE cameras...")
if not CAMERA_SDK_AVAILABLE:
self.logger.warning("Camera SDK not available - no cameras will be discovered")
self.available_cameras = []
return
# Enumerate cameras using mvsdk # Enumerate cameras using mvsdk
device_list = mvsdk.CameraEnumerateDevice() device_list = mvsdk.CameraEnumerateDevice()
self.available_cameras = device_list self.available_cameras = device_list

View File

@@ -1,10 +1,10 @@
# Environment Configuration for Pecan Experiments Application # Environment Configuration for Pecan Experiments Application
# USDA Vision Camera System API Configuration # USDA Vision Camera System API Configuration
# Default: http://vision:8000 (current working setup) # Default: http://localhost:8000 (current working setup)
# For localhost setup, use: http://localhost:8000 # For localhost setup, use: http://localhost:8000
# For remote systems, use: http://192.168.1.100:8000 (replace with actual IP) # For remote systems, use: http://192.168.1.100:8000 (replace with actual IP)
VITE_VISION_API_URL=http://vision:8000 VITE_VISION_API_URL=http://localhost:8000
# Supabase Configuration (if needed for production) # Supabase Configuration (if needed for production)
# VITE_SUPABASE_URL=your_supabase_url # VITE_SUPABASE_URL=your_supabase_url

View File

@@ -40,7 +40,7 @@ The Vision System dashboard provides real-time monitoring and control of the USD
## API Integration ## API Integration
The dashboard connects to the Vision System API running on `http://vision:8000` and provides: The dashboard connects to the Vision System API running on `http://localhost:8000` and provides:
### Endpoints Used ### Endpoints Used
- `GET /system/status` - System overview and status - `GET /system/status` - System overview and status
@@ -103,7 +103,7 @@ The dashboard includes comprehensive error handling:
### Common Issues ### Common Issues
1. **"Failed to fetch vision system data"** 1. **"Failed to fetch vision system data"**
- Ensure the vision system API is running on vision:8000 - Ensure the vision system API is running on localhost:8000
- Check network connectivity - Check network connectivity
- Verify the vision system service is started - Verify the vision system service is started
@@ -121,7 +121,7 @@ The dashboard includes comprehensive error handling:
The API base URL is configured in `src/lib/visionApi.ts`: The API base URL is configured in `src/lib/visionApi.ts`:
```typescript ```typescript
const VISION_API_BASE_URL = 'http://vision:8000' const VISION_API_BASE_URL = 'http://localhost:8000'
``` ```
To change the API endpoint, modify this constant and rebuild the application. To change the API endpoint, modify this constant and rebuild the application.

View File

@@ -1,6 +1,6 @@
############################################################################### ###############################################################################
# USDA Vision Camera System - Complete API Endpoints Documentation # USDA Vision Camera System - Complete API Endpoints Documentation
# Base URL: http://vision:8000 # Base URL: http://localhost:8000
############################################################################### ###############################################################################
############################################################################### ###############################################################################
@@ -8,7 +8,7 @@
############################################################################### ###############################################################################
### Root endpoint - API information ### Root endpoint - API information
GET http://vision:8000/ GET http://localhost:8000/
# Response: SuccessResponse # Response: SuccessResponse
# { # {
# "success": true, # "success": true,
@@ -20,7 +20,7 @@ GET http://vision:8000/
### ###
### Health check ### Health check
GET http://vision:8000/health GET http://localhost:8000/health
# Response: Simple health status # Response: Simple health status
# { # {
# "status": "healthy", # "status": "healthy",
@@ -30,7 +30,7 @@ GET http://vision:8000/health
### ###
### Get system status ### Get system status
GET http://vision:8000/system/status GET http://localhost:8000/system/status
# Response: SystemStatusResponse # Response: SystemStatusResponse
# { # {
# "system_started": true, # "system_started": true,
@@ -60,7 +60,7 @@ GET http://vision:8000/system/status
############################################################################### ###############################################################################
### Get all machines status ### Get all machines status
GET http://vision:8000/machines GET http://localhost:8000/machines
# Response: Dict[str, MachineStatusResponse] # Response: Dict[str, MachineStatusResponse]
# { # {
# "vibratory_conveyor": { # "vibratory_conveyor": {
@@ -84,7 +84,7 @@ GET http://vision:8000/machines
############################################################################### ###############################################################################
### Get MQTT status and statistics ### Get MQTT status and statistics
GET http://vision:8000/mqtt/status GET http://localhost:8000/mqtt/status
# Response: MQTTStatusResponse # Response: MQTTStatusResponse
# { # {
# "connected": true, # "connected": true,
@@ -101,7 +101,7 @@ GET http://vision:8000/mqtt/status
# } # }
### Get recent MQTT events history ### Get recent MQTT events history
GET http://vision:8000/mqtt/events GET http://localhost:8000/mqtt/events
# Optional query parameter: limit (default: 5, max: 50) # Optional query parameter: limit (default: 5, max: 50)
# Response: MQTTEventsHistoryResponse # Response: MQTTEventsHistoryResponse
# { # {
@@ -128,14 +128,14 @@ GET http://vision:8000/mqtt/events
# } # }
### Get recent MQTT events with custom limit ### Get recent MQTT events with custom limit
GET http://vision:8000/mqtt/events?limit=10 GET http://localhost:8000/mqtt/events?limit=10
############################################################################### ###############################################################################
# CAMERA ENDPOINTS # CAMERA ENDPOINTS
############################################################################### ###############################################################################
### Get all cameras status ### Get all cameras status
GET http://vision:8000/cameras GET http://localhost:8000/cameras
# Response: Dict[str, CameraStatusResponse] # Response: Dict[str, CameraStatusResponse]
# { # {
# "camera1": { # "camera1": {
@@ -157,9 +157,9 @@ GET http://vision:8000/cameras
### ###
### Get specific camera status ### Get specific camera status
GET http://vision:8000/cameras/camera1/status GET http://localhost:8000/cameras/camera1/status
### Get specific camera status ### Get specific camera status
GET http://vision:8000/cameras/camera2/status GET http://localhost:8000/cameras/camera2/status
# Response: CameraStatusResponse (same as above for single camera) # Response: CameraStatusResponse (same as above for single camera)
############################################################################### ###############################################################################
@@ -167,7 +167,7 @@ GET http://vision:8000/cameras/camera2/status
############################################################################### ###############################################################################
### Start recording (with all optional parameters) ### Start recording (with all optional parameters)
POST http://vision:8000/cameras/camera1/start-recording POST http://localhost:8000/cameras/camera1/start-recording
Content-Type: application/json Content-Type: application/json
{ {
@@ -193,7 +193,7 @@ Content-Type: application/json
### ###
### Start recording (minimal - only filename) ### Start recording (minimal - only filename)
POST http://vision:8000/cameras/camera1/start-recording POST http://localhost:8000/cameras/camera1/start-recording
Content-Type: application/json Content-Type: application/json
{ {
@@ -203,7 +203,7 @@ Content-Type: application/json
### ###
### Start recording (only camera settings) ### Start recording (only camera settings)
POST http://vision:8000/cameras/camera1/start-recording POST http://localhost:8000/cameras/camera1/start-recording
Content-Type: application/json Content-Type: application/json
{ {
@@ -215,7 +215,7 @@ Content-Type: application/json
### ###
### Start recording (empty body - all defaults) ### Start recording (empty body - all defaults)
POST http://vision:8000/cameras/camera1/start-recording POST http://localhost:8000/cameras/camera1/start-recording
Content-Type: application/json Content-Type: application/json
{} {}
@@ -223,9 +223,9 @@ Content-Type: application/json
### ###
### Stop recording ### Stop recording
POST http://vision:8000/cameras/camera1/stop-recording POST http://localhost:8000/cameras/camera1/stop-recording
### Stop recording ### Stop recording
POST http://vision:8000/cameras/camera2/stop-recording POST http://localhost:8000/cameras/camera2/stop-recording
# No request body required # No request body required
# Response: StopRecordingResponse # Response: StopRecordingResponse
# { # {
@@ -239,8 +239,8 @@ POST http://vision:8000/cameras/camera2/stop-recording
############################################################################### ###############################################################################
### Test camera connection ### Test camera connection
POST http://vision:8000/cameras/camera1/test-connection POST http://localhost:8000/cameras/camera1/test-connection
POST http://vision:8000/cameras/camera2/test-connection POST http://localhost:8000/cameras/camera2/test-connection
# No request body required # No request body required
# Response: CameraTestResponse # Response: CameraTestResponse
# { # {
@@ -253,8 +253,8 @@ POST http://vision:8000/cameras/camera2/test-connection
### ###
### Reconnect camera (soft recovery) ### Reconnect camera (soft recovery)
POST http://vision:8000/cameras/camera1/reconnect POST http://localhost:8000/cameras/camera1/reconnect
POST http://vision:8000/cameras/camera2/reconnect POST http://localhost:8000/cameras/camera2/reconnect
# No request body required # No request body required
# Response: CameraRecoveryResponse # Response: CameraRecoveryResponse
# { # {
@@ -268,33 +268,33 @@ POST http://vision:8000/cameras/camera2/reconnect
### ###
### Restart camera grab process ### Restart camera grab process
POST http://vision:8000/cameras/camera1/restart-grab POST http://localhost:8000/cameras/camera1/restart-grab
POST http://vision:8000/cameras/camera2/restart-grab POST http://localhost:8000/cameras/camera2/restart-grab
# Response: CameraRecoveryResponse (same structure as reconnect) # Response: CameraRecoveryResponse (same structure as reconnect)
### ###
### Reset camera timestamp ### Reset camera timestamp
POST http://vision:8000/cameras/camera1/reset-timestamp POST http://localhost:8000/cameras/camera1/reset-timestamp
POST http://vision:8000/cameras/camera2/reset-timestamp POST http://localhost:8000/cameras/camera2/reset-timestamp
# Response: CameraRecoveryResponse (same structure as reconnect) # Response: CameraRecoveryResponse (same structure as reconnect)
### ###
### Full camera reset (hard recovery) ### Full camera reset (hard recovery)
POST http://vision:8000/cameras/camera1/full-reset POST http://localhost:8000/cameras/camera1/full-reset
### Full camera reset (hard recovery) ### Full camera reset (hard recovery)
POST http://vision:8000/cameras/camera2/full-reset POST http://localhost:8000/cameras/camera2/full-reset
# Response: CameraRecoveryResponse (same structure as reconnect) # Response: CameraRecoveryResponse (same structure as reconnect)
### ###
### Reinitialize failed camera ### Reinitialize failed camera
POST http://vision:8000/cameras/camera1/reinitialize POST http://localhost:8000/cameras/camera1/reinitialize
### Reinitialize failed camera ### Reinitialize failed camera
POST http://vision:8000/cameras/camera2/reinitialize POST http://localhost:8000/cameras/camera2/reinitialize
# Response: CameraRecoveryResponse (same structure as reconnect) # Response: CameraRecoveryResponse (same structure as reconnect)
############################################################################### ###############################################################################
@@ -302,7 +302,7 @@ POST http://vision:8000/cameras/camera2/reinitialize
############################################################################### ###############################################################################
### Get all recording sessions ### Get all recording sessions
GET http://vision:8000/recordings GET http://localhost:8000/recordings
# Response: Dict[str, RecordingInfoResponse] # Response: Dict[str, RecordingInfoResponse]
# { # {
# "rec_001": { # "rec_001": {
@@ -323,7 +323,7 @@ GET http://vision:8000/recordings
############################################################################### ###############################################################################
### Get storage statistics ### Get storage statistics
GET http://vision:8000/storage/stats GET http://localhost:8000/storage/stats
# Response: StorageStatsResponse # Response: StorageStatsResponse
# { # {
# "base_path": "/storage", # "base_path": "/storage",
@@ -345,7 +345,7 @@ GET http://vision:8000/storage/stats
### ###
### Get recording files list (with filters) ### Get recording files list (with filters)
POST http://vision:8000/storage/files POST http://localhost:8000/storage/files
Content-Type: application/json Content-Type: application/json
{ {
@@ -377,7 +377,7 @@ Content-Type: application/json
### ###
### Get all files (no camera filter) ### Get all files (no camera filter)
POST http://vision:8000/storage/files POST http://localhost:8000/storage/files
Content-Type: application/json Content-Type: application/json
{ {
@@ -387,7 +387,7 @@ Content-Type: application/json
### ###
### Cleanup old storage files ### Cleanup old storage files
POST http://vision:8000/storage/cleanup POST http://localhost:8000/storage/cleanup
Content-Type: application/json Content-Type: application/json
{ {

View File

@@ -46,10 +46,10 @@ Create a `.env` file with the following configuration:
```bash ```bash
# USDA Vision Camera System API Configuration # USDA Vision Camera System API Configuration
# Default: http://vision:8000 (Docker container) # Default: http://localhost:8000 (Docker container)
# For local development without Docker: http://localhost:8000 # For local development without Docker: http://localhost:8000
# For remote systems: http://192.168.1.100:8000 # For remote systems: http://192.168.1.100:8000
VITE_VISION_API_URL=http://vision:8000 VITE_VISION_API_URL=http://localhost:8000
``` ```
### API Endpoints Used ### API Endpoints Used

View File

@@ -16,8 +16,8 @@ import {
import { performanceMonitor } from '../utils/performanceMonitor'; import { performanceMonitor } from '../utils/performanceMonitor';
// Configuration - Use environment variable or default to vision container // Configuration - Use environment variable or default to vision container
// The API is accessible at vision:8000 in the current setup // The API is accessible at localhost:8000 in the current setup
const API_BASE_URL = import.meta.env.VITE_VISION_API_URL || 'http://vision:8000'; const API_BASE_URL = import.meta.env.VITE_VISION_API_URL || 'http://localhost:8000';
/** /**
* Custom error class for video API errors * Custom error class for video API errors

View File

@@ -1,7 +1,7 @@
// Vision System API Client // Vision System API Client
// Base URL for the vision system API - Use environment variable or default to vision container // Base URL for the vision system API - Use environment variable or default to vision container
// The API is accessible at vision:8000 in the current setup // The API is accessible at localhost:8000 in the current setup
const VISION_API_BASE_URL = import.meta.env.VITE_VISION_API_URL || 'http://vision:8000' const VISION_API_BASE_URL = import.meta.env.VITE_VISION_API_URL || 'http://localhost:8000'
// Types based on the API documentation // Types based on the API documentation
export interface SystemStatus { export interface SystemStatus {

View File

@@ -3,7 +3,7 @@
class TestVisionApiClient { class TestVisionApiClient {
constructor() { constructor() {
this.baseUrl = 'http://vision:8000' this.baseUrl = 'http://localhost:8000'
} }
async request(endpoint) { async request(endpoint) {

View File

@@ -81,7 +81,7 @@
<script src="test-api-fix.js"></script> <script src="test-api-fix.js"></script>
<script> <script>
const API_BASE = 'http://vision:8000'; // Change to your vision API URL if different const API_BASE = 'http://localhost:8000'; // Change to your vision API URL if different
async function testCameraList() { async function testCameraList() {
const resultsDiv = document.getElementById('test-results'); const resultsDiv = document.getElementById('test-results');

View File

@@ -106,7 +106,7 @@
</div> </div>
<script> <script>
const API_BASE = 'http://vision:8000'; const API_BASE = 'http://localhost:8000';
let cameras = {}; let cameras = {};
// Load cameras on page load // Load cameras on page load