-
Notifications
You must be signed in to change notification settings - Fork 0
README cleanup + add Slide section into docs #5
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
Jurgee
wants to merge
3
commits into
main
Choose a base branch
from
docs/README-cleanup
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+57
−199
Open
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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. | ||
| [](https://www.python.org/downloads/) | ||
| [](https://opensource.org/licenses/MIT) | ||
| [](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. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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? | ||
|
|
||
|
|
@@ -52,6 +53,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`). | ||
|
Comment on lines
+58
to
+72
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do not copy the API reference to quick start. Also remove it for the other methods |
||
|
|
||
| ### Quality control (QC) | ||
|
|
||
| #### `client.qc.check_slide` | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The quick-start page now includes a new “Slide” section, but earlier in this same document the list of exposed resources only mentions
client.modelsandclient.qc. To keep the page internally consistent (and help readers discover the new API), please update that earlier list to includeclient.slideas well.