hmgill commited on
Commit
2cd8aa5
Β·
verified Β·
1 Parent(s): 63f35ec

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +11 -22
app.py CHANGED
@@ -3,15 +3,14 @@ import asyncio
3
  import os
4
  import glob
5
  import torch
6
- import sys
7
  from pathlib import Path
8
- from PIL import Image
9
 
10
- # --- CRITICAL FIX: Redirect stdin to avoid "Invalid file descriptor" crash ---
11
- # The agent runner checks stdin for potential human-in-the-loop confirmation.
12
- # In a web app (Gradio/Cloud Run), stdin is closed/invalid. Redirecting to
13
- # devnull tricks the runner into proceeding without crashing.
14
- sys.stdin = open(os.devnull, 'r')
15
 
16
  # GenAI & ADK Imports
17
  from google.adk.runners import InMemoryRunner
@@ -23,7 +22,6 @@ from cellemetry.config import AnalysisDeps
23
  from transformers import Sam3Processor, Sam3Model
24
 
25
  # --- Global State for Heavy Models ---
26
- # We load the model once when the app starts to avoid reloading per request.
27
  MODEL_CACHE = {
28
  "model": None,
29
  "processor": None,
@@ -40,15 +38,11 @@ def load_models():
40
  MODEL_CACHE["device"] = device
41
 
42
  try:
43
- # Note: Ensure you have access to facebook/sam3 or use a public alternative
44
- # If running on CPU only, this might be slow!
45
  MODEL_CACHE["model"] = Sam3Model.from_pretrained("facebook/sam3").to(device)
46
  MODEL_CACHE["processor"] = Sam3Processor.from_pretrained("facebook/sam3")
47
  print(f"βœ… SAM3 loaded on {device}")
48
  except Exception as e:
49
  print(f"⚠️ SAM3 load failed (using mock or fallback): {e}")
50
- # We allow the app to continue; the agent tools will handle the missing model
51
- # (check sam.py for the mock/fallback logic)
52
 
53
  # Load immediately on startup
54
  load_models()
@@ -77,7 +71,7 @@ async def run_analysis(image_path_str, user_prompt, progress=gr.Progress()):
77
  sam_processor=MODEL_CACHE["processor"],
78
  image_path=image_path,
79
  device=MODEL_CACHE["device"],
80
- pixel_size_microns=None # Agent will parse this from prompt
81
  )
82
 
83
  # 2. Initialize Runner
@@ -124,19 +118,16 @@ async def run_analysis(image_path_str, user_prompt, progress=gr.Progress()):
124
  for part in event.content.parts:
125
  if hasattr(part, 'text') and part.text:
126
  if event.partial:
127
- # Update the last log line if it's the same thought being streamed
128
  if logs and logs[-1].startswith(f"πŸ’¬ **{author}**"):
129
  logs[-1] = f"πŸ’¬ **{author}**: {part.text}..."
130
  else:
131
  logs.append(f"πŸ’¬ **{author}**: {part.text}...")
132
  else:
133
- # Finalize the log line
134
  if logs and logs[-1].startswith(f"πŸ’¬ **{author}**"):
135
  logs[-1] = f"βœ… **{author}**: {part.text}"
136
  else:
137
  logs.append(f"βœ… **{author}**: {part.text}")
138
 
139
- # Yield updated logs immediately
140
  yield "\n\n".join(logs), None, None
141
 
142
  except Exception as e:
@@ -148,10 +139,7 @@ async def run_analysis(image_path_str, user_prompt, progress=gr.Progress()):
148
  logs.append("\n🏁 **Analysis Complete.** gathering files...")
149
  yield "\n\n".join(logs), None, None
150
 
151
- # Collect output images (segmentation maps)
152
  output_images = glob.glob("/tmp/out_*.png")
153
-
154
- # Collect excel report
155
  excel_files = glob.glob("/tmp/*.xlsx")
156
  report_file = excel_files[0] if excel_files else None
157
 
@@ -160,7 +148,8 @@ async def run_analysis(image_path_str, user_prompt, progress=gr.Progress()):
160
 
161
 
162
  # --- Gradio UI Layout ---
163
- with gr.Blocks(title="Cellemetry Agent", theme=gr.themes.Soft()) as demo:
 
164
  gr.Markdown("# πŸ”¬ Cellemetry: Agentic Microscopy Analysis")
165
  gr.Markdown("Upload a microscopy image and ask the agent to identify, segment, and quantify biological structures.")
166
 
@@ -185,7 +174,6 @@ with gr.Blocks(title="Cellemetry Agent", theme=gr.themes.Soft()) as demo:
185
  # Output Section
186
  with gr.Tabs():
187
  with gr.Tab("Live Agent Logs"):
188
- # Markdown component to render bolding/formatting in logs
189
  log_output = gr.Markdown(label="Agent Thought Process", height=500)
190
 
191
  with gr.Tab("Visual Results"):
@@ -202,4 +190,5 @@ with gr.Blocks(title="Cellemetry Agent", theme=gr.themes.Soft()) as demo:
202
  )
203
 
204
  if __name__ == "__main__":
205
- demo.queue().launch()
 
 
3
  import os
4
  import glob
5
  import torch
6
+ import builtins # <--- Import builtins
7
  from pathlib import Path
 
8
 
9
+ # --- CRITICAL FIX: Safe Input Mocking ---
10
+ # Instead of messing with sys.stdin (which breaks asyncio), we override
11
+ # the python input() function to auto-approve all tool execution prompts.
12
+ # This prevents the "Invalid file descriptor" crash in cloud containers.
13
+ builtins.input = lambda *args: "y"
14
 
15
  # GenAI & ADK Imports
16
  from google.adk.runners import InMemoryRunner
 
22
  from transformers import Sam3Processor, Sam3Model
23
 
24
  # --- Global State for Heavy Models ---
 
25
  MODEL_CACHE = {
26
  "model": None,
27
  "processor": None,
 
38
  MODEL_CACHE["device"] = device
39
 
40
  try:
 
 
41
  MODEL_CACHE["model"] = Sam3Model.from_pretrained("facebook/sam3").to(device)
42
  MODEL_CACHE["processor"] = Sam3Processor.from_pretrained("facebook/sam3")
43
  print(f"βœ… SAM3 loaded on {device}")
44
  except Exception as e:
45
  print(f"⚠️ SAM3 load failed (using mock or fallback): {e}")
 
 
46
 
47
  # Load immediately on startup
48
  load_models()
 
71
  sam_processor=MODEL_CACHE["processor"],
72
  image_path=image_path,
73
  device=MODEL_CACHE["device"],
74
+ pixel_size_microns=None
75
  )
76
 
77
  # 2. Initialize Runner
 
118
  for part in event.content.parts:
119
  if hasattr(part, 'text') and part.text:
120
  if event.partial:
 
121
  if logs and logs[-1].startswith(f"πŸ’¬ **{author}**"):
122
  logs[-1] = f"πŸ’¬ **{author}**: {part.text}..."
123
  else:
124
  logs.append(f"πŸ’¬ **{author}**: {part.text}...")
125
  else:
 
126
  if logs and logs[-1].startswith(f"πŸ’¬ **{author}**"):
127
  logs[-1] = f"βœ… **{author}**: {part.text}"
128
  else:
129
  logs.append(f"βœ… **{author}**: {part.text}")
130
 
 
131
  yield "\n\n".join(logs), None, None
132
 
133
  except Exception as e:
 
139
  logs.append("\n🏁 **Analysis Complete.** gathering files...")
140
  yield "\n\n".join(logs), None, None
141
 
 
142
  output_images = glob.glob("/tmp/out_*.png")
 
 
143
  excel_files = glob.glob("/tmp/*.xlsx")
144
  report_file = excel_files[0] if excel_files else None
145
 
 
148
 
149
 
150
  # --- Gradio UI Layout ---
151
+ # Note: 'theme' is passed to Blocks for initial render, but can also be configured in launch
152
+ with gr.Blocks(title="Cellemetry Agent") as demo:
153
  gr.Markdown("# πŸ”¬ Cellemetry: Agentic Microscopy Analysis")
154
  gr.Markdown("Upload a microscopy image and ask the agent to identify, segment, and quantify biological structures.")
155
 
 
174
  # Output Section
175
  with gr.Tabs():
176
  with gr.Tab("Live Agent Logs"):
 
177
  log_output = gr.Markdown(label="Agent Thought Process", height=500)
178
 
179
  with gr.Tab("Visual Results"):
 
190
  )
191
 
192
  if __name__ == "__main__":
193
+ # Fix for Gradio 6.0 warning: theme is best handled here if dynamic, or in Blocks
194
+ demo.queue().launch(theme=gr.themes.Soft(), ssr_mode=False)