# AEY Vision Python SDK

Official Python SDK for the AEY Vision API - AI-powered video analytics for security and surveillance.

## What's New in v0.2.0 🎉

- **🔧 Fluent Builder Pattern**: Chainable, intuitive API for configuration
- **🔄 Automatic Retry Logic**: Exponential backoff for network resilience
- **🎯 Custom Error Classes**: Better error handling with specific exception types
- **📊 Typed Responses**: Strongly typed response models with IDE autocomplete
- **🔐 Context Manager Support**: Proper resource cleanup with `with` statement
- **⚡ Enhanced Configuration**: Timeout, retry, and other advanced options
- **📦 Better Imports**: All types and exceptions exported from main module

## Installation

```bash
pip install aeyvision
```

Or install from source:

```bash
git clone https://github.com/yourusername/monorepo.git
cd monorepo/sdks/python
pip install -e .
```

## Quick Start

### Traditional Approach

```python
from aeyvision import AeyVision, RegionCounterConfig

# Initialize the SDK
sdk = AeyVision(api_key='your-api-key')

# Configure analysis
config = [
    RegionCounterConfig(
        confidence=0.5,
        classes=['person', 'car'],
        zones=[{
            'name': 'entrance',
            'points': [[0, 0], [100, 0], [100, 100], [0, 100]]
        }]
    )
]

# Analyze video
result = sdk.analyze('path/to/video.mp4', config)
print(result.analyzers)  # Typed response!
```

### Builder Pattern (New! ⭐)

```python
from aeyvision import AeyVision

# Initialize SDK with advanced options
sdk = AeyVision(
    api_key='your-api-key',
    max_retries=3,
    timeout=300
)

# Use fluent builder pattern
result = (sdk.movement_in_zone('video.mp4')
    .with_zones([{'name': 'entrance', 'points': [[0,0], [100,0], [100,100], [0,100]]}])
    .with_classes(['person', 'car'])
    .with_confidence(0.7)
    .with_annotated_video(True)
    .execute())

print(f"Detected {result.analyzers['RegionCounterAnalyzer']['total_tracks']} objects")
```

### With Context Manager

```python
from aeyvision import AeyVision

# Automatic resource cleanup
with AeyVision(api_key='your-api-key') as sdk:
    result = sdk.analyze('video.mp4', config)
    print(result.meta.total_frames)
```

## Features

- **Movement in Zone Detection**: Track objects entering/exiting defined zones
- **PPE Detection**: Verify personal protective equipment compliance
- **Video Redaction**: Automatically blur faces, persons, or license plates
- **ALPR**: Automatic license plate recognition
- **Age & Emotion Detection**: Analyze demographics and emotional states
- **Time in Region**: Track how long objects spend in specific areas
- **Entry/Exit Counting**: Count objects crossing defined lines
- **Fall Detection**: Detect falls for safety monitoring

## Configuration Options

### RegionCounterConfig

Track and count objects in defined zones.

```python
from aeyvision import RegionCounterConfig

config = RegionCounterConfig(
    type="region_counter",
    classes=["person", "car", "truck"],
    confidence=0.5,
    zones=[
        {
            'name': 'zone1',
            'points': [[x1, y1], [x2, y2], [x3, y3], [x4, y4]]
        }
    ]
)
```

### PPEConfig

Detect personal protective equipment.

```python
from aeyvision import PPEConfig

config = PPEConfig(
    type="ppe",
    confidence=0.5,
    required_ppe=["helmet", "vest", "gloves"]
)
```

### RedactionConfig

Redact sensitive information from videos.

```python
from aeyvision import RedactionConfig

config = RedactionConfig(
    type="redaction",
    backend="opencv",
    blur_kernel_size=[99, 99]
)
```

## Error Handling

The SDK provides specific exception types for better error handling:

```python
from aeyvision import (
    AeyVision,
    AuthenticationError,
    RateLimitError,
    ValidationError,
    APIError,
    NetworkError,
    TimeoutError
)

sdk = AeyVision(api_key='your-api-key')

try:
    result = sdk.analyze('video.mp4', config)
except AuthenticationError:
    print("Invalid API key")
except RateLimitError as e:
    print(f"Rate limited. Retry after {e.retry_after} seconds")
except ValidationError as e:
    print(f"Invalid configuration: {e}")
except NetworkError as e:
    print(f"Network error: {e}")
except TimeoutError as e:
    print(f"Request timed out: {e}")
except APIError as e:
    print(f"API error {e.status_code}: {e}")
```

## Builder Pattern Examples

### PPE Detection

```python
result = (sdk.ppe_detection('construction-site.mp4')
    .with_required_ppe(['hardhat', 'safety_vest', 'gloves'])
    .with_confidence(0.6)
    .with_annotated_video(True)
    .execute())

if result.analyzers['PPEAnalyzer']['violations']:
    print("PPE violations detected!")
```

### Video Redaction

```python
video_bytes = (sdk.video_redaction('sensitive-footage.mp4')
    .with_classes(['face', 'license_plate'])
    .with_blur_kernel(99, 99)
    .with_backend('opencv')
    .execute())

# Save redacted video
with open('redacted.mp4', 'wb') as f:
    f.write(video_bytes)
```

### Time in Region

```python
result = (sdk.time_in_region('store-footage.mp4')
    .with_zones([{
        'name': 'checkout_area',
        'points': [[0.2, 0.2], [0.8, 0.2], [0.8, 0.8], [0.2, 0.8]]
    }])
    .with_fps(10)
    .execute())

for track_id, duration in result.analyzers['TimeInRegionAnalyzer']['time_spent'].items():
    print(f"Object {track_id} spent {duration}s in checkout area")
```
```

## Advanced Usage

### Get Annotated Video

```python
# Return annotated video as bytes
annotated_video = sdk.analyze(
    'path/to/video.mp4',
    config,
    return_annotated=True
)

# Save to file
with open('output.mp4', 'wb') as f:
    f.write(annotated_video)
```

### Multi-Feature Analysis

Run multiple analyzers on a single video for comprehensive insights. **Save 25% on token costs** when using 2 or more features together!

#### Using the Dedicated Method

```python
# Run multiple analyzers on the same video
result = sdk.multi_feature_analysis(
    'video.mp4',
    features=[
        RegionCounterConfig(
            classes=['person'],
            zones=[{'name': 'entrance', 'points': [[0,0], [100,0], [100,100], [0,100]]}]
        ),
        PPEConfig(
            required_ppe=['hardhat', 'safety_vest']
        ),
        {
            'type': 'fall_detection',
            'confidence': 0.6
        }
    ]
)

# Access results for each analyzer
print(result['analyzers']['RegionCounterAnalyzer'])
print(result['analyzers']['PPEAnalyzer'])
print(result['analyzers']['FallDetectionAnalyzer'])
```

#### Using the Generic Method

```python
# Run multiple analyzers on the same video
config = [
    RegionCounterConfig(
        classes=['person'],
        zones=[{'name': 'entrance', 'points': [[0,0], [100,0], [100,100], [0,100]]}]
    ),
    PPEConfig(
        required_ppe=['helmet', 'vest']
    )
]

result = sdk.analyze('video.mp4', config)
```

#### Real-World Use Cases

**Construction Site Safety**
```python
# Monitor PPE compliance, track movement, and detect falls
result = sdk.multi_feature_analysis(
    'construction-site.mp4',
    features=[
        PPEConfig(required_ppe=['hardhat', 'safety_vest']),
        RegionCounterConfig(
            zones=[{'name': 'restricted_area', 'points': [[0.2,0.2], [0.8,0.2], [0.8,0.8], [0.2,0.8]]}]
        ),
        {'type': 'fall_detection'}
    ]
)
```

**Parking Lot Security**
```python
# Track vehicles, read license plates, and monitor entry/exit
result = sdk.multi_feature_analysis(
    'parking-lot.mp4',
    features=[
        {'type': 'alpr'},
        {'type': 'entry_exit', 'lines': [{'name': 'gate', 'points': [[0.5,0], [0.5,1]]}]},
        RegionCounterConfig(
            zones=[{'name': 'parking_zone', 'points': [[0,0], [1,0], [1,1], [0,1]]}],
            classes=['car', 'truck']
        )
    ]
)
```

**Retail Analytics**
```python
# Analyze customer demographics and track time in regions
result = sdk.multi_feature_analysis(
    'retail-store.mp4',
    features=[
        {'type': 'age_emotion'},
        {'type': 'time_in_region', 'zones': [{'name': 'product_display', 'points': [[0.3,0.3], [0.7,0.3], [0.7,0.7], [0.3,0.7]]}]}
    ]
)
```

#### Response Structure

```json
{
  "meta": {
    "total_frames": 309,
    "fps": 29.97,
    "duration": 10.31,
    "processing_time": 3.58
  },
  "analyzers": {
    "RegionCounterAnalyzer": {
      "region_counts": {"entrance": 5},
      "total_tracks": 5
    },
    "PPEAnalyzer": {
      "violations": [],
      "compliance_rate": 1.0
    },
    "FallDetectionAnalyzer": {
      "falls_detected": 0
    }
  },
  "timing": {
    "processing_time": 3.67,
    "gpu_seconds": 3.67
  },
  "billing": {
    "tokens_used": 225,
    "gpu_seconds": 3.67,
    "tokens_per_gpu_second": 10
  }
}
```

> **Note**: The `tokens_used` reflects the 25% discount (300 → 225 tokens) when using multiple features.


### Custom Base URL

```python
# Use a custom API endpoint
sdk = AeyVision(
    api_key='your-api-key',
    base_url='https://custom.api.endpoint.com'
)
```

## API Response

The SDK returns a JSON response with the following structure:

```json
{
  "meta": {
    "total_frames": 309,
    "fps": 29.97,
    "duration": 10.31,
    "processing_time": 3.58
  },
  "analyzers": {
    "RegionCounterAnalyzer": {
      "region_counts": {
        "entrance": 5
      },
      "total_tracks": 5,
      "detected_classes": ["person", "car"]
    }
  },
  "timing": {
    "processing_time": 3.67,
    "gpu_seconds": 3.67
  },
  "billing": {
    "tokens_used": 1,
    "gpu_seconds": 3.67,
    "tokens_per_gpu_second": 10
  }
}
```

## Error Handling

```python
try:
    result = sdk.analyze('video.mp4', config)
except Exception as e:
    print(f"Analysis failed: {e}")
```

## Requirements

- Python 3.7+
- requests

## License

MIT License - see LICENSE file for details

## Support

- Documentation: https://docs.aeyvision.com
- Email: support@aeyvision.com
- Issues: https://github.com/yourusername/monorepo/issues
# python-sdk.aeyvision.com
