andreped commited on
Commit
2afcdda
·
unverified ·
2 Parent(s): b6670af 6f9d64a

Merge pull request #32 from andreped/render-fix

Browse files

Added logging and sidebar widgets with clear/toggle methods

Files changed (3) hide show
  1. demo/src/gui.py +103 -56
  2. demo/src/inference.py +0 -3
  3. demo/src/logger.py +37 -0
demo/src/gui.py CHANGED
@@ -3,10 +3,16 @@ import os
3
  import gradio as gr
4
 
5
  from .inference import run_model
 
 
 
6
  from .utils import load_ct_to_numpy
7
  from .utils import load_pred_volume_to_numpy
8
  from .utils import nifti_to_glb
9
 
 
 
 
10
 
11
  class WebUI:
12
  def __init__(
@@ -53,14 +59,16 @@ class WebUI:
53
  ).style(height=512)
54
 
55
  def set_class_name(self, value):
56
- print("Changed task to:", value)
57
  self.class_name = value
58
 
59
  def combine_ct_and_seg(self, img, pred):
60
  return (img, [(pred, self.class_name)])
61
 
62
  def upload_file(self, file):
63
- return file.name
 
 
64
 
65
  def process(self, mesh_file_name):
66
  path = mesh_file_name.name
@@ -70,9 +78,13 @@ class WebUI:
70
  task=self.class_names[self.class_name],
71
  name=self.result_names[self.class_name],
72
  )
 
73
  nifti_to_glb("prediction.nii.gz")
74
 
 
75
  self.images = load_ct_to_numpy(path)
 
 
76
  self.pred_images = load_pred_volume_to_numpy("./prediction.nii.gz")
77
 
78
  return "./prediction.obj"
@@ -90,6 +102,10 @@ class WebUI:
90
  )
91
  return out
92
 
 
 
 
 
93
  def run(self):
94
  css = """
95
  #model-3d {
@@ -100,69 +116,100 @@ class WebUI:
100
  margin: auto;
101
  }
102
  #upload {
103
- height: 120px;
104
  }
105
  """
106
  with gr.Blocks(css=css) as demo:
107
  with gr.Row():
108
- file_output = gr.File(file_count="single", elem_id="upload")
109
- file_output.upload(self.upload_file, file_output, file_output)
110
-
111
- model_selector = gr.Dropdown(
112
- list(self.class_names.keys()),
113
- label="Task",
114
- info="Which task to perform",
115
- multiselect=False,
116
- size="sm",
117
- )
118
- model_selector.input(
119
- fn=lambda x: self.set_class_name(x),
120
- inputs=model_selector,
121
- outputs=None,
122
- )
123
-
124
- run_btn = gr.Button("Run analysis").style(
125
- full_width=False, size="lg"
126
- )
127
- run_btn.click(
128
- fn=lambda x: self.process(x),
129
- inputs=file_output,
130
- outputs=self.volume_renderer,
131
- )
132
-
133
- with gr.Row():
134
- gr.Examples(
135
- examples=[
136
- os.path.join(self.cwd, "test_thorax_CT.nii.gz"),
137
- ],
138
- inputs=file_output,
139
- outputs=file_output,
140
- fn=self.upload_file,
141
- cache_examples=True,
142
- )
143
-
144
- with gr.Row():
145
- with gr.Box():
146
- with gr.Column():
147
- # create dummy image to be replaced by loaded images
148
- t = gr.AnnotatedImage(
149
- visible=True, elem_id="model-2d"
150
- ).style(
151
- color_map={self.class_name: "#ffae00"},
152
- height=512,
153
- width=512,
154
  )
155
 
156
- self.slider.input(
157
- self.get_img_pred_pair,
158
- self.slider,
159
- t,
 
 
 
 
 
 
 
160
  )
161
 
162
- self.slider.render()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
163
 
164
- with gr.Box():
165
- self.volume_renderer.render()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
166
 
167
  # sharing app publicly -> share=True:
168
  # https://gradio.app/sharing-your-app/
 
3
  import gradio as gr
4
 
5
  from .inference import run_model
6
+ from .logger import flush_logs
7
+ from .logger import read_logs
8
+ from .logger import setup_logger
9
  from .utils import load_ct_to_numpy
10
  from .utils import load_pred_volume_to_numpy
11
  from .utils import nifti_to_glb
12
 
13
+ # setup logging
14
+ LOGGER = setup_logger()
15
+
16
 
17
  class WebUI:
18
  def __init__(
 
59
  ).style(height=512)
60
 
61
  def set_class_name(self, value):
62
+ LOGGER.info(f"Changed task to: {value}")
63
  self.class_name = value
64
 
65
  def combine_ct_and_seg(self, img, pred):
66
  return (img, [(pred, self.class_name)])
67
 
68
  def upload_file(self, file):
69
+ out = file.name
70
+ LOGGER.info(f"File uploaded: {out}")
71
+ return out
72
 
73
  def process(self, mesh_file_name):
74
  path = mesh_file_name.name
 
78
  task=self.class_names[self.class_name],
79
  name=self.result_names[self.class_name],
80
  )
81
+ LOGGER.info("Converting prediction NIfTI to GLB...")
82
  nifti_to_glb("prediction.nii.gz")
83
 
84
+ LOGGER.info("Loading CT to numpy...")
85
  self.images = load_ct_to_numpy(path)
86
+
87
+ LOGGER.info("Loading prediction volume to numpy..")
88
  self.pred_images = load_pred_volume_to_numpy("./prediction.nii.gz")
89
 
90
  return "./prediction.obj"
 
102
  )
103
  return out
104
 
105
+ def toggle_sidebar(self, state):
106
+ state = not state
107
+ return gr.update(visible=state), state
108
+
109
  def run(self):
110
  css = """
111
  #model-3d {
 
116
  margin: auto;
117
  }
118
  #upload {
119
+ height: 160px;
120
  }
121
  """
122
  with gr.Blocks(css=css) as demo:
123
  with gr.Row():
124
+ with gr.Column(visible=True, scale=0.2) as sidebar_left:
125
+ # gr.Markdown("SideBar Left")
126
+ logs = gr.Textbox(
127
+ label="Logs",
128
+ info="Verbose from inference will be displayed below.",
129
+ max_lines=16,
130
+ autoscroll=True,
131
+ elem_id="logs",
132
+ show_copy_button=True,
133
+ )
134
+ demo.load(read_logs, None, logs, every=1)
135
+
136
+ with gr.Column():
137
+ with gr.Row():
138
+ file_output = gr.File(
139
+ file_count="single", elem_id="upload"
140
+ )
141
+ file_output.upload(
142
+ self.upload_file, file_output, file_output
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
143
  )
144
 
145
+ model_selector = gr.Dropdown(
146
+ list(self.class_names.keys()),
147
+ label="Task",
148
+ info="Which task to perform",
149
+ multiselect=False,
150
+ size="sm",
151
+ )
152
+ model_selector.input(
153
+ fn=lambda x: self.set_class_name(x),
154
+ inputs=model_selector,
155
+ outputs=None,
156
  )
157
 
158
+ with gr.Column():
159
+ run_btn = gr.Button("Run analysis").style(
160
+ full_width=False, size="lg"
161
+ )
162
+ run_btn.click(
163
+ fn=lambda x: self.process(x),
164
+ inputs=file_output,
165
+ outputs=self.volume_renderer,
166
+ )
167
+
168
+ sidebar_state = gr.State(True)
169
+
170
+ btn_toggle_sidebar = gr.Button("Toggle Sidebar")
171
+ btn_toggle_sidebar.click(
172
+ self.toggle_sidebar,
173
+ [sidebar_state],
174
+ [sidebar_left, sidebar_state],
175
+ )
176
+
177
+ btn_clear_logs = gr.Button("Clear logs")
178
+ btn_clear_logs.click(flush_logs, [], [])
179
+
180
+ with gr.Row():
181
+ gr.Examples(
182
+ examples=[
183
+ os.path.join(self.cwd, "test_thorax_CT.nii.gz"),
184
+ ],
185
+ inputs=file_output,
186
+ outputs=file_output,
187
+ fn=self.upload_file,
188
+ cache_examples=True,
189
+ )
190
 
191
+ with gr.Row():
192
+ with gr.Box():
193
+ with gr.Column():
194
+ # create dummy image to be replaced by loaded images
195
+ t = gr.AnnotatedImage(
196
+ visible=True, elem_id="model-2d"
197
+ ).style(
198
+ color_map={self.class_name: "#ffae00"},
199
+ height=512,
200
+ width=512,
201
+ )
202
+
203
+ self.slider.input(
204
+ self.get_img_pred_pair,
205
+ self.slider,
206
+ t,
207
+ )
208
+
209
+ self.slider.render()
210
+
211
+ with gr.Box():
212
+ self.volume_renderer.render()
213
 
214
  # sharing app publicly -> share=True:
215
  # https://gradio.app/sharing-your-app/
demo/src/inference.py CHANGED
@@ -12,9 +12,6 @@ def run_model(
12
  task: str = "CT_Airways",
13
  name: str = "Airways",
14
  ):
15
- logging.basicConfig()
16
- logging.getLogger().setLevel(logging.WARNING)
17
-
18
  if verbose == "debug":
19
  logging.getLogger().setLevel(logging.DEBUG)
20
  elif verbose == "info":
 
12
  task: str = "CT_Airways",
13
  name: str = "Airways",
14
  ):
 
 
 
15
  if verbose == "debug":
16
  logging.getLogger().setLevel(logging.DEBUG)
17
  elif verbose == "info":
demo/src/logger.py ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import logging
2
+ import sys
3
+
4
+
5
+ def get_logger():
6
+ return logging.getLogger(__name__)
7
+
8
+
9
+ def setup_logger():
10
+ # clear log
11
+ file_to_delete = open("log.txt", "w")
12
+ file_to_delete.close()
13
+
14
+ file_handler = logging.FileHandler(filename="log.txt")
15
+ stdout_handler = logging.StreamHandler(stream=sys.stdout)
16
+ handlers = [file_handler, stdout_handler]
17
+
18
+ logging.basicConfig(
19
+ level=logging.INFO,
20
+ format="[%(asctime)s] {%(filename)s:%(lineno)d} %(levelname)s - %(message)s",
21
+ handlers=handlers,
22
+ )
23
+
24
+ return get_logger()
25
+
26
+
27
+ def read_logs():
28
+ sys.stdout.flush()
29
+ with open("log.txt", "r") as f:
30
+ return f.read()
31
+
32
+
33
+ def flush_logs():
34
+ sys.stdout.flush()
35
+ # clear log
36
+ file_to_delete = open("log.txt", "w")
37
+ file_to_delete.close()