ON DIH CHEESE ts is just so food

This commit is contained in:
lda committed 2026-01-11 02:18:09 +07:00
1 parent 013c082447
commit 02e00cbaa2
15 files changed
+1228 -86

No files matched your search

+63 -14
View File
@@ -23,26 +23,46 @@ The pipeline operates in a "Fail-Fast" cascade to optimize performance:
- Runs a dedicated Binary Classifier to verify "Smoking" vs "Not Smoking".
- _Output_: Only high-confidence events are flagged as alerts.
### Key Features
- **GPU Acceleration**: Auto-detects CUDA and runs inference on GPU when available.
- **Async Inference**: Detection runs in a background thread; video output never lags.
- **Adaptive Sampling**:
- **Idle Mode (2 FPS)**: When no people are detected, saves compute.
- **Active Mode (Max FPS)**: Switches to full speed when activity is detected.
- **Cooldown**: Stays active for 2 seconds after people leave frame.
- **Non-Maximum Suppression (NMS)**: Cleans up overlapping boxes per-class.
- **Smart Event Recording**: Captures 2s before + 3s after each smoking event as separate clips.
## 🚀 Usage
### Prerequisites
- Python 3.12+
- Dependencies: `ultralytics`, `opencv-python`, `numpy`
- Python 3.13+
- [uv](https://docs.astral.sh/uv/) package manager (recommended)
- CUDA 13.0+ (optional, for GPU acceleration)
### Installation
```bash
# Clone and enter directory
cd gp
# Install dependencies with uv
uv sync
```
### Running the Pipeline
Run the entry point `main.py` with your video source:
```bash
# Run on a local video file
python main.py --source videos/test_footage.mp4
uv run main.py --source videos/test_footage.mp4
# Run on an RTSP stream
python main.py --source rtsp://admin:[email protected]:554/stream --rtsp
uv run main.py --source rtsp://admin:[email protected]:554/stream --rtsp
# Enable debug logging (see frame-by-frame details)
python main.py --source videos/test.mp4 --debug
uv run main.py --source videos/test.mp4 --debug
```
### CLI Arguments
@@ -59,7 +79,7 @@ python main.py --source videos/test.mp4 --debug
## 📊 Outputs
The system generates three types of artifacts during execution:
The system generates four types of artifacts during execution:
1. **Visual Debug (`output.mp4`)**:
@@ -78,17 +98,46 @@ The system generates three types of artifacts during execution:
- A structured log file containing **only** confirmed smoking events.
- Use this file to trigger external notifications or audit logic.
4. **Event Clips (`events/event_<timestamp>.mp4`)**:
- Smart clips containing only the smoking incidents.
- Includes 2 seconds of pre-event context and 3 seconds post-event.
- Automatically extends if smoking continues.
5. **Application Logs (`logs/pipeline.log`)**:
- Rotating log files with detailed debug information.
- Includes thread names, function calls, and timing data.
## 📂 Project Structure
```text
gp/
├── main.py # CLI Entry point
├── pyproject.toml # Project config (uv/pip)
├── models/ # Directory for .pt model weights
├── logs/ # Rotating application logs
├── events/ # Smart event clips (auto-created)
├── pipeline/
│ ├── core.py # Main logic loop (Pipeline class)
│ ├── models.py # Ultralytics model wrappers
│ ├── sources.py # Stream inputs (File vs RTSP)
│ ├── outputs.py # Sinks (VideoWriter, JSONL logger)
│ ├── protocols.py # Interfaces (Model, Verifier, etc.)
│ └── types.py # Data classes (Frame, Detection, Ticket)
│ ├── core.py # Main logic loop (Pipeline class, Async Inference)
│ ├── models.py # Ultralytics model wrappers (GPU-enabled)
│ ├── sources.py # Stream inputs (File, ThreadedRTSP)
│ ├── outputs.py # Sinks (VideoFileStore, SmartEventSink, FileAlertStore)
│ ├── protocols.py # Interfaces (Model, Verifier, Sink, StreamSource)
│ └── types.py # Data classes (Frame, Detection, Ticket, NMS)
```
## ⚙️ Performance Tuning
The pipeline is designed for real-time performance. Key parameters in `main.py`:
```python
pipeline = SmokingDetectionPipeline(
...
inference_interval=0.5, # Idle: 2 FPS (saves GPU when empty)
active_interval=0.0, # Active: Process every frame
cooldown_frames=60, # Stay active 2s after person leaves
)
```
For RTSP streams, the `ThreadedRTSPSource` uses a background thread to prevent frame buildup and handles reconnection automatically.
BIN
View File
Binary file not shown.
Binary file not shown.
View File
File renamed without changes.
+385
View File
@@ -0,0 +1,385 @@
2026-01-11 01:42:17,502 | INFO | MainThread | main.main:97 - Loading models... Person: models/human-det-best.pt, Cig: models/cig-det-best.pt, Verifier: models/cig-cls-best.pt
2026-01-11 01:42:17,502 | INFO | MainThread | pipeline.models.__init__:22 - Loading Person Detector: models/human-det-best.pt
2026-01-11 01:42:17,529 | INFO | MainThread | pipeline.models.__init__:49 - Loading Cigarette Detector: models/cig-det-best.pt
2026-01-11 01:42:17,570 | INFO | MainThread | pipeline.models.__init__:77 - Loading Smoking Classifier: models/cig-cls-best.pt
2026-01-11 01:42:17,609 | INFO | MainThread | pipeline.outputs.__init__:198 - Initialized Async VideoFileStore writing to output.mp4
2026-01-11 01:42:17,610 | INFO | MainThread | pipeline.outputs.__init__:49 - Initialized SmartEventSink in events
2026-01-11 01:42:17,610 | INFO | MainThread | pipeline.outputs.__init__:143 - Initialized FileAlertStore writing to alerts.jsonl
2026-01-11 01:42:17,611 | INFO | MainThread | pipeline.core.__init__:52 - Pipeline initialized with 3 sinks. Async Inference enabled.
2026-01-11 01:42:17,611 | INFO | MainThread | pipeline.core.process_stream:58 - Starting stream processing...
2026-01-11 01:42:17,611 | INFO | MainThread | pipeline.sources.stream:43 - Opening video file: .\Group_project_smoking_detection\img\stock-footage-girl-on-a-break-smoking-a-cigarette.webm
2026-01-11 01:42:17,665 | INFO | MainThread | pipeline.core.process_stream:64 - Processed 100 frames...
2026-01-11 01:42:17,700 | INFO | MainThread | pipeline.core.process_stream:64 - Processed 200 frames...
2026-01-11 01:42:17,733 | INFO | MainThread | pipeline.core.process_stream:64 - Processed 300 frames...
2026-01-11 01:42:17,768 | INFO | MainThread | pipeline.core.process_stream:64 - Processed 400 frames...
2026-01-11 01:42:17,802 | INFO | MainThread | pipeline.core.process_stream:64 - Processed 500 frames...
2026-01-11 01:42:17,835 | INFO | MainThread | pipeline.core.process_stream:64 - Processed 600 frames...
2026-01-11 01:42:17,858 | INFO | MainThread | pipeline.sources.stream:49 - End of video file reached.
2026-01-11 01:42:17,861 | INFO | MainThread | pipeline.core.process_stream:129 - Stream processing finished.
2026-01-11 01:42:17,889 | INFO | MainThread | pipeline.outputs.close:321 - VideoFileStore closed.
2026-01-11 01:42:18,387 | DEBUG | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:189 - Inference took 0.770s (Slow)
2026-01-11 01:45:01,042 | INFO | MainThread | main.main:97 - Loading models... Person: models/human-det-best.pt, Cig: models/cig-det-best.pt, Verifier: models/cig-cls-best.pt
2026-01-11 01:45:01,042 | INFO | MainThread | pipeline.models.__init__:22 - Loading Person Detector: models/human-det-best.pt
2026-01-11 01:45:01,070 | INFO | MainThread | pipeline.models.__init__:49 - Loading Cigarette Detector: models/cig-det-best.pt
2026-01-11 01:45:01,123 | INFO | MainThread | pipeline.models.__init__:77 - Loading Smoking Classifier: models/cig-cls-best.pt
2026-01-11 01:45:01,151 | INFO | MainThread | pipeline.outputs.__init__:198 - Initialized Async VideoFileStore writing to output.mp4
2026-01-11 01:45:01,152 | INFO | MainThread | pipeline.outputs.__init__:49 - Initialized SmartEventSink in events
2026-01-11 01:45:01,153 | INFO | MainThread | pipeline.outputs.__init__:143 - Initialized FileAlertStore writing to alerts.jsonl
2026-01-11 01:45:01,153 | INFO | MainThread | pipeline.core.__init__:52 - Pipeline initialized with 3 sinks. Async Inference enabled.
2026-01-11 01:45:01,153 | INFO | MainThread | pipeline.core.process_stream:58 - Starting stream processing...
2026-01-11 01:45:01,153 | INFO | MainThread | pipeline.sources.stream:43 - Opening video file: .\Group_project_smoking_detection\img\stock-footage-girl-on-a-break-smoking-a-cigarette.webm
2026-01-11 01:45:01,205 | INFO | MainThread | pipeline.core.process_stream:64 - Processed 100 frames...
2026-01-11 01:45:01,238 | INFO | MainThread | pipeline.core.process_stream:64 - Processed 200 frames...
2026-01-11 01:45:01,268 | INFO | MainThread | pipeline.core.process_stream:64 - Processed 300 frames...
2026-01-11 01:45:01,301 | INFO | MainThread | pipeline.core.process_stream:64 - Processed 400 frames...
2026-01-11 01:45:01,333 | INFO | MainThread | pipeline.core.process_stream:64 - Processed 500 frames...
2026-01-11 01:45:01,364 | INFO | MainThread | pipeline.core.process_stream:64 - Processed 600 frames...
2026-01-11 01:45:01,379 | INFO | MainThread | pipeline.sources.stream:49 - End of video file reached.
2026-01-11 01:45:01,385 | INFO | MainThread | pipeline.core.process_stream:129 - Stream processing finished.
2026-01-11 01:45:01,414 | INFO | MainThread | pipeline.outputs.close:321 - VideoFileStore closed.
2026-01-11 01:45:01,878 | DEBUG | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:189 - Inference took 0.718s (Slow)
2026-01-11 01:45:25,018 | INFO | MainThread | main.main:97 - Loading models... Person: models/human-det-best.pt, Cig: models/cig-det-best.pt, Verifier: models/cig-cls-best.pt
2026-01-11 01:45:25,018 | INFO | MainThread | pipeline.models.__init__:22 - Loading Person Detector: models/human-det-best.pt
2026-01-11 01:45:25,046 | INFO | MainThread | pipeline.models.__init__:49 - Loading Cigarette Detector: models/cig-det-best.pt
2026-01-11 01:45:25,079 | INFO | MainThread | pipeline.models.__init__:77 - Loading Smoking Classifier: models/cig-cls-best.pt
2026-01-11 01:45:25,278 | INFO | MainThread | pipeline.outputs.__init__:198 - Initialized Async VideoFileStore writing to output.mp4
2026-01-11 01:45:25,279 | INFO | MainThread | pipeline.outputs.__init__:49 - Initialized SmartEventSink in events
2026-01-11 01:45:25,280 | INFO | MainThread | pipeline.outputs.__init__:143 - Initialized FileAlertStore writing to alerts.jsonl
2026-01-11 01:45:25,280 | INFO | MainThread | pipeline.core.__init__:52 - Pipeline initialized with 3 sinks. Async Inference enabled.
2026-01-11 01:45:25,281 | INFO | MainThread | pipeline.core.process_stream:58 - Starting stream processing...
2026-01-11 01:45:25,281 | INFO | MainThread | pipeline.sources.stream:43 - Opening video file: .\Group_project_smoking_detection\img\vecteezy_man-lights-a-cigarette-and-smokes-it_2657337.mov
2026-01-11 01:45:26,528 | INFO | MainThread | pipeline.core.process_stream:81 - Frame 46: Activity detected! Switching to ACTIVE mode (0s interval).
2026-01-11 01:45:26,650 | DEBUG | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:189 - Inference took 0.121s (Slow)
2026-01-11 01:45:27,792 | INFO | MainThread | pipeline.core.process_stream:64 - Processed 100 frames...
2026-01-11 01:45:28,253 | DEBUG | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:189 - Inference took 0.117s (Slow)
2026-01-11 01:45:28,377 | INFO | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:164 - CONFIRMED SMOKING! Score: 0.92
2026-01-11 01:45:28,378 | DEBUG | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:189 - Inference took 0.117s (Slow)
2026-01-11 01:45:30,125 | INFO | MainThread | pipeline.core.process_stream:64 - Processed 200 frames...
2026-01-11 01:45:31,182 | INFO | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:164 - CONFIRMED SMOKING! Score: 0.95
2026-01-11 01:45:31,254 | INFO | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:164 - CONFIRMED SMOKING! Score: 1.00
2026-01-11 01:45:31,398 | INFO | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:164 - CONFIRMED SMOKING! Score: 0.99
2026-01-11 01:45:31,399 | DEBUG | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:189 - Inference took 0.119s (Slow)
2026-01-11 01:45:31,495 | INFO | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:164 - CONFIRMED SMOKING! Score: 0.99
2026-01-11 01:45:31,802 | DEBUG | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:189 - Inference took 0.103s (Slow)
2026-01-11 01:45:32,246 | INFO | MainThread | pipeline.core.process_stream:64 - Processed 300 frames...
2026-01-11 01:45:32,467 | DEBUG | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:189 - Inference took 0.129s (Slow)
2026-01-11 01:45:33,206 | INFO | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:164 - CONFIRMED SMOKING! Score: 0.90
2026-01-11 01:45:33,435 | INFO | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:164 - CONFIRMED SMOKING! Score: 0.84
2026-01-11 01:45:33,697 | INFO | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:164 - CONFIRMED SMOKING! Score: 0.90
2026-01-11 01:45:33,798 | INFO | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:164 - CONFIRMED SMOKING! Score: 0.89
2026-01-11 01:45:33,850 | INFO | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:164 - CONFIRMED SMOKING! Score: 0.93
2026-01-11 01:45:33,940 | INFO | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:164 - CONFIRMED SMOKING! Score: 0.81
2026-01-11 01:45:34,003 | INFO | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:164 - CONFIRMED SMOKING! Score: 0.89
2026-01-11 01:45:34,654 | INFO | MainThread | pipeline.core.process_stream:64 - Processed 400 frames...
2026-01-11 01:45:36,804 | INFO | MainThread | pipeline.core.process_stream:64 - Processed 500 frames...
2026-01-11 01:45:37,027 | INFO | MainThread | pipeline.sources.stream:49 - End of video file reached.
2026-01-11 01:45:37,058 | INFO | MainThread | pipeline.core.process_stream:129 - Stream processing finished.
2026-01-11 01:45:38,521 | INFO | MainThread | pipeline.outputs.close:321 - VideoFileStore closed.
2026-01-11 01:59:42,251 | INFO | MainThread | main.main:97 - Loading models... Person: models/human-det-best.pt, Cig: models/cig-det-best.pt, Verifier: models/cig-cls-best.pt
2026-01-11 01:59:42,252 | INFO | MainThread | pipeline.models.__init__:22 - Loading Person Detector: models/human-det-best.pt
2026-01-11 01:59:42,283 | INFO | MainThread | pipeline.models.__init__:49 - Loading Cigarette Detector: models/cig-det-best.pt
2026-01-11 01:59:42,325 | INFO | MainThread | pipeline.models.__init__:77 - Loading Smoking Classifier: models/cig-cls-best.pt
2026-01-11 01:59:42,512 | INFO | MainThread | pipeline.outputs.__init__:204 - Initialized Async VideoFileStore writing to output.mp4
2026-01-11 01:59:42,513 | INFO | MainThread | pipeline.outputs.__init__:49 - Initialized SmartEventSink in events
2026-01-11 01:59:42,514 | INFO | MainThread | pipeline.outputs.__init__:149 - Initialized FileAlertStore writing to alerts.jsonl
2026-01-11 01:59:42,514 | INFO | MainThread | pipeline.core.__init__:52 - Pipeline initialized with 3 sinks. Async Inference enabled.
2026-01-11 01:59:42,515 | INFO | MainThread | pipeline.core.process_stream:58 - Starting stream processing...
2026-01-11 01:59:42,515 | INFO | MainThread | pipeline.sources.stream:43 - Opening video file: .\Group_project_smoking_detection\img\vecteezy_man-lights-a-cigarette-and-smokes-it_2657337.mov
2026-01-11 01:59:43,812 | INFO | MainThread | pipeline.core.process_stream:81 - Frame 40: Activity detected! Switching to ACTIVE mode (0s interval).
2026-01-11 01:59:43,932 | DEBUG | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:190 - Inference took 0.120s (Slow)
2026-01-11 01:59:46,922 | INFO | MainThread | pipeline.core.process_stream:64 - Processed 100 frames...
2026-01-11 01:59:47,993 | DEBUG | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:190 - Inference took 0.130s (Slow)
2026-01-11 01:59:48,150 | DEBUG | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:190 - Inference took 0.101s (Slow)
2026-01-11 01:59:48,281 | INFO | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:165 - CONFIRMED SMOKING! Score: 0.92
2026-01-11 01:59:48,281 | DEBUG | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:190 - Inference took 0.117s (Slow)
2026-01-11 01:59:48,334 | INFO | MainThread | pipeline.outputs.handle:168 - [ALERT SAVED] 0.92 confirmed at Verifier
2026-01-11 01:59:51,012 | INFO | MainThread | pipeline.outputs._trigger_event:97 - Started recording event 1768071588
2026-01-11 01:59:51,821 | DEBUG | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:190 - Inference took 0.124s (Slow)
2026-01-11 01:59:52,014 | DEBUG | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:190 - Inference took 0.142s (Slow)
2026-01-11 01:59:54,541 | DEBUG | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:190 - Inference took 0.109s (Slow)
2026-01-11 01:59:55,645 | INFO | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:165 - CONFIRMED SMOKING! Score: 0.81
2026-01-11 01:59:55,664 | INFO | MainThread | pipeline.outputs.handle:168 - [ALERT SAVED] 0.81 confirmed at Verifier
2026-01-11 01:59:55,733 | DEBUG | MainThread | pipeline.outputs.handle:68 - Event 1768071588 extended due to new detection.
2026-01-11 01:59:56,770 | INFO | MainThread | pipeline.core.process_stream:64 - Processed 200 frames...
2026-01-11 02:00:00,183 | INFO | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:165 - CONFIRMED SMOKING! Score: 0.95
2026-01-11 02:00:00,228 | INFO | MainThread | pipeline.outputs.handle:168 - [ALERT SAVED] 0.95 confirmed at Verifier
2026-01-11 02:00:00,288 | INFO | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:165 - CONFIRMED SMOKING! Score: 0.98
2026-01-11 02:00:00,290 | DEBUG | MainThread | pipeline.outputs.handle:68 - Event 1768071588 extended due to new detection.
2026-01-11 02:00:00,309 | INFO | MainThread | pipeline.outputs.handle:168 - [ALERT SAVED] 0.98 confirmed at Verifier
2026-01-11 02:00:00,362 | INFO | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:165 - CONFIRMED SMOKING! Score: 1.00
2026-01-11 02:00:00,397 | INFO | MainThread | pipeline.outputs.handle:168 - [ALERT SAVED] 1.00 confirmed at Verifier
2026-01-11 02:00:00,451 | INFO | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:165 - CONFIRMED SMOKING! Score: 1.00
2026-01-11 02:00:00,474 | INFO | MainThread | pipeline.outputs.handle:168 - [ALERT SAVED] 1.00 confirmed at Verifier
2026-01-11 02:00:00,526 | INFO | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:165 - CONFIRMED SMOKING! Score: 1.00
2026-01-11 02:00:00,559 | INFO | MainThread | pipeline.outputs.handle:168 - [ALERT SAVED] 1.00 confirmed at Verifier
2026-01-11 02:00:00,714 | INFO | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:165 - CONFIRMED SMOKING! Score: 1.00
2026-01-11 02:00:00,715 | DEBUG | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:190 - Inference took 0.156s (Slow)
2026-01-11 02:00:00,728 | INFO | MainThread | pipeline.outputs.handle:168 - [ALERT SAVED] 1.00 confirmed at Verifier
2026-01-11 02:00:00,779 | INFO | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:165 - CONFIRMED SMOKING! Score: 0.98
2026-01-11 02:00:00,795 | DEBUG | MainThread | pipeline.outputs.handle:68 - Event 1768071588 extended due to new detection.
2026-01-11 02:00:00,822 | INFO | MainThread | pipeline.outputs.handle:168 - [ALERT SAVED] 0.98 confirmed at Verifier
2026-01-11 02:00:00,871 | INFO | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:165 - CONFIRMED SMOKING! Score: 0.98
2026-01-11 02:00:00,898 | INFO | MainThread | pipeline.outputs.handle:168 - [ALERT SAVED] 0.98 confirmed at Verifier
2026-01-11 02:00:00,953 | INFO | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:165 - CONFIRMED SMOKING! Score: 1.00
2026-01-11 02:00:00,973 | INFO | MainThread | pipeline.outputs.handle:168 - [ALERT SAVED] 1.00 confirmed at Verifier
2026-01-11 02:00:01,059 | INFO | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:165 - CONFIRMED SMOKING! Score: 0.99
2026-01-11 02:00:01,119 | INFO | MainThread | pipeline.outputs.handle:168 - [ALERT SAVED] 0.99 confirmed at Verifier
2026-01-11 02:00:01,183 | DEBUG | MainThread | pipeline.outputs.handle:68 - Event 1768071588 extended due to new detection.
2026-01-11 02:00:01,194 | INFO | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:165 - CONFIRMED SMOKING! Score: 0.99
2026-01-11 02:00:01,197 | INFO | MainThread | pipeline.outputs.handle:168 - [ALERT SAVED] 0.99 confirmed at Verifier
2026-01-11 02:00:01,239 | INFO | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:165 - CONFIRMED SMOKING! Score: 0.97
2026-01-11 02:00:01,272 | INFO | MainThread | pipeline.outputs.handle:168 - [ALERT SAVED] 0.97 confirmed at Verifier
2026-01-11 02:00:01,478 | DEBUG | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:190 - Inference took 0.124s (Slow)
2026-01-11 02:00:03,769 | INFO | MainThread | pipeline.core.process_stream:64 - Processed 300 frames...
2026-01-11 02:00:06,642 | INFO | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:165 - CONFIRMED SMOKING! Score: 0.90
2026-01-11 02:00:06,650 | INFO | MainThread | pipeline.outputs.handle:168 - [ALERT SAVED] 0.90 confirmed at Verifier
2026-01-11 02:00:06,701 | DEBUG | MainThread | pipeline.outputs.handle:68 - Event 1768071588 extended due to new detection.
2026-01-11 02:00:07,362 | INFO | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:165 - CONFIRMED SMOKING! Score: 0.84
2026-01-11 02:00:07,425 | INFO | MainThread | pipeline.outputs.handle:168 - [ALERT SAVED] 0.84 confirmed at Verifier
2026-01-11 02:00:07,482 | DEBUG | MainThread | pipeline.outputs.handle:68 - Event 1768071588 extended due to new detection.
2026-01-11 02:00:07,756 | DEBUG | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:190 - Inference took 0.110s (Slow)
2026-01-11 02:00:08,038 | INFO | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:165 - CONFIRMED SMOKING! Score: 0.97
2026-01-11 02:00:08,098 | INFO | MainThread | pipeline.outputs.handle:168 - [ALERT SAVED] 0.97 confirmed at Verifier
2026-01-11 02:00:08,161 | DEBUG | MainThread | pipeline.outputs.handle:68 - Event 1768071588 extended due to new detection.
2026-01-11 02:00:08,191 | INFO | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:165 - CONFIRMED SMOKING! Score: 0.93
2026-01-11 02:00:08,250 | INFO | MainThread | pipeline.outputs.handle:168 - [ALERT SAVED] 0.93 confirmed at Verifier
2026-01-11 02:00:08,305 | DEBUG | MainThread | pipeline.outputs.handle:68 - Event 1768071588 extended due to new detection.
2026-01-11 02:00:08,341 | INFO | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:165 - CONFIRMED SMOKING! Score: 0.95
2026-01-11 02:00:08,403 | INFO | MainThread | pipeline.outputs.handle:168 - [ALERT SAVED] 0.95 confirmed at Verifier
2026-01-11 02:00:08,460 | DEBUG | MainThread | pipeline.outputs.handle:68 - Event 1768071588 extended due to new detection.
2026-01-11 02:00:08,480 | INFO | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:165 - CONFIRMED SMOKING! Score: 0.90
2026-01-11 02:00:08,560 | INFO | MainThread | pipeline.outputs.handle:168 - [ALERT SAVED] 0.90 confirmed at Verifier
2026-01-11 02:00:08,612 | DEBUG | MainThread | pipeline.outputs.handle:68 - Event 1768071588 extended due to new detection.
2026-01-11 02:00:08,638 | INFO | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:165 - CONFIRMED SMOKING! Score: 0.96
2026-01-11 02:00:08,707 | INFO | MainThread | pipeline.outputs.handle:168 - [ALERT SAVED] 0.96 confirmed at Verifier
2026-01-11 02:00:08,763 | DEBUG | MainThread | pipeline.outputs.handle:68 - Event 1768071588 extended due to new detection.
2026-01-11 02:00:08,792 | INFO | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:165 - CONFIRMED SMOKING! Score: 0.94
2026-01-11 02:00:08,843 | INFO | MainThread | pipeline.outputs.handle:168 - [ALERT SAVED] 0.94 confirmed at Verifier
2026-01-11 02:00:08,905 | DEBUG | MainThread | pipeline.outputs.handle:68 - Event 1768071588 extended due to new detection.
2026-01-11 02:00:08,921 | INFO | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:165 - CONFIRMED SMOKING! Score: 0.91
2026-01-11 02:00:08,925 | INFO | MainThread | pipeline.outputs.handle:168 - [ALERT SAVED] 0.91 confirmed at Verifier
2026-01-11 02:00:09,126 | INFO | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:165 - CONFIRMED SMOKING! Score: 0.89
2026-01-11 02:00:09,169 | INFO | MainThread | pipeline.outputs.handle:168 - [ALERT SAVED] 0.89 confirmed at Verifier
2026-01-11 02:00:09,223 | DEBUG | MainThread | pipeline.outputs.handle:68 - Event 1768071588 extended due to new detection.
2026-01-11 02:00:09,468 | INFO | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:165 - CONFIRMED SMOKING! Score: 0.96
2026-01-11 02:00:09,471 | INFO | MainThread | pipeline.outputs.handle:168 - [ALERT SAVED] 0.96 confirmed at Verifier
2026-01-11 02:00:09,530 | DEBUG | MainThread | pipeline.outputs.handle:68 - Event 1768071588 extended due to new detection.
2026-01-11 02:00:09,659 | DEBUG | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:190 - Inference took 0.104s (Slow)
2026-01-11 02:00:10,124 | DEBUG | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:190 - Inference took 0.123s (Slow)
2026-01-11 02:00:11,328 | INFO | MainThread | pipeline.core.process_stream:64 - Processed 400 frames...
2026-01-11 02:00:14,426 | INFO | MainThread | pipeline.outputs._stop_event:131 - Finished recording event 1768071588
2026-01-11 02:00:15,329 | INFO | MainThread | pipeline.core.process_stream:64 - Processed 500 frames...
2026-01-11 02:00:15,824 | INFO | MainThread | pipeline.sources.stream:49 - End of video file reached.
2026-01-11 02:00:15,855 | INFO | MainThread | pipeline.core.process_stream:130 - Stream processing finished.
2026-01-11 02:00:17,022 | INFO | MainThread | pipeline.outputs.close:318 - VideoFileStore closed.
2026-01-11 02:00:17,022 | INFO | MainThread | pipeline.outputs.close:137 - SmartEventSink closed.
2026-01-11 02:02:42,895 | INFO | MainThread | main.main:97 - Loading models... Person: models/human-det-best.pt, Cig: models/cig-det-best.pt, Verifier: models/cig-cls-best.pt
2026-01-11 02:02:42,895 | INFO | MainThread | pipeline.models.__init__:22 - Loading Person Detector: models/human-det-best.pt
2026-01-11 02:02:42,924 | INFO | MainThread | pipeline.models.__init__:49 - Loading Cigarette Detector: models/cig-det-best.pt
2026-01-11 02:02:42,964 | INFO | MainThread | pipeline.models.__init__:77 - Loading Smoking Classifier: models/cig-cls-best.pt
2026-01-11 02:02:43,140 | INFO | MainThread | pipeline.outputs.__init__:204 - Initialized Async VideoFileStore writing to output.mp4
2026-01-11 02:02:43,141 | INFO | MainThread | pipeline.outputs.__init__:49 - Initialized SmartEventSink in events
2026-01-11 02:02:43,142 | INFO | MainThread | pipeline.outputs.__init__:149 - Initialized FileAlertStore writing to alerts.jsonl
2026-01-11 02:02:43,142 | INFO | MainThread | pipeline.core.__init__:52 - Pipeline initialized with 3 sinks. Async Inference enabled.
2026-01-11 02:02:43,142 | INFO | MainThread | pipeline.core.process_stream:58 - Starting stream processing...
2026-01-11 02:02:43,142 | INFO | MainThread | pipeline.sources.stream:43 - Opening video file: .\Group_project_smoking_detection\img\vecteezy_man-lights-a-cigarette-and-smokes-it_2657337.mov
2026-01-11 02:02:44,358 | INFO | MainThread | pipeline.core.process_stream:81 - Frame 45: Activity detected! Switching to ACTIVE mode (0s interval).
2026-01-11 02:02:44,490 | DEBUG | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:190 - Inference took 0.132s (Slow)
2026-01-11 02:02:44,601 | DEBUG | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:190 - Inference took 0.102s (Slow)
2026-01-11 02:02:45,734 | INFO | MainThread | pipeline.core.process_stream:64 - Processed 100 frames...
2026-01-11 02:02:46,756 | DEBUG | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:190 - Inference took 0.132s (Slow)
2026-01-11 02:02:46,925 | DEBUG | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:190 - Inference took 0.121s (Slow)
2026-01-11 02:02:47,748 | INFO | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:165 - CONFIRMED SMOKING! Score: 0.86
2026-01-11 02:02:47,800 | INFO | MainThread | pipeline.outputs.handle:168 - [ALERT SAVED] 0.86 confirmed at Verifier
2026-01-11 02:02:50,001 | INFO | MainThread | pipeline.outputs._trigger_event:97 - Started recording event 1768071767
2026-01-11 02:02:53,377 | INFO | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:165 - CONFIRMED SMOKING! Score: 0.81
2026-01-11 02:02:53,415 | INFO | MainThread | pipeline.outputs.handle:168 - [ALERT SAVED] 0.81 confirmed at Verifier
2026-01-11 02:02:53,470 | DEBUG | MainThread | pipeline.outputs.handle:68 - Event 1768071767 extended due to new detection.
2026-01-11 02:02:54,478 | INFO | MainThread | pipeline.core.process_stream:64 - Processed 200 frames...
2026-01-11 02:02:57,925 | INFO | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:165 - CONFIRMED SMOKING! Score: 0.95
2026-01-11 02:02:57,995 | INFO | MainThread | pipeline.outputs.handle:168 - [ALERT SAVED] 0.95 confirmed at Verifier
2026-01-11 02:02:58,062 | DEBUG | MainThread | pipeline.outputs.handle:68 - Event 1768071767 extended due to new detection.
2026-01-11 02:02:58,125 | INFO | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:165 - CONFIRMED SMOKING! Score: 1.00
2026-01-11 02:02:58,126 | DEBUG | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:190 - Inference took 0.131s (Slow)
2026-01-11 02:02:58,181 | INFO | MainThread | pipeline.outputs.handle:168 - [ALERT SAVED] 1.00 confirmed at Verifier
2026-01-11 02:02:58,250 | DEBUG | MainThread | pipeline.outputs.handle:68 - Event 1768071767 extended due to new detection.
2026-01-11 02:02:58,306 | INFO | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:165 - CONFIRMED SMOKING! Score: 1.00
2026-01-11 02:02:58,306 | DEBUG | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:190 - Inference took 0.126s (Slow)
2026-01-11 02:02:58,345 | INFO | MainThread | pipeline.outputs.handle:168 - [ALERT SAVED] 1.00 confirmed at Verifier
2026-01-11 02:02:58,395 | DEBUG | MainThread | pipeline.outputs.handle:68 - Event 1768071767 extended due to new detection.
2026-01-11 02:02:58,509 | INFO | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:165 - CONFIRMED SMOKING! Score: 0.99
2026-01-11 02:02:58,510 | DEBUG | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:190 - Inference took 0.165s (Slow)
2026-01-11 02:02:58,577 | INFO | MainThread | pipeline.outputs.handle:168 - [ALERT SAVED] 0.99 confirmed at Verifier
2026-01-11 02:02:58,637 | DEBUG | MainThread | pipeline.outputs.handle:68 - Event 1768071767 extended due to new detection.
2026-01-11 02:02:58,688 | INFO | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:165 - CONFIRMED SMOKING! Score: 1.00
2026-01-11 02:02:58,689 | DEBUG | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:190 - Inference took 0.112s (Slow)
2026-01-11 02:02:58,743 | INFO | MainThread | pipeline.outputs.handle:168 - [ALERT SAVED] 1.00 confirmed at Verifier
2026-01-11 02:02:58,805 | DEBUG | MainThread | pipeline.outputs.handle:68 - Event 1768071767 extended due to new detection.
2026-01-11 02:02:58,848 | INFO | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:165 - CONFIRMED SMOKING! Score: 1.00
2026-01-11 02:02:58,848 | DEBUG | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:190 - Inference took 0.105s (Slow)
2026-01-11 02:02:58,900 | INFO | MainThread | pipeline.outputs.handle:168 - [ALERT SAVED] 1.00 confirmed at Verifier
2026-01-11 02:02:58,950 | DEBUG | MainThread | pipeline.outputs.handle:68 - Event 1768071767 extended due to new detection.
2026-01-11 02:02:59,000 | INFO | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:165 - CONFIRMED SMOKING! Score: 0.97
2026-01-11 02:02:59,000 | DEBUG | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:190 - Inference took 0.101s (Slow)
2026-01-11 02:02:59,056 | INFO | MainThread | pipeline.outputs.handle:168 - [ALERT SAVED] 0.97 confirmed at Verifier
2026-01-11 02:02:59,114 | DEBUG | MainThread | pipeline.outputs.handle:68 - Event 1768071767 extended due to new detection.
2026-01-11 02:02:59,221 | DEBUG | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:190 - Inference took 0.165s (Slow)
2026-01-11 02:02:59,540 | DEBUG | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:190 - Inference took 0.101s (Slow)
2026-01-11 02:02:59,855 | DEBUG | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:190 - Inference took 0.115s (Slow)
2026-01-11 02:03:00,007 | DEBUG | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:190 - Inference took 0.107s (Slow)
2026-01-11 02:03:00,171 | DEBUG | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:190 - Inference took 0.110s (Slow)
2026-01-11 02:03:01,059 | DEBUG | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:190 - Inference took 0.110s (Slow)
2026-01-11 02:03:01,221 | DEBUG | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:190 - Inference took 0.104s (Slow)
2026-01-11 02:03:01,507 | INFO | MainThread | pipeline.core.process_stream:64 - Processed 300 frames...
2026-01-11 02:03:01,535 | DEBUG | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:190 - Inference took 0.101s (Slow)
2026-01-11 02:03:01,847 | DEBUG | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:190 - Inference took 0.103s (Slow)
2026-01-11 02:03:02,564 | DEBUG | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:190 - Inference took 0.101s (Slow)
2026-01-11 02:03:02,735 | DEBUG | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:190 - Inference took 0.112s (Slow)
2026-01-11 02:03:02,892 | DEBUG | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:190 - Inference took 0.113s (Slow)
2026-01-11 02:03:03,040 | DEBUG | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:190 - Inference took 0.109s (Slow)
2026-01-11 02:03:03,176 | DEBUG | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:190 - Inference took 0.101s (Slow)
2026-01-11 02:03:03,696 | DEBUG | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:190 - Inference took 0.101s (Slow)
2026-01-11 02:03:04,022 | DEBUG | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:190 - Inference took 0.107s (Slow)
2026-01-11 02:03:04,461 | INFO | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:165 - CONFIRMED SMOKING! Score: 0.90
2026-01-11 02:03:04,462 | DEBUG | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:190 - Inference took 0.110s (Slow)
2026-01-11 02:03:04,511 | INFO | MainThread | pipeline.outputs.handle:168 - [ALERT SAVED] 0.90 confirmed at Verifier
2026-01-11 02:03:04,569 | DEBUG | MainThread | pipeline.outputs.handle:68 - Event 1768071767 extended due to new detection.
2026-01-11 02:03:04,614 | DEBUG | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:190 - Inference took 0.103s (Slow)
2026-01-11 02:03:04,778 | DEBUG | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:190 - Inference took 0.101s (Slow)
2026-01-11 02:03:04,932 | DEBUG | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:190 - Inference took 0.106s (Slow)
2026-01-11 02:03:05,087 | DEBUG | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:190 - Inference took 0.104s (Slow)
2026-01-11 02:03:05,519 | DEBUG | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:190 - Inference took 0.102s (Slow)
2026-01-11 02:03:05,820 | INFO | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:165 - CONFIRMED SMOKING! Score: 0.97
2026-01-11 02:03:05,820 | DEBUG | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:190 - Inference took 0.114s (Slow)
2026-01-11 02:03:05,867 | INFO | MainThread | pipeline.outputs.handle:168 - [ALERT SAVED] 0.97 confirmed at Verifier
2026-01-11 02:03:05,922 | DEBUG | MainThread | pipeline.outputs.handle:68 - Event 1768071767 extended due to new detection.
2026-01-11 02:03:06,022 | INFO | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:165 - CONFIRMED SMOKING! Score: 0.93
2026-01-11 02:03:06,022 | DEBUG | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:190 - Inference took 0.155s (Slow)
2026-01-11 02:03:06,080 | INFO | MainThread | pipeline.outputs.handle:168 - [ALERT SAVED] 0.93 confirmed at Verifier
2026-01-11 02:03:06,136 | DEBUG | MainThread | pipeline.outputs.handle:68 - Event 1768071767 extended due to new detection.
2026-01-11 02:03:06,211 | INFO | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:165 - CONFIRMED SMOKING! Score: 0.89
2026-01-11 02:03:06,211 | DEBUG | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:190 - Inference took 0.132s (Slow)
2026-01-11 02:03:06,249 | INFO | MainThread | pipeline.outputs.handle:168 - [ALERT SAVED] 0.89 confirmed at Verifier
2026-01-11 02:03:06,304 | DEBUG | MainThread | pipeline.outputs.handle:68 - Event 1768071767 extended due to new detection.
2026-01-11 02:03:06,343 | INFO | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:165 - CONFIRMED SMOKING! Score: 0.97
2026-01-11 02:03:06,393 | INFO | MainThread | pipeline.outputs.handle:168 - [ALERT SAVED] 0.97 confirmed at Verifier
2026-01-11 02:03:06,442 | INFO | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:165 - CONFIRMED SMOKING! Score: 0.93
2026-01-11 02:03:06,459 | DEBUG | MainThread | pipeline.outputs.handle:68 - Event 1768071767 extended due to new detection.
2026-01-11 02:03:06,477 | INFO | MainThread | pipeline.outputs.handle:168 - [ALERT SAVED] 0.93 confirmed at Verifier
2026-01-11 02:03:06,566 | INFO | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:165 - CONFIRMED SMOKING! Score: 0.94
2026-01-11 02:03:06,623 | INFO | MainThread | pipeline.outputs.handle:168 - [ALERT SAVED] 0.94 confirmed at Verifier
2026-01-11 02:03:06,687 | DEBUG | MainThread | pipeline.outputs.handle:68 - Event 1768071767 extended due to new detection.
2026-01-11 02:03:06,714 | INFO | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:165 - CONFIRMED SMOKING! Score: 0.91
2026-01-11 02:03:06,779 | INFO | MainThread | pipeline.outputs.handle:168 - [ALERT SAVED] 0.91 confirmed at Verifier
2026-01-11 02:03:06,835 | DEBUG | MainThread | pipeline.outputs.handle:68 - Event 1768071767 extended due to new detection.
2026-01-11 02:03:07,160 | INFO | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:165 - CONFIRMED SMOKING! Score: 0.87
2026-01-11 02:03:07,212 | INFO | MainThread | pipeline.outputs.handle:168 - [ALERT SAVED] 0.87 confirmed at Verifier
2026-01-11 02:03:07,271 | DEBUG | MainThread | pipeline.outputs.handle:68 - Event 1768071767 extended due to new detection.
2026-01-11 02:03:08,923 | INFO | MainThread | pipeline.core.process_stream:64 - Processed 400 frames...
2026-01-11 02:03:11,810 | INFO | MainThread | pipeline.outputs._stop_event:131 - Finished recording event 1768071767
2026-01-11 02:03:12,699 | INFO | MainThread | pipeline.core.process_stream:64 - Processed 500 frames...
2026-01-11 02:03:12,862 | INFO | MainThread | pipeline.sources.stream:49 - End of video file reached.
2026-01-11 02:03:12,895 | INFO | MainThread | pipeline.core.process_stream:130 - Stream processing finished.
2026-01-11 02:03:14,287 | INFO | MainThread | pipeline.outputs.close:318 - VideoFileStore closed.
2026-01-11 02:03:14,287 | INFO | MainThread | pipeline.outputs.close:137 - SmartEventSink closed.
2026-01-11 02:10:20,713 | INFO | MainThread | main.main:97 - Loading models... Person: models/human-det-best.pt, Cig: models/cig-det-best.pt, Verifier: models/cig-cls-best.pt
2026-01-11 02:10:20,713 | INFO | MainThread | pipeline.models.__init__:22 - Loading Person Detector: models/human-det-best.pt
2026-01-11 02:10:20,744 | INFO | MainThread | pipeline.models.__init__:49 - Loading Cigarette Detector: models/cig-det-best.pt
2026-01-11 02:10:20,785 | INFO | MainThread | pipeline.models.__init__:77 - Loading Smoking Classifier: models/cig-cls-best.pt
2026-01-11 02:10:20,964 | INFO | MainThread | pipeline.outputs.__init__:204 - Initialized Async VideoFileStore writing to output.mp4
2026-01-11 02:10:20,966 | INFO | MainThread | pipeline.outputs.__init__:49 - Initialized SmartEventSink in events
2026-01-11 02:10:20,966 | INFO | MainThread | pipeline.outputs.__init__:149 - Initialized FileAlertStore writing to alerts.jsonl
2026-01-11 02:10:20,966 | INFO | MainThread | pipeline.core.__init__:52 - Pipeline initialized with 3 sinks. Async Inference enabled.
2026-01-11 02:10:20,967 | INFO | MainThread | pipeline.core.process_stream:58 - Starting stream processing...
2026-01-11 02:10:20,967 | INFO | MainThread | pipeline.sources.stream:43 - Opening video file: .\Group_project_smoking_detection\img\vecteezy_man-lights-a-cigarette-and-smokes-it_2657337.mov
2026-01-11 02:10:22,182 | INFO | MainThread | pipeline.core.process_stream:81 - Frame 42: Activity detected! Switching to ACTIVE mode (0s interval).
2026-01-11 02:10:22,304 | DEBUG | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:193 - Inference took 0.121s (Slow)
2026-01-11 02:10:22,414 | DEBUG | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:193 - Inference took 0.101s (Slow)
2026-01-11 02:10:23,648 | INFO | MainThread | pipeline.core.process_stream:64 - Processed 100 frames...
2026-01-11 02:10:24,659 | DEBUG | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:193 - Inference took 0.134s (Slow)
2026-01-11 02:10:24,834 | DEBUG | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:193 - Inference took 0.138s (Slow)
2026-01-11 02:10:25,650 | INFO | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:168 - CONFIRMED SMOKING! Score: 0.86
2026-01-11 02:10:25,720 | INFO | MainThread | pipeline.outputs.handle:168 - [ALERT SAVED] 0.86 confirmed at Verifier
2026-01-11 02:10:27,899 | INFO | MainThread | pipeline.outputs._trigger_event:97 - Started recording event 1768072225
2026-01-11 02:10:31,119 | INFO | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:168 - CONFIRMED SMOKING! Score: 0.81
2026-01-11 02:10:31,158 | INFO | MainThread | pipeline.outputs.handle:168 - [ALERT SAVED] 0.81 confirmed at Verifier
2026-01-11 02:10:31,208 | DEBUG | MainThread | pipeline.outputs.handle:68 - Event 1768072225 extended due to new detection.
2026-01-11 02:10:32,228 | INFO | MainThread | pipeline.core.process_stream:64 - Processed 200 frames...
2026-01-11 02:10:35,482 | INFO | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:168 - CONFIRMED SMOKING! Score: 0.95
2026-01-11 02:10:35,505 | INFO | MainThread | pipeline.outputs.handle:168 - [ALERT SAVED] 0.95 confirmed at Verifier
2026-01-11 02:10:35,562 | DEBUG | MainThread | pipeline.outputs.handle:68 - Event 1768072225 extended due to new detection.
2026-01-11 02:10:35,587 | INFO | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:168 - CONFIRMED SMOKING! Score: 0.98
2026-01-11 02:10:35,654 | INFO | MainThread | pipeline.outputs.handle:168 - [ALERT SAVED] 0.98 confirmed at Verifier
2026-01-11 02:10:35,714 | DEBUG | MainThread | pipeline.outputs.handle:68 - Event 1768072225 extended due to new detection.
2026-01-11 02:10:35,736 | INFO | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:168 - CONFIRMED SMOKING! Score: 1.00
2026-01-11 02:10:35,809 | INFO | MainThread | pipeline.outputs.handle:168 - [ALERT SAVED] 1.00 confirmed at Verifier
2026-01-11 02:10:35,868 | DEBUG | MainThread | pipeline.outputs.handle:68 - Event 1768072225 extended due to new detection.
2026-01-11 02:10:35,967 | INFO | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:168 - CONFIRMED SMOKING! Score: 1.00
2026-01-11 02:10:35,967 | DEBUG | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:193 - Inference took 0.159s (Slow)
2026-01-11 02:10:36,030 | INFO | MainThread | pipeline.outputs.handle:168 - [ALERT SAVED] 1.00 confirmed at Verifier
2026-01-11 02:10:36,092 | DEBUG | MainThread | pipeline.outputs.handle:68 - Event 1768072225 extended due to new detection.
2026-01-11 02:10:36,099 | INFO | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:168 - CONFIRMED SMOKING! Score: 0.98
2026-01-11 02:10:36,112 | INFO | MainThread | pipeline.outputs.handle:168 - [ALERT SAVED] 0.98 confirmed at Verifier
2026-01-11 02:10:36,193 | INFO | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:168 - CONFIRMED SMOKING! Score: 1.00
2026-01-11 02:10:36,255 | INFO | MainThread | pipeline.outputs.handle:168 - [ALERT SAVED] 1.00 confirmed at Verifier
2026-01-11 02:10:36,324 | DEBUG | MainThread | pipeline.outputs.handle:68 - Event 1768072225 extended due to new detection.
2026-01-11 02:10:36,346 | INFO | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:168 - CONFIRMED SMOKING! Score: 1.00
2026-01-11 02:10:36,411 | INFO | MainThread | pipeline.outputs.handle:168 - [ALERT SAVED] 1.00 confirmed at Verifier
2026-01-11 02:10:36,473 | DEBUG | MainThread | pipeline.outputs.handle:68 - Event 1768072225 extended due to new detection.
2026-01-11 02:10:36,485 | INFO | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:168 - CONFIRMED SMOKING! Score: 0.97
2026-01-11 02:10:36,496 | INFO | MainThread | pipeline.outputs.handle:168 - [ALERT SAVED] 0.97 confirmed at Verifier
2026-01-11 02:10:36,760 | DEBUG | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:193 - Inference took 0.119s (Slow)
2026-01-11 02:10:37,426 | DEBUG | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:193 - Inference took 0.107s (Slow)
2026-01-11 02:10:37,598 | DEBUG | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:193 - Inference took 0.113s (Slow)
2026-01-11 02:10:38,341 | DEBUG | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:193 - Inference took 0.104s (Slow)
2026-01-11 02:10:38,985 | INFO | MainThread | pipeline.core.process_stream:64 - Processed 300 frames...
2026-01-11 02:10:40,039 | DEBUG | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:193 - Inference took 0.105s (Slow)
2026-01-11 02:10:41,778 | INFO | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:168 - CONFIRMED SMOKING! Score: 0.90
2026-01-11 02:10:41,832 | INFO | MainThread | pipeline.outputs.handle:168 - [ALERT SAVED] 0.90 confirmed at Verifier
2026-01-11 02:10:41,893 | DEBUG | MainThread | pipeline.outputs.handle:68 - Event 1768072225 extended due to new detection.
2026-01-11 02:10:42,087 | DEBUG | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:193 - Inference took 0.105s (Slow)
2026-01-11 02:10:42,242 | DEBUG | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:193 - Inference took 0.112s (Slow)
2026-01-11 02:10:42,407 | DEBUG | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:193 - Inference took 0.109s (Slow)
2026-01-11 02:10:42,530 | DEBUG | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:193 - Inference took 0.100s (Slow)
2026-01-11 02:10:42,845 | DEBUG | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:193 - Inference took 0.107s (Slow)
2026-01-11 02:10:43,152 | INFO | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:168 - CONFIRMED SMOKING! Score: 0.97
2026-01-11 02:10:43,152 | DEBUG | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:193 - Inference took 0.123s (Slow)
2026-01-11 02:10:43,198 | INFO | MainThread | pipeline.outputs.handle:168 - [ALERT SAVED] 0.97 confirmed at Verifier
2026-01-11 02:10:43,262 | DEBUG | MainThread | pipeline.outputs.handle:68 - Event 1768072225 extended due to new detection.
2026-01-11 02:10:43,345 | INFO | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:168 - CONFIRMED SMOKING! Score: 0.93
2026-01-11 02:10:43,345 | DEBUG | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:193 - Inference took 0.148s (Slow)
2026-01-11 02:10:43,382 | INFO | MainThread | pipeline.outputs.handle:168 - [ALERT SAVED] 0.93 confirmed at Verifier
2026-01-11 02:10:43,445 | DEBUG | MainThread | pipeline.outputs.handle:68 - Event 1768072225 extended due to new detection.
2026-01-11 02:10:43,475 | INFO | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:168 - CONFIRMED SMOKING! Score: 0.95
2026-01-11 02:10:43,545 | INFO | MainThread | pipeline.outputs.handle:168 - [ALERT SAVED] 0.95 confirmed at Verifier
2026-01-11 02:10:43,594 | DEBUG | MainThread | pipeline.outputs.handle:68 - Event 1768072225 extended due to new detection.
2026-01-11 02:10:43,630 | INFO | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:168 - CONFIRMED SMOKING! Score: 0.90
2026-01-11 02:10:43,679 | INFO | MainThread | pipeline.outputs.handle:168 - [ALERT SAVED] 0.90 confirmed at Verifier
2026-01-11 02:10:43,743 | DEBUG | MainThread | pipeline.outputs.handle:68 - Event 1768072225 extended due to new detection.
2026-01-11 02:10:43,766 | INFO | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:168 - CONFIRMED SMOKING! Score: 0.96
2026-01-11 02:10:43,837 | INFO | MainThread | pipeline.outputs.handle:168 - [ALERT SAVED] 0.96 confirmed at Verifier
2026-01-11 02:10:43,900 | DEBUG | MainThread | pipeline.outputs.handle:68 - Event 1768072225 extended due to new detection.
2026-01-11 02:10:43,982 | INFO | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:168 - CONFIRMED SMOKING! Score: 0.94
2026-01-11 02:10:43,982 | DEBUG | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:193 - Inference took 0.146s (Slow)
2026-01-11 02:10:44,016 | INFO | MainThread | pipeline.outputs.handle:168 - [ALERT SAVED] 0.94 confirmed at Verifier
2026-01-11 02:10:44,074 | DEBUG | MainThread | pipeline.outputs.handle:68 - Event 1768072225 extended due to new detection.
2026-01-11 02:10:44,124 | INFO | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:168 - CONFIRMED SMOKING! Score: 0.91
2026-01-11 02:10:44,124 | DEBUG | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:193 - Inference took 0.109s (Slow)
2026-01-11 02:10:44,172 | INFO | MainThread | pipeline.outputs.handle:168 - [ALERT SAVED] 0.91 confirmed at Verifier
2026-01-11 02:10:44,233 | DEBUG | MainThread | pipeline.outputs.handle:68 - Event 1768072225 extended due to new detection.
2026-01-11 02:10:44,279 | DEBUG | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:193 - Inference took 0.107s (Slow)
2026-01-11 02:10:44,501 | DEBUG | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:193 - Inference took 0.107s (Slow)
2026-01-11 02:10:44,650 | INFO | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:168 - CONFIRMED SMOKING! Score: 0.96
2026-01-11 02:10:44,651 | DEBUG | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:193 - Inference took 0.105s (Slow)
2026-01-11 02:10:44,714 | INFO | MainThread | pipeline.outputs.handle:168 - [ALERT SAVED] 0.96 confirmed at Verifier
2026-01-11 02:10:44,764 | DEBUG | MainThread | pipeline.outputs.handle:68 - Event 1768072225 extended due to new detection.
2026-01-11 02:10:44,827 | DEBUG | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:193 - Inference took 0.113s (Slow)
2026-01-11 02:10:45,119 | DEBUG | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:193 - Inference took 0.100s (Slow)
2026-01-11 02:10:45,282 | DEBUG | ThreadPoolExecutor-0_0 | pipeline.core._run_inference:193 - Inference took 0.110s (Slow)
2026-01-11 02:10:46,315 | INFO | MainThread | pipeline.core.process_stream:64 - Processed 400 frames...
2026-01-11 02:10:49,179 | INFO | MainThread | pipeline.outputs._stop_event:131 - Finished recording event 1768072225
2026-01-11 02:10:50,041 | INFO | MainThread | pipeline.core.process_stream:64 - Processed 500 frames...
2026-01-11 02:10:50,214 | INFO | MainThread | pipeline.sources.stream:49 - End of video file reached.
2026-01-11 02:10:50,252 | INFO | MainThread | pipeline.core.process_stream:133 - Stream processing finished.
2026-01-11 02:10:51,666 | INFO | MainThread | pipeline.outputs.close:318 - VideoFileStore closed.
2026-01-11 02:10:51,667 | INFO | MainThread | pipeline.outputs.close:137 - SmartEventSink closed.
+79 -22
View File
@@ -1,21 +1,60 @@
import argparse
import logging
import logging.handlers
import sys
from pathlib import Path
from pipeline.core import SmokingDetectionPipeline
from pipeline.models import YoloCigaretteDetector, YoloClassifier, YoloPersonDetector
from pipeline.outputs import FileAlertStore, VideoFileStore
from pipeline.outputs import FileAlertStore, SmartEventSink, VideoFileStore
from pipeline.sources import FileStreamSource, ThreadedRTSPSource
def main():
# Configure logging
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s [%(levelname)s] %(name)s: %(message)s",
handlers=[logging.StreamHandler(sys.stdout)],
def setup_logging(debug: bool = False):
"""Configures application-wide logging with console and file handlers."""
root_log = logging.getLogger()
root_log.setLevel(logging.DEBUG if debug else logging.INFO)
# Remove existing handlers to avoid duplicates if called multiple times
root_log.handlers = []
# Formatters
# Console: Concise and colorful (if possible, but using standard plain text for compatibility)
console_format = logging.Formatter(
fmt="%(asctime)s [%(levelname)s] %(name)s: %(message)s", datefmt="%H:%M:%S"
)
# File: Detailed debugging info
file_format = logging.Formatter(
fmt="%(asctime)s | %(levelname)-8s | %(threadName)s | %(name)s.%(funcName)s:%(lineno)d - %(message)s"
)
# 1. Console Handler (stdout)
console_handler = logging.StreamHandler(sys.stdout)
console_handler.setFormatter(console_format)
# console_handler.setLevel(logging.INFO) # Console can show less if needed, but linking to root level is simpler
# 2. File Handler (Rotating)
log_dir = Path("logs")
log_dir.mkdir(exist_ok=True)
file_handler = logging.handlers.RotatingFileHandler(
filename=log_dir / "pipeline.log",
maxBytes=10 * 1024 * 1024, # 10MB
backupCount=5,
encoding="utf-8",
)
file_handler.setFormatter(file_format)
file_handler.setLevel(logging.DEBUG) # Always log detailed debug to file
root_log.addHandler(console_handler)
root_log.addHandler(file_handler)
# Suppress chatty libraries if needed
logging.getLogger("ultralytics").setLevel(logging.WARNING)
logging.getLogger("matplotlib").setLevel(logging.WARNING)
def main():
parser = argparse.ArgumentParser(description="Smoking Detection Pipeline")
parser.add_argument("--source", type=str, help="Path to video file or RTSP stream")
parser.add_argument("--rtsp", action="store_true", help="Flag if source is RTSP")
@@ -47,23 +86,37 @@ def main():
args = parser.parse_args()
# Setup Logging immediately after parsing args
setup_logging(args.debug)
logger = logging.getLogger("main")
if not args.source:
print("Please provide --source")
logger.error("Please provide --source")
sys.exit(1)
print(
logger.info(
f"Loading models... Person: {args.person_model}, Cig: {args.cig_model}, Verifier: {args.verify_model}"
)
if args.debug:
logging.getLogger().setLevel(logging.DEBUG)
# Initialize implementation-specific classes
person_model = YoloPersonDetector(args.person_model)
cigarette_model = YoloCigaretteDetector(args.cig_model)
verifier = YoloClassifier(args.verify_model)
# Initialize Source first to get FPS
if args.rtsp:
# Use background thread for RTSP to prevent frame drop issues / lag
source = ThreadedRTSPSource(args.source)
else:
# Simple file reader
source = FileStreamSource(args.source)
# Initialize Output Sink
video_sink = VideoFileStore(args.output)
# Pass FPS from source so output video plays at correct speed
video_sink = VideoFileStore(args.output, fps=int(source.fps))
# Initialize Smart Sink (Optional, writes small clips only when smoking is detected)
smart_sink = SmartEventSink("events", fps=source.fps)
# Initialize Alert Store
# This persists confirmed smoking events to a dedicated log file
@@ -74,27 +127,31 @@ def main():
cigarette_model=cigarette_model,
verifier_model=verifier,
vlm_model=None, # Optional
sinks=[video_sink, alert_store],
inference_interval=0,
sinks=[video_sink, alert_store, smart_sink],
inference_interval=0.5, # Slow mode (2 FPS) when nobody is home
active_interval=0.0, # Max speed when person detected
cooldown_frames=int(
source.fps * 2
), # Stay active for 2 seconds after person leaves
)
if args.rtsp:
# Use background thread for RTSP to prevent frame drop issues / lag
source = ThreadedRTSPSource(args.source)
else:
# Simple file reader
source = FileStreamSource(args.source)
print("Starting pipeline...")
try:
# Pass the already initialized source
pipeline.process_stream(source)
except KeyboardInterrupt:
print("Stopped by user.")
finally:
if args.rtsp and hasattr(source, "stop"):
source.stop() # pyright: ignore[reportAttributeAccessIssue]
source.stop() # pyright: ignore[reportAttributeAccessIssue]
# Explicitly close all sinks
if video_sink:
video_sink.close()
if smart_sink:
smart_sink.close()
if alert_store:
alert_store.close()
if __name__ == "__main__":
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
+129 -20
View File
@@ -1,9 +1,12 @@
import concurrent.futures
import logging
import time
from collections import deque
from concurrent.futures import Future
from typing import List, Optional, Tuple
from pipeline.protocols import Model, Sink, StreamSource, Verifier
from pipeline.types import BoundingBox, Detection, Frame, Ticket
from pipeline.types import BoundingBox, Detection, Frame, Ticket, nms_by_class
logger = logging.getLogger(__name__)
@@ -17,73 +20,179 @@ class SmokingDetectionPipeline:
vlm_model: Optional[Verifier] = None,
sinks: Optional[list[Sink]] = None,
inference_interval: float = 0.5,
active_interval: float = 0.0,
cooldown_frames: int = 60,
):
self.person_model = person_model
self.cigarette_model = cigarette_model
self.verifier_model = verifier_model
self.vlm_model = vlm_model
self.sinks = sinks or []
self.inference_interval = inference_interval
# Adaptive Sampling Settings
self.idle_interval = inference_interval
self.active_interval = active_interval
self.cooldown_frames = cooldown_frames
# State
self.current_interval = self.idle_interval
self.active_cooldown = 0
self.last_inference_time = 0.0
# Async Inference State
self.executor = concurrent.futures.ThreadPoolExecutor(max_workers=1)
self.current_future: Optional[Future] = None
self.latest_detections: List[
Detection
] = [] # Cache for display to prevent flickering
self.latest_ticket: Optional[Ticket] = None
# Buffer for temporal context (optional, for VLM or sequence logic)
self.frame_buffer = deque(maxlen=30)
logger.info(f"Pipeline initialized with {len(self.sinks)} sinks.")
logger.info(
f"Pipeline initialized with {len(self.sinks)} sinks. Async Inference enabled."
)
def process_stream(self, source: StreamSource):
"""Main loop processing the video stream."""
logger.info("Starting stream processing...")
# Batch processing strategy:
# Instead of strict batches, we process frame-by-frame but can look back
count = 0
for frame in source.stream():
count += 1
if count % 100 == 0:
logger.info(f"Processed {count} frames...")
self.frame_buffer.append(frame)
# Skip inference if too soon
if (frame.timestamp - self.last_inference_time) >= self.inference_interval:
self._process_frame(frame)
self.last_inference_time = frame.timestamp
# 1. Check if previous inference finished
if self.current_future and self.current_future.done():
try:
# Retrieve results from the finished job
has_activity, detections, ticket = self.current_future.result()
# Update Cache
self.latest_detections = detections
self.latest_ticket = ticket
self.current_future = None
# Adaptive Logic Update
if has_activity:
if self.current_interval != self.active_interval:
logger.info(
"Frame %s: Activity detected! Switching to ACTIVE mode (0s interval).",
frame.frame_id,
)
self.current_interval = self.active_interval
self.active_cooldown = self.cooldown_frames
elif self.active_cooldown > 0:
if self.active_cooldown % 30 == 0:
logger.debug(
"Cooling down... %s frames left.", self.active_cooldown
)
self.active_cooldown -= 1
else:
if self.current_interval != self.idle_interval:
logger.info(
"Cooldown complete. Switching to IDLE mode (0.5s interval)."
)
self.current_interval = self.idle_interval
except Exception as e:
logger.error(f"Inference error: {e}")
self.current_future = None
# 2. Schedule new inference if idle and time condition met
now = frame.timestamp
time_since_last = now - self.last_inference_time
if self.current_future is None and time_since_last >= self.current_interval:
# Submit 'detect' job. We pass a COPY of data or rely on immutable usage.
# Frame.data is numpy, which is mutable but we trust models not to write to it.
# Since models might run on GPU/Thread, and we continue, it's safer to not rely on 'frame' object mutation.
# We will return the results and apply them later.
self.last_inference_time = now
self.current_future = self.executor.submit(self._run_inference, frame)
# 3. Apply cached detections to current frame for visualization
# This ensures smooth video output even if inference runs at 10fps
frame.detections.extend(self.latest_detections)
# 4. Run NMS to clean up overlapping boxes before display
frame.detections = nms_by_class(frame.detections, iou_threshold=0.5)
# Ticket dispatch: Only attach to ONE frame, then clear
# This prevents duplicate alerts in sinks like FileAlertStore
if self.latest_ticket:
frame.ticket = self.latest_ticket
self.latest_ticket = None # Consume the ticket
# Update sinks (Visualizers, etc)
for sink in self.sinks:
sink.handle(frame)
logger.info("Stream processing finished.")
self.executor.shutdown(wait=False)
def _run_inference(
self, frame: Frame
) -> Tuple[bool, List[Detection], Optional[Ticket]]:
"""
Runs the full detection chain.
Returns (ActivityDetected, ListOfDetections, TicketOrNone).
Does NOT modify frame in place (thread safety).
"""
t0 = time.time()
detections = []
def _process_frame(self, frame: Frame):
# --- Step 1: Broad Phase (Person Detection) ---
people = self.person_model.predict(frame.data)
frame.detections.extend(people)
detections.extend(people)
if not people:
return # FAST EXIT
logger.debug(f"Frame {frame.frame_id}: Found {len(people)} people.")
# logger.debug("No people found.")
return False, detections, None
# --- Step 2: Narrow Phase (Cigarette Candidate) ---
candidates = self._find_candidates(frame, people)
if not candidates:
return # EXIT
logger.debug(f"Frame {frame.frame_id}: Found {len(candidates)} candidates.")
return True, detections, None
# --- Step 3: Verification (Classifier) ---
best_hit = self._verify_candidates(frame, candidates)
ticket = None
# --- Step 4: Action ---
if best_hit:
person, cig, score = best_hit
logger.info("CONFIRMED SMOKING! Score: %.2f", score)
ticket = Ticket(
frame_id=frame.frame_id,
confidence=score,
evidence=[frame.data],
stage_confirmed="Verifier", # Simplified for now
evidence=[frame.data], # Note: this keeps ref to image data
stage_confirmed="Verifier",
)
frame.ticket = ticket
# Add the verified box to detections for visualization
verified_det = Detection(
box=BoundingBox(
x1=person.box.x1
+ cig.box.x1, # Approx logic, need exact coords from find_candidates
y1=person.box.y1 + cig.box.y1,
x2=person.box.x1 + cig.box.x2,
y2=person.box.y1 + cig.box.y2,
conf=score, # Placeholder
),
score=score,
label="verified_smoking",
)
detections.append(verified_det)
dt = time.time() - t0
if dt > 0.1:
logger.debug("Inference took %.3fs (Slow)", dt)
return True, detections, ticket
def _find_candidates(
self, frame: Frame, people: List[Detection]
+171 -6
View File
@@ -1,16 +1,142 @@
import collections
import json
import logging
import threading
import time
from pathlib import Path
from typing import List, Optional
from queue import Empty, Queue
from typing import Deque, List, Optional
import cv2
import numpy as np
from pipeline.protocols import Sink
from pipeline.types import Detection, Frame
logger = logging.getLogger(__name__)
class SmartEventSink(Sink):
"""
Smart Event Sink:
- Maintains a ring buffer of recent frames (e.g., 2 seconds context).
- When an alert (Ticket) occurs, it triggers a 'recording' state.
- Captures pre-event context + event + post-event context.
- Saves these 'events' as separate video clips or sequences.
"""
def __init__(
self,
output_dir: str,
fps: float = 30.0,
pre_event_seconds=2,
post_event_seconds=3,
):
self.output_dir = Path(output_dir)
self.output_dir.mkdir(parents=True, exist_ok=True)
self.fps = fps
self.buffer_size = int(fps * pre_event_seconds)
self.post_event_frames = int(fps * post_event_seconds)
self.buffer: Deque[Frame] = collections.deque(maxlen=self.buffer_size)
# State
self.recording = False
self.remaining_post_frames = 0
self.current_event_writer: Optional[cv2.VideoWriter] = None
self.current_event_id = None
logger.info(f"Initialized SmartEventSink in {output_dir}")
def handle(self, frame: Frame):
# Always add to buffer if not recording to keep context
if not self.recording:
self.buffer.append(frame)
# Check for trigger
if frame.ticket:
self._trigger_event(frame)
# If recording, write frame
if self.recording:
self._write_to_event(frame)
# Decrement counter
# If we keep getting tickets, we keep updating the counter (extending recording)
if frame.ticket:
if self.remaining_post_frames != self.post_event_frames:
logger.debug(
"Event %s extended due to new detection.", self.current_event_id
)
self.remaining_post_frames = self.post_event_frames
else:
self.remaining_post_frames -= 1
if self.remaining_post_frames <= 0:
self._stop_event()
def _trigger_event(self, trigger_frame: Frame):
if not self.recording:
# Start new event
self.recording = True
self.current_event_id = int(time.time())
self.remaining_post_frames = self.post_event_frames
filename = self.output_dir / f"event_{self.current_event_id}.mp4"
h, w = trigger_frame.data.shape[:2]
self.current_event_writer = cv2.VideoWriter(
str(filename), cv2.VideoWriter.fourcc(*"mp4v"), self.fps, (w, h)
)
# Dump buffer (Pre-event context)
while self.buffer:
f = self.buffer.popleft()
self._write_to_event(f)
logger.info("Started recording event %s", self.current_event_id)
def _write_to_event(self, frame: Frame):
if self.current_event_writer:
# Draw simple visualization for the clip
vis = frame.data.copy()
if frame.ticket:
cv2.rectangle(vis, (0, 0), (vis.shape[1], 40), (0, 0, 255), -1)
cv2.putText(
vis,
"SMOKING DETECTED",
(10, 30),
cv2.FONT_HERSHEY_SIMPLEX,
1,
(255, 255, 255),
2,
)
for det in frame.detections:
cv2.rectangle(
vis,
(det.box.x1, det.box.y1),
(det.box.x2, det.box.y2),
(255, 0, 0),
2,
)
self.current_event_writer.write(vis)
def _stop_event(self):
self.recording = False
if self.current_event_writer:
self.current_event_writer.release()
self.current_event_writer = None
logger.info("Finished recording event %s", self.current_event_id)
def close(self):
"""Releases resources and stops any active recording."""
if self.recording:
self._stop_event()
logger.info("SmartEventSink closed.")
class FileAlertStore:
"""
Persists actionable alerts (Tickets) to a JSONL file.
@@ -51,9 +177,16 @@ class VideoFileStore:
"""
Writes processed frames to a video file with visualization overlays.
Also optionally writes metadata sidecar files.
Async implementation to prevent blocking the main pipeline.
"""
def __init__(self, output_path: str, fps: int = 30, fourcc: str = "mp4v"):
def __init__(
self,
output_path: str,
fps: float = 30.0,
fourcc: str = "mp4v",
queue_size: int = 60,
):
self.output_path = output_path
self.metadata_path = str(Path(output_path).with_suffix(".jsonl"))
self.fps = fps
@@ -61,14 +194,42 @@ class VideoFileStore:
self.writer: Optional[cv2.VideoWriter] = None
self.frame_size = None
# Async setup
self.queue = Queue(maxsize=queue_size)
self.running = True
self.thread = threading.Thread(target=self._writer_loop, daemon=True)
# Open metadata file
self.meta_file = open(self.metadata_path, "w")
logger.info(
f"Initialized VideoFileStore writing to {output_path} and {self.metadata_path}"
)
logger.info(f"Initialized Async VideoFileStore writing to {output_path}")
self.thread.start()
def handle(self, frame: Frame):
"""Process a frame: Draw boxes and write to video/log."""
"""Enqueue frame for processing."""
if not self.running:
return
# We BLOCK here if queue is full to guarantee no frames are dropped.
# This may cause the main loop to slow down, but output integrity > speed.
# The queue size (30 frames ~1 second) provides a buffer for burst writes.
self.queue.put(frame, block=True)
def _writer_loop(self):
while self.running or not self.queue.empty():
try:
frame = self.queue.get(timeout=1.0)
except Empty:
continue
try:
self._process_frame(frame)
except Exception as e:
logger.error(f"Error processing video output: {e}")
finally:
self.queue.task_done()
def _process_frame(self, frame: Frame):
# Heavy lifting happens here in the thread
vis_image = frame.data.copy()
# 1. Visualization
@@ -146,6 +307,10 @@ class VideoFileStore:
self.meta_file.flush()
def close(self):
self.running = False
if self.thread.is_alive():
self.thread.join(timeout=2.0)
if self.writer:
self.writer.release()
if self.meta_file:
+9
View File
@@ -16,6 +16,11 @@ class Verifier(Protocol):
class StreamSource(Protocol):
@property
def fps(self) -> float:
"""Return the frames per second of the source."""
...
def stream(self) -> Iterator[Frame]:
"""Yield frames from source."""
...
@@ -25,3 +30,7 @@ class Sink(Protocol):
def handle(self, frame: Frame):
"""Process or persist a frame (and its ticket/detections)."""
...
def close(self):
"""Clean up resources."""
...
+30
View File
@@ -15,6 +15,21 @@ logger = logging.getLogger(__name__)
class FileStreamSource(StreamSource):
def __init__(self, path: str):
self.path = path
self._fps = 30.0
# Probe for FPS if it's a single file
if "*" not in self.path:
try:
cap = cv2.VideoCapture(self.path)
if cap.isOpened():
self._fps = cap.get(cv2.CAP_PROP_FPS) or 30.0
cap.release()
except Exception as e:
logger.warning(f"Could not probe FPS from {path}: {e}")
@property
def fps(self) -> float:
return self._fps
def stream(self) -> Iterator[Frame]:
# Handle glob patterns if path is a directory
@@ -48,11 +63,26 @@ class ThreadedRTSPSource(StreamSource):
def __init__(self, rtsp_url: str, queue_size=5):
self.rtsp_url = rtsp_url
self.queue = Queue(maxsize=queue_size)
self._fps = 30.0
# Probe FPS (with timeout safety ideally, but simple here)
try:
cap = cv2.VideoCapture(self.rtsp_url)
if cap.isOpened():
self._fps = cap.get(cv2.CAP_PROP_FPS) or 30.0
cap.release()
except Exception:
logger.warning("Could not probe FPS from RTSP source.")
self.stopped = False
self.thread = threading.Thread(target=self._update, daemon=True)
self._start()
logger.info(f"Initialized ThreadedRTSPSource for {rtsp_url}")
@property
def fps(self) -> float:
return self._fps
def _start(self):
self.thread.start()
+76 -1
View File
@@ -14,12 +14,31 @@ class BoundingBox:
@property
def area(self):
return (self.x2 - self.x1) * (self.y2 - self.y1)
return max(0, self.x2 - self.x1) * max(0, self.y2 - self.y1)
@property
def xyxy(self):
return [self.x1, self.y1, self.x2, self.y2]
def iou(self, other: "BoundingBox") -> float:
"""Calculate Intersection over Union with another box."""
# Intersection
ix1 = max(self.x1, other.x1)
iy1 = max(self.y1, other.y1)
ix2 = min(self.x2, other.x2)
iy2 = min(self.y2, other.y2)
inter_w = max(0, ix2 - ix1)
inter_h = max(0, iy2 - iy1)
inter_area = inter_w * inter_h
# Union
union_area = self.area + other.area - inter_area
if union_area == 0:
return 0.0
return inter_area / union_area
def crop(self, image: Any) -> Any:
# Assuming image is a numpy array (H, W, C)
# Handle cases where box is partially out of bounds
@@ -39,6 +58,62 @@ class Detection:
metadata: dict = field(default_factory=dict)
def nms(detections: List[Detection], iou_threshold: float = 0.5) -> List[Detection]:
"""
Non-Maximum Suppression: Remove overlapping boxes, keeping the highest confidence ones.
Args:
detections: List of Detection objects
iou_threshold: Boxes with IoU > threshold are suppressed
Returns:
Filtered list of detections
"""
if not detections:
return []
# Sort by confidence (highest first)
sorted_dets = sorted(detections, key=lambda d: d.score, reverse=True)
keep = []
while sorted_dets:
# Take the best one
best = sorted_dets.pop(0)
keep.append(best)
# Filter out boxes that overlap too much with 'best'
remaining = []
for det in sorted_dets:
if best.box.iou(det.box) < iou_threshold:
remaining.append(det)
sorted_dets = remaining
return keep
def nms_by_class(
detections: List[Detection], iou_threshold: float = 0.5
) -> List[Detection]:
"""
Run NMS separately for each class label.
This prevents boxes of different classes from suppressing each other.
"""
if not detections:
return []
# Group by label
by_label: dict[str, List[Detection]] = {}
for det in detections:
by_label.setdefault(det.label, []).append(det)
# Run NMS per class
result = []
for label, dets in by_label.items():
result.extend(nms(dets, iou_threshold))
return result
@dataclass
class Ticket:
"""Represents a potential alert event."""
+2 -1
View File
@@ -3,11 +3,12 @@ name = "gp"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.14"
requires-python = ">=3.13"
dependencies = [
"numpy>=2.4.0",
"opencv-python>=4.11.0.86",
"torch>=2.9.1",
"torchvision>=0.24.1",
"ultralytics>=8.3.248",
]
Generated
+272 -22
View File
@@ -1,11 +1,11 @@
version = 1
revision = 3
requires-python = ">=3.14"
requires-python = ">=3.13"
resolution-markers = [
"sys_platform == 'win32'",
"sys_platform == 'darwin'",
"platform_machine == 'aarch64' and sys_platform == 'linux'",
"sys_platform == 'win32'",
"platform_machine != 'aarch64' and sys_platform == 'linux'",
"sys_platform == 'darwin'",
"sys_platform != 'darwin' and sys_platform != 'linux' and sys_platform != 'win32'",
]
@@ -24,6 +24,22 @@ version = "3.4.4"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/13/69/33ddede1939fdd074bce5434295f38fae7136463422fe4fd3e0e89b98062/charset_normalizer-3.4.4.tar.gz", hash = "sha256:94537985111c35f28720e43603b8e7b43a6ecfb2ce1d3058bbe955b73404e21a", size = 129418, upload-time = "2025-10-14T04:42:32.879Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/97/45/4b3a1239bbacd321068ea6e7ac28875b03ab8bc0aa0966452db17cd36714/charset_normalizer-3.4.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:e1f185f86a6f3403aa2420e815904c67b2f9ebc443f045edd0de921108345794", size = 208091, upload-time = "2025-10-14T04:41:13.346Z" },
{ url = "https://files.pythonhosted.org/packages/7d/62/73a6d7450829655a35bb88a88fca7d736f9882a27eacdca2c6d505b57e2e/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b39f987ae8ccdf0d2642338faf2abb1862340facc796048b604ef14919e55ed", size = 147936, upload-time = "2025-10-14T04:41:14.461Z" },
{ url = "https://files.pythonhosted.org/packages/89/c5/adb8c8b3d6625bef6d88b251bbb0d95f8205831b987631ab0c8bb5d937c2/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3162d5d8ce1bb98dd51af660f2121c55d0fa541b46dff7bb9b9f86ea1d87de72", size = 144180, upload-time = "2025-10-14T04:41:15.588Z" },
{ url = "https://files.pythonhosted.org/packages/91/ed/9706e4070682d1cc219050b6048bfd293ccf67b3d4f5a4f39207453d4b99/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:81d5eb2a312700f4ecaa977a8235b634ce853200e828fbadf3a9c50bab278328", size = 161346, upload-time = "2025-10-14T04:41:16.738Z" },
{ url = "https://files.pythonhosted.org/packages/d5/0d/031f0d95e4972901a2f6f09ef055751805ff541511dc1252ba3ca1f80cf5/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5bd2293095d766545ec1a8f612559f6b40abc0eb18bb2f5d1171872d34036ede", size = 158874, upload-time = "2025-10-14T04:41:17.923Z" },
{ url = "https://files.pythonhosted.org/packages/f5/83/6ab5883f57c9c801ce5e5677242328aa45592be8a00644310a008d04f922/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a8a8b89589086a25749f471e6a900d3f662d1d3b6e2e59dcecf787b1cc3a1894", size = 153076, upload-time = "2025-10-14T04:41:19.106Z" },
{ url = "https://files.pythonhosted.org/packages/75/1e/5ff781ddf5260e387d6419959ee89ef13878229732732ee73cdae01800f2/charset_normalizer-3.4.4-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:bc7637e2f80d8530ee4a78e878bce464f70087ce73cf7c1caf142416923b98f1", size = 150601, upload-time = "2025-10-14T04:41:20.245Z" },
{ url = "https://files.pythonhosted.org/packages/d7/57/71be810965493d3510a6ca79b90c19e48696fb1ff964da319334b12677f0/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f8bf04158c6b607d747e93949aa60618b61312fe647a6369f88ce2ff16043490", size = 150376, upload-time = "2025-10-14T04:41:21.398Z" },
{ url = "https://files.pythonhosted.org/packages/e5/d5/c3d057a78c181d007014feb7e9f2e65905a6c4ef182c0ddf0de2924edd65/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:554af85e960429cf30784dd47447d5125aaa3b99a6f0683589dbd27e2f45da44", size = 144825, upload-time = "2025-10-14T04:41:22.583Z" },
{ url = "https://files.pythonhosted.org/packages/e6/8c/d0406294828d4976f275ffbe66f00266c4b3136b7506941d87c00cab5272/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:74018750915ee7ad843a774364e13a3db91682f26142baddf775342c3f5b1133", size = 162583, upload-time = "2025-10-14T04:41:23.754Z" },
{ url = "https://files.pythonhosted.org/packages/d7/24/e2aa1f18c8f15c4c0e932d9287b8609dd30ad56dbe41d926bd846e22fb8d/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:c0463276121fdee9c49b98908b3a89c39be45d86d1dbaa22957e38f6321d4ce3", size = 150366, upload-time = "2025-10-14T04:41:25.27Z" },
{ url = "https://files.pythonhosted.org/packages/e4/5b/1e6160c7739aad1e2df054300cc618b06bf784a7a164b0f238360721ab86/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:362d61fd13843997c1c446760ef36f240cf81d3ebf74ac62652aebaf7838561e", size = 160300, upload-time = "2025-10-14T04:41:26.725Z" },
{ url = "https://files.pythonhosted.org/packages/7a/10/f882167cd207fbdd743e55534d5d9620e095089d176d55cb22d5322f2afd/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9a26f18905b8dd5d685d6d07b0cdf98a79f3c7a918906af7cc143ea2e164c8bc", size = 154465, upload-time = "2025-10-14T04:41:28.322Z" },
{ url = "https://files.pythonhosted.org/packages/89/66/c7a9e1b7429be72123441bfdbaf2bc13faab3f90b933f664db506dea5915/charset_normalizer-3.4.4-cp313-cp313-win32.whl", hash = "sha256:9b35f4c90079ff2e2edc5b26c0c77925e5d2d255c42c74fdb70fb49b172726ac", size = 99404, upload-time = "2025-10-14T04:41:29.95Z" },
{ url = "https://files.pythonhosted.org/packages/c4/26/b9924fa27db384bdcd97ab83b4f0a8058d96ad9626ead570674d5e737d90/charset_normalizer-3.4.4-cp313-cp313-win_amd64.whl", hash = "sha256:b435cba5f4f750aa6c0a0d92c541fb79f69a387c91e61f1795227e4ed9cece14", size = 107092, upload-time = "2025-10-14T04:41:31.188Z" },
{ url = "https://files.pythonhosted.org/packages/af/8f/3ed4bfa0c0c72a7ca17f0380cd9e4dd842b09f664e780c13cff1dcf2ef1b/charset_normalizer-3.4.4-cp313-cp313-win_arm64.whl", hash = "sha256:542d2cee80be6f80247095cc36c418f7bddd14f4a6de45af91dfad36d817bba2", size = 100408, upload-time = "2025-10-14T04:41:32.624Z" },
{ url = "https://files.pythonhosted.org/packages/2a/35/7051599bd493e62411d6ede36fd5af83a38f37c4767b92884df7301db25d/charset_normalizer-3.4.4-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:da3326d9e65ef63a817ecbcc0df6e94463713b754fe293eaa03da99befb9a5bd", size = 207746, upload-time = "2025-10-14T04:41:33.773Z" },
{ url = "https://files.pythonhosted.org/packages/10/9a/97c8d48ef10d6cd4fcead2415523221624bf58bcf68a802721a6bc807c8f/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8af65f14dc14a79b924524b1e7fffe304517b2bff5a58bf64f30b98bbc5079eb", size = 147889, upload-time = "2025-10-14T04:41:34.897Z" },
{ url = "https://files.pythonhosted.org/packages/10/bf/979224a919a1b606c82bd2c5fa49b5c6d5727aa47b4312bb27b1734f53cd/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:74664978bb272435107de04e36db5a9735e78232b85b77d45cfb38f758efd33e", size = 143641, upload-time = "2025-10-14T04:41:36.116Z" },
@@ -52,6 +68,28 @@ dependencies = [
]
sdist = { url = "https://files.pythonhosted.org/packages/58/01/1253e6698a07380cd31a736d248a3f2a50a7c88779a1813da27503cadc2a/contourpy-1.3.3.tar.gz", hash = "sha256:083e12155b210502d0bca491432bb04d56dc3432f95a979b429f2848c3dbe880", size = 13466174, upload-time = "2025-07-26T12:03:12.549Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/68/35/0167aad910bbdb9599272bd96d01a9ec6852f36b9455cf2ca67bd4cc2d23/contourpy-1.3.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:177fb367556747a686509d6fef71d221a4b198a3905fe824430e5ea0fda54eb5", size = 293257, upload-time = "2025-07-26T12:01:39.367Z" },
{ url = "https://files.pythonhosted.org/packages/96/e4/7adcd9c8362745b2210728f209bfbcf7d91ba868a2c5f40d8b58f54c509b/contourpy-1.3.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d002b6f00d73d69333dac9d0b8d5e84d9724ff9ef044fd63c5986e62b7c9e1b1", size = 274034, upload-time = "2025-07-26T12:01:40.645Z" },
{ url = "https://files.pythonhosted.org/packages/73/23/90e31ceeed1de63058a02cb04b12f2de4b40e3bef5e082a7c18d9c8ae281/contourpy-1.3.3-cp313-cp313-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:348ac1f5d4f1d66d3322420f01d42e43122f43616e0f194fc1c9f5d830c5b286", size = 334672, upload-time = "2025-07-26T12:01:41.942Z" },
{ url = "https://files.pythonhosted.org/packages/ed/93/b43d8acbe67392e659e1d984700e79eb67e2acb2bd7f62012b583a7f1b55/contourpy-1.3.3-cp313-cp313-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:655456777ff65c2c548b7c454af9c6f33f16c8884f11083244b5819cc214f1b5", size = 381234, upload-time = "2025-07-26T12:01:43.499Z" },
{ url = "https://files.pythonhosted.org/packages/46/3b/bec82a3ea06f66711520f75a40c8fc0b113b2a75edb36aa633eb11c4f50f/contourpy-1.3.3-cp313-cp313-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:644a6853d15b2512d67881586bd03f462c7ab755db95f16f14d7e238f2852c67", size = 385169, upload-time = "2025-07-26T12:01:45.219Z" },
{ url = "https://files.pythonhosted.org/packages/4b/32/e0f13a1c5b0f8572d0ec6ae2f6c677b7991fafd95da523159c19eff0696a/contourpy-1.3.3-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4debd64f124ca62069f313a9cb86656ff087786016d76927ae2cf37846b006c9", size = 362859, upload-time = "2025-07-26T12:01:46.519Z" },
{ url = "https://files.pythonhosted.org/packages/33/71/e2a7945b7de4e58af42d708a219f3b2f4cff7386e6b6ab0a0fa0033c49a9/contourpy-1.3.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a15459b0f4615b00bbd1e91f1b9e19b7e63aea7483d03d804186f278c0af2659", size = 1332062, upload-time = "2025-07-26T12:01:48.964Z" },
{ url = "https://files.pythonhosted.org/packages/12/fc/4e87ac754220ccc0e807284f88e943d6d43b43843614f0a8afa469801db0/contourpy-1.3.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ca0fdcd73925568ca027e0b17ab07aad764be4706d0a925b89227e447d9737b7", size = 1403932, upload-time = "2025-07-26T12:01:51.979Z" },
{ url = "https://files.pythonhosted.org/packages/a6/2e/adc197a37443f934594112222ac1aa7dc9a98faf9c3842884df9a9d8751d/contourpy-1.3.3-cp313-cp313-win32.whl", hash = "sha256:b20c7c9a3bf701366556e1b1984ed2d0cedf999903c51311417cf5f591d8c78d", size = 185024, upload-time = "2025-07-26T12:01:53.245Z" },
{ url = "https://files.pythonhosted.org/packages/18/0b/0098c214843213759692cc638fce7de5c289200a830e5035d1791d7a2338/contourpy-1.3.3-cp313-cp313-win_amd64.whl", hash = "sha256:1cadd8b8969f060ba45ed7c1b714fe69185812ab43bd6b86a9123fe8f99c3263", size = 226578, upload-time = "2025-07-26T12:01:54.422Z" },
{ url = "https://files.pythonhosted.org/packages/8a/9a/2f6024a0c5995243cd63afdeb3651c984f0d2bc727fd98066d40e141ad73/contourpy-1.3.3-cp313-cp313-win_arm64.whl", hash = "sha256:fd914713266421b7536de2bfa8181aa8c699432b6763a0ea64195ebe28bff6a9", size = 193524, upload-time = "2025-07-26T12:01:55.73Z" },
{ url = "https://files.pythonhosted.org/packages/c0/b3/f8a1a86bd3298513f500e5b1f5fd92b69896449f6cab6a146a5d52715479/contourpy-1.3.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:88df9880d507169449d434c293467418b9f6cbe82edd19284aa0409e7fdb933d", size = 306730, upload-time = "2025-07-26T12:01:57.051Z" },
{ url = "https://files.pythonhosted.org/packages/3f/11/4780db94ae62fc0c2053909b65dc3246bd7cecfc4f8a20d957ad43aa4ad8/contourpy-1.3.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:d06bb1f751ba5d417047db62bca3c8fde202b8c11fb50742ab3ab962c81e8216", size = 287897, upload-time = "2025-07-26T12:01:58.663Z" },
{ url = "https://files.pythonhosted.org/packages/ae/15/e59f5f3ffdd6f3d4daa3e47114c53daabcb18574a26c21f03dc9e4e42ff0/contourpy-1.3.3-cp313-cp313t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e4e6b05a45525357e382909a4c1600444e2a45b4795163d3b22669285591c1ae", size = 326751, upload-time = "2025-07-26T12:02:00.343Z" },
{ url = "https://files.pythonhosted.org/packages/0f/81/03b45cfad088e4770b1dcf72ea78d3802d04200009fb364d18a493857210/contourpy-1.3.3-cp313-cp313t-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ab3074b48c4e2cf1a960e6bbeb7f04566bf36b1861d5c9d4d8ac04b82e38ba20", size = 375486, upload-time = "2025-07-26T12:02:02.128Z" },
{ url = "https://files.pythonhosted.org/packages/0c/ba/49923366492ffbdd4486e970d421b289a670ae8cf539c1ea9a09822b371a/contourpy-1.3.3-cp313-cp313t-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:6c3d53c796f8647d6deb1abe867daeb66dcc8a97e8455efa729516b997b8ed99", size = 388106, upload-time = "2025-07-26T12:02:03.615Z" },
{ url = "https://files.pythonhosted.org/packages/9f/52/5b00ea89525f8f143651f9f03a0df371d3cbd2fccd21ca9b768c7a6500c2/contourpy-1.3.3-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:50ed930df7289ff2a8d7afeb9603f8289e5704755c7e5c3bbd929c90c817164b", size = 352548, upload-time = "2025-07-26T12:02:05.165Z" },
{ url = "https://files.pythonhosted.org/packages/32/1d/a209ec1a3a3452d490f6b14dd92e72280c99ae3d1e73da74f8277d4ee08f/contourpy-1.3.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:4feffb6537d64b84877da813a5c30f1422ea5739566abf0bd18065ac040e120a", size = 1322297, upload-time = "2025-07-26T12:02:07.379Z" },
{ url = "https://files.pythonhosted.org/packages/bc/9e/46f0e8ebdd884ca0e8877e46a3f4e633f6c9c8c4f3f6e72be3fe075994aa/contourpy-1.3.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:2b7e9480ffe2b0cd2e787e4df64270e3a0440d9db8dc823312e2c940c167df7e", size = 1391023, upload-time = "2025-07-26T12:02:10.171Z" },
{ url = "https://files.pythonhosted.org/packages/b9/70/f308384a3ae9cd2209e0849f33c913f658d3326900d0ff5d378d6a1422d2/contourpy-1.3.3-cp313-cp313t-win32.whl", hash = "sha256:283edd842a01e3dcd435b1c5116798d661378d83d36d337b8dde1d16a5fc9ba3", size = 196157, upload-time = "2025-07-26T12:02:11.488Z" },
{ url = "https://files.pythonhosted.org/packages/b2/dd/880f890a6663b84d9e34a6f88cded89d78f0091e0045a284427cb6b18521/contourpy-1.3.3-cp313-cp313t-win_amd64.whl", hash = "sha256:87acf5963fc2b34825e5b6b048f40e3635dd547f590b04d2ab317c2619ef7ae8", size = 240570, upload-time = "2025-07-26T12:02:12.754Z" },
{ url = "https://files.pythonhosted.org/packages/80/99/2adc7d8ffead633234817ef8e9a87115c8a11927a94478f6bb3d3f4d4f7d/contourpy-1.3.3-cp313-cp313t-win_arm64.whl", hash = "sha256:3c30273eb2a55024ff31ba7d052dde990d7d8e5450f4bbb6e913558b3d6c2301", size = 199713, upload-time = "2025-07-26T12:02:14.4Z" },
{ url = "https://files.pythonhosted.org/packages/72/8b/4546f3ab60f78c514ffb7d01a0bd743f90de36f0019d1be84d0a708a580a/contourpy-1.3.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:fde6c716d51c04b1c25d0b90364d0be954624a0ee9d60e23e850e8d48353d07a", size = 292189, upload-time = "2025-07-26T12:02:16.095Z" },
{ url = "https://files.pythonhosted.org/packages/fd/e1/3542a9cb596cadd76fcef413f19c79216e002623158befe6daa03dbfa88c/contourpy-1.3.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:cbedb772ed74ff5be440fa8eee9bd49f64f6e3fc09436d9c7d8f1c287b121d77", size = 273251, upload-time = "2025-07-26T12:02:17.524Z" },
{ url = "https://files.pythonhosted.org/packages/b1/71/f93e1e9471d189f79d0ce2497007731c1e6bf9ef6d1d61b911430c3db4e5/contourpy-1.3.3-cp314-cp314-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:22e9b1bd7a9b1d652cd77388465dc358dafcd2e217d35552424aa4f996f524f5", size = 335810, upload-time = "2025-07-26T12:02:18.9Z" },
@@ -100,6 +138,14 @@ version = "4.61.1"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/ec/ca/cf17b88a8df95691275a3d77dc0a5ad9907f328ae53acbe6795da1b2f5ed/fonttools-4.61.1.tar.gz", hash = "sha256:6675329885c44657f826ef01d9e4fb33b9158e9d93c537d84ad8399539bc6f69", size = 3565756, upload-time = "2025-12-12T17:31:24.246Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/4b/cf/00ba28b0990982530addb8dc3e9e6f2fa9cb5c20df2abdda7baa755e8fe1/fonttools-4.61.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:8c56c488ab471628ff3bfa80964372fc13504ece601e0d97a78ee74126b2045c", size = 2846454, upload-time = "2025-12-12T17:30:24.938Z" },
{ url = "https://files.pythonhosted.org/packages/5a/ca/468c9a8446a2103ae645d14fee3f610567b7042aba85031c1c65e3ef7471/fonttools-4.61.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:dc492779501fa723b04d0ab1f5be046797fee17d27700476edc7ee9ae535a61e", size = 2398191, upload-time = "2025-12-12T17:30:27.343Z" },
{ url = "https://files.pythonhosted.org/packages/a3/4b/d67eedaed19def5967fade3297fed8161b25ba94699efc124b14fb68cdbc/fonttools-4.61.1-cp313-cp313-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:64102ca87e84261419c3747a0d20f396eb024bdbeb04c2bfb37e2891f5fadcb5", size = 4928410, upload-time = "2025-12-12T17:30:29.771Z" },
{ url = "https://files.pythonhosted.org/packages/b0/8d/6fb3494dfe61a46258cd93d979cf4725ded4eb46c2a4ca35e4490d84daea/fonttools-4.61.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4c1b526c8d3f615a7b1867f38a9410849c8f4aef078535742198e942fba0e9bd", size = 4984460, upload-time = "2025-12-12T17:30:32.073Z" },
{ url = "https://files.pythonhosted.org/packages/f7/f1/a47f1d30b3dc00d75e7af762652d4cbc3dff5c2697a0dbd5203c81afd9c3/fonttools-4.61.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:41ed4b5ec103bd306bb68f81dc166e77409e5209443e5773cb4ed837bcc9b0d3", size = 4925800, upload-time = "2025-12-12T17:30:34.339Z" },
{ url = "https://files.pythonhosted.org/packages/a7/01/e6ae64a0981076e8a66906fab01539799546181e32a37a0257b77e4aa88b/fonttools-4.61.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b501c862d4901792adaec7c25b1ecc749e2662543f68bb194c42ba18d6eec98d", size = 5067859, upload-time = "2025-12-12T17:30:36.593Z" },
{ url = "https://files.pythonhosted.org/packages/73/aa/28e40b8d6809a9b5075350a86779163f074d2b617c15d22343fce81918db/fonttools-4.61.1-cp313-cp313-win32.whl", hash = "sha256:4d7092bb38c53bbc78e9255a59158b150bcdc115a1e3b3ce0b5f267dc35dd63c", size = 2267821, upload-time = "2025-12-12T17:30:38.478Z" },
{ url = "https://files.pythonhosted.org/packages/1a/59/453c06d1d83dc0951b69ef692d6b9f1846680342927df54e9a1ca91c6f90/fonttools-4.61.1-cp313-cp313-win_amd64.whl", hash = "sha256:21e7c8d76f62ab13c9472ccf74515ca5b9a761d1bde3265152a6dc58700d895b", size = 2318169, upload-time = "2025-12-12T17:30:40.951Z" },
{ url = "https://files.pythonhosted.org/packages/32/8f/4e7bf82c0cbb738d3c2206c920ca34ca74ef9dabde779030145d28665104/fonttools-4.61.1-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:fff4f534200a04b4a36e7ae3cb74493afe807b517a09e99cb4faa89a34ed6ecd", size = 2846094, upload-time = "2025-12-12T17:30:43.511Z" },
{ url = "https://files.pythonhosted.org/packages/71/09/d44e45d0a4f3a651f23a1e9d42de43bc643cce2971b19e784cc67d823676/fonttools-4.61.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:d9203500f7c63545b4ce3799319fe4d9feb1a1b89b28d3cb5abd11b9dd64147e", size = 2396589, upload-time = "2025-12-12T17:30:45.681Z" },
{ url = "https://files.pythonhosted.org/packages/89/18/58c64cafcf8eb677a99ef593121f719e6dcbdb7d1c594ae5a10d4997ca8a/fonttools-4.61.1-cp314-cp314-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:fa646ecec9528bef693415c79a86e733c70a4965dd938e9a226b0fc64c9d2e6c", size = 4877892, upload-time = "2025-12-12T17:30:47.709Z" },
@@ -137,6 +183,9 @@ dependencies = [
{ name = "opencv-python" },
{ name = "torch", version = "2.9.1", source = { registry = "https://pypi.org/simple" }, marker = "sys_platform != 'linux' and sys_platform != 'win32'" },
{ name = "torch", version = "2.9.1+cu130", source = { registry = "https://download.pytorch.org/whl/cu130" }, marker = "sys_platform == 'linux' or sys_platform == 'win32'" },
{ name = "torchvision", version = "0.24.1", source = { registry = "https://download.pytorch.org/whl/cu130" }, marker = "platform_machine == 'aarch64' and sys_platform == 'linux'" },
{ name = "torchvision", version = "0.24.1", source = { registry = "https://pypi.org/simple" }, marker = "sys_platform != 'linux' and sys_platform != 'win32'" },
{ name = "torchvision", version = "0.24.1+cu130", source = { registry = "https://download.pytorch.org/whl/cu130" }, marker = "(platform_machine != 'aarch64' and sys_platform == 'linux') or sys_platform == 'win32'" },
{ name = "ultralytics" },
]
@@ -146,6 +195,8 @@ requires-dist = [
{ name = "opencv-python", specifier = ">=4.11.0.86" },
{ name = "torch", marker = "sys_platform != 'linux' and sys_platform != 'win32'", specifier = ">=2.9.1" },
{ name = "torch", marker = "sys_platform == 'linux' or sys_platform == 'win32'", specifier = ">=2.9.1", index = "https://download.pytorch.org/whl/cu130" },
{ name = "torchvision", marker = "sys_platform != 'linux' and sys_platform != 'win32'", specifier = ">=0.24.1" },
{ name = "torchvision", marker = "sys_platform == 'linux' or sys_platform == 'win32'", specifier = ">=0.24.1", index = "https://download.pytorch.org/whl/cu130" },
{ name = "ultralytics", specifier = ">=8.3.248" },
]
@@ -176,6 +227,31 @@ version = "1.4.9"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/5c/3c/85844f1b0feb11ee581ac23fe5fce65cd049a200c1446708cc1b7f922875/kiwisolver-1.4.9.tar.gz", hash = "sha256:c3b22c26c6fd6811b0ae8363b95ca8ce4ea3c202d3d0975b2914310ceb1bcc4d", size = 97564, upload-time = "2025-08-10T21:27:49.279Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/31/c1/c2686cda909742ab66c7388e9a1a8521a59eb89f8bcfbee28fc980d07e24/kiwisolver-1.4.9-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a5d0432ccf1c7ab14f9949eec60c5d1f924f17c037e9f8b33352fa05799359b8", size = 123681, upload-time = "2025-08-10T21:26:26.725Z" },
{ url = "https://files.pythonhosted.org/packages/ca/f0/f44f50c9f5b1a1860261092e3bc91ecdc9acda848a8b8c6abfda4a24dd5c/kiwisolver-1.4.9-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efb3a45b35622bb6c16dbfab491a8f5a391fe0e9d45ef32f4df85658232ca0e2", size = 66464, upload-time = "2025-08-10T21:26:27.733Z" },
{ url = "https://files.pythonhosted.org/packages/2d/7a/9d90a151f558e29c3936b8a47ac770235f436f2120aca41a6d5f3d62ae8d/kiwisolver-1.4.9-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1a12cf6398e8a0a001a059747a1cbf24705e18fe413bc22de7b3d15c67cffe3f", size = 64961, upload-time = "2025-08-10T21:26:28.729Z" },
{ url = "https://files.pythonhosted.org/packages/e9/e9/f218a2cb3a9ffbe324ca29a9e399fa2d2866d7f348ec3a88df87fc248fc5/kiwisolver-1.4.9-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:b67e6efbf68e077dd71d1a6b37e43e1a99d0bff1a3d51867d45ee8908b931098", size = 1474607, upload-time = "2025-08-10T21:26:29.798Z" },
{ url = "https://files.pythonhosted.org/packages/d9/28/aac26d4c882f14de59041636292bc838db8961373825df23b8eeb807e198/kiwisolver-1.4.9-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5656aa670507437af0207645273ccdfee4f14bacd7f7c67a4306d0dcaeaf6eed", size = 1276546, upload-time = "2025-08-10T21:26:31.401Z" },
{ url = "https://files.pythonhosted.org/packages/8b/ad/8bfc1c93d4cc565e5069162f610ba2f48ff39b7de4b5b8d93f69f30c4bed/kiwisolver-1.4.9-cp313-cp313-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:bfc08add558155345129c7803b3671cf195e6a56e7a12f3dde7c57d9b417f525", size = 1294482, upload-time = "2025-08-10T21:26:32.721Z" },
{ url = "https://files.pythonhosted.org/packages/da/f1/6aca55ff798901d8ce403206d00e033191f63d82dd708a186e0ed2067e9c/kiwisolver-1.4.9-cp313-cp313-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:40092754720b174e6ccf9e845d0d8c7d8e12c3d71e7fc35f55f3813e96376f78", size = 1343720, upload-time = "2025-08-10T21:26:34.032Z" },
{ url = "https://files.pythonhosted.org/packages/d1/91/eed031876c595c81d90d0f6fc681ece250e14bf6998c3d7c419466b523b7/kiwisolver-1.4.9-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:497d05f29a1300d14e02e6441cf0f5ee81c1ff5a304b0d9fb77423974684e08b", size = 2224907, upload-time = "2025-08-10T21:26:35.824Z" },
{ url = "https://files.pythonhosted.org/packages/e9/ec/4d1925f2e49617b9cca9c34bfa11adefad49d00db038e692a559454dfb2e/kiwisolver-1.4.9-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:bdd1a81a1860476eb41ac4bc1e07b3f07259e6d55bbf739b79c8aaedcf512799", size = 2321334, upload-time = "2025-08-10T21:26:37.534Z" },
{ url = "https://files.pythonhosted.org/packages/43/cb/450cd4499356f68802750c6ddc18647b8ea01ffa28f50d20598e0befe6e9/kiwisolver-1.4.9-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:e6b93f13371d341afee3be9f7c5964e3fe61d5fa30f6a30eb49856935dfe4fc3", size = 2488313, upload-time = "2025-08-10T21:26:39.191Z" },
{ url = "https://files.pythonhosted.org/packages/71/67/fc76242bd99f885651128a5d4fa6083e5524694b7c88b489b1b55fdc491d/kiwisolver-1.4.9-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:d75aa530ccfaa593da12834b86a0724f58bff12706659baa9227c2ccaa06264c", size = 2291970, upload-time = "2025-08-10T21:26:40.828Z" },
{ url = "https://files.pythonhosted.org/packages/75/bd/f1a5d894000941739f2ae1b65a32892349423ad49c2e6d0771d0bad3fae4/kiwisolver-1.4.9-cp313-cp313-win_amd64.whl", hash = "sha256:dd0a578400839256df88c16abddf9ba14813ec5f21362e1fe65022e00c883d4d", size = 73894, upload-time = "2025-08-10T21:26:42.33Z" },
{ url = "https://files.pythonhosted.org/packages/95/38/dce480814d25b99a391abbddadc78f7c117c6da34be68ca8b02d5848b424/kiwisolver-1.4.9-cp313-cp313-win_arm64.whl", hash = "sha256:d4188e73af84ca82468f09cadc5ac4db578109e52acb4518d8154698d3a87ca2", size = 64995, upload-time = "2025-08-10T21:26:43.889Z" },
{ url = "https://files.pythonhosted.org/packages/e2/37/7d218ce5d92dadc5ebdd9070d903e0c7cf7edfe03f179433ac4d13ce659c/kiwisolver-1.4.9-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:5a0f2724dfd4e3b3ac5a82436a8e6fd16baa7d507117e4279b660fe8ca38a3a1", size = 126510, upload-time = "2025-08-10T21:26:44.915Z" },
{ url = "https://files.pythonhosted.org/packages/23/b0/e85a2b48233daef4b648fb657ebbb6f8367696a2d9548a00b4ee0eb67803/kiwisolver-1.4.9-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:1b11d6a633e4ed84fc0ddafd4ebfd8ea49b3f25082c04ad12b8315c11d504dc1", size = 67903, upload-time = "2025-08-10T21:26:45.934Z" },
{ url = "https://files.pythonhosted.org/packages/44/98/f2425bc0113ad7de24da6bb4dae1343476e95e1d738be7c04d31a5d037fd/kiwisolver-1.4.9-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:61874cdb0a36016354853593cffc38e56fc9ca5aa97d2c05d3dcf6922cd55a11", size = 66402, upload-time = "2025-08-10T21:26:47.101Z" },
{ url = "https://files.pythonhosted.org/packages/98/d8/594657886df9f34c4177cc353cc28ca7e6e5eb562d37ccc233bff43bbe2a/kiwisolver-1.4.9-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:60c439763a969a6af93b4881db0eed8fadf93ee98e18cbc35bc8da868d0c4f0c", size = 1582135, upload-time = "2025-08-10T21:26:48.665Z" },
{ url = "https://files.pythonhosted.org/packages/5c/c6/38a115b7170f8b306fc929e166340c24958347308ea3012c2b44e7e295db/kiwisolver-1.4.9-cp313-cp313t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:92a2f997387a1b79a75e7803aa7ded2cfbe2823852ccf1ba3bcf613b62ae3197", size = 1389409, upload-time = "2025-08-10T21:26:50.335Z" },
{ url = "https://files.pythonhosted.org/packages/bf/3b/e04883dace81f24a568bcee6eb3001da4ba05114afa622ec9b6fafdc1f5e/kiwisolver-1.4.9-cp313-cp313t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a31d512c812daea6d8b3be3b2bfcbeb091dbb09177706569bcfc6240dcf8b41c", size = 1401763, upload-time = "2025-08-10T21:26:51.867Z" },
{ url = "https://files.pythonhosted.org/packages/9f/80/20ace48e33408947af49d7d15c341eaee69e4e0304aab4b7660e234d6288/kiwisolver-1.4.9-cp313-cp313t-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:52a15b0f35dad39862d376df10c5230155243a2c1a436e39eb55623ccbd68185", size = 1453643, upload-time = "2025-08-10T21:26:53.592Z" },
{ url = "https://files.pythonhosted.org/packages/64/31/6ce4380a4cd1f515bdda976a1e90e547ccd47b67a1546d63884463c92ca9/kiwisolver-1.4.9-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:a30fd6fdef1430fd9e1ba7b3398b5ee4e2887783917a687d86ba69985fb08748", size = 2330818, upload-time = "2025-08-10T21:26:55.051Z" },
{ url = "https://files.pythonhosted.org/packages/fa/e9/3f3fcba3bcc7432c795b82646306e822f3fd74df0ee81f0fa067a1f95668/kiwisolver-1.4.9-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:cc9617b46837c6468197b5945e196ee9ca43057bb7d9d1ae688101e4e1dddf64", size = 2419963, upload-time = "2025-08-10T21:26:56.421Z" },
{ url = "https://files.pythonhosted.org/packages/99/43/7320c50e4133575c66e9f7dadead35ab22d7c012a3b09bb35647792b2a6d/kiwisolver-1.4.9-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:0ab74e19f6a2b027ea4f845a78827969af45ce790e6cb3e1ebab71bdf9f215ff", size = 2594639, upload-time = "2025-08-10T21:26:57.882Z" },
{ url = "https://files.pythonhosted.org/packages/65/d6/17ae4a270d4a987ef8a385b906d2bdfc9fce502d6dc0d3aea865b47f548c/kiwisolver-1.4.9-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:dba5ee5d3981160c28d5490f0d1b7ed730c22470ff7f6cc26cfcfaacb9896a07", size = 2391741, upload-time = "2025-08-10T21:26:59.237Z" },
{ url = "https://files.pythonhosted.org/packages/2a/8f/8f6f491d595a9e5912971f3f863d81baddccc8a4d0c3749d6a0dd9ffc9df/kiwisolver-1.4.9-cp313-cp313t-win_arm64.whl", hash = "sha256:0749fd8f4218ad2e851e11cc4dc05c7cbc0cbc4267bdfdb31782e65aace4ee9c", size = 68646, upload-time = "2025-08-10T21:27:00.52Z" },
{ url = "https://files.pythonhosted.org/packages/6b/32/6cc0fbc9c54d06c2969faa9c1d29f5751a2e51809dd55c69055e62d9b426/kiwisolver-1.4.9-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:9928fe1eb816d11ae170885a74d074f57af3a0d65777ca47e9aeb854a1fba386", size = 123806, upload-time = "2025-08-10T21:27:01.537Z" },
{ url = "https://files.pythonhosted.org/packages/b2/dd/2bfb1d4a4823d92e8cbb420fe024b8d2167f72079b3bb941207c42570bdf/kiwisolver-1.4.9-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:d0005b053977e7b43388ddec89fa567f43d4f6d5c2c0affe57de5ebf290dc552", size = 66605, upload-time = "2025-08-10T21:27:03.335Z" },
{ url = "https://files.pythonhosted.org/packages/f7/69/00aafdb4e4509c2ca6064646cba9cd4b37933898f426756adb2cb92ebbed/kiwisolver-1.4.9-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:2635d352d67458b66fd0667c14cb1d4145e9560d503219034a18a87e971ce4f3", size = 64925, upload-time = "2025-08-10T21:27:04.339Z" },
@@ -210,6 +286,28 @@ version = "3.0.3"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/7e/99/7690b6d4034fffd95959cbe0c02de8deb3098cc577c67bb6a24fe5d7caa7/markupsafe-3.0.3.tar.gz", hash = "sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698", size = 80313, upload-time = "2025-09-27T18:37:40.426Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/38/2f/907b9c7bbba283e68f20259574b13d005c121a0fa4c175f9bed27c4597ff/markupsafe-3.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e1cf1972137e83c5d4c136c43ced9ac51d0e124706ee1c8aa8532c1287fa8795", size = 11622, upload-time = "2025-09-27T18:36:41.777Z" },
{ url = "https://files.pythonhosted.org/packages/9c/d9/5f7756922cdd676869eca1c4e3c0cd0df60ed30199ffd775e319089cb3ed/markupsafe-3.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:116bb52f642a37c115f517494ea5feb03889e04df47eeff5b130b1808ce7c219", size = 12029, upload-time = "2025-09-27T18:36:43.257Z" },
{ url = "https://files.pythonhosted.org/packages/00/07/575a68c754943058c78f30db02ee03a64b3c638586fba6a6dd56830b30a3/markupsafe-3.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:133a43e73a802c5562be9bbcd03d090aa5a1fe899db609c29e8c8d815c5f6de6", size = 24374, upload-time = "2025-09-27T18:36:44.508Z" },
{ url = "https://files.pythonhosted.org/packages/a9/21/9b05698b46f218fc0e118e1f8168395c65c8a2c750ae2bab54fc4bd4e0e8/markupsafe-3.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ccfcd093f13f0f0b7fdd0f198b90053bf7b2f02a3927a30e63f3ccc9df56b676", size = 22980, upload-time = "2025-09-27T18:36:45.385Z" },
{ url = "https://files.pythonhosted.org/packages/7f/71/544260864f893f18b6827315b988c146b559391e6e7e8f7252839b1b846a/markupsafe-3.0.3-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:509fa21c6deb7a7a273d629cf5ec029bc209d1a51178615ddf718f5918992ab9", size = 21990, upload-time = "2025-09-27T18:36:46.916Z" },
{ url = "https://files.pythonhosted.org/packages/c2/28/b50fc2f74d1ad761af2f5dcce7492648b983d00a65b8c0e0cb457c82ebbe/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a4afe79fb3de0b7097d81da19090f4df4f8d3a2b3adaa8764138aac2e44f3af1", size = 23784, upload-time = "2025-09-27T18:36:47.884Z" },
{ url = "https://files.pythonhosted.org/packages/ed/76/104b2aa106a208da8b17a2fb72e033a5a9d7073c68f7e508b94916ed47a9/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:795e7751525cae078558e679d646ae45574b47ed6e7771863fcc079a6171a0fc", size = 21588, upload-time = "2025-09-27T18:36:48.82Z" },
{ url = "https://files.pythonhosted.org/packages/b5/99/16a5eb2d140087ebd97180d95249b00a03aa87e29cc224056274f2e45fd6/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8485f406a96febb5140bfeca44a73e3ce5116b2501ac54fe953e488fb1d03b12", size = 23041, upload-time = "2025-09-27T18:36:49.797Z" },
{ url = "https://files.pythonhosted.org/packages/19/bc/e7140ed90c5d61d77cea142eed9f9c303f4c4806f60a1044c13e3f1471d0/markupsafe-3.0.3-cp313-cp313-win32.whl", hash = "sha256:bdd37121970bfd8be76c5fb069c7751683bdf373db1ed6c010162b2a130248ed", size = 14543, upload-time = "2025-09-27T18:36:51.584Z" },
{ url = "https://files.pythonhosted.org/packages/05/73/c4abe620b841b6b791f2edc248f556900667a5a1cf023a6646967ae98335/markupsafe-3.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:9a1abfdc021a164803f4d485104931fb8f8c1efd55bc6b748d2f5774e78b62c5", size = 15113, upload-time = "2025-09-27T18:36:52.537Z" },
{ url = "https://files.pythonhosted.org/packages/f0/3a/fa34a0f7cfef23cf9500d68cb7c32dd64ffd58a12b09225fb03dd37d5b80/markupsafe-3.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:7e68f88e5b8799aa49c85cd116c932a1ac15caaa3f5db09087854d218359e485", size = 13911, upload-time = "2025-09-27T18:36:53.513Z" },
{ url = "https://files.pythonhosted.org/packages/e4/d7/e05cd7efe43a88a17a37b3ae96e79a19e846f3f456fe79c57ca61356ef01/markupsafe-3.0.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:218551f6df4868a8d527e3062d0fb968682fe92054e89978594c28e642c43a73", size = 11658, upload-time = "2025-09-27T18:36:54.819Z" },
{ url = "https://files.pythonhosted.org/packages/99/9e/e412117548182ce2148bdeacdda3bb494260c0b0184360fe0d56389b523b/markupsafe-3.0.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3524b778fe5cfb3452a09d31e7b5adefeea8c5be1d43c4f810ba09f2ceb29d37", size = 12066, upload-time = "2025-09-27T18:36:55.714Z" },
{ url = "https://files.pythonhosted.org/packages/bc/e6/fa0ffcda717ef64a5108eaa7b4f5ed28d56122c9a6d70ab8b72f9f715c80/markupsafe-3.0.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4e885a3d1efa2eadc93c894a21770e4bc67899e3543680313b09f139e149ab19", size = 25639, upload-time = "2025-09-27T18:36:56.908Z" },
{ url = "https://files.pythonhosted.org/packages/96/ec/2102e881fe9d25fc16cb4b25d5f5cde50970967ffa5dddafdb771237062d/markupsafe-3.0.3-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8709b08f4a89aa7586de0aadc8da56180242ee0ada3999749b183aa23df95025", size = 23569, upload-time = "2025-09-27T18:36:57.913Z" },
{ url = "https://files.pythonhosted.org/packages/4b/30/6f2fce1f1f205fc9323255b216ca8a235b15860c34b6798f810f05828e32/markupsafe-3.0.3-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b8512a91625c9b3da6f127803b166b629725e68af71f8184ae7e7d54686a56d6", size = 23284, upload-time = "2025-09-27T18:36:58.833Z" },
{ url = "https://files.pythonhosted.org/packages/58/47/4a0ccea4ab9f5dcb6f79c0236d954acb382202721e704223a8aafa38b5c8/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9b79b7a16f7fedff2495d684f2b59b0457c3b493778c9eed31111be64d58279f", size = 24801, upload-time = "2025-09-27T18:36:59.739Z" },
{ url = "https://files.pythonhosted.org/packages/6a/70/3780e9b72180b6fecb83a4814d84c3bf4b4ae4bf0b19c27196104149734c/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:12c63dfb4a98206f045aa9563db46507995f7ef6d83b2f68eda65c307c6829eb", size = 22769, upload-time = "2025-09-27T18:37:00.719Z" },
{ url = "https://files.pythonhosted.org/packages/98/c5/c03c7f4125180fc215220c035beac6b9cb684bc7a067c84fc69414d315f5/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8f71bc33915be5186016f675cd83a1e08523649b0e33efdb898db577ef5bb009", size = 23642, upload-time = "2025-09-27T18:37:01.673Z" },
{ url = "https://files.pythonhosted.org/packages/80/d6/2d1b89f6ca4bff1036499b1e29a1d02d282259f3681540e16563f27ebc23/markupsafe-3.0.3-cp313-cp313t-win32.whl", hash = "sha256:69c0b73548bc525c8cb9a251cddf1931d1db4d2258e9599c28c07ef3580ef354", size = 14612, upload-time = "2025-09-27T18:37:02.639Z" },
{ url = "https://files.pythonhosted.org/packages/2b/98/e48a4bfba0a0ffcf9925fe2d69240bfaa19c6f7507b8cd09c70684a53c1e/markupsafe-3.0.3-cp313-cp313t-win_amd64.whl", hash = "sha256:1b4b79e8ebf6b55351f0d91fe80f893b4743f104bff22e90697db1590e47a218", size = 15200, upload-time = "2025-09-27T18:37:03.582Z" },
{ url = "https://files.pythonhosted.org/packages/0e/72/e3cc540f351f316e9ed0f092757459afbc595824ca724cbc5a5d4263713f/markupsafe-3.0.3-cp313-cp313t-win_arm64.whl", hash = "sha256:ad2cf8aa28b8c020ab2fc8287b0f823d0a7d8630784c31e9ee5edea20f406287", size = 13973, upload-time = "2025-09-27T18:37:04.929Z" },
{ url = "https://files.pythonhosted.org/packages/33/8a/8e42d4838cd89b7dde187011e97fe6c3af66d8c044997d2183fbd6d31352/markupsafe-3.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:eaa9599de571d72e2daf60164784109f19978b327a3910d3e9de8c97b5b70cfe", size = 11619, upload-time = "2025-09-27T18:37:06.342Z" },
{ url = "https://files.pythonhosted.org/packages/b5/64/7660f8a4a8e53c924d0fa05dc3a55c9cee10bbd82b11c5afb27d44b096ce/markupsafe-3.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c47a551199eb8eb2121d4f0f15ae0f923d31350ab9280078d1e5f12b249e0026", size = 12029, upload-time = "2025-09-27T18:37:07.213Z" },
{ url = "https://files.pythonhosted.org/packages/da/ef/e648bfd021127bef5fa12e1720ffed0c6cbb8310c8d9bea7266337ff06de/markupsafe-3.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f34c41761022dd093b4b6896d4810782ffbabe30f2d443ff5f083e0cbbb8c737", size = 24408, upload-time = "2025-09-27T18:37:09.572Z" },
@@ -251,6 +349,20 @@ dependencies = [
]
sdist = { url = "https://files.pythonhosted.org/packages/8a/76/d3c6e3a13fe484ebe7718d14e269c9569c4eb0020a968a327acb3b9a8fe6/matplotlib-3.10.8.tar.gz", hash = "sha256:2299372c19d56bcd35cf05a2738308758d32b9eaed2371898d8f5bd33f084aa3", size = 34806269, upload-time = "2025-12-10T22:56:51.155Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/3d/b9/15fd5541ef4f5b9a17eefd379356cf12175fe577424e7b1d80676516031a/matplotlib-3.10.8-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:3f2e409836d7f5ac2f1c013110a4d50b9f7edc26328c108915f9075d7d7a91b6", size = 8261076, upload-time = "2025-12-10T22:55:44.648Z" },
{ url = "https://files.pythonhosted.org/packages/8d/a0/2ba3473c1b66b9c74dc7107c67e9008cb1782edbe896d4c899d39ae9cf78/matplotlib-3.10.8-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:56271f3dac49a88d7fca5060f004d9d22b865f743a12a23b1e937a0be4818ee1", size = 8148794, upload-time = "2025-12-10T22:55:46.252Z" },
{ url = "https://files.pythonhosted.org/packages/75/97/a471f1c3eb1fd6f6c24a31a5858f443891d5127e63a7788678d14e249aea/matplotlib-3.10.8-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:a0a7f52498f72f13d4a25ea70f35f4cb60642b466cbb0a9be951b5bc3f45a486", size = 8718474, upload-time = "2025-12-10T22:55:47.864Z" },
{ url = "https://files.pythonhosted.org/packages/01/be/cd478f4b66f48256f42927d0acbcd63a26a893136456cd079c0cc24fbabf/matplotlib-3.10.8-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:646d95230efb9ca614a7a594d4fcacde0ac61d25e37dd51710b36477594963ce", size = 9549637, upload-time = "2025-12-10T22:55:50.048Z" },
{ url = "https://files.pythonhosted.org/packages/5d/7c/8dc289776eae5109e268c4fb92baf870678dc048a25d4ac903683b86d5bf/matplotlib-3.10.8-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f89c151aab2e2e23cb3fe0acad1e8b82841fd265379c4cecd0f3fcb34c15e0f6", size = 9613678, upload-time = "2025-12-10T22:55:52.21Z" },
{ url = "https://files.pythonhosted.org/packages/64/40/37612487cc8a437d4dd261b32ca21fe2d79510fe74af74e1f42becb1bdb8/matplotlib-3.10.8-cp313-cp313-win_amd64.whl", hash = "sha256:e8ea3e2d4066083e264e75c829078f9e149fa119d27e19acd503de65e0b13149", size = 8142686, upload-time = "2025-12-10T22:55:54.253Z" },
{ url = "https://files.pythonhosted.org/packages/66/52/8d8a8730e968185514680c2a6625943f70269509c3dcfc0dcf7d75928cb8/matplotlib-3.10.8-cp313-cp313-win_arm64.whl", hash = "sha256:c108a1d6fa78a50646029cb6d49808ff0fc1330fda87fa6f6250c6b5369b6645", size = 8012917, upload-time = "2025-12-10T22:55:56.268Z" },
{ url = "https://files.pythonhosted.org/packages/b5/27/51fe26e1062f298af5ef66343d8ef460e090a27fea73036c76c35821df04/matplotlib-3.10.8-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:ad3d9833a64cf48cc4300f2b406c3d0f4f4724a91c0bd5640678a6ba7c102077", size = 8305679, upload-time = "2025-12-10T22:55:57.856Z" },
{ url = "https://files.pythonhosted.org/packages/2c/1e/4de865bc591ac8e3062e835f42dd7fe7a93168d519557837f0e37513f629/matplotlib-3.10.8-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:eb3823f11823deade26ce3b9f40dcb4a213da7a670013929f31d5f5ed1055b22", size = 8198336, upload-time = "2025-12-10T22:55:59.371Z" },
{ url = "https://files.pythonhosted.org/packages/c6/cb/2f7b6e75fb4dce87ef91f60cac4f6e34f4c145ab036a22318ec837971300/matplotlib-3.10.8-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d9050fee89a89ed57b4fb2c1bfac9a3d0c57a0d55aed95949eedbc42070fea39", size = 8731653, upload-time = "2025-12-10T22:56:01.032Z" },
{ url = "https://files.pythonhosted.org/packages/46/b3/bd9c57d6ba670a37ab31fb87ec3e8691b947134b201f881665b28cc039ff/matplotlib-3.10.8-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b44d07310e404ba95f8c25aa5536f154c0a8ec473303535949e52eb71d0a1565", size = 9561356, upload-time = "2025-12-10T22:56:02.95Z" },
{ url = "https://files.pythonhosted.org/packages/c0/3d/8b94a481456dfc9dfe6e39e93b5ab376e50998cddfd23f4ae3b431708f16/matplotlib-3.10.8-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:0a33deb84c15ede243aead39f77e990469fff93ad1521163305095b77b72ce4a", size = 9614000, upload-time = "2025-12-10T22:56:05.411Z" },
{ url = "https://files.pythonhosted.org/packages/bd/cd/bc06149fe5585ba800b189a6a654a75f1f127e8aab02fd2be10df7fa500c/matplotlib-3.10.8-cp313-cp313t-win_amd64.whl", hash = "sha256:3a48a78d2786784cc2413e57397981fb45c79e968d99656706018d6e62e57958", size = 8220043, upload-time = "2025-12-10T22:56:07.551Z" },
{ url = "https://files.pythonhosted.org/packages/e3/de/b22cf255abec916562cc04eef457c13e58a1990048de0c0c3604d082355e/matplotlib-3.10.8-cp313-cp313t-win_arm64.whl", hash = "sha256:15d30132718972c2c074cd14638c7f4592bd98719e2308bccea40e0538bc0cb5", size = 8062075, upload-time = "2025-12-10T22:56:09.178Z" },
{ url = "https://files.pythonhosted.org/packages/3c/43/9c0ff7a2f11615e516c3b058e1e6e8f9614ddeca53faca06da267c48345d/matplotlib-3.10.8-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:b53285e65d4fa4c86399979e956235deb900be5baa7fc1218ea67fbfaeaadd6f", size = 8262481, upload-time = "2025-12-10T22:56:10.885Z" },
{ url = "https://files.pythonhosted.org/packages/6f/ca/e8ae28649fcdf039fda5ef554b40a95f50592a3c47e6f7270c9561c12b07/matplotlib-3.10.8-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:32f8dce744be5569bebe789e46727946041199030db8aeb2954d26013a0eb26b", size = 8151473, upload-time = "2025-12-10T22:56:12.377Z" },
{ url = "https://files.pythonhosted.org/packages/f1/6f/009d129ae70b75e88cbe7e503a12a4c0670e08ed748a902c2568909e9eb5/matplotlib-3.10.8-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4cf267add95b1c88300d96ca837833d4112756045364f5c734a2276038dae27d", size = 9553896, upload-time = "2025-12-10T22:56:14.432Z" },
@@ -291,6 +403,27 @@ version = "2.4.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/a4/7a/6a3d14e205d292b738db449d0de649b373a59edb0d0b4493821d0a3e8718/numpy-2.4.0.tar.gz", hash = "sha256:6e504f7b16118198f138ef31ba24d985b124c2c469fe8467007cf30fd992f934", size = 20685720, upload-time = "2025-12-20T16:18:19.023Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/a7/0d/853fd96372eda07c824d24adf02e8bc92bb3731b43a9b2a39161c3667cc4/numpy-2.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a152d86a3ae00ba5f47b3acf3b827509fd0b6cb7d3259665e63dafbad22a75ea", size = 16649088, upload-time = "2025-12-20T16:16:31.421Z" },
{ url = "https://files.pythonhosted.org/packages/e3/37/cc636f1f2a9f585434e20a3e6e63422f70bfe4f7f6698e941db52ea1ac9a/numpy-2.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:39b19251dec4de8ff8496cd0806cbe27bf0684f765abb1f4809554de93785f2d", size = 12364065, upload-time = "2025-12-20T16:16:33.491Z" },
{ url = "https://files.pythonhosted.org/packages/ed/69/0b78f37ca3690969beee54103ce5f6021709134e8020767e93ba691a72f1/numpy-2.4.0-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:009bd0ea12d3c784b6639a8457537016ce5172109e585338e11334f6a7bb88ee", size = 5192640, upload-time = "2025-12-20T16:16:35.636Z" },
{ url = "https://files.pythonhosted.org/packages/1d/2a/08569f8252abf590294dbb09a430543ec8f8cc710383abfb3e75cc73aeda/numpy-2.4.0-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:5fe44e277225fd3dff6882d86d3d447205d43532c3627313d17e754fb3905a0e", size = 6541556, upload-time = "2025-12-20T16:16:37.276Z" },
{ url = "https://files.pythonhosted.org/packages/93/e9/a949885a4e177493d61519377952186b6cbfdf1d6002764c664ba28349b5/numpy-2.4.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f935c4493eda9069851058fa0d9e39dbf6286be690066509305e52912714dbb2", size = 14396562, upload-time = "2025-12-20T16:16:38.953Z" },
{ url = "https://files.pythonhosted.org/packages/99/98/9d4ad53b0e9ef901c2ef1d550d2136f5ac42d3fd2988390a6def32e23e48/numpy-2.4.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8cfa5f29a695cb7438965e6c3e8d06e0416060cf0d709c1b1c1653a939bf5c2a", size = 16351719, upload-time = "2025-12-20T16:16:41.503Z" },
{ url = "https://files.pythonhosted.org/packages/28/de/5f3711a38341d6e8dd619f6353251a0cdd07f3d6d101a8fd46f4ef87f895/numpy-2.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ba0cb30acd3ef11c94dc27fbfba68940652492bc107075e7ffe23057f9425681", size = 16176053, upload-time = "2025-12-20T16:16:44.552Z" },
{ url = "https://files.pythonhosted.org/packages/2a/5b/2a3753dc43916501b4183532e7ace862e13211042bceafa253afb5c71272/numpy-2.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:60e8c196cd82cbbd4f130b5290007e13e6de3eca79f0d4d38014769d96a7c475", size = 18277859, upload-time = "2025-12-20T16:16:47.174Z" },
{ url = "https://files.pythonhosted.org/packages/2c/c5/a18bcdd07a941db3076ef489d036ab16d2bfc2eae0cf27e5a26e29189434/numpy-2.4.0-cp313-cp313-win32.whl", hash = "sha256:5f48cb3e88fbc294dc90e215d86fbaf1c852c63dbdb6c3a3e63f45c4b57f7344", size = 5953849, upload-time = "2025-12-20T16:16:49.554Z" },
{ url = "https://files.pythonhosted.org/packages/4f/f1/719010ff8061da6e8a26e1980cf090412d4f5f8060b31f0c45d77dd67a01/numpy-2.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:a899699294f28f7be8992853c0c60741f16ff199205e2e6cdca155762cbaa59d", size = 12302840, upload-time = "2025-12-20T16:16:51.227Z" },
{ url = "https://files.pythonhosted.org/packages/f5/5a/b3d259083ed8b4d335270c76966cb6cf14a5d1b69e1a608994ac57a659e6/numpy-2.4.0-cp313-cp313-win_arm64.whl", hash = "sha256:9198f447e1dc5647d07c9a6bbe2063cc0132728cc7175b39dbc796da5b54920d", size = 10308509, upload-time = "2025-12-20T16:16:53.313Z" },
{ url = "https://files.pythonhosted.org/packages/31/01/95edcffd1bb6c0633df4e808130545c4f07383ab629ac7e316fb44fff677/numpy-2.4.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:74623f2ab5cc3f7c886add4f735d1031a1d2be4a4ae63c0546cfd74e7a31ddf6", size = 12491815, upload-time = "2025-12-20T16:16:55.496Z" },
{ url = "https://files.pythonhosted.org/packages/59/ea/5644b8baa92cc1c7163b4b4458c8679852733fa74ca49c942cfa82ded4e0/numpy-2.4.0-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:0804a8e4ab070d1d35496e65ffd3cf8114c136a2b81f61dfab0de4b218aacfd5", size = 5320321, upload-time = "2025-12-20T16:16:57.468Z" },
{ url = "https://files.pythonhosted.org/packages/26/4e/e10938106d70bc21319bd6a86ae726da37edc802ce35a3a71ecdf1fdfe7f/numpy-2.4.0-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:02a2038eb27f9443a8b266a66911e926566b5a6ffd1a689b588f7f35b81e7dc3", size = 6641635, upload-time = "2025-12-20T16:16:59.379Z" },
{ url = "https://files.pythonhosted.org/packages/b3/8d/a8828e3eaf5c0b4ab116924df82f24ce3416fa38d0674d8f708ddc6c8aac/numpy-2.4.0-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1889b3a3f47a7b5bee16bc25a2145bd7cb91897f815ce3499db64c7458b6d91d", size = 14456053, upload-time = "2025-12-20T16:17:01.768Z" },
{ url = "https://files.pythonhosted.org/packages/68/a1/17d97609d87d4520aa5ae2dcfb32305654550ac6a35effb946d303e594ce/numpy-2.4.0-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:85eef4cb5625c47ee6425c58a3502555e10f45ee973da878ac8248ad58c136f3", size = 16401702, upload-time = "2025-12-20T16:17:04.235Z" },
{ url = "https://files.pythonhosted.org/packages/18/32/0f13c1b2d22bea1118356b8b963195446f3af124ed7a5adfa8fdecb1b6ca/numpy-2.4.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6dc8b7e2f4eb184b37655195f421836cfae6f58197b67e3ffc501f1333d993fa", size = 16242493, upload-time = "2025-12-20T16:17:06.856Z" },
{ url = "https://files.pythonhosted.org/packages/ae/23/48f21e3d309fbc137c068a1475358cbd3a901b3987dcfc97a029ab3068e2/numpy-2.4.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:44aba2f0cafd287871a495fb3163408b0bd25bbce135c6f621534a07f4f7875c", size = 18324222, upload-time = "2025-12-20T16:17:09.392Z" },
{ url = "https://files.pythonhosted.org/packages/ac/52/41f3d71296a3dcaa4f456aaa3c6fc8e745b43d0552b6bde56571bb4b4a0f/numpy-2.4.0-cp313-cp313t-win32.whl", hash = "sha256:20c115517513831860c573996e395707aa9fb691eb179200125c250e895fcd93", size = 6076216, upload-time = "2025-12-20T16:17:11.437Z" },
{ url = "https://files.pythonhosted.org/packages/35/ff/46fbfe60ab0710d2a2b16995f708750307d30eccbb4c38371ea9e986866e/numpy-2.4.0-cp313-cp313t-win_amd64.whl", hash = "sha256:b48e35f4ab6f6a7597c46e301126ceba4c44cd3280e3750f85db48b082624fa4", size = 12444263, upload-time = "2025-12-20T16:17:13.182Z" },
{ url = "https://files.pythonhosted.org/packages/a3/e3/9189ab319c01d2ed556c932ccf55064c5d75bb5850d1df7a482ce0badead/numpy-2.4.0-cp313-cp313t-win_arm64.whl", hash = "sha256:4d1cfce39e511069b11e67cd0bd78ceff31443b7c9e5c04db73c7a19f572967c", size = 10378265, upload-time = "2025-12-20T16:17:15.211Z" },
{ url = "https://files.pythonhosted.org/packages/ab/ed/52eac27de39d5e5a6c9aadabe672bc06f55e24a3d9010cd1183948055d76/numpy-2.4.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:c95eb6db2884917d86cde0b4d4cf31adf485c8ec36bf8696dd66fa70de96f36b", size = 16647476, upload-time = "2025-12-20T16:17:17.671Z" },
{ url = "https://files.pythonhosted.org/packages/77/c0/990ce1b7fcd4e09aeaa574e2a0a839589e4b08b2ca68070f1acb1fea6736/numpy-2.4.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:65167da969cd1ec3a1df31cb221ca3a19a8aaa25370ecb17d428415e93c1935e", size = 12374563, upload-time = "2025-12-20T16:17:20.216Z" },
{ url = "https://files.pythonhosted.org/packages/37/7c/8c5e389c6ae8f5fd2277a988600d79e9625db3fff011a2d87ac80b881a4c/numpy-2.4.0-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:3de19cfecd1465d0dcf8a5b5ea8b3155b42ed0b639dba4b71e323d74f2a3be5e", size = 5203107, upload-time = "2025-12-20T16:17:22.47Z" },
@@ -355,7 +488,7 @@ name = "nvidia-cudnn-cu13"
version = "9.13.0.50"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "nvidia-cublas", marker = "sys_platform == 'linux'" },
{ name = "nvidia-cublas", marker = "sys_platform == 'linux' or sys_platform == 'win32'" },
]
wheels = [
{ url = "https://files.pythonhosted.org/packages/8a/9c/9e99c00dc23db324244ec257d1e84d79539202ee2f185dee2c1fa97c9549/nvidia_cudnn_cu13-9.13.0.50-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:33f0aa0b64230101b348648fd0693342188071d3f8a137c0cf50051c24b3584b", size = 412337597, upload-time = "2025-09-04T20:22:31.535Z" },
@@ -367,7 +500,7 @@ name = "nvidia-cufft"
version = "12.0.0.15"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "nvidia-nvjitlink", marker = "sys_platform == 'linux'" },
{ name = "nvidia-nvjitlink", marker = "sys_platform == 'linux' or sys_platform == 'win32'" },
]
wheels = [
{ url = "https://files.pythonhosted.org/packages/9b/e9/4e49b1baf6899e42eeec324a49d7aa2219fec42076327c4e468000dd375a/nvidia_cufft-12.0.0.15-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:1885731254835797572ff075f3daf43a2a0a2801210dea26971940dae7e1a367", size = 214053580, upload-time = "2025-08-04T10:20:45.781Z" },
@@ -397,9 +530,9 @@ name = "nvidia-cusolver"
version = "12.0.3.29"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "nvidia-cublas", marker = "sys_platform == 'linux'" },
{ name = "nvidia-cusparse", marker = "sys_platform == 'linux'" },
{ name = "nvidia-nvjitlink", marker = "sys_platform == 'linux'" },
{ name = "nvidia-cublas", marker = "sys_platform == 'linux' or sys_platform == 'win32'" },
{ name = "nvidia-cusparse", marker = "sys_platform == 'linux' or sys_platform == 'win32'" },
{ name = "nvidia-nvjitlink", marker = "sys_platform == 'linux' or sys_platform == 'win32'" },
]
wheels = [
{ url = "https://files.pythonhosted.org/packages/a7/bb/2e60de9bb1f0c3395eabd91ccad00f4ba3ef736dc9190a158a9d268419f5/nvidia_cusolver-12.0.3.29-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:3bb6e65ce0beaeafdd069b320246e8f17c1cd30ddb27a0539143a3706733a4d8", size = 193104180, upload-time = "2025-08-04T10:22:19.821Z" },
@@ -411,7 +544,7 @@ name = "nvidia-cusparse"
version = "12.6.2.49"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "nvidia-nvjitlink", marker = "sys_platform == 'linux'" },
{ name = "nvidia-nvjitlink", marker = "sys_platform == 'linux' or sys_platform == 'win32'" },
]
wheels = [
{ url = "https://files.pythonhosted.org/packages/fc/30/f32023427f2ef4ec27e8293dfddb5068de566912cd0a45eccfd400017a62/nvidia_cusparse-12.6.2.49-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:5d3269c19283a0057fb5ebfb003ae2a10c97a28a6958f4238354826b055827c7", size = 155888587, upload-time = "2025-08-04T10:23:04.091Z" },
@@ -495,6 +628,31 @@ version = "12.1.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/d0/02/d52c733a2452ef1ffcc123b68e6606d07276b0e358db70eabad7e40042b7/pillow-12.1.0.tar.gz", hash = "sha256:5c5ae0a06e9ea030ab786b0251b32c7e4ce10e58d983c0d5c56029455180b5b9", size = 46977283, upload-time = "2026-01-02T09:13:29.892Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/dd/c7/2530a4aa28248623e9d7f27316b42e27c32ec410f695929696f2e0e4a778/pillow-12.1.0-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:7b5dd7cbae20285cdb597b10eb5a2c13aa9de6cde9bb64a3c1317427b1db1ae1", size = 4062543, upload-time = "2026-01-02T09:11:31.566Z" },
{ url = "https://files.pythonhosted.org/packages/8f/1f/40b8eae823dc1519b87d53c30ed9ef085506b05281d313031755c1705f73/pillow-12.1.0-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:29a4cef9cb672363926f0470afc516dbf7305a14d8c54f7abbb5c199cd8f8179", size = 4138373, upload-time = "2026-01-02T09:11:33.367Z" },
{ url = "https://files.pythonhosted.org/packages/d4/77/6fa60634cf06e52139fd0e89e5bbf055e8166c691c42fb162818b7fda31d/pillow-12.1.0-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:681088909d7e8fa9e31b9799aaa59ba5234c58e5e4f1951b4c4d1082a2e980e0", size = 3601241, upload-time = "2026-01-02T09:11:35.011Z" },
{ url = "https://files.pythonhosted.org/packages/4f/bf/28ab865de622e14b747f0cd7877510848252d950e43002e224fb1c9ababf/pillow-12.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:983976c2ab753166dc66d36af6e8ec15bb511e4a25856e2227e5f7e00a160587", size = 5262410, upload-time = "2026-01-02T09:11:36.682Z" },
{ url = "https://files.pythonhosted.org/packages/1c/34/583420a1b55e715937a85bd48c5c0991598247a1fd2eb5423188e765ea02/pillow-12.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:db44d5c160a90df2d24a24760bbd37607d53da0b34fb546c4c232af7192298ac", size = 4657312, upload-time = "2026-01-02T09:11:38.535Z" },
{ url = "https://files.pythonhosted.org/packages/1d/fd/f5a0896839762885b3376ff04878f86ab2b097c2f9a9cdccf4eda8ba8dc0/pillow-12.1.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:6b7a9d1db5dad90e2991645874f708e87d9a3c370c243c2d7684d28f7e133e6b", size = 6232605, upload-time = "2026-01-02T09:11:40.602Z" },
{ url = "https://files.pythonhosted.org/packages/98/aa/938a09d127ac1e70e6ed467bd03834350b33ef646b31edb7452d5de43792/pillow-12.1.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:6258f3260986990ba2fa8a874f8b6e808cf5abb51a94015ca3dc3c68aa4f30ea", size = 8041617, upload-time = "2026-01-02T09:11:42.721Z" },
{ url = "https://files.pythonhosted.org/packages/17/e8/538b24cb426ac0186e03f80f78bc8dc7246c667f58b540bdd57c71c9f79d/pillow-12.1.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e115c15e3bc727b1ca3e641a909f77f8ca72a64fff150f666fcc85e57701c26c", size = 6346509, upload-time = "2026-01-02T09:11:44.955Z" },
{ url = "https://files.pythonhosted.org/packages/01/9a/632e58ec89a32738cabfd9ec418f0e9898a2b4719afc581f07c04a05e3c9/pillow-12.1.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6741e6f3074a35e47c77b23a4e4f2d90db3ed905cb1c5e6e0d49bff2045632bc", size = 7038117, upload-time = "2026-01-02T09:11:46.736Z" },
{ url = "https://files.pythonhosted.org/packages/c7/a2/d40308cf86eada842ca1f3ffa45d0ca0df7e4ab33c83f81e73f5eaed136d/pillow-12.1.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:935b9d1aed48fcfb3f838caac506f38e29621b44ccc4f8a64d575cb1b2a88644", size = 6460151, upload-time = "2026-01-02T09:11:48.625Z" },
{ url = "https://files.pythonhosted.org/packages/f1/88/f5b058ad6453a085c5266660a1417bdad590199da1b32fb4efcff9d33b05/pillow-12.1.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5fee4c04aad8932da9f8f710af2c1a15a83582cfb884152a9caa79d4efcdbf9c", size = 7164534, upload-time = "2026-01-02T09:11:50.445Z" },
{ url = "https://files.pythonhosted.org/packages/19/ce/c17334caea1db789163b5d855a5735e47995b0b5dc8745e9a3605d5f24c0/pillow-12.1.0-cp313-cp313-win32.whl", hash = "sha256:a786bf667724d84aa29b5db1c61b7bfdde380202aaca12c3461afd6b71743171", size = 6332551, upload-time = "2026-01-02T09:11:52.234Z" },
{ url = "https://files.pythonhosted.org/packages/e5/07/74a9d941fa45c90a0d9465098fe1ec85de3e2afbdc15cc4766622d516056/pillow-12.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:461f9dfdafa394c59cd6d818bdfdbab4028b83b02caadaff0ffd433faf4c9a7a", size = 7040087, upload-time = "2026-01-02T09:11:54.822Z" },
{ url = "https://files.pythonhosted.org/packages/88/09/c99950c075a0e9053d8e880595926302575bc742b1b47fe1bbcc8d388d50/pillow-12.1.0-cp313-cp313-win_arm64.whl", hash = "sha256:9212d6b86917a2300669511ed094a9406888362e085f2431a7da985a6b124f45", size = 2452470, upload-time = "2026-01-02T09:11:56.522Z" },
{ url = "https://files.pythonhosted.org/packages/b5/ba/970b7d85ba01f348dee4d65412476321d40ee04dcb51cd3735b9dc94eb58/pillow-12.1.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:00162e9ca6d22b7c3ee8e61faa3c3253cd19b6a37f126cad04f2f88b306f557d", size = 5264816, upload-time = "2026-01-02T09:11:58.227Z" },
{ url = "https://files.pythonhosted.org/packages/10/60/650f2fb55fdba7a510d836202aa52f0baac633e50ab1cf18415d332188fb/pillow-12.1.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:7d6daa89a00b58c37cb1747ec9fb7ac3bc5ffd5949f5888657dfddde6d1312e0", size = 4660472, upload-time = "2026-01-02T09:12:00.798Z" },
{ url = "https://files.pythonhosted.org/packages/2b/c0/5273a99478956a099d533c4f46cbaa19fd69d606624f4334b85e50987a08/pillow-12.1.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:e2479c7f02f9d505682dc47df8c0ea1fc5e264c4d1629a5d63fe3e2334b89554", size = 6268974, upload-time = "2026-01-02T09:12:02.572Z" },
{ url = "https://files.pythonhosted.org/packages/b4/26/0bf714bc2e73d5267887d47931d53c4ceeceea6978148ed2ab2a4e6463c4/pillow-12.1.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f188d580bd870cda1e15183790d1cc2fa78f666e76077d103edf048eed9c356e", size = 8073070, upload-time = "2026-01-02T09:12:04.75Z" },
{ url = "https://files.pythonhosted.org/packages/43/cf/1ea826200de111a9d65724c54f927f3111dc5ae297f294b370a670c17786/pillow-12.1.0-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0fde7ec5538ab5095cc02df38ee99b0443ff0e1c847a045554cf5f9af1f4aa82", size = 6380176, upload-time = "2026-01-02T09:12:06.626Z" },
{ url = "https://files.pythonhosted.org/packages/03/e0/7938dd2b2013373fd85d96e0f38d62b7a5a262af21ac274250c7ca7847c9/pillow-12.1.0-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0ed07dca4a8464bada6139ab38f5382f83e5f111698caf3191cb8dbf27d908b4", size = 7067061, upload-time = "2026-01-02T09:12:08.624Z" },
{ url = "https://files.pythonhosted.org/packages/86/ad/a2aa97d37272a929a98437a8c0ac37b3cf012f4f8721e1bd5154699b2518/pillow-12.1.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:f45bd71d1fa5e5749587613037b172e0b3b23159d1c00ef2fc920da6f470e6f0", size = 6491824, upload-time = "2026-01-02T09:12:10.488Z" },
{ url = "https://files.pythonhosted.org/packages/a4/44/80e46611b288d51b115826f136fb3465653c28f491068a72d3da49b54cd4/pillow-12.1.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:277518bf4fe74aa91489e1b20577473b19ee70fb97c374aa50830b279f25841b", size = 7190911, upload-time = "2026-01-02T09:12:12.772Z" },
{ url = "https://files.pythonhosted.org/packages/86/77/eacc62356b4cf81abe99ff9dbc7402750044aed02cfd6a503f7c6fc11f3e/pillow-12.1.0-cp313-cp313t-win32.whl", hash = "sha256:7315f9137087c4e0ee73a761b163fc9aa3b19f5f606a7fc08d83fd3e4379af65", size = 6336445, upload-time = "2026-01-02T09:12:14.775Z" },
{ url = "https://files.pythonhosted.org/packages/e7/3c/57d81d0b74d218706dafccb87a87ea44262c43eef98eb3b164fd000e0491/pillow-12.1.0-cp313-cp313t-win_amd64.whl", hash = "sha256:0ddedfaa8b5f0b4ffbc2fa87b556dc59f6bb4ecb14a53b33f9189713ae8053c0", size = 7045354, upload-time = "2026-01-02T09:12:16.599Z" },
{ url = "https://files.pythonhosted.org/packages/ac/82/8b9b97bba2e3576a340f93b044a3a3a09841170ab4c1eb0d5c93469fd32f/pillow-12.1.0-cp313-cp313t-win_arm64.whl", hash = "sha256:80941e6d573197a0c28f394753de529bb436b1ca990ed6e765cf42426abc39f8", size = 2454547, upload-time = "2026-01-02T09:12:18.704Z" },
{ url = "https://files.pythonhosted.org/packages/8c/87/bdf971d8bbcf80a348cc3bacfcb239f5882100fe80534b0ce67a784181d8/pillow-12.1.0-cp314-cp314-ios_13_0_arm64_iphoneos.whl", hash = "sha256:5cb7bc1966d031aec37ddb9dcf15c2da5b2e9f7cc3ca7c54473a20a927e1eb91", size = 4062533, upload-time = "2026-01-02T09:12:20.791Z" },
{ url = "https://files.pythonhosted.org/packages/ff/4f/5eb37a681c68d605eb7034c004875c81f86ec9ef51f5be4a63eadd58859a/pillow-12.1.0-cp314-cp314-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:97e9993d5ed946aba26baf9c1e8cf18adbab584b99f452ee72f7ee8acb882796", size = 4138546, upload-time = "2026-01-02T09:12:23.664Z" },
{ url = "https://files.pythonhosted.org/packages/11/6d/19a95acb2edbace40dcd582d077b991646b7083c41b98da4ed7555b59733/pillow-12.1.0-cp314-cp314-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:414b9a78e14ffeb98128863314e62c3f24b8a86081066625700b7985b3f529bd", size = 3601163, upload-time = "2026-01-02T09:12:26.338Z" },
@@ -554,6 +712,12 @@ version = "7.2.1"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/73/cb/09e5184fb5fc0358d110fc3ca7f6b1d033800734d34cac10f4136cfac10e/psutil-7.2.1.tar.gz", hash = "sha256:f7583aec590485b43ca601dd9cea0dcd65bd7bb21d30ef4ddbf4ea6b5ed1bdd3", size = 490253, upload-time = "2025-12-29T08:26:00.169Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/77/8e/f0c242053a368c2aa89584ecd1b054a18683f13d6e5a318fc9ec36582c94/psutil-7.2.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:ba9f33bb525b14c3ea563b2fd521a84d2fa214ec59e3e6a2858f78d0844dd60d", size = 129624, upload-time = "2025-12-29T08:26:04.255Z" },
{ url = "https://files.pythonhosted.org/packages/26/97/a58a4968f8990617decee234258a2b4fc7cd9e35668387646c1963e69f26/psutil-7.2.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:81442dac7abfc2f4f4385ea9e12ddf5a796721c0f6133260687fec5c3780fa49", size = 130132, upload-time = "2025-12-29T08:26:06.228Z" },
{ url = "https://files.pythonhosted.org/packages/db/6d/ed44901e830739af5f72a85fa7ec5ff1edea7f81bfbf4875e409007149bd/psutil-7.2.1-cp313-cp313t-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ea46c0d060491051d39f0d2cff4f98d5c72b288289f57a21556cc7d504db37fc", size = 180612, upload-time = "2025-12-29T08:26:08.276Z" },
{ url = "https://files.pythonhosted.org/packages/c7/65/b628f8459bca4efbfae50d4bf3feaab803de9a160b9d5f3bd9295a33f0c2/psutil-7.2.1-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:35630d5af80d5d0d49cfc4d64c1c13838baf6717a13effb35869a5919b854cdf", size = 183201, upload-time = "2025-12-29T08:26:10.622Z" },
{ url = "https://files.pythonhosted.org/packages/fb/23/851cadc9764edcc18f0effe7d0bf69f727d4cf2442deb4a9f78d4e4f30f2/psutil-7.2.1-cp313-cp313t-win_amd64.whl", hash = "sha256:923f8653416604e356073e6e0bccbe7c09990acef442def2f5640dd0faa9689f", size = 139081, upload-time = "2025-12-29T08:26:12.483Z" },
{ url = "https://files.pythonhosted.org/packages/59/82/d63e8494ec5758029f31c6cb06d7d161175d8281e91d011a4a441c8a43b5/psutil-7.2.1-cp313-cp313t-win_arm64.whl", hash = "sha256:cfbe6b40ca48019a51827f20d830887b3107a74a79b01ceb8cc8de4ccb17b672", size = 134767, upload-time = "2025-12-29T08:26:14.528Z" },
{ url = "https://files.pythonhosted.org/packages/05/c2/5fb764bd61e40e1fe756a44bd4c21827228394c17414ade348e28f83cd79/psutil-7.2.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:494c513ccc53225ae23eec7fe6e1482f1b8a44674241b54561f755a898650679", size = 129716, upload-time = "2025-12-29T08:26:16.017Z" },
{ url = "https://files.pythonhosted.org/packages/c9/d2/935039c20e06f615d9ca6ca0ab756cf8408a19d298ffaa08666bc18dc805/psutil-7.2.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:3fce5f92c22b00cdefd1645aa58ab4877a01679e901555067b1bd77039aa589f", size = 130133, upload-time = "2025-12-29T08:26:18.009Z" },
{ url = "https://files.pythonhosted.org/packages/77/69/19f1eb0e01d24c2b3eacbc2f78d3b5add8a89bf0bb69465bc8d563cc33de/psutil-7.2.1-cp314-cp314t-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:93f3f7b0bb07711b49626e7940d6fe52aa9940ad86e8f7e74842e73189712129", size = 181518, upload-time = "2025-12-29T08:26:20.241Z" },
@@ -597,6 +761,16 @@ version = "6.0.3"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f", size = 130960, upload-time = "2025-09-25T21:33:16.546Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/d1/11/0fd08f8192109f7169db964b5707a2f1e8b745d4e239b784a5a1dd80d1db/pyyaml-6.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8da9669d359f02c0b91ccc01cac4a67f16afec0dac22c2ad09f46bee0697eba8", size = 181669, upload-time = "2025-09-25T21:32:23.673Z" },
{ url = "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2283a07e2c21a2aa78d9c4442724ec1eb15f5e42a723b99cb3d822d48f5f7ad1", size = 173252, upload-time = "2025-09-25T21:32:25.149Z" },
{ url = "https://files.pythonhosted.org/packages/50/31/b20f376d3f810b9b2371e72ef5adb33879b25edb7a6d072cb7ca0c486398/pyyaml-6.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee2922902c45ae8ccada2c5b501ab86c36525b883eff4255313a253a3160861c", size = 767081, upload-time = "2025-09-25T21:32:26.575Z" },
{ url = "https://files.pythonhosted.org/packages/49/1e/a55ca81e949270d5d4432fbbd19dfea5321eda7c41a849d443dc92fd1ff7/pyyaml-6.0.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a33284e20b78bd4a18c8c2282d549d10bc8408a2a7ff57653c0cf0b9be0afce5", size = 841159, upload-time = "2025-09-25T21:32:27.727Z" },
{ url = "https://files.pythonhosted.org/packages/74/27/e5b8f34d02d9995b80abcef563ea1f8b56d20134d8f4e5e81733b1feceb2/pyyaml-6.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0f29edc409a6392443abf94b9cf89ce99889a1dd5376d94316ae5145dfedd5d6", size = 801626, upload-time = "2025-09-25T21:32:28.878Z" },
{ url = "https://files.pythonhosted.org/packages/f9/11/ba845c23988798f40e52ba45f34849aa8a1f2d4af4b798588010792ebad6/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f7057c9a337546edc7973c0d3ba84ddcdf0daa14533c2065749c9075001090e6", size = 753613, upload-time = "2025-09-25T21:32:30.178Z" },
{ url = "https://files.pythonhosted.org/packages/3d/e0/7966e1a7bfc0a45bf0a7fb6b98ea03fc9b8d84fa7f2229e9659680b69ee3/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:eda16858a3cab07b80edaf74336ece1f986ba330fdb8ee0d6c0d68fe82bc96be", size = 794115, upload-time = "2025-09-25T21:32:31.353Z" },
{ url = "https://files.pythonhosted.org/packages/de/94/980b50a6531b3019e45ddeada0626d45fa85cbe22300844a7983285bed3b/pyyaml-6.0.3-cp313-cp313-win32.whl", hash = "sha256:d0eae10f8159e8fdad514efdc92d74fd8d682c933a6dd088030f3834bc8e6b26", size = 137427, upload-time = "2025-09-25T21:32:32.58Z" },
{ url = "https://files.pythonhosted.org/packages/97/c9/39d5b874e8b28845e4ec2202b5da735d0199dbe5b8fb85f91398814a9a46/pyyaml-6.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:79005a0d97d5ddabfeeea4cf676af11e647e41d81c9a7722a193022accdb6b7c", size = 154090, upload-time = "2025-09-25T21:32:33.659Z" },
{ url = "https://files.pythonhosted.org/packages/73/e8/2bdf3ca2090f68bb3d75b44da7bbc71843b19c9f2b9cb9b0f4ab7a5a4329/pyyaml-6.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:5498cd1645aa724a7c71c8f378eb29ebe23da2fc0d7a08071d89469bf1d2defb", size = 140246, upload-time = "2025-09-25T21:32:34.663Z" },
{ url = "https://files.pythonhosted.org/packages/9d/8c/f4bd7f6465179953d3ac9bc44ac1a8a3e6122cf8ada906b4f96c60172d43/pyyaml-6.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:8d1fab6bb153a416f9aeb4b8763bc0f22a5586065f86f7664fc23339fc1c1fac", size = 181814, upload-time = "2025-09-25T21:32:35.712Z" },
{ url = "https://files.pythonhosted.org/packages/bd/9c/4d95bb87eb2063d20db7b60faa3840c1b18025517ae857371c4dd55a6b3a/pyyaml-6.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:34d5fcd24b8445fadc33f9cf348c1047101756fd760b4dacb5c3e99755703310", size = 173809, upload-time = "2025-09-25T21:32:36.789Z" },
{ url = "https://files.pythonhosted.org/packages/92/b5/47e807c2623074914e29dabd16cbbdd4bf5e9b2db9f8090fa64411fc5382/pyyaml-6.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:501a031947e3a9025ed4405a168e6ef5ae3126c59f90ce0cd6f2bfc477be31b7", size = 766454, upload-time = "2025-09-25T21:32:37.966Z" },
@@ -641,6 +815,26 @@ dependencies = [
]
sdist = { url = "https://files.pythonhosted.org/packages/0a/ca/d8ace4f98322d01abcd52d381134344bf7b431eba7ed8b42bdea5a3c2ac9/scipy-1.16.3.tar.gz", hash = "sha256:01e87659402762f43bd2fee13370553a17ada367d42e7487800bf2916535aecb", size = 30597883, upload-time = "2025-10-28T17:38:54.068Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/72/f1/57e8327ab1508272029e27eeef34f2302ffc156b69e7e233e906c2a5c379/scipy-1.16.3-cp313-cp313-macosx_10_14_x86_64.whl", hash = "sha256:d2ec56337675e61b312179a1ad124f5f570c00f920cc75e1000025451b88241c", size = 36617856, upload-time = "2025-10-28T17:33:31.375Z" },
{ url = "https://files.pythonhosted.org/packages/44/13/7e63cfba8a7452eb756306aa2fd9b37a29a323b672b964b4fdeded9a3f21/scipy-1.16.3-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:16b8bc35a4cc24db80a0ec836a9286d0e31b2503cb2fd7ff7fb0e0374a97081d", size = 28874306, upload-time = "2025-10-28T17:33:36.516Z" },
{ url = "https://files.pythonhosted.org/packages/15/65/3a9400efd0228a176e6ec3454b1fa998fbbb5a8defa1672c3f65706987db/scipy-1.16.3-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:5803c5fadd29de0cf27fa08ccbfe7a9e5d741bf63e4ab1085437266f12460ff9", size = 20865371, upload-time = "2025-10-28T17:33:42.094Z" },
{ url = "https://files.pythonhosted.org/packages/33/d7/eda09adf009a9fb81827194d4dd02d2e4bc752cef16737cc4ef065234031/scipy-1.16.3-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:b81c27fc41954319a943d43b20e07c40bdcd3ff7cf013f4fb86286faefe546c4", size = 23524877, upload-time = "2025-10-28T17:33:48.483Z" },
{ url = "https://files.pythonhosted.org/packages/7d/6b/3f911e1ebc364cb81320223a3422aab7d26c9c7973109a9cd0f27c64c6c0/scipy-1.16.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:0c3b4dd3d9b08dbce0f3440032c52e9e2ab9f96ade2d3943313dfe51a7056959", size = 33342103, upload-time = "2025-10-28T17:33:56.495Z" },
{ url = "https://files.pythonhosted.org/packages/21/f6/4bfb5695d8941e5c570a04d9fcd0d36bce7511b7d78e6e75c8f9791f82d0/scipy-1.16.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7dc1360c06535ea6116a2220f760ae572db9f661aba2d88074fe30ec2aa1ff88", size = 35697297, upload-time = "2025-10-28T17:34:04.722Z" },
{ url = "https://files.pythonhosted.org/packages/04/e1/6496dadbc80d8d896ff72511ecfe2316b50313bfc3ebf07a3f580f08bd8c/scipy-1.16.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:663b8d66a8748051c3ee9c96465fb417509315b99c71550fda2591d7dd634234", size = 36021756, upload-time = "2025-10-28T17:34:13.482Z" },
{ url = "https://files.pythonhosted.org/packages/fe/bd/a8c7799e0136b987bda3e1b23d155bcb31aec68a4a472554df5f0937eef7/scipy-1.16.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:eab43fae33a0c39006a88096cd7b4f4ef545ea0447d250d5ac18202d40b6611d", size = 38696566, upload-time = "2025-10-28T17:34:22.384Z" },
{ url = "https://files.pythonhosted.org/packages/cd/01/1204382461fcbfeb05b6161b594f4007e78b6eba9b375382f79153172b4d/scipy-1.16.3-cp313-cp313-win_amd64.whl", hash = "sha256:062246acacbe9f8210de8e751b16fc37458213f124bef161a5a02c7a39284304", size = 38529877, upload-time = "2025-10-28T17:35:51.076Z" },
{ url = "https://files.pythonhosted.org/packages/7f/14/9d9fbcaa1260a94f4bb5b64ba9213ceb5d03cd88841fe9fd1ffd47a45b73/scipy-1.16.3-cp313-cp313-win_arm64.whl", hash = "sha256:50a3dbf286dbc7d84f176f9a1574c705f277cb6565069f88f60db9eafdbe3ee2", size = 25455366, upload-time = "2025-10-28T17:35:59.014Z" },
{ url = "https://files.pythonhosted.org/packages/e2/a3/9ec205bd49f42d45d77f1730dbad9ccf146244c1647605cf834b3a8c4f36/scipy-1.16.3-cp313-cp313t-macosx_10_14_x86_64.whl", hash = "sha256:fb4b29f4cf8cc5a8d628bc8d8e26d12d7278cd1f219f22698a378c3d67db5e4b", size = 37027931, upload-time = "2025-10-28T17:34:31.451Z" },
{ url = "https://files.pythonhosted.org/packages/25/06/ca9fd1f3a4589cbd825b1447e5db3a8ebb969c1eaf22c8579bd286f51b6d/scipy-1.16.3-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:8d09d72dc92742988b0e7750bddb8060b0c7079606c0d24a8cc8e9c9c11f9079", size = 29400081, upload-time = "2025-10-28T17:34:39.087Z" },
{ url = "https://files.pythonhosted.org/packages/6a/56/933e68210d92657d93fb0e381683bc0e53a965048d7358ff5fbf9e6a1b17/scipy-1.16.3-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:03192a35e661470197556de24e7cb1330d84b35b94ead65c46ad6f16f6b28f2a", size = 21391244, upload-time = "2025-10-28T17:34:45.234Z" },
{ url = "https://files.pythonhosted.org/packages/a8/7e/779845db03dc1418e215726329674b40576879b91814568757ff0014ad65/scipy-1.16.3-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:57d01cb6f85e34f0946b33caa66e892aae072b64b034183f3d87c4025802a119", size = 23929753, upload-time = "2025-10-28T17:34:51.793Z" },
{ url = "https://files.pythonhosted.org/packages/4c/4b/f756cf8161d5365dcdef9e5f460ab226c068211030a175d2fc7f3f41ca64/scipy-1.16.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:96491a6a54e995f00a28a3c3badfff58fd093bf26cd5fb34a2188c8c756a3a2c", size = 33496912, upload-time = "2025-10-28T17:34:59.8Z" },
{ url = "https://files.pythonhosted.org/packages/09/b5/222b1e49a58668f23839ca1542a6322bb095ab8d6590d4f71723869a6c2c/scipy-1.16.3-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:cd13e354df9938598af2be05822c323e97132d5e6306b83a3b4ee6724c6e522e", size = 35802371, upload-time = "2025-10-28T17:35:08.173Z" },
{ url = "https://files.pythonhosted.org/packages/c1/8d/5964ef68bb31829bde27611f8c9deeac13764589fe74a75390242b64ca44/scipy-1.16.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:63d3cdacb8a824a295191a723ee5e4ea7768ca5ca5f2838532d9f2e2b3ce2135", size = 36190477, upload-time = "2025-10-28T17:35:16.7Z" },
{ url = "https://files.pythonhosted.org/packages/ab/f2/b31d75cb9b5fa4dd39a0a931ee9b33e7f6f36f23be5ef560bf72e0f92f32/scipy-1.16.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:e7efa2681ea410b10dde31a52b18b0154d66f2485328830e45fdf183af5aefc6", size = 38796678, upload-time = "2025-10-28T17:35:26.354Z" },
{ url = "https://files.pythonhosted.org/packages/b4/1e/b3723d8ff64ab548c38d87055483714fefe6ee20e0189b62352b5e015bb1/scipy-1.16.3-cp313-cp313t-win_amd64.whl", hash = "sha256:2d1ae2cf0c350e7705168ff2429962a89ad90c2d49d1dd300686d8b2a5af22fc", size = 38640178, upload-time = "2025-10-28T17:35:35.304Z" },
{ url = "https://files.pythonhosted.org/packages/8e/f3/d854ff38789aca9b0cc23008d607ced9de4f7ab14fa1ca4329f86b3758ca/scipy-1.16.3-cp313-cp313t-win_arm64.whl", hash = "sha256:0c623a54f7b79dd88ef56da19bc2873afec9673a48f3b85b18e4d402bdd29a5a", size = 25803246, upload-time = "2025-10-28T17:35:42.155Z" },
{ url = "https://files.pythonhosted.org/packages/99/f6/99b10fd70f2d864c1e29a28bbcaa0c6340f9d8518396542d9ea3b4aaae15/scipy-1.16.3-cp314-cp314-macosx_10_14_x86_64.whl", hash = "sha256:875555ce62743e1d54f06cdf22c1e0bc47b91130ac40fe5d783b6dfa114beeb6", size = 36606469, upload-time = "2025-10-28T17:36:08.741Z" },
{ url = "https://files.pythonhosted.org/packages/4d/74/043b54f2319f48ea940dd025779fa28ee360e6b95acb7cd188fad4391c6b/scipy-1.16.3-cp314-cp314-macosx_12_0_arm64.whl", hash = "sha256:bb61878c18a470021fb515a843dc7a76961a8daceaaaa8bad1332f1bf4b54657", size = 28872043, upload-time = "2025-10-28T17:36:16.599Z" },
{ url = "https://files.pythonhosted.org/packages/4d/e1/24b7e50cc1c4ee6ffbcb1f27fe9f4c8b40e7911675f6d2d20955f41c6348/scipy-1.16.3-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:f2622206f5559784fa5c4b53a950c3c7c1cf3e84ca1b9c4b6c03f062f289ca26", size = 20862952, upload-time = "2025-10-28T17:36:22.966Z" },
@@ -711,6 +905,8 @@ dependencies = [
{ name = "typing-extensions", marker = "sys_platform != 'linux' and sys_platform != 'win32'" },
]
wheels = [
{ url = "https://files.pythonhosted.org/packages/28/0e/2a37247957e72c12151b33a01e4df651d9d155dd74d8cfcbfad15a79b44a/torch-2.9.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:5be4bf7496f1e3ffb1dd44b672adb1ac3f081f204c5ca81eba6442f5f634df8e", size = 74830751, upload-time = "2025-11-12T15:21:43.792Z" },
{ url = "https://files.pythonhosted.org/packages/40/60/71c698b466dd01e65d0e9514b5405faae200c52a76901baf6906856f17e4/torch-2.9.1-cp313-none-macosx_11_0_arm64.whl", hash = "sha256:2c14b3da5df416cf9cb5efab83aa3056f5b8cd8620b8fde81b4987ecab730587", size = 74480347, upload-time = "2025-11-12T15:21:57.648Z" },
{ url = "https://files.pythonhosted.org/packages/48/50/c4b5112546d0d13cc9eaa1c732b823d676a9f49ae8b6f97772f795874a03/torch-2.9.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:1edee27a7c9897f4e0b7c14cfc2f3008c571921134522d5b9b5ec4ebbc69041a", size = 74433245, upload-time = "2025-11-12T15:22:39.027Z" },
{ url = "https://files.pythonhosted.org/packages/bd/b2/2d15a52516b2ea3f414643b8de68fa4cb220d3877ac8b1028c83dc8ca1c4/torch-2.9.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:cb10896a1f7fedaddbccc2017ce6ca9ecaaf990f0973bdfcf405439750118d2c", size = 74823558, upload-time = "2025-11-12T15:22:43.392Z" },
]
@@ -720,8 +916,8 @@ name = "torch"
version = "2.9.1+cu130"
source = { registry = "https://download.pytorch.org/whl/cu130" }
resolution-markers = [
"sys_platform == 'win32'",
"platform_machine == 'aarch64' and sys_platform == 'linux'",
"sys_platform == 'win32'",
"platform_machine != 'aarch64' and sys_platform == 'linux'",
]
dependencies = [
@@ -750,6 +946,12 @@ dependencies = [
{ name = "typing-extensions", marker = "sys_platform == 'linux' or sys_platform == 'win32'" },
]
wheels = [
{ url = "https://download.pytorch.org/whl/cu130/torch-2.9.1%2Bcu130-cp313-cp313-manylinux_2_28_aarch64.whl" },
{ url = "https://download.pytorch.org/whl/cu130/torch-2.9.1%2Bcu130-cp313-cp313-manylinux_2_28_x86_64.whl" },
{ url = "https://download.pytorch.org/whl/cu130/torch-2.9.1%2Bcu130-cp313-cp313-win_amd64.whl" },
{ url = "https://download.pytorch.org/whl/cu130/torch-2.9.1%2Bcu130-cp313-cp313t-manylinux_2_28_aarch64.whl" },
{ url = "https://download.pytorch.org/whl/cu130/torch-2.9.1%2Bcu130-cp313-cp313t-manylinux_2_28_x86_64.whl" },
{ url = "https://download.pytorch.org/whl/cu130/torch-2.9.1%2Bcu130-cp313-cp313t-win_amd64.whl" },
{ url = "https://download.pytorch.org/whl/cu130/torch-2.9.1%2Bcu130-cp314-cp314-manylinux_2_28_aarch64.whl" },
{ url = "https://download.pytorch.org/whl/cu130/torch-2.9.1%2Bcu130-cp314-cp314-manylinux_2_28_x86_64.whl" },
{ url = "https://download.pytorch.org/whl/cu130/torch-2.9.1%2Bcu130-cp314-cp314-win_amd64.whl" },
@@ -761,22 +963,64 @@ wheels = [
[[package]]
name = "torchvision"
version = "0.24.1"
source = { registry = "https://pypi.org/simple" }
source = { registry = "https://download.pytorch.org/whl/cu130" }
resolution-markers = [
"platform_machine == 'aarch64' and sys_platform == 'linux'",
]
dependencies = [
{ name = "numpy" },
{ name = "pillow" },
{ name = "torch", version = "2.9.1", source = { registry = "https://pypi.org/simple" }, marker = "sys_platform != 'linux' and sys_platform != 'win32'" },
{ name = "torch", version = "2.9.1+cu130", source = { registry = "https://download.pytorch.org/whl/cu130" }, marker = "sys_platform == 'linux' or sys_platform == 'win32'" },
{ name = "numpy", marker = "platform_machine == 'aarch64' and sys_platform == 'linux'" },
{ name = "pillow", marker = "platform_machine == 'aarch64' and sys_platform == 'linux'" },
{ name = "torch", version = "2.9.1+cu130", source = { registry = "https://download.pytorch.org/whl/cu130" }, marker = "platform_machine == 'aarch64' and sys_platform == 'linux'" },
]
wheels = [
{ url = "https://download.pytorch.org/whl/cu130/torchvision-0.24.1-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:7bf2cb6167244750e905fbada15b9b25b9487883cc212b9586eee74c455af02a" },
{ url = "https://download.pytorch.org/whl/cu130/torchvision-0.24.1-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:27b7593f236e8cb264b12a1166e59d744af76fdb347b598a9c2665118bc27533" },
{ url = "https://download.pytorch.org/whl/cu130/torchvision-0.24.1-cp314-cp314-manylinux_2_28_aarch64.whl", hash = "sha256:083b9361e677a51e3e5632c80d7a1fdee200ecabf787a14cad9f9ebe1bb523d5" },
{ url = "https://download.pytorch.org/whl/cu130/torchvision-0.24.1-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:2681f8ddf7ccd89b94906e2e303adee498d1641452ce07b0dd1cc928475b970f" },
]
[[package]]
name = "torchvision"
version = "0.24.1"
source = { registry = "https://pypi.org/simple" }
resolution-markers = [
"sys_platform == 'darwin'",
"sys_platform != 'darwin' and sys_platform != 'linux' and sys_platform != 'win32'",
]
dependencies = [
{ name = "numpy", marker = "sys_platform != 'linux' and sys_platform != 'win32'" },
{ name = "pillow", marker = "sys_platform != 'linux' and sys_platform != 'win32'" },
{ name = "torch", version = "2.9.1", source = { registry = "https://pypi.org/simple" }, marker = "sys_platform != 'linux' and sys_platform != 'win32'" },
]
wheels = [
{ url = "https://files.pythonhosted.org/packages/e4/97/ab40550f482577f2788304c27220e8ba02c63313bd74cf2f8920526aac20/torchvision-0.24.1-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:8a6696db7fb71eadb2c6a48602106e136c785642e598eb1533e0b27744f2cce6", size = 1891435, upload-time = "2025-11-12T15:25:28.642Z" },
{ url = "https://files.pythonhosted.org/packages/d5/f3/a90a389a7e547f3eb8821b13f96ea7c0563cdefbbbb60a10e08dda9720ff/torchvision-0.24.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:e3f96208b4bef54cd60e415545f5200346a65024e04f29a26cd0006dbf9e8e66", size = 2005342, upload-time = "2025-11-12T15:25:11.871Z" },
{ url = "https://files.pythonhosted.org/packages/42/84/577b2cef8f32094add5f52887867da4c2a3e6b4261538447e9b48eb25812/torchvision-0.24.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:cccf4b4fec7fdfcd3431b9ea75d1588c0a8596d0333245dafebee0462abe3388", size = 2005319, upload-time = "2025-11-12T15:25:23.827Z" },
{ url = "https://files.pythonhosted.org/packages/5f/34/ecb786bffe0159a3b49941a61caaae089853132f3cd1e8f555e3621f7e6f/torchvision-0.24.1-cp314-cp314-manylinux_2_28_aarch64.whl", hash = "sha256:1b495edd3a8f9911292424117544f0b4ab780452e998649425d1f4b2bed6695f", size = 2338844, upload-time = "2025-11-12T15:25:32.625Z" },
{ url = "https://files.pythonhosted.org/packages/51/99/a84623786a6969504c87f2dc3892200f586ee13503f519d282faab0bb4f0/torchvision-0.24.1-cp314-cp314-manylinux_2_28_x86_64.whl", hash = "sha256:ab211e1807dc3e53acf8f6638df9a7444c80c0ad050466e8d652b3e83776987b", size = 8175144, upload-time = "2025-11-12T15:25:31.355Z" },
{ url = "https://files.pythonhosted.org/packages/6d/ba/8fae3525b233e109317ce6a9c1de922ab2881737b029a7e88021f81e068f/torchvision-0.24.1-cp314-cp314-win_amd64.whl", hash = "sha256:18f9cb60e64b37b551cd605a3d62c15730c086362b40682d23e24b616a697d41", size = 4234459, upload-time = "2025-11-12T15:25:19.859Z" },
{ url = "https://files.pythonhosted.org/packages/50/33/481602c1c72d0485d4b3a6b48c9534b71c2957c9d83bf860eb837bf5a620/torchvision-0.24.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:ec9d7379c519428395e4ffda4dbb99ec56be64b0a75b95989e00f9ec7ae0b2d7", size = 2005336, upload-time = "2025-11-12T15:25:27.225Z" },
{ url = "https://files.pythonhosted.org/packages/d0/7f/372de60bf3dd8f5593bd0d03f4aecf0d1fd58f5bc6943618d9d913f5e6d5/torchvision-0.24.1-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:af9201184c2712d808bd4eb656899011afdfce1e83721c7cb08000034df353fe", size = 2341704, upload-time = "2025-11-12T15:25:29.857Z" },
{ url = "https://files.pythonhosted.org/packages/36/9b/0f3b9ff3d0225ee2324ec663de0e7fb3eb855615ca958ac1875f22f1f8e5/torchvision-0.24.1-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:9ef95d819fd6df81bc7cc97b8f21a15d2c0d3ac5dbfaab5cbc2d2ce57114b19e", size = 8177422, upload-time = "2025-11-12T15:25:37.357Z" },
{ url = "https://files.pythonhosted.org/packages/d6/ab/e2bcc7c2f13d882a58f8b30ff86f794210b075736587ea50f8c545834f8a/torchvision-0.24.1-cp314-cp314t-win_amd64.whl", hash = "sha256:480b271d6edff83ac2e8d69bbb4cf2073f93366516a50d48f140ccfceedb002e", size = 4335190, upload-time = "2025-11-12T15:25:35.745Z" },
]
[[package]]
name = "torchvision"
version = "0.24.1+cu130"
source = { registry = "https://download.pytorch.org/whl/cu130" }
resolution-markers = [
"sys_platform == 'win32'",
"platform_machine != 'aarch64' and sys_platform == 'linux'",
]
dependencies = [
{ name = "numpy", marker = "(platform_machine != 'aarch64' and sys_platform == 'linux') or sys_platform == 'win32'" },
{ name = "pillow", marker = "(platform_machine != 'aarch64' and sys_platform == 'linux') or sys_platform == 'win32'" },
{ name = "torch", version = "2.9.1+cu130", source = { registry = "https://download.pytorch.org/whl/cu130" }, marker = "(platform_machine != 'aarch64' and sys_platform == 'linux') or sys_platform == 'win32'" },
]
wheels = [
{ url = "https://download.pytorch.org/whl/cu130/torchvision-0.24.1%2Bcu130-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:1cac548fc20d6bd1da437f1bf586bbf9159ca3225222bacaa79b8a672197a535" },
{ url = "https://download.pytorch.org/whl/cu130/torchvision-0.24.1%2Bcu130-cp313-cp313-win_amd64.whl", hash = "sha256:d688426d623b8ba763087726faf5b34b1fe404f44741656978d855403dbc7444" },
{ url = "https://download.pytorch.org/whl/cu130/torchvision-0.24.1%2Bcu130-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:e342aa662dbd4dcb43a01e697e03f61f615fc34011f13f8c9bfcd1527f8a40c5" },
{ url = "https://download.pytorch.org/whl/cu130/torchvision-0.24.1%2Bcu130-cp313-cp313t-win_amd64.whl", hash = "sha256:878ce9b16d2c8797cb846709d31c270e9b985bd7cc59e8c8e5bbb0ed372b31c7" },
{ url = "https://download.pytorch.org/whl/cu130/torchvision-0.24.1%2Bcu130-cp314-cp314-manylinux_2_28_x86_64.whl", hash = "sha256:461a5f5fdd4b2e9adf972bd4f2e2bd96299fac64b524542c3805bad898438416" },
{ url = "https://download.pytorch.org/whl/cu130/torchvision-0.24.1%2Bcu130-cp314-cp314-win_amd64.whl", hash = "sha256:ae9ca2c3e6a517a01625404e72f485d0205463cb7c14f4f1dca8f5f368401be4" },
{ url = "https://download.pytorch.org/whl/cu130/torchvision-0.24.1%2Bcu130-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:8dbd486b3e73bb21df3734bf06e03664bdbc015c3d97b27ddf17eb7fb99c529f" },
{ url = "https://download.pytorch.org/whl/cu130/torchvision-0.24.1%2Bcu130-cp314-cp314t-win_amd64.whl", hash = "sha256:85c4606ff11773627d325f812628c4ea2d9a83b6c8417a344fdc16305ec0a454" },
]
[[package]]
@@ -784,6 +1028,10 @@ name = "triton"
version = "3.5.1"
source = { registry = "https://pypi.org/simple" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/f1/ba/805684a992ee32d486b7948d36aed2f5e3c643fc63883bf8bdca1c3f3980/triton-3.5.1-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:56765ffe12c554cd560698398b8a268db1f616c120007bfd8829d27139abd24a", size = 159955460, upload-time = "2025-11-11T17:52:01.861Z" },
{ url = "https://files.pythonhosted.org/packages/27/46/8c3bbb5b0a19313f50edcaa363b599e5a1a5ac9683ead82b9b80fe497c8d/triton-3.5.1-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f3f4346b6ebbd4fad18773f5ba839114f4826037c9f2f34e0148894cd5dd3dba", size = 170470410, upload-time = "2025-11-11T17:41:06.319Z" },
{ url = "https://files.pythonhosted.org/packages/84/1e/7df59baef41931e21159371c481c31a517ff4c2517343b62503d0cd2be99/triton-3.5.1-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:02c770856f5e407d24d28ddc66e33cf026e6f4d360dcb8b2fabe6ea1fc758621", size = 160072799, upload-time = "2025-11-11T17:52:07.293Z" },
{ url = "https://files.pythonhosted.org/packages/37/92/e97fcc6b2c27cdb87ce5ee063d77f8f26f19f06916aa680464c8104ef0f6/triton-3.5.1-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0b4d2c70127fca6a23e247f9348b8adde979d2e7a20391bfbabaac6aebc7e6a8", size = 170579924, upload-time = "2025-11-11T17:41:12.455Z" },
{ url = "https://files.pythonhosted.org/packages/14/f9/0430e879c1e63a1016cb843261528fd3187c872c3a9539132efc39514753/triton-3.5.1-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f617aa7925f9ea9968ec2e1adaf93e87864ff51549c8f04ce658f29bbdb71e2d", size = 159956163, upload-time = "2025-11-11T17:52:12.999Z" },
{ url = "https://files.pythonhosted.org/packages/a4/e6/c595c35e5c50c4bc56a7bac96493dad321e9e29b953b526bbbe20f9911d0/triton-3.5.1-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d0637b1efb1db599a8e9dc960d53ab6e4637db7d4ab6630a0974705d77b14b60", size = 170480488, upload-time = "2025-11-11T17:41:18.222Z" },
{ url = "https://files.pythonhosted.org/packages/41/1e/63d367c576c75919e268e4fbc33c1cb33b6dc12bb85e8bfe531c2a8bd5d3/triton-3.5.1-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8932391d7f93698dfe5bc9bead77c47a24f97329e9f20c10786bb230a9083f56", size = 160073620, upload-time = "2025-11-11T17:52:18.403Z" },
@@ -815,7 +1063,9 @@ dependencies = [
{ name = "scipy" },
{ name = "torch", version = "2.9.1", source = { registry = "https://pypi.org/simple" }, marker = "sys_platform != 'linux' and sys_platform != 'win32'" },
{ name = "torch", version = "2.9.1+cu130", source = { registry = "https://download.pytorch.org/whl/cu130" }, marker = "sys_platform == 'linux' or sys_platform == 'win32'" },
{ name = "torchvision" },
{ name = "torchvision", version = "0.24.1", source = { registry = "https://download.pytorch.org/whl/cu130" }, marker = "platform_machine == 'aarch64' and sys_platform == 'linux'" },
{ name = "torchvision", version = "0.24.1", source = { registry = "https://pypi.org/simple" }, marker = "sys_platform != 'linux' and sys_platform != 'win32'" },
{ name = "torchvision", version = "0.24.1+cu130", source = { registry = "https://download.pytorch.org/whl/cu130" }, marker = "(platform_machine != 'aarch64' and sys_platform == 'linux') or sys_platform == 'win32'" },
{ name = "ultralytics-thop" },
]
sdist = { url = "https://files.pythonhosted.org/packages/1f/74/dc3628b3ff540e496174179d66f7b3fee411401096f676f10b9375e1b524/ultralytics-8.3.248.tar.gz", hash = "sha256:a543cfd2a043dc94010bc6e7e05d07bec80d5b00eda94f5e95ea93e5c75de652", size = 988736, upload-time = "2026-01-04T17:21:46.726Z" }