From d9dd124edc407d674eec016bd65fc0ffd8cc83f5 Mon Sep 17 00:00:00 2001 From: JiriStipek <567776@mail.muni.cz> Date: Tue, 3 Mar 2026 19:58:37 +0100 Subject: [PATCH 1/4] feat: README cleanup --- README.md | 227 +++++++----------------------------------------------- 1 file changed, 28 insertions(+), 199 deletions(-) diff --git a/README.md b/README.md index bb03b5b..77ec3b5 100644 --- a/README.md +++ b/README.md @@ -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. From a06b79c8be533c157e4e46bbfab0bd872947046a Mon Sep 17 00:00:00 2001 From: JiriStipek <567776@mail.muni.cz> Date: Tue, 3 Mar 2026 20:05:36 +0100 Subject: [PATCH 2/4] feat: add slide into docs --- docs/learn/get-started/quick-start.md | 18 ++++++++++++++++++ docs/reference/resources/slide.md | 9 +++++++++ mkdocs.yml | 1 + 3 files changed, 28 insertions(+) create mode 100644 docs/reference/resources/slide.md diff --git a/docs/learn/get-started/quick-start.md b/docs/learn/get-started/quick-start.md index 7200266..51b6147 100644 --- a/docs/learn/get-started/quick-start.md +++ b/docs/learn/get-started/quick-start.md @@ -52,6 +52,24 @@ Signature: - `timeout`: Optional request timeout (defaults to the client’s timeout). - Returns: `float16` NumPy array with shape `(num_classes, height, width)`. +### Slide + +#### `client.slide.heatmap` + +Signature: + +`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=1000) -> str` + +- `model`: Model identifier appended to `models_base_url`. +- `slide_path`: Path to the whole-slide image (evaluated by the service). +- `tissue_mask_path`: Path to the tissue mask for the slide (evaluated by the service). +- `output_path`: Path where the output heatmap BigTIFF will be saved (evaluated by the service). +- `stride_fraction`: Fraction of the tile size used as stride between tiles (default: `0.5`). +- `output_bigtiff_tile_height`: Tile height of the generated BigTIFF heatmap in pixels (default: `512`). +- `output_bigtiff_tile_width`: Tile width of the generated BigTIFF heatmap in pixels (default: `512`). +- `timeout`: Optional request timeout (default is 1000 seconds). +- Returns: path to the generated heatmap (matches `output_path`). + ### Quality control (QC) #### `client.qc.check_slide` diff --git a/docs/reference/resources/slide.md b/docs/reference/resources/slide.md new file mode 100644 index 0000000..96fda2f --- /dev/null +++ b/docs/reference/resources/slide.md @@ -0,0 +1,9 @@ +# Slide + +## `rationai.resources.slide.Slide` + +::: rationai.resources.slide.Slide + +## `rationai.resources.slide.AsyncSlide` + +::: rationai.resources.slide.AsyncSlide diff --git a/mkdocs.yml b/mkdocs.yml index 21348fa..f94713e 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -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 From ecaf45ba444b90272e3f6ab7aa18fe9d04f12929 Mon Sep 17 00:00:00 2001 From: JiriStipek <567776@mail.muni.cz> Date: Tue, 3 Mar 2026 20:12:04 +0100 Subject: [PATCH 3/4] fix: add slide to document start --- docs/learn/get-started/quick-start.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/learn/get-started/quick-start.md b/docs/learn/get-started/quick-start.md index 51b6147..7ca2014 100644 --- a/docs/learn/get-started/quick-start.md +++ b/docs/learn/get-started/quick-start.md @@ -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? From 6be756611e1938525213da8d0945b126612ab154 Mon Sep 17 00:00:00 2001 From: JiriStipek <567776@mail.muni.cz> Date: Sat, 7 Mar 2026 14:01:02 +0100 Subject: [PATCH 4/4] docs: remove API references --- docs/learn/get-started/quick-start.md | 70 +-------------------------- 1 file changed, 1 insertion(+), 69 deletions(-) diff --git a/docs/learn/get-started/quick-start.md b/docs/learn/get-started/quick-start.md index 7ca2014..c0c41c0 100644 --- a/docs/learn/get-started/quick-start.md +++ b/docs/learn/get-started/quick-start.md @@ -27,75 +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)`. - -### Slide - -#### `client.slide.heatmap` - -Signature: - -`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=1000) -> str` - -- `model`: Model identifier appended to `models_base_url`. -- `slide_path`: Path to the whole-slide image (evaluated by the service). -- `tissue_mask_path`: Path to the tissue mask for the slide (evaluated by the service). -- `output_path`: Path where the output heatmap BigTIFF will be saved (evaluated by the service). -- `stride_fraction`: Fraction of the tile size used as stride between tiles (default: `0.5`). -- `output_bigtiff_tile_height`: Tile height of the generated BigTIFF heatmap in pixels (default: `512`). -- `output_bigtiff_tile_width`: Tile width of the generated BigTIFF heatmap in pixels (default: `512`). -- `timeout`: Optional request timeout (default is 1000 seconds). -- Returns: path to the generated heatmap (matches `output_path`). - -### 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