Joseph Pollack commited on
Commit
c8e9e6f
Β·
unverified Β·
1 Parent(s): d3f57e1

use gradio blocks

Browse files
Files changed (1) hide show
  1. app.py +117 -96
app.py CHANGED
@@ -129,58 +129,50 @@ class LOperatorDemo:
129
  logger.error(f"Error generating action: {str(e)}")
130
  return f"❌ Error generating action: {str(e)}"
131
 
132
- @spaces.GPU(duration=90) # 1.5 minutes for chat responses
133
- def chat_with_model(self, message: str, history: List[Dict[str, str]], image=None) -> List[Dict[str, str]]:
134
- """Chat interface function for Gradio"""
135
- if not self.is_loaded:
136
- return history + [{"role": "user", "content": message}, {"role": "assistant", "content": "❌ Model not loaded. Please load the model first."}]
137
-
138
- if image is None:
139
- return history + [{"role": "user", "content": message}, {"role": "assistant", "content": "❌ Please upload an Android screenshot image."}]
140
-
141
- try:
142
- # Handle different image formats
143
- pil_image = None
144
- if hasattr(image, 'mode'): # PIL Image object
145
- pil_image = image
146
- elif isinstance(image, str) and os.path.exists(image):
147
- # Handle file path (from examples)
148
- pil_image = Image.open(image)
149
- elif hasattr(image, 'name') and os.path.exists(image.name):
150
- # Handle Gradio file object
151
- pil_image = Image.open(image.name)
152
- else:
153
- return history + [{"role": "user", "content": message}, {"role": "assistant", "content": "❌ Invalid image format. Please upload a valid image."}]
154
-
155
- if pil_image is None:
156
- return history + [{"role": "user", "content": message}, {"role": "assistant", "content": "❌ Failed to process image. Please try again."}]
157
-
158
- # Use the message as the goal/instruction
159
- goal = "Complete the requested action"
160
- instruction = message
161
-
162
- # Generate action
163
- response = self.generate_action(pil_image, goal, instruction)
164
- return history + [{"role": "user", "content": message}, {"role": "assistant", "content": response}]
165
-
166
- except Exception as e:
167
- logger.error(f"Error in chat: {str(e)}")
168
- return history + [{"role": "user", "content": message}, {"role": "assistant", "content": f"❌ Error: {str(e)}"}]
169
 
170
  # Initialize demo
171
  demo_instance = LOperatorDemo()
172
 
173
- def load_model():
174
- """Load model normally"""
 
 
 
 
 
 
 
 
 
175
  try:
176
- logger.info("Loading L-Operator model...")
177
- result = demo_instance.load_model()
178
- logger.info(f"Model loading result: {result}")
179
- return result
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
180
  except Exception as e:
181
- logger.error(f"Error loading model: {str(e)}")
182
- return f"❌ Error loading model: {str(e)}"
183
-
184
 
185
 
186
  def load_example_episodes():
@@ -227,7 +219,7 @@ def load_example_episodes():
227
 
228
  # Create Gradio interface
229
  def create_demo():
230
- """Create the Gradio demo interface"""
231
 
232
  with gr.Blocks(
233
  title="L-Operator: Android Device Control Demo",
@@ -236,8 +228,8 @@ def create_demo():
236
  .gradio-container {
237
  max-width: 1200px !important;
238
  }
239
- .chat-container {
240
- height: 600px;
241
  }
242
  """
243
  ) as demo:
@@ -252,10 +244,9 @@ def create_demo():
252
 
253
  ## πŸš€ How to Use
254
 
255
- 1. **Model Loading**: The L-Operator model loads automatically on startup
256
- 2. **Upload Screenshot**: Upload an Android device screenshot
257
- 3. **Provide Instructions**: Enter your goal and step instructions
258
- 4. **Get Actions**: The model will generate JSON actions for Android device control
259
 
260
  ## πŸ“‹ Expected Output Format
261
 
@@ -276,55 +267,85 @@ def create_demo():
276
 
277
  with gr.Row():
278
  with gr.Column(scale=1):
279
- gr.Markdown("### πŸ€– Model Status")
280
- model_status = gr.Textbox(
281
- label="L-Operator Model",
282
- value="πŸ”„ Loading model on startup...",
283
- interactive=False
284
  )
285
 
286
- with gr.Column(scale=3):
287
- gr.Markdown("### πŸ’¬ L-Operator Chat Interface")
288
- # Load examples with error handling
289
- try:
290
- examples = load_example_episodes()
291
- except Exception as e:
292
- logger.warning(f"Failed to load examples: {str(e)}")
293
- examples = []
294
 
295
- chat_interface = gr.ChatInterface(
296
- fn=demo_instance.chat_with_model,
297
- title="L-Operator: Android Device Control",
298
- description="Upload an Android screenshot and describe your goal. The model will generate JSON actions for device control.",
299
- examples=examples,
300
- type="messages",
301
- cache_examples=False,
302
- textbox=gr.Textbox(
303
- label="Goal",
304
- placeholder="e.g., Open the Settings app and navigate to Display settings",
305
- lines=2,
306
- show_label=True
307
- )
308
  )
309
 
310
- # Update model status on page load
311
- def update_model_status():
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
312
  if not demo_instance.is_loaded:
313
- logger.info("Loading model on Gradio startup...")
314
- result = load_model()
315
- logger.info(f"Model loading result: {result}")
316
- return result
317
-
318
- if demo_instance.is_loaded:
319
- return "βœ… L-Operator model loaded and ready!"
320
- else:
321
- return "❌ Model failed to load. Please check logs."
322
 
323
- # Load model and update status on page load
324
- demo.load(
325
- fn=update_model_status,
326
- outputs=model_status
327
- )
328
 
329
  gr.Markdown("""
330
  ---
@@ -345,7 +366,7 @@ def create_demo():
345
  - **Remote Support**: Remote device troubleshooting
346
  - **Development Workflows**: UI/UX testing automation
347
 
348
- ---
349
 
350
  **Made with ❀️ by Tonic** | [Model on Hugging Face](https://huggingface.co/Tonic/l-android-control)
351
  """)
 
129
  logger.error(f"Error generating action: {str(e)}")
130
  return f"❌ Error generating action: {str(e)}"
131
 
132
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
133
 
134
  # Initialize demo
135
  demo_instance = LOperatorDemo()
136
 
137
+ def process_input(image, goal):
138
+ """Process the input and generate action"""
139
+ if image is None:
140
+ return "❌ Please upload an Android screenshot image."
141
+
142
+ if not goal.strip():
143
+ return "❌ Please provide a goal."
144
+
145
+ if not demo_instance.is_loaded:
146
+ return "❌ Model not loaded. Please wait for it to load automatically."
147
+
148
  try:
149
+ # Handle different image formats
150
+ pil_image = None
151
+ if hasattr(image, 'mode'): # PIL Image object
152
+ pil_image = image
153
+ elif isinstance(image, str) and os.path.exists(image):
154
+ # Handle file path (from examples)
155
+ pil_image = Image.open(image)
156
+ elif hasattr(image, 'name') and os.path.exists(image.name):
157
+ # Handle Gradio file object
158
+ pil_image = Image.open(image.name)
159
+ else:
160
+ return "❌ Invalid image format. Please upload a valid image."
161
+
162
+ if pil_image is None:
163
+ return "❌ Failed to process image. Please try again."
164
+
165
+ # Convert image to RGB if needed
166
+ if pil_image.mode != "RGB":
167
+ pil_image = pil_image.convert("RGB")
168
+
169
+ # Generate action using goal as both goal and instruction
170
+ response = demo_instance.generate_action(pil_image, goal, goal)
171
+ return response
172
+
173
  except Exception as e:
174
+ logger.error(f"Error processing input: {str(e)}")
175
+ return f"❌ Error: {str(e)}"
 
176
 
177
 
178
  def load_example_episodes():
 
219
 
220
  # Create Gradio interface
221
  def create_demo():
222
+ """Create the Gradio demo interface using Blocks"""
223
 
224
  with gr.Blocks(
225
  title="L-Operator: Android Device Control Demo",
 
228
  .gradio-container {
229
  max-width: 1200px !important;
230
  }
231
+ .output-container {
232
+ min-height: 200px;
233
  }
234
  """
235
  ) as demo:
 
244
 
245
  ## πŸš€ How to Use
246
 
247
+ 1. **Upload Screenshot**: Upload an Android device screenshot
248
+ 2. **Describe Goal**: Enter what you want to accomplish
249
+ 3. **Get Actions**: The model will generate JSON actions for Android device control
 
250
 
251
  ## πŸ“‹ Expected Output Format
252
 
 
267
 
268
  with gr.Row():
269
  with gr.Column(scale=1):
270
+ gr.Markdown("### πŸ“± Upload Screenshot")
271
+ image_input = gr.Image(
272
+ label="Android Screenshot",
273
+ type="pil",
274
+ height=400
275
  )
276
 
277
+ gr.Markdown("### 🎯 Goal")
278
+ goal_input = gr.Textbox(
279
+ label="What would you like to accomplish?",
280
+ placeholder="e.g., Open the Settings app and navigate to Display settings",
281
+ lines=3
282
+ )
 
 
283
 
284
+ # Process button
285
+ process_btn = gr.Button("πŸš€ Generate Action", variant="primary", size="lg")
286
+
287
+ with gr.Column(scale=1):
288
+ gr.Markdown("### πŸ“Š Generated Action")
289
+ output_text = gr.Textbox(
290
+ label="JSON Action Output",
291
+ lines=15,
292
+ max_lines=20,
293
+ interactive=False,
294
+ elem_classes=["output-container"]
 
 
295
  )
296
 
297
+ # Connect the process button
298
+ process_btn.click(
299
+ fn=process_input,
300
+ inputs=[image_input, goal_input],
301
+ outputs=output_text
302
+ )
303
+
304
+ # Load examples
305
+ gr.Markdown("### πŸ“š Example Episodes")
306
+ try:
307
+ examples = load_example_episodes()
308
+ if examples:
309
+ with gr.Row():
310
+ for i, (image, goal) in enumerate(examples):
311
+ with gr.Column(scale=1):
312
+ gr.Markdown(f"**Episode {i+1}**")
313
+ example_image = gr.Image(
314
+ value=image,
315
+ label=f"Example {i+1}",
316
+ height=200,
317
+ interactive=False
318
+ )
319
+ example_goal = gr.Textbox(
320
+ value=goal,
321
+ label="Goal",
322
+ lines=2,
323
+ interactive=False
324
+ )
325
+ # Create a button to load this example
326
+ load_example_btn = gr.Button(f"Load Example {i+1}", size="sm")
327
+ load_example_btn.click(
328
+ fn=lambda img, g: (img, g),
329
+ inputs=[example_image, example_goal],
330
+ outputs=[image_input, goal_input]
331
+ )
332
+ except Exception as e:
333
+ logger.warning(f"Failed to load examples: {str(e)}")
334
+ gr.Markdown("❌ Failed to load examples. Please upload your own screenshot.")
335
+
336
+ # Load model automatically on startup
337
+ def load_model_on_startup():
338
+ """Load model automatically without user feedback"""
339
  if not demo_instance.is_loaded:
340
+ logger.info("Loading L-Operator model automatically...")
341
+ try:
342
+ demo_instance.load_model()
343
+ logger.info("Model loaded successfully in background")
344
+ except Exception as e:
345
+ logger.error(f"Failed to load model: {str(e)}")
 
 
 
346
 
347
+ # Load model automatically on page load
348
+ demo.load(fn=load_model_on_startup)
 
 
 
349
 
350
  gr.Markdown("""
351
  ---
 
366
  - **Remote Support**: Remote device troubleshooting
367
  - **Development Workflows**: UI/UX testing automation
368
 
369
+ ---
370
 
371
  **Made with ❀️ by Tonic** | [Model on Hugging Face](https://huggingface.co/Tonic/l-android-control)
372
  """)