Pixedar commited on
Commit
f85b856
·
verified ·
1 Parent(s): 1461443

Improve MindVisualizer streamed probe explanations

Browse files
Files changed (1) hide show
  1. app.py +55 -0
app.py CHANGED
@@ -1,3 +1,4 @@
 
1
  import os
2
  import sys
3
  from functools import lru_cache
@@ -7,6 +8,7 @@ from typing import Literal
7
  import numpy as np
8
  from fastapi import FastAPI, HTTPException
9
  from fastapi.middleware.cors import CORSMiddleware
 
10
  from pydantic import BaseModel, Field
11
 
12
 
@@ -150,26 +152,79 @@ def trajectory(req: TrajectoryRequest):
150
 
151
  @app.post("/api/mindvis/explain")
152
  def explain(req: ExplainRequest):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
153
  svc = services()
154
  traj = np.asarray(req.trajectory, dtype=np.float32)
155
  if traj.ndim != 2 or traj.shape[1] != 3:
156
  raise HTTPException(status_code=400, detail="trajectory must be an array of [x,y,z] points")
157
 
 
158
  world = denormalized(np.clip(traj, 0.0, 1.0), svc["amin"], svc["span"])
159
  sampler = svc["samplers"].get(req.fieldMode, svc["samplers"]["mean"])
160
  mags = np.linalg.norm(sampler.sample_vec(world), axis=1).astype(np.float32)
 
161
  transitions = analyze_regions(world, mags, req.callLlm)
 
162
  text = format_transition_text(transitions)
163
 
164
  if req.callLlm:
165
  from src.region_analyzer import analyze_with_gpt
166
 
 
167
  text = analyze_with_gpt(
168
  transitions,
169
  use_rag=os.environ.get("MINDVIS_USE_RAG", "0") == "1",
170
  model=os.environ.get("OPENAI_MODEL", "gpt-5.4-mini"),
171
  debug=os.environ.get("MINDVIS_DEBUG", "0") == "1",
172
  )
 
173
 
174
  return {"text": text, "transitions": transitions, "regionText": format_transition_text(transitions)}
175
 
 
1
+ import json
2
  import os
3
  import sys
4
  from functools import lru_cache
 
8
  import numpy as np
9
  from fastapi import FastAPI, HTTPException
10
  from fastapi.middleware.cors import CORSMiddleware
11
+ from fastapi.responses import StreamingResponse
12
  from pydantic import BaseModel, Field
13
 
14
 
 
152
 
153
  @app.post("/api/mindvis/explain")
154
  def explain(req: ExplainRequest):
155
+ return build_explanation(req)
156
+
157
+
158
+ @app.post("/api/mindvis/explain/stream")
159
+ def explain_stream(req: ExplainRequest):
160
+ def event_stream():
161
+ def event(payload: dict) -> str:
162
+ return json.dumps(payload) + "\n"
163
+
164
+ try:
165
+ yield event({"type": "log", "message": "Loading MindVisualizer field samplers and brain label grid."})
166
+ svc = services()
167
+ traj = np.asarray(req.trajectory, dtype=np.float32)
168
+ if traj.ndim != 2 or traj.shape[1] != 3:
169
+ raise HTTPException(status_code=400, detail="trajectory must be an array of [x,y,z] points")
170
+
171
+ yield event({"type": "log", "message": f"Received {len(traj)} normalized probe samples in {req.fieldMode} mode."})
172
+ world = denormalized(np.clip(traj, 0.0, 1.0), svc["amin"], svc["span"])
173
+ sampler = svc["samplers"].get(req.fieldMode, svc["samplers"]["mean"])
174
+ mags = np.linalg.norm(sampler.sample_vec(world), axis=1).astype(np.float32)
175
+
176
+ yield event({"type": "log", "message": "Sampling flow strength and entropy along the traveled path."})
177
+ transitions = analyze_regions(world, mags, req.callLlm)
178
+ yield event({"type": "log", "message": f"Detected {len(transitions)} entered or nearby anatomical regions."})
179
+
180
+ text = format_transition_text(transitions)
181
+ if req.callLlm:
182
+ from src.region_analyzer import analyze_with_gpt
183
+
184
+ yield event({"type": "log", "message": "Calling the OpenAI model for the neuroscience interpretation."})
185
+ text = analyze_with_gpt(
186
+ transitions,
187
+ use_rag=os.environ.get("MINDVIS_USE_RAG", "0") == "1",
188
+ model=os.environ.get("OPENAI_MODEL", "gpt-5.4-mini"),
189
+ debug=os.environ.get("MINDVIS_DEBUG", "0") == "1",
190
+ )
191
+ yield event({"type": "log", "message": "LLM interpretation finished."})
192
+
193
+ yield event({"type": "result", "text": text, "transitions": transitions, "regionText": format_transition_text(transitions)})
194
+ except Exception as exc:
195
+ yield event({"type": "error", "message": str(exc)})
196
+
197
+ return StreamingResponse(event_stream(), media_type="application/x-ndjson")
198
+
199
+
200
+ def build_explanation(req: ExplainRequest, log=None):
201
+ log = log or (lambda _message: None)
202
+ log("Loading MindVisualizer field samplers and brain label grid.")
203
  svc = services()
204
  traj = np.asarray(req.trajectory, dtype=np.float32)
205
  if traj.ndim != 2 or traj.shape[1] != 3:
206
  raise HTTPException(status_code=400, detail="trajectory must be an array of [x,y,z] points")
207
 
208
+ log(f"Received {len(traj)} normalized probe samples in {req.fieldMode} mode.")
209
  world = denormalized(np.clip(traj, 0.0, 1.0), svc["amin"], svc["span"])
210
  sampler = svc["samplers"].get(req.fieldMode, svc["samplers"]["mean"])
211
  mags = np.linalg.norm(sampler.sample_vec(world), axis=1).astype(np.float32)
212
+ log("Sampling flow strength and entropy along the traveled path.")
213
  transitions = analyze_regions(world, mags, req.callLlm)
214
+ log(f"Detected {len(transitions)} entered or nearby anatomical regions.")
215
  text = format_transition_text(transitions)
216
 
217
  if req.callLlm:
218
  from src.region_analyzer import analyze_with_gpt
219
 
220
+ log("Calling the OpenAI model for the neuroscience interpretation.")
221
  text = analyze_with_gpt(
222
  transitions,
223
  use_rag=os.environ.get("MINDVIS_USE_RAG", "0") == "1",
224
  model=os.environ.get("OPENAI_MODEL", "gpt-5.4-mini"),
225
  debug=os.environ.get("MINDVIS_DEBUG", "0") == "1",
226
  )
227
+ log("LLM interpretation finished.")
228
 
229
  return {"text": text, "transitions": transitions, "regionText": format_transition_text(transitions)}
230