Skip to content

BodyMaps AI assistant: streaming chat, organ segmentation & measurement, screenshot vision - #119

Merged
Awpoon123 merged 3 commits into
mainfrom
bodymaps-ai-assistant
Aug 3, 2026
Merged

BodyMaps AI assistant: streaming chat, organ segmentation & measurement, screenshot vision#119
Awpoon123 merged 3 commits into
mainfrom
bodymaps-ai-assistant

Conversation

@Awpoon123

Copy link
Copy Markdown
Collaborator

Summary

Adds a conversational AI assistant embedded in the CT viewer. Users can segment
and measure organs, read the CT views, and ask general medical questions. It runs
entirely on local models via Ollama, so no external API is required.

What's included

  • Sidebar chat with streaming responses; the viewer shifts left and the panel is resizable.
  • "Segment the liver and tell me its volume" isolates the organ and returns the exact
    volume computed from the segmentation mask (voxel count × voxel size → cm³).
  • Screenshot capture of the axial/sagittal/coronal/3D views, with a color→organ legend
    so the assistant can identify each mask color.
  • On-demand 3D mesh generation (with a HuggingFace fallback) so 3D works locally;
    scripts/precompute_meshes.py can pre-bake meshes.
  • Backend boots without a local dataset; concise, complete answers.

How to run

Backend: set flask-server/.env (see .env.example) and run python app.py.
Frontend: npm install && npm run dev. Models: Ollama with llama3.1, qwen3-vl, qwen3.

Comment thread flask-server/api/api_blueprint.py Outdated
return jsonify(manifest)
except Exception as exc:
print(f"[mesh] manifest generation failed for {display_id}: {exc}")
return jsonify({"error": f"Error generating mesh manifest: {exc}"}), 500
def get_mesh_file(display_id, filename):
# Both segments come straight from the URL and are joined into a path;
# apply the same id-guard + secure_filename barrier as the other routes.
if not _is_safe_id(display_id):
Comment thread flask-server/api/api_blueprint.py Fixed
return (job.get("status") or "").lower() if job else ""
Returns None when the session is genuinely unknown. A job found only on
disk was started by a *previous* process (a job from this process would
still be in memory); if that disk copy is still "running" its worker
reporting a phantom "running" that would poll forever.
"""
job = inference_jobs.get(session_id)
if job:
@@ -948,15 +1009,9 @@ def _uploaded_file_candidate(session_id, uploaded_filename):
return candidate if os.path.exists(candidate) else None
@@ -948,15 +1009,9 @@ def _uploaded_file_candidate(session_id, uploaded_filename):
return candidate if os.path.exists(candidate) else None
@Awpoon123

Copy link
Copy Markdown
Collaborator Author

The CodeQL alerts here are all pre-existing repo issues, not introduced by this PR, the critical SSRF is the existing /proxy-image route, and several are in services/inference_job_queue.py, which this PR doesn't touch. They surface as "new" only because main has no CodeQL baseline (the repo already lists 88 alerts). All new file paths in this PR validate case IDs as integers before any file access. Happy to open a separate hardening PR for the pre-existing findings if useful.

@Awpoon123
Awpoon123 merged commit 5a98363 into main Aug 3, 2026
7 of 8 checks passed
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.

2 participants