Metadata-Version: 2.4
Name: tesla-clip-tools
Version: 0.4.0
Summary: Reusable primitives for IP-camera clip tools (Tesla, Wyze, Reolink, UniFi, Ring, Nest, Eufy, Frigate).
Project-URL: Homepage, https://github.com/Raymondriter/tesla-clip-tools
Project-URL: Repository, https://github.com/Raymondriter/tesla-clip-tools
Project-URL: Issues, https://github.com/Raymondriter/tesla-clip-tools/issues
Project-URL: Changelog, https://github.com/Raymondriter/tesla-clip-tools/blob/main/CHANGELOG.md
Author-email: Raymondriter <tenzinshare@gmail.com>
License: MIT
License-File: LICENSE
Keywords: dashcam,eufy,ffmpeg,frigate,keyframe,nest,nvr,reolink,ring,sei,sentry,tesla,teslacam,unifi,video,vlm,wyze
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Home Automation
Classifier: Topic :: Multimedia :: Video
Requires-Python: >=3.12
Requires-Dist: httpx>=0.27
Requires-Dist: imageio[ffmpeg]>=2.34
Requires-Dist: numpy>=1.26
Requires-Dist: openai>=1.55
Requires-Dist: pillow>=10.4
Requires-Dist: pydantic>=2.7
Provides-Extra: dev
Requires-Dist: pytest>=8; extra == 'dev'
Requires-Dist: ruff>=0.7; extra == 'dev'
Provides-Extra: sei
Requires-Dist: pandas>=2.2; extra == 'sei'
Requires-Dist: protobuf>=5; extra == 'sei'
Description-Content-Type: text/markdown

# tesla-clip-tools

[![PyPI](https://img.shields.io/pypi/v/tesla-clip-tools.svg)](https://pypi.org/project/tesla-clip-tools/) [![CI](https://github.com/Raymondriter/tesla-clip-tools/actions/workflows/ci.yml/badge.svg)](https://github.com/Raymondriter/tesla-clip-tools/actions/workflows/ci.yml)

Reusable primitives for building tools that read Tesla TeslaCam, SentryClips, and SEI data — plus the same `Source`/`Event`/`sampler`/`vlm`/`notify` pipeline applied to Wyze, Reolink, UniFi Protect, Ring, Nest, Eufy, and Frigate.

Extracted from [`sentrytriage`](https://github.com/Raymondriter/sentrytriage) v0.2 → v0.3 so that future projects (planned: an FSD-Disengagement Studio, a Wyze/Reolink/UniFi port of sentrytriage) can share the same primitives without forking.

## Install

```bash
pip install tesla-clip-tools                      # base
pip install 'tesla-clip-tools[sei]'               # adds protobuf+pandas for sei_dataframe()
```

Or with `uv`:

```bash
uv add tesla-clip-tools
uv add 'tesla-clip-tools[sei]'
```

Until the first PyPI release lands, install directly from GitHub:

```bash
uv add git+https://github.com/Raymondriter/tesla-clip-tools
```

## What's inside

```
tesla_clip_tools/
├── sources/
│   ├── base.py          Abstract Source + Event dataclass
│   ├── tesla.py         SentryClips/<YYYY-MM-DD_HH-MM-SS>/{cam}.mp4 (HW3 4-cam + HW4 6-cam)
│   ├── wyze.py          Wyze SD-card / RTSP folder layout
│   ├── reolink.py       Reolink NVR folder layout
│   ├── unifi_protect.py UniFi Protect export layout
│   ├── ring.py          Ring downloads layout
│   ├── nest.py          Nest / Google Home downloads layout
│   ├── eufy.py          Eufy app / HomeBase NAS export layout
│   └── frigate.py       Frigate NVR clips/ layout (+ sibling .json metadata)
├── sampler.py           Frame extraction via imageio (bundled ffmpeg, no system dep)
├── vlm/
│   ├── base.py          Generic VLMBackend protocol parameterised on a Pydantic response_format
│   ├── openai.py        gpt-4o-mini default, structured outputs via beta.chat.completions.parse
│   └── ollama.py        Local Qwen2.5-VL etc. via the Ollama HTTP API + JSON-schema format
├── notify/
│   ├── base.py          Notifier protocol
│   ├── pushover.py
│   └── telegram.py
├── sei.py               SEI metadata extraction from Dashcam (Saved/Recent) clips
└── dashcam.proto        Tesla's published proto schema (vendored)
```

## Generating the SEI protobuf module

For the SEI dataframe convenience function, you also need to generate the protobuf module once:

```bash
protoc --python_out=src/tesla_clip_tools src/tesla_clip_tools/dashcam.proto
```

`iter_sei_payloads()` works without protobuf — it just yields raw protobuf-encoded byte payloads.

## Minimal example

```python
from pathlib import Path
from tesla_clip_tools.sources.tesla import TeslaSource
from tesla_clip_tools.sampler import sample_keyframes
from tesla_clip_tools.vlm.openai import OpenAIBackend
from pydantic import BaseModel

class MyVerdict(BaseModel):
    is_interesting: bool
    why: str

source = TeslaSource(Path("~/Tesla/SentryClips"))
vlm = OpenAIBackend(model="gpt-4o-mini")

for event in source.discover():
    samples = sample_keyframes(event.cams, n_per_cam=4)
    captions = [f"[{s.cam} t={s.timestamp_seconds:.1f}s]" for s in samples]
    verdict = vlm.classify(
        images=[s.image for s in samples],
        captions=captions,
        system_prompt="Decide if this Sentry event deserves attention. Default to false.",
        response_format=MyVerdict,
    )
    print(event.id, verdict.is_interesting, verdict.why)
```

## Design choices

- **Generic VLM API.** Every backend takes a `response_format: type[BaseModel]` so different consumers (sentrytriage, FSD-Disengagement Studio, future tools) define their own verdict schema without forking the backend.
- **No state.** No SQLite, no daemon, no notifications-orchestration. Those are application concerns; the library is just primitives. Use `notify/` if you want one of the included notifiers, but it's optional.
- **No system ffmpeg required for the read path.** `sampler.py` uses `imageio[ffmpeg]` which bundles its own ffmpeg binary. (Tools that build filter graphs — the highlight reel in sentrytriage, e.g. — still need system ffmpeg.)
- **Source-pluggable.** `tesla.py` implements the canonical TeslaCam folder layout; `wyze.py`, `reolink.py`, `unifi_protect.py`, `ring.py`, `nest.py`, `eufy.py`, and `frigate.py` ship in 0.4. Add a new vendor by subclassing `Source` — the rest of the pipeline doesn't care.

## Status

v0.4 — alpha, API may still change. Used in production by `sentrytriage` v0.3+ and `fsd-disengagement-studio`.

## Changelog

See [CHANGELOG.md](CHANGELOG.md) for the version history. Releases are cut
following the steps in [RELEASE.md](RELEASE.md).

## License

MIT.

## CI

[![ci](https://github.com/Raymondriter/tesla-clip-tools/actions/workflows/ci.yml/badge.svg)](https://github.com/Raymondriter/tesla-clip-tools/actions/workflows/ci.yml)

GitHub Actions runs ruff + pytest on Python 3.12 and 3.13 against every push and PR. See [`.github/workflows/ci.yml`](.github/workflows/ci.yml). The same tests also run as part of the workspace-level monorepo CI at `C:\Dev\tesla\.github\workflows\ci.yml`.
