Skip to content

Prov-gigapath#6

Merged
Jurgee merged 4 commits into
mainfrom
feature/gigapath
May 11, 2026
Merged

Prov-gigapath#6
Jurgee merged 4 commits into
mainfrom
feature/gigapath

Conversation

@Jurgee
Copy link
Copy Markdown
Collaborator

@Jurgee Jurgee commented May 7, 2026

Summary by CodeRabbit

  • New Features

    • Added a ProvGigaPath service for LZ4-compressed GigaPath tile ingestion and on-server model inference (tiling, batching, and compressed responses).
  • Performance Improvements

    • Increased request queue capacity for multiple analysis services (semantic segmentation, heatmap builder, prostate classifier, virchow2) to support higher concurrent workloads and improve throughput.
  • Deployment

    • Registered the new ProvGigaPath application in the service list.

Review Change Stack

Jurgee and others added 3 commits May 6, 2026 19:40
Co-authored-by: Copilot <copilot@github.com>
@Jurgee Jurgee requested review from a team, JakubPekar, Copilot and ejdam87 May 7, 2026 15:57
@Jurgee Jurgee self-assigned this May 7, 2026
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 7, 2026

📝 Walkthrough

Walkthrough

Adds a new ProvGigaPath Ray Serve FastAPI deployment with typed config, model loading, batched inference, and LZ4 I/O; registers it in Helm values. Increases max_queued_requests for SemanticSegmentation, HeatmapBuilder, BinaryClassifier, and Virchow2.

Changes

ProvGigaPath Deployment

Layer / File(s) Summary
Configuration / Types
helm/rayservice/applications/prov-gigapath.yaml, helm/rayservice/values.yaml, models/prov_gigapath.py
New Helm app entry and Config TypedDict (tile_size, model, max_batch_size, batch_wait_timeout_s).
Deployment Initialization
models/prov_gigapath.py
Device selection, load HF model via timm.create_model, move to device, set eval mode, build transforms, reconfigure() updates model and batch params.
Batch Inference
models/prov_gigapath.py
predict() stacks inputs, moves to device, runs inference under torch.inference_mode(), returns outputs list.
HTTP Handler
models/prov_gigapath.py
FastAPI POST / decompresses LZ4 request into (tile_size,tile_size,3) image, applies transforms, calls predict(), converts outputs to requested dtype, compresses response, sets x-output-shape.
Integration
models/prov_gigapath.py
Exports app via ProvGigaPath.bind() and registers application in Helm values.

Queue Capacity Tuning

Layer / File(s) Summary
Deployment Queue Limits
helm/rayservice/applications/episeg-1.yaml, helm/rayservice/applications/heatmap-builder.yaml, helm/rayservice/applications/prostate-classifier-1.yaml, helm/rayservice/applications/virchow2.yaml
SemanticSegmentation: 32 → 128; HeatmapBuilder: 32 → 128; BinaryClassifier: 1024 → 4096; Virchow2: 2048 → 8192.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • Adames4
  • matejpekar

Poem

🐰 A rabbit in code, I nibble a line,
ProvGigaPath springs — tiles align.
Queues grow wider, batches take flight,
Compressed bytes hop home through the night.
Cheers to deployments running bright!

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title 'Prov-gigapath' is vague and non-descriptive—it merely names a component without conveying what changed or why. Use a more descriptive title that explains the change, such as 'Add ProvGigaPath model deployment with LZ4 compression support' or 'Implement ProvGigaPath Ray Serve application and increase queue limits'.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/gigapath

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces the prov-gigapath model service, including its Helm configuration and implementation using Ray Serve and FastAPI. It also increases the max_queued_requests for several existing deployments to improve request handling capacity. Feedback was provided to offload CPU-bound operations, such as image transformations and data compression, to separate threads using asyncio.to_thread to prevent blocking the event loop.

Comment thread models/prov_gigapath.py
Comment thread models/prov_gigapath.py
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new Ray Serve application for the Prov-GigaPath tile encoder and updates Ray Serve queue sizing across several deployments to allow higher request buffering.

Changes:

  • Introduces models/prov_gigapath.py, a FastAPI + Ray Serve tile-embedding endpoint that loads a TIMM model from Hugging Face Hub and returns LZ4-compressed embeddings.
  • Adds a new Helm application entry for prov-gigapath and registers it in values.yaml.
  • Increases max_queued_requests for multiple existing Ray Serve deployments.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
models/prov_gigapath.py New Prov-GigaPath model deployment with LZ4-in/LZ4-out inference endpoint.
helm/rayservice/values.yaml Registers the new prov-gigapath application in the Helm values list.
helm/rayservice/applications/prov-gigapath.yaml New Ray Serve application config for Prov-GigaPath (resources, autoscaling, user_config).
helm/rayservice/applications/virchow2.yaml Increases request queue limit for Virchow2 deployment.
helm/rayservice/applications/prostate-classifier-1.yaml Increases request queue limit for BinaryClassifier deployment.
helm/rayservice/applications/heatmap-builder.yaml Increases request queue limit for HeatmapBuilder deployment.
helm/rayservice/applications/episeg-1.yaml Increases request queue limit for SemanticSegmentation deployment.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread models/prov_gigapath.py
Comment thread models/prov_gigapath.py
Comment thread helm/rayservice/applications/virchow2.yaml
Comment thread helm/rayservice/applications/prostate-classifier-1.yaml
Comment thread helm/rayservice/applications/heatmap-builder.yaml
Comment thread helm/rayservice/applications/episeg-1.yaml
Comment thread helm/rayservice/applications/prov-gigapath.yaml
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@models/prov_gigapath.py`:
- Around line 86-89: Wrap the LZ4 decompression and image reshaping code that
calls lz4.frame.decompress(await request.body()) and
np.frombuffer(...).reshape(self.tile_size, self.tile_size, 3) in a try/except
that catches RuntimeError and ValueError (and optionally lz4/frame-specific
exceptions), and convert those into an HTTP 400 response with a clear error
message instead of letting them propagate to a 500; ensure the except block
returns the same response type used in this handler (e.g.,
fastapi.HTTPException(status_code=400, detail=... ) or the handler's response
object) and include context (e.g., "invalid compressed image data" or
"decompressed size mismatch") to aid clients and logs.
- Around line 91-93: The code directly calls np.dtype(...) on
request.headers.get("x-output-dtype", "float32") which raises
TypeError/ValueError for invalid strings and allows unsafe dtypes like 'object';
update the logic around the output_dtype assignment to (1) read the header
value, (2) attempt to construct np.dtype inside a try/except catching TypeError
and ValueError, (3) validate the resulting dtype.kind is numeric (e.g.,
dtype.kind in ('f','i','u')) to reject 'O'/'S' etc, and (4) on invalid/unsafe
dtype either return an HTTP 400 error response or fall back to a safe default
like float32; reference the output_dtype variable and the
request.headers.get("x-output-dtype", "float32") call and ensure this prevents
unsafe dtypes from reaching result.tobytes().
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 80ccdc44-8b84-4749-b273-1327ff3314ca

📥 Commits

Reviewing files that changed from the base of the PR and between 2372b71 and 80efa00.

📒 Files selected for processing (7)
  • helm/rayservice/applications/episeg-1.yaml
  • helm/rayservice/applications/heatmap-builder.yaml
  • helm/rayservice/applications/prostate-classifier-1.yaml
  • helm/rayservice/applications/prov-gigapath.yaml
  • helm/rayservice/applications/virchow2.yaml
  • helm/rayservice/values.yaml
  • models/prov_gigapath.py

Comment thread models/prov_gigapath.py
Comment thread models/prov_gigapath.py
@Jurgee Jurgee requested a review from matejpekar May 7, 2026 16:09
ejdam87
ejdam87 previously approved these changes May 10, 2026
Comment thread models/prov_gigapath.py Outdated
Comment thread models/prov_gigapath.py Outdated
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (2)
models/prov_gigapath.py (2)

84-87: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Handle malformed LZ4 payloads and shape mismatches as HTTP 400 (still unresolved).

On Line 84 and Line 85, invalid compressed data or decompressed-size mismatch currently bubbles to 500. This should be translated to a client error.

Proposed minimal fix
-from fastapi import FastAPI, Request, Response
+from fastapi import FastAPI, HTTPException, Request, Response
@@
-        data = await asyncio.to_thread(lz4.frame.decompress, await request.body())
-        image = np.frombuffer(data, dtype=np.uint8).reshape(
-            self.tile_size, self.tile_size, 3
-        )
+        try:
+            data = await asyncio.to_thread(lz4.frame.decompress, await request.body())
+            image = np.frombuffer(data, dtype=np.uint8).reshape(
+                self.tile_size, self.tile_size, 3
+            )
+        except (RuntimeError, ValueError) as exc:
+            raise HTTPException(
+                status_code=400,
+                detail=f"Invalid compressed image payload: {exc}",
+            ) from exc
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@models/prov_gigapath.py` around lines 84 - 87, The decompression and reshape
steps (the lz4.frame.decompress call and
np.frombuffer(...).reshape(...)/self.tile_size usage) can raise
lz4.frame.LZ4FrameError or ValueError and currently propagate as 500; catch
these specific exceptions around the decompress + frombuffer/reshape block and
translate them into a client 400 response by raising FastAPI/Starlette
HTTPException(status_code=400, detail="Malformed LZ4 payload or size mismatch")
(add the import for HTTPException if needed). Ensure you catch
lz4.frame.LZ4FrameError and ValueError (or numpy/struct shape errors) and raise
the HTTPException rather than letting the exception bubble.

89-91: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Validate x-output-dtype and reject unsafe/invalid dtypes (still unresolved).

On Line 89, direct np.dtype(...) on untrusted header input can raise and return 500; it also permits non-numeric dtypes (for example object/string kinds) that should not be serialized here.

Proposed minimal fix
-        output_dtype = np.dtype(
-            request.headers.get("x-output-dtype", "float32").lower()
-        )
+        dtype_raw = request.headers.get("x-output-dtype", "float32").lower()
+        try:
+            output_dtype = np.dtype(dtype_raw)
+        except (TypeError, ValueError) as exc:
+            raise HTTPException(
+                status_code=400,
+                detail=f"Unsupported x-output-dtype: {dtype_raw!r}",
+            ) from exc
+        if output_dtype.kind not in {"f", "i", "u"}:
+            raise HTTPException(
+                status_code=400,
+                detail=f"Non-numeric x-output-dtype not supported: {dtype_raw!r}",
+            )
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@models/prov_gigapath.py` around lines 89 - 91, The current code calls
np.dtype on untrusted header input (request.headers.get("x-output-dtype")) which
can raise and also allow unsafe non-numeric kinds; fix by validating and
sanitizing the header: parse the header inside a try/except around np.dtype(...)
to catch invalid strings, then ensure the resulting dtype.kind is one of the
numeric kinds (e.g., 'i','u','f','c') or check against a small whitelist of
allowed dtype names (e.g., "float32","float64","int32", etc.); if parsing fails
or the kind is not numeric, reject the request with a 4xx error (do not allow
object/string dtypes) and only set output_dtype when validation passes.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Duplicate comments:
In `@models/prov_gigapath.py`:
- Around line 84-87: The decompression and reshape steps (the
lz4.frame.decompress call and np.frombuffer(...).reshape(...)/self.tile_size
usage) can raise lz4.frame.LZ4FrameError or ValueError and currently propagate
as 500; catch these specific exceptions around the decompress +
frombuffer/reshape block and translate them into a client 400 response by
raising FastAPI/Starlette HTTPException(status_code=400, detail="Malformed LZ4
payload or size mismatch") (add the import for HTTPException if needed). Ensure
you catch lz4.frame.LZ4FrameError and ValueError (or numpy/struct shape errors)
and raise the HTTPException rather than letting the exception bubble.
- Around line 89-91: The current code calls np.dtype on untrusted header input
(request.headers.get("x-output-dtype")) which can raise and also allow unsafe
non-numeric kinds; fix by validating and sanitizing the header: parse the header
inside a try/except around np.dtype(...) to catch invalid strings, then ensure
the resulting dtype.kind is one of the numeric kinds (e.g., 'i','u','f','c') or
check against a small whitelist of allowed dtype names (e.g.,
"float32","float64","int32", etc.); if parsing fails or the kind is not numeric,
reject the request with a 4xx error (do not allow object/string dtypes) and only
set output_dtype when validation passes.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 63ed7cb2-c134-4d0e-97eb-88a7e7ebaf81

📥 Commits

Reviewing files that changed from the base of the PR and between 80efa00 and a101567.

📒 Files selected for processing (1)
  • models/prov_gigapath.py

@Jurgee Jurgee requested a review from matejpekar May 10, 2026 18:05
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

@Jurgee Jurgee requested a review from ejdam87 May 11, 2026 05:10
@Jurgee Jurgee merged commit 55a5bb2 into main May 11, 2026
6 of 7 checks passed
@Jurgee Jurgee deleted the feature/gigapath branch May 11, 2026 11:03
@coderabbitai coderabbitai Bot mentioned this pull request May 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants