<p align="center">
  <img src="https://evren.ssyz.org.tr/logo.svg" alt="EVREN" width="200" />
</p>

<h1 align="center">evren-sdk</h1>

<p align="center">
  <a href="https://pypi.org/project/evren-sdk/"><img src="https://img.shields.io/pypi/v/evren-sdk?color=emerald" alt="PyPI" /></a>
  <a href="https://pypi.org/project/evren-sdk/"><img src="https://img.shields.io/pypi/pyversions/evren-sdk" alt="Python" /></a>
  <a href="https://github.com/speker/evren-sdk/blob/main/LICENSE"><img src="https://img.shields.io/github/license/speker/evren-sdk" alt="License" /></a>
</p>

<p align="center">
  <a href="#türkçe">Türkçe</a> · <a href="#english">English</a>
</p>

---

## Türkçe

EVREN platformu üzerinde eğitilmiş bilgisayarlı görü modellerine Python'dan
çıkarım (inference) yapmanızı sağlayan resmi SDK.

**Desteklenen görevler:** nesne tespiti, sınıflandırma, segmentasyon,
döndürülmüş kutu (OBB), anahtar nokta (keypoint).

```bash
pip install evren-sdk
```

### Hızlı Başlangıç

```python
from evren_sdk import EvrenClient

client = EvrenClient(api_key="evren_xxxxx")

result = client.predict("kullanici/model-adi", "foto.jpg", confidence=0.3)

for det in result.predictions:
    print(f"{det.class_name}: {det.confidence:.0%}  bbox={det.bbox}")

print(f"Çıkarım süresi: {result.inference_ms:.0f} ms")
```

### Kimlik Doğrulama

Platformda **Ayarlar → API Anahtarları** sayfasından anahtar oluşturun.
Anahtar `evren_` ön eki ile başlar ve `X-API-Key` başlığı üzerinden
otomatik gönderilir.

```python
# API anahtarı ile (önerilen)
client = EvrenClient(api_key="evren_xxxxx")

# JWT token ile de çalışır
client = EvrenClient(api_key="eyJhbGci...")
```

### Tekil Çıkarım

```python
result = client.predict(
    model="kullanici/model-adi",        # slug veya UUID
    image="resim.jpg",                  # dosya yolu, Path veya bytes
    confidence=0.25,
    iou=0.45,
    image_size=640,
    classes=["araba", "insan"],         # isteğe bağlı sınıf filtresi
)
```

`model` parametresi üç format kabul eder:

| Format | Açıklama |
|---|---|
| `"owner/slug"` | Son versiyonu otomatik çözer |
| `"owner/slug:v2.0"` | Belirli versiyon etiketi |
| `"019cec..."` (UUID) | Doğrudan versiyon kimliği |

### Toplu Çıkarım (Batch)

Birden fazla görseli tek istekte GPU batch çıkarımı ile işleyin.

```python
batch = client.predict_batch(
    model="kullanici/model-adi",
    images=["img1.jpg", "img2.jpg", "img3.jpg"],
    confidence=0.3,
)

for r in batch:
    print(f"{r.count} tespit, {r.inference_ms:.0f} ms")

print(f"Toplam: {batch.total_ms:.0f} ms, {batch.count} görsel")
```

### Model Bilgileri

```python
info = client.model_classes("kullanici/model-adi")
print(info.architecture)
for cls in info.classes:
    print(f"  {cls.name}: {cls.color}")

for m in client.list_models():
    print(f"{m.full_slug} — {m.architecture}")
```

### Ön Yükleme (Warmup)

İlk çıkarım gecikmesini ortadan kaldırmak için modelleri önceden GPU'ya yükleyin.

```python
client.warmup(["kullanici/model-adi", "diger/model"])
```

### Asenkron Kullanım

```python
import asyncio
from evren_sdk import AsyncEvrenClient

async def main():
    async with AsyncEvrenClient(api_key="evren_xxxxx") as client:
        result = await client.predict("kullanici/model-adi", "foto.jpg")
        batch = await client.predict_batch(
            "kullanici/model-adi", ["a.jpg", "b.jpg"],
        )

asyncio.run(main())
```

### Hata Yönetimi

```python
from evren_sdk import EvrenClient, NotFoundError, RateLimitError, InferenceError

client = EvrenClient(api_key="evren_xxxxx")

try:
    result = client.predict("kullanici/model", "test.jpg")
except NotFoundError:
    print("Model bulunamadı")
except RateLimitError as e:
    time.sleep(e.retry_after)
except InferenceError:
    print("GPU sunucusu geçici olarak kullanılamıyor")
```

| Exception | HTTP | Açıklama |
|---|---|---|
| `AuthenticationError` | 401, 403 | Geçersiz veya süresi dolmuş anahtar |
| `NotFoundError` | 404 | Model veya versiyon bulunamadı |
| `ValidationError` | 422 | Hatalı parametre |
| `RateLimitError` | 429 | İstek limiti aşıldı |
| `InferenceError` | 502, 503 | GPU sunucusu hatası |

### Edge Modu (GPU'suz Cihazlar)

GPU olmayan cihazlarda (Raspberry Pi, laptop, endüstriyel PC) kamera veya
video üzerinden gerçek zamanlı çıkarım yapın. Çıkarım EVREN GPU'larında
çalışır, kullanıcı lokal model gibi deneyimler.

```bash
pip install evren-sdk[edge]
```

```python
from evren_sdk import EvrenCamera

cam = EvrenCamera("evren_...", "owner/model")

# Tek satir: webcam ac, ESC ile kapat
cam.run(0)
```

```python
# Iterator olarak — kendi dongunuzde kullanin
for frame, result in cam.stream(0):
    print(f"{result.count} tespit, {result.inference_ms:.0f}ms")
    # frame zaten annotated (bbox + label cizili)
```

```python
# Video dosyasi isle + annotated cikti kaydet
cam.record("input.mp4", "output.mp4")
```

```python
# Klasordeki gorselleri toplu isle
for path, result in cam.scan("images/", save_to="results/"):
    print(f"{path.name}: {result.count} nesne")
```

```python
# RTSP IP kamera
for frame, result in cam.stream("rtsp://192.168.1.10/stream"):
    ...
```

Desteklenen kaynaklar: webcam (`0`, `1`), video dosyası (`*.mp4`, `*.avi`),
RTSP akışı, HTTP stream, görsel klasörü.

| Parametre | Varsayılan | Açıklama |
|---|---|---|
| `max_fps` | 15.0 | Bant genişliğini korumak için FPS limiti |
| `jpeg_quality` | 70 | JPEG sıkıştırma kalitesi (20-95) |
| `draw` | True | Tahminleri frame üzerine çiz |
| `confidence` | 0.25 | Minimum güven eşiği |

```python
# draw_predictions() bagimsiz kullanilabilir
from evren_sdk import draw_predictions

frame = cv2.imread("foto.jpg")
result = client.predict("owner/model", "foto.jpg")
draw_predictions(frame, result.predictions)
cv2.imwrite("annotated.jpg", frame)
```

---

## English

Official Python SDK for running inference on computer vision models trained
on the EVREN platform.

**Supported tasks:** object detection, classification, segmentation,
oriented bounding box (OBB), keypoint detection.

```bash
pip install evren-sdk
```

### Quick Start

```python
from evren_sdk import EvrenClient

client = EvrenClient(api_key="evren_xxxxx")

result = client.predict("owner/model-name", "photo.jpg", confidence=0.3)

for det in result.predictions:
    print(f"{det.class_name}: {det.confidence:.0%}  bbox={det.bbox}")

print(f"Inference time: {result.inference_ms:.0f} ms")
```

### Authentication

Create an API key from **Settings → API Keys** on the platform.
Keys start with the `evren_` prefix and are sent automatically via the
`X-API-Key` header.

```python
# API key (recommended)
client = EvrenClient(api_key="evren_xxxxx")

# JWT tokens also work
client = EvrenClient(api_key="eyJhbGci...")
```

### Single Prediction

```python
result = client.predict(
    model="owner/model-name",           # slug or UUID
    image="image.jpg",                  # file path, Path, or bytes
    confidence=0.25,
    iou=0.45,
    image_size=640,
    classes=["car", "person"],          # optional class filter
)
```

The `model` parameter accepts three formats:

| Format | Description |
|---|---|
| `"owner/slug"` | Resolves to latest version automatically |
| `"owner/slug:v2.0"` | Specific version tag |
| `"019cec..."` (UUID) | Direct version ID |

### Batch Prediction

Process multiple images in a single request with GPU batch inference.

```python
batch = client.predict_batch(
    model="owner/model-name",
    images=["img1.jpg", "img2.jpg", "img3.jpg"],
    confidence=0.3,
)

for r in batch:
    print(f"{r.count} detections, {r.inference_ms:.0f} ms")

print(f"Total: {batch.total_ms:.0f} ms, {batch.count} images")
```

### Model Information

```python
info = client.model_classes("owner/model-name")
print(info.architecture)
for cls in info.classes:
    print(f"  {cls.name}: {cls.color}")

for m in client.list_models():
    print(f"{m.full_slug} — {m.architecture}")
```

### Warmup

Pre-load models onto the GPU to eliminate cold-start latency.

```python
client.warmup(["owner/model-name", "other/model"])
```

### Async Usage

Same API surface with `async/await`:

```python
import asyncio
from evren_sdk import AsyncEvrenClient

async def main():
    async with AsyncEvrenClient(api_key="evren_xxxxx") as client:
        result = await client.predict("owner/model-name", "photo.jpg")
        batch = await client.predict_batch(
            "owner/model-name", ["a.jpg", "b.jpg"],
        )

asyncio.run(main())
```

### Error Handling

```python
from evren_sdk import EvrenClient, NotFoundError, RateLimitError, InferenceError

client = EvrenClient(api_key="evren_xxxxx")

try:
    result = client.predict("owner/model", "test.jpg")
except NotFoundError:
    print("Model not found")
except RateLimitError as e:
    time.sleep(e.retry_after)
except InferenceError:
    print("GPU server temporarily unavailable")
```

| Exception | HTTP | Description |
|---|---|---|
| `AuthenticationError` | 401, 403 | Invalid or expired key |
| `NotFoundError` | 404 | Model or version not found |
| `ValidationError` | 422 | Invalid parameter |
| `RateLimitError` | 429 | Rate limit exceeded |
| `InferenceError` | 502, 503 | GPU server error |

### Edge Mode (GPU-free Devices)

Run real-time inference on devices without a GPU (Raspberry Pi, laptops,
industrial PCs). Inference runs on EVREN's cloud GPUs — the user experience
feels completely local.

```bash
pip install evren-sdk[edge]
```

```python
from evren_sdk import EvrenCamera

cam = EvrenCamera("evren_...", "owner/model")

# One-liner: opens webcam, press ESC to quit
cam.run(0)
```

```python
# Iterator — use in your own loop
for frame, result in cam.stream(0):
    print(f"{result.count} detections, {result.inference_ms:.0f}ms")
    # frame is already annotated (bboxes + labels drawn)
```

```python
# Process video file + save annotated output
cam.record("input.mp4", "output.mp4")
```

```python
# Batch process a folder of images
for path, result in cam.scan("images/", save_to="results/"):
    print(f"{path.name}: {result.count} objects")
```

```python
# RTSP IP camera
for frame, result in cam.stream("rtsp://192.168.1.10/stream"):
    ...
```

Supported sources: webcam (`0`, `1`), video files (`*.mp4`, `*.avi`),
RTSP streams, HTTP streams, image folders.

| Parameter | Default | Description |
|---|---|---|
| `max_fps` | 15.0 | FPS cap to conserve bandwidth |
| `jpeg_quality` | 70 | JPEG compression quality (20-95) |
| `draw` | True | Render predictions on frame |
| `confidence` | 0.25 | Minimum confidence threshold |

```python
# draw_predictions() works standalone
from evren_sdk import draw_predictions

frame = cv2.imread("photo.jpg")
result = client.predict("owner/model", "photo.jpg")
draw_predictions(frame, result.predictions)
cv2.imwrite("annotated.jpg", frame)
```

### Data Models

| Class | Key Fields |
|---|---|
| `PredictResult` | `predictions`, `inference_ms`, `image_width`, `image_height`, `count` |
| `Prediction` | `class_name`, `confidence`, `bbox`, `color`, `mask`, `keypoints`, `obb` |
| `BatchResult` | `results`, `total_ms`, `count` — iterable |
| `ModelClasses` | `classes`, `architecture`, `model_name`, `imgsz` — supports `in` operator |
| `ModelInfo` | `id`, `name`, `slug`, `architecture`, `full_slug` |
| `ModelVersion` | `id`, `version_tag`, `framework`, `metrics` |
| `EvrenCamera` | `stream()`, `run()`, `scan()`, `record()`, `stats` |

---

## Requirements

- Python >= 3.10
- [httpx](https://www.python-httpx.org/) >= 0.27
- [opencv-python](https://pypi.org/project/opencv-python/) >= 4.8 *(only for `evren-sdk[edge]`)*

## License

[Apache License 2.0](LICENSE)
