Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
227 changes: 28 additions & 199 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,222 +1,51 @@
# RationAI Python SDK

A Python SDK for interacting with RationAI pathology image analysis services. This library provides both synchronous and asynchronous clients for image classification, segmentation, and quality control operations.
[![Python 3.12+](https://img.shields.io/badge/python-3.12%2B-blue)](https://www.python.org/downloads/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![Documentation](https://img.shields.io/badge/docs-latest-brightgreen)](https://rationai.github.io/rationai-sdk-python/)

## Installation
Python SDK for interacting with RationAI pathology image analysis services. This library provides both synchronous and asynchronous clients for image classification, segmentation, and quality control operations.

```bash
pip install git+https://github.com/RationAI/rationai-sdk-python.git
```
## Documentation

## Quick Start
Comprehensive documentation is available at **[rationai.github.io/rationai-sdk-python](https://rationai.github.io/rationai-sdk-python/)**.

### Synchronous Client
## Features

```python
import rationai
import numpy as np
from PIL import Image

# Initialize the client
client = rationai.Client()

# Load an image
image = Image.open("path/to/image.jpg").convert("RGB")
- **Image Analysis**: Classify and segment pathology images (WSI patches) using deployed models.
- **Quality Control**: Automated QC workflows for Whole Slide Images (WSI).
- **Concurrency**: Built-in async support for high-throughput processing.
- **Efficiency**: Optimized data transfer with LZ4 compression.

# Classify the image
result = client.models.classify_image("model-name", image)
print(result)
## Requirements

# Segment the image
segmentation = client.models.segment_image("segmentation-model", image)
print(segmentation.shape) # (num_classes, height, width)
- Python 3.12 or higher

client.close()
```

### Asynchronous Client

```python
import asyncio
import rationai
## Installation

async def main():
async with rationai.AsyncClient() as client:
# Your async operations here
result = await client.models.classify_image("model-name", image)
print(result)
Install the package directly from GitHub:

asyncio.run(main())
```bash
pip install git+https://github.com/RationAI/rationai-sdk-python.git
```

## API Reference

### Models (`client.models`)

#### `classify_image(model: str, image: Image | NDArray[np.uint8]) -> float | dict[str, float]`

Classify an image using the specified model.

**Parameters:**

- `model`: The name of the model to use for classification
- `image`: The image to classify (must be uint8 RGB image)
- `timeout`: Optional timeout for the request (defaults to 100 seconds)

**Returns:** Classification result as a float (binary) or dict of probabilities per class

#### `segment_image(model: str, image: Image | NDArray[np.uint8]) -> NDArray[np.float16]`

Segment an image using the specified model.

**Parameters:**

- `model`: The name of the model to use for segmentation
- `image`: The image to segment (must be uint8 RGB image)
- `timeout`: Optional timeout for the request (defaults to 100 seconds)

**Returns:** Segmentation mask as numpy array with shape `(num_classes, height, width)`

### Slide (`client.slide`)

#### `heatmap(model: str, slide_path: str, tissue_mask_path: str, output_path: str, stride_fraction: float = 0.5, output_bigtiff_tile_height: int = 512, output_bigtiff_tile_width: int = 512, timeout: int = 1000) -> str`

Generate a heatmap for a whole slide image using the specified model.

**Parameters:**

- `model`: The name of the model to use for heatmap generation
- `slide_path`: Path to the whole slide image
- `tissue_mask_path`: Path to the tissue mask for the slide
- `output_path`: Directory to save the generated heatmap tiles
- `stride_fraction`: Fraction of tile size to use as stride between tiles (default: 0.5)
- `output_bigtiff_tile_height`: Height of output heatmap tiles in pixels (default: 512)
- `output_bigtiff_tile_width`: Width of output heatmap tiles in pixels (default: 512)
- `timeout`: Optional timeout for the request (defaults to 1000 seconds)

**Returns:** The path to the generated heatmap. Should match the output_path provided.

### Quality Control (`client.qc`)

#### `check_slide(wsi_path, output_path, config=None, timeout=3600) -> str`

Check quality of a whole slide image.

**Parameters:**

- `wsi_path`: Path to the whole slide image
- `output_path`: Directory to save output masks
- `config`: Optional `SlideCheckConfig` for the quality check
- `timeout`: Optional timeout for the request (defaults to 3600 seconds)

**Returns:** xOpat link containing the processed WSI for visual inspection of generated masks

#### `check_slides(wsi_paths, output_path, config=None, timeout=3600, max_concurrent=4)` (async only)

Check quality of multiple slides concurrently.

**Parameters:**

- `wsi_paths`: List of paths to whole slide images
- `output_path`: Directory to save output masks
- `config`: Optional `SlideCheckConfig` for the quality check
- `timeout`: Optional timeout for each request (defaults to 3600 seconds)
- `max_concurrent`: Maximum number of concurrent slide checks (defaults to 4)

**Yields:** `SlideCheckResult` for each slide containing the path, xOpat URL (if successful), and any error information

#### `generate_report(backgrounds, mask_dir, save_location, compute_metrics=True, timeout=None) -> None`

Generate a QC report from processed slides.

**Parameters:**

- `backgrounds`: List of paths to background (slide) images
- `mask_dir`: Directory containing generated masks
- `save_location`: Path where the report HTML will be saved
- `compute_metrics`: Whether to compute quality metrics (default: True)
- `timeout`: Optional timeout for the request

For more details, refer to the [QC documentation](https://quality-control-rationai-digital-pathology-quali-82f7255ed88b44.gitlab-pages.ics.muni.cz).

## Managing Concurrency

To avoid overloading the server, it's important to limit concurrent requests. Here are recommended approaches:

### Using `asyncio.Semaphore`

Limit the number of concurrent requests:
## Quick Start

```python
import asyncio
from PIL import Image
import rationai

async def process_images_with_semaphore(image_paths, model_name, max_concurrent):
semaphore = asyncio.Semaphore(max_concurrent)

async def bounded_segment(client, path):
async with semaphore:
image = Image.open(path).convert("RGB")
return await client.models.segment_image(model_name, image)

async with rationai.AsyncClient() as client:
tasks = [bounded_segment(client, path) for path in image_paths]
results = await asyncio.gather(*tasks)

return results

# Process up to 16 images concurrently
results = asyncio.run(process_images_with_semaphore(image_paths, "model-name", max_concurrent=16))
```

### Using `asyncio.as_completed()`

Process results as they complete:

```python
import asyncio
from rationai import AsyncClient

async def process_with_as_completed(image_paths, model_name, max_concurrent):
semaphore = asyncio.Semaphore(max_concurrent)

async def bounded_request(client, path):
async with semaphore:
image = Image.open(path).convert("RGB")
return path, await client.models.segment_image(model_name, image)

async with AsyncClient(models_base_url="http://localhost:8000") as client:
tasks = {asyncio.create_task(bounded_request(client, path)): path
for path in image_paths}

for future in asyncio.as_completed(tasks):
path, result = await future
print(f"Processed {path}")
# Process result immediately without waiting for all tasks

asyncio.run(process_with_as_completed(image_paths, "model-name", max_concurrent=16))
```

Start with a conservative limit and monitor server resources to find the optimal value for your setup.

## Configuration

### Custom Timeouts

```python
from rationai import AsyncClient
# Load an image (must be RGB)
image = Image.open("path/to/image.jpg").convert("RGB")

async with AsyncClient(timeout=300) as client: # 300 second timeout
result = await client.models.segment_image("model", image, timeout=60)
# Initialize the client and run classification
with rationai.Client() as client:
result = client.models.classify_image("model-name", image)
print(f"Classification result: {result}")
```

### Custom Base URLs
For asynchronous usage, configuration options, and advanced features, please refer to the [documentation](https://rationai.github.io/rationai-sdk-python/).

```python
from rationai import Client
## License

client = Client(
models_base_url="http://custom-models-server:8000",
qc_base_url="http://custom-qc-server:8000"
)
```
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
53 changes: 2 additions & 51 deletions docs/learn/get-started/quick-start.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ Both clients expose the same high-level resources:

- `client.models` for image classification/segmentation
- `client.qc` for quality control endpoints
- `client.slide` for slide-level operations (e.g. heatmaps)

### What’s the actual difference?

Expand All @@ -26,57 +27,7 @@ Both clients expose the same high-level resources:

For details on what is sent over the wire (compression, payloads), see: [How it works](../how-it-works.md).

## API at a glance

### Models

#### `client.models.classify_image`

Signature:

`classify_image(model: str, image: PIL.Image.Image | numpy.typing.NDArray[numpy.uint8], timeout=...) -> float | dict[str, float]`

- `model`: Model name / path appended to `models_base_url`.
- `image`: **uint8 RGB** image (PIL or NumPy array of shape `(H, W, 3)`).
- `timeout`: Optional request timeout (defaults to the client’s timeout).
- Returns: classification result from JSON (often `float` for binary, or `dict[class, prob]`).

#### `client.models.segment_image`

Signature:

`segment_image(model: str, image: PIL.Image.Image | numpy.typing.NDArray[numpy.uint8], timeout=...) -> numpy.typing.NDArray[numpy.float16]`

- `model`: Model name / path appended to `models_base_url`.
- `image`: **uint8 RGB** image (PIL or NumPy array of shape `(H, W, 3)`).
- `timeout`: Optional request timeout (defaults to the client’s timeout).
- Returns: `float16` NumPy array with shape `(num_classes, height, width)`.

### Quality control (QC)

#### `client.qc.check_slide`

Signature:

`check_slide(wsi_path: os.PathLike[str] | str, output_path: os.PathLike[str] | str, config: SlideCheckConfig | None = None, timeout=3600) -> str`

- `wsi_path`: Path to a whole-slide image (evaluated by the QC service).
- `output_path`: Directory where the QC service should write masks (evaluated by the QC service).
- `config`: Optional `SlideCheckConfig` (see reference types).
- `timeout`: Request timeout (default is 3600 seconds).
- Returns: xOpat URL as plain text.

#### `client.qc.generate_report`

Signature:

`generate_report(backgrounds: Iterable[os.PathLike[str] | str], mask_dir: os.PathLike[str] | str, save_location: os.PathLike[str] | str, compute_metrics: bool = True, timeout=...) -> None`

- `backgrounds`: Iterable of slide/background image paths.
- `mask_dir`: Directory containing generated masks.
- `save_location`: Path where the report HTML should be written.
- `compute_metrics`: Whether to compute aggregated metrics (default: `True`).
- Returns: nothing.
For the full API reference, see the [reference documentation](../../reference/client.md).

## Synchronous client

Expand Down
9 changes: 9 additions & 0 deletions docs/reference/resources/slide.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Slide

## `rationai.resources.slide.Slide`

::: rationai.resources.slide.Slide

## `rationai.resources.slide.AsyncSlide`

::: rationai.resources.slide.AsyncSlide
1 change: 1 addition & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ nav:
- Resources:
- Models: reference/resources/models.md
- Quality control: reference/resources/qc.md
- Slide: reference/resources/slide.md
- Types:
- QC types: reference/types/qc.md

Expand Down