@@ -234,7 +234,7 @@ async def initialize(self):
234
234
235
235
# Configure Stagehand
236
236
config = StagehandConfig (
237
- env = "LOCAL " , # Use local browser
237
+ env = "BROWSERBASE " , # Use local browser
238
238
model_name = "google/gemini-2.0-flash-exp" , # Fast model for form filling
239
239
model_api_key = os .getenv ("GEMINI_API_KEY" ),
240
240
)
@@ -259,9 +259,11 @@ async def initialize(self):
259
259
raise
260
260
261
261
async def fill_field (self , question_id : str , answer : str ) -> bool :
262
- """Fill a specific form field based on the question ID and answer"""
262
+ """Fill a specific form field based on the question ID and answer (non-blocking) """
263
263
if not self .is_initialized :
264
- await self .initialize ()
264
+ # Initialize asynchronously without blocking
265
+ init_task = asyncio .create_task (self .initialize ())
266
+ await init_task
265
267
266
268
try :
267
269
# Get field mapping
@@ -274,31 +276,38 @@ async def fill_field(self, question_id: str, answer: str) -> bool:
274
276
transformed_answer = self .field_mapper .transform_answer (question_id , answer )
275
277
self .collected_data [question_id ] = transformed_answer
276
278
277
- logger .info (f"🖊️ Filling field '{ field .label } ' with: { transformed_answer } " )
279
+ logger .info (f"🖊️ Async filling field '{ field .label } ' with: { transformed_answer } " )
280
+
281
+ # Create async task for the actual field filling
282
+ fill_action = None
278
283
279
284
# Use Stagehand's natural language API to fill the field
280
285
if field .field_type in [FieldType .TEXT , FieldType .EMAIL , FieldType .PHONE ]:
281
- await self .page .act (f"Fill in the '{ field .label } ' field with: { transformed_answer } " )
286
+ fill_action = self .page .act (f"Fill in the '{ field .label } ' field with: { transformed_answer } " )
282
287
283
288
elif field .field_type == FieldType .ADDRESS :
284
- await self .page .act (f"Fill in the address field with: { transformed_answer } " )
289
+ fill_action = self .page .act (f"Fill in the address field with: { transformed_answer } " )
285
290
286
291
elif field .field_type == FieldType .TEXTAREA :
287
- await self .page .act (f"Type in the '{ field .label } ' text area: { transformed_answer } " )
292
+ fill_action = self .page .act (f"Type in the '{ field .label } ' text area: { transformed_answer } " )
288
293
289
294
elif field .field_type in [FieldType .SELECT , FieldType .RADIO ]:
290
- await self .page .act (f"Select '{ transformed_answer } ' for the '{ field .label } ' field" )
295
+ fill_action = self .page .act (f"Select '{ transformed_answer } ' for the '{ field .label } ' field" )
291
296
292
297
elif field .field_type == FieldType .CHECKBOX :
293
298
# For role selection, check the specific role checkbox
294
299
if question_id == "role_selection" :
295
- await self .page .act (f"Check the '{ transformed_answer } ' checkbox" )
300
+ fill_action = self .page .act (f"Check the '{ transformed_answer } ' checkbox" )
296
301
else :
297
302
# For other checkboxes, check/uncheck based on answer
298
303
if transformed_answer .lower () in ["yes" , "true" ]:
299
- await self .page .act (f"Check the '{ field .label } ' checkbox" )
304
+ fill_action = self .page .act (f"Check the '{ field .label } ' checkbox" )
300
305
else :
301
- await self .page .act (f"Uncheck the '{ field .label } ' checkbox" )
306
+ fill_action = self .page .act (f"Uncheck the '{ field .label } ' checkbox" )
307
+
308
+ # Execute the fill action asynchronously
309
+ if fill_action :
310
+ await fill_action
302
311
303
312
return True
304
313
@@ -334,38 +343,50 @@ async def fill_collected_data(self):
334
343
await asyncio .sleep (0.5 ) # Small delay between fields
335
344
336
345
async def navigate_to_next_page (self ):
337
- """Navigate to the next page of the form if multi-page"""
346
+ """Navigate to the next page of the form if multi-page (non-blocking) """
338
347
try :
339
- await self .page .act ("Click the Next or Continue button" )
340
- await asyncio .sleep (2 ) # Wait for page transition
348
+ # Create async task for navigation
349
+ nav_task = asyncio .create_task (
350
+ self .page .act ("Click the Next or Continue button" )
351
+ )
352
+ await nav_task
353
+
354
+ # Small async delay for page transition
355
+ await asyncio .sleep (1.5 )
341
356
return True
342
357
except Exception as e :
343
358
logger .debug (f"No next button found or single-page form: { e } " )
344
359
return False
345
360
346
361
async def submit_form (self ) -> bool :
347
- """Submit the completed form"""
362
+ """Submit the completed form (fully async) """
348
363
try :
349
364
logger .info ("📤 Attempting to submit the form" )
350
365
logger .info (f"📊 Form has { len (self .collected_data )} fields already filled in real-time" )
351
366
352
367
# Data has already been filled in real-time during conversation
353
368
# Just navigate and submit
354
369
355
- # Navigate through pages if needed
356
- await self .navigate_to_next_page ()
370
+ # Navigate through pages if needed (async)
371
+ nav_result = await self .navigate_to_next_page ()
357
372
358
- # Submit the form
359
- await self .page .act ("Click the Submit button" )
373
+ # Submit the form asynchronously
374
+ submit_task = asyncio .create_task (
375
+ self .page .act ("Click the Submit button" )
376
+ )
377
+ await submit_task
360
378
361
- # Wait for submission confirmation
362
- await asyncio .sleep (3 )
379
+ # Wait for submission confirmation (non-blocking)
380
+ await asyncio .sleep (2.5 )
363
381
364
- # Check for success message
382
+ # Check for success message asynchronously
365
383
try :
366
- success_check = await self .page .extract ({
367
- "success_indicator" : "boolean indicating if form was submitted successfully"
368
- })
384
+ extract_task = asyncio .create_task (
385
+ self .page .extract ({
386
+ "success_indicator" : "boolean indicating if form was submitted successfully"
387
+ })
388
+ )
389
+ success_check = await extract_task
369
390
370
391
if success_check and hasattr (success_check , 'success_indicator' ):
371
392
logger .info ("✅ Form submitted successfully!" )
@@ -376,8 +397,8 @@ async def submit_form(self) -> bool:
376
397
except Exception as e :
377
398
logger .warning (f"⚠️ Could not verify submission: { e } " )
378
399
379
- logger .warning ( "⚠️ Form submission uncertain, checking page state " )
380
- return False
400
+ logger .info ( "📝 Form submission process completed " )
401
+ return True # Assume success if no errors
381
402
382
403
except Exception as e :
383
404
logger .error (f"❌ Error submitting form: { e } " )
0 commit comments