Skip to content

Commit

Permalink
Upload volume to server (#64)
Browse files Browse the repository at this point in the history
- Updated module layout
- Send volume to server

---------

Co-authored-by: adiazpinto <[email protected]>
  • Loading branch information
diazandr3s and adiazpinto authored Jan 27, 2025
1 parent c6c367b commit cb20d90
Show file tree
Hide file tree
Showing 3 changed files with 491 additions and 33 deletions.
62 changes: 57 additions & 5 deletions plugins/RadCoPilot_Slicer/RadCoPilot.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,17 +151,19 @@ def setup(self):
# Set icons and tune widget properties
self.ui.serverComboBox.lineEdit().setPlaceholderText("enter server address or leave empty to use default")
self.ui.fetchServerInfoButton.setIcon(self.icon("refresh-icon.png"))
# self.ui.uploadImageButton.setIcon(self.icon("upload.svg"))
self.ui.uploadImageButton.setIcon(self.icon("upload.svg"))

# start with button disabled
self.ui.sendPrompt.setEnabled(False)
self.ui.uploadImageButton.setEnabled(False)
self.ui.outputText.setReadOnly(True)

# Connections
self.ui.fetchServerInfoButton.connect("clicked(bool)", self.onClickFetchInfo)
self.ui.serverComboBox.connect("currentIndexChanged(int)", self.onClickFetchInfo)
self.ui.sendPrompt.connect("clicked(bool)", self.onClickSendPrompt)
self.ui.cleanOutputButton.connect("clicked(bool)", self.onClickCleanOutputButton)
self.ui.uploadImageButton.connect("clicked(bool)", self.onUploadImage)

def icon(self, name="RadCoPilot.png"):
'''Get the icon for the RadCoPilot module.'''
Expand Down Expand Up @@ -229,6 +231,10 @@ def onClickFetchInfo(self):
print(f"Connected to RadCoPilot Server - Obtained info from server: {self.info}")
self.show_popup("Information", "Connected to RadCoPilot Server")
self.ui.sendPrompt.setEnabled(True)
self.ui.uploadImageButton.setEnabled(True)
# Updating model name
self.ui.appComboBox.clear()
self.ui.appComboBox.addItem(self.info)

except AttributeError as e:
slicer.util.errorDisplay(
Expand All @@ -244,6 +250,46 @@ def onClickCleanOutputButton(self):
'''Handle the click event for cleaning the output text.'''
self.ui.outputText.clear()

def onUploadImage(self):
'''Gets the volume and sen it to the server.'''
volumeNode = slicer.mrmlScene.GetFirstNodeByClass("vtkMRMLScalarVolumeNode")
image_id = volumeNode.GetName()

try:
qt.QApplication.setOverrideCursor(qt.Qt.WaitCursor)
in_file = tempfile.NamedTemporaryFile(suffix=self.file_ext, dir=self.tmpdir).name
self.current_sample = in_file
self.reportProgress(5)
start = time.time()
slicer.util.saveNode(volumeNode, in_file)
info = self.logic.uploadScan(in_file)
self.reportProgress(30)
self.info = info
print(f"Response from the upload image call: {self.info['status']}")
logging.info(f"Saved Input Node into {in_file} in {time.time() - start:3.1f}s")
print(f'Latest volume submitted: {in_file}')
self.reportProgress(100)

self._volumeNode = volumeNode
qt.QApplication.restoreOverrideCursor()
self.show_popup("Information", "Volume uploaded")

return True
except BaseException as e:
msg = f"Message: {e.msg}" if hasattr(e, "msg") else ""
self.reportProgress(100)
qt.QApplication.restoreOverrideCursor()
return False

def reportProgress(self, progressPercentage):
'''Reports progress of an event.'''
if not self.progressBar:
self.progressBar = slicer.util.createProgressDialog(windowTitle=_("Wait..."), maximum=100)
self.progressBar.show()
self.progressBar.activateWindow()
self.progressBar.setValue(progressPercentage)
slicer.app.processEvents()

def has_text(self, ui_text):
'''Check if the given UI text element has any content.'''
return len(ui_text.toPlainText()) < 1
Expand All @@ -255,14 +301,16 @@ def onClickSendPrompt(self):

self.ui.outputText.clear()

print(f"This is the image to send for analysis: {self.current_sample}")

if self.has_text(self.ui.inputText):
self.show_popup("Information", "Empty prompt")
self.ui.outputText.clear()
else:
start = time.time()
self.updateServerSettings()
inText = self.ui.inputText.toPlainText()
info = self.logic.getAnswer(inputText=inText)
info = self.logic.getAnswer(inputText=inText, volumePath=self.current_sample)
if info is not None:
self.info = info
self.ui.outputText.setText(info['choices'][0]['message']['content'])
Expand All @@ -277,7 +325,7 @@ def __init__(self, server_url=None, tmpdir=None, progress_callback=None):
ScriptedLoadableModuleLogic.__init__(self)

self.server_url = server_url
self.tmpdir = slicer.util.tempDirectory("slicer-radvilla") if tmpdir is None else tmpdir
self.tmpdir = slicer.util.tempDirectory("slicer-radcopilot") if tmpdir is None else tmpdir
self.progress_callback = progress_callback

def __del__(self):
Expand All @@ -295,10 +343,14 @@ def _client(self):
def info(self):
'''Get information from the RadCoPilot server.'''
return self._client().info()

def uploadScan(self, filePath):
'''Upload the volume to be analyzed.'''
return self._client().uploadFile(filePath)

def getAnswer(self, inputText):
def getAnswer(self, inputText, volumePath=""):
'''Get an answer from the RadCoPilot server for the given input text.'''
return self._client().getAnswer(inputText)
return self._client().getAnswer(inputText, volumePath)


class RadCoPilotTest(ScriptedLoadableModuleTest):
Expand Down
Loading

0 comments on commit cb20d90

Please sign in to comment.