wuhp commited on
Commit
cb1b9d8
·
verified ·
1 Parent(s): 910909f

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +150 -226
app.py CHANGED
@@ -229,54 +229,35 @@ def greet():
229
  return [{"role": "assistant", "content": "Welcome! Please log in to Hugging Face and provide your Google AI Studio API key to start building Spaces. Once ready, type 'generate me a gradio app called myapp' or 'create' to begin."}]
230
 
231
  # Helper function to update send button interactivity based on prereqs
232
- # MODIFIED: Signature takes exactly 4 inputs, removed *args, **kwargs
233
- # FIXED: Return type hint corrected to gr.update
234
- # MODIFIED: Internal logic uses bool() check for simplicity
235
- # REMOVED: problematic debug prints involving *args, **kwargs
236
  def check_send_button_ready(hf_profile: gr.OAuthProfile | None, hf_token: gr.OAuthToken | None, gemini_key: str | None, gemini_model: str | None) -> gr.update:
237
  """Checks if HF login and Gemini configuration are complete and returns update for button interactivity."""
238
  # --- START ENHANCED DEBUGGING LOGS ---
239
  print("\n--- check_send_button_ready START ---")
240
- print(f" Received hf_profile: Type={type(hf_profile)}, Value={'present' if hf_profile else 'None'}")
241
- print(f" Received hf_token: Type={type(hf_token)}, Value={'present' if hf_token else 'None'}")
242
  # For api_key, print part of the key if not None/empty for verification
243
  api_key_display = gemini_key[:5] if isinstance(gemini_key, str) and gemini_key else ('Empty String' if isinstance(gemini_key, str) and gemini_key == "" else 'None')
244
- print(f" Received gemini_key: Type={type(gemini_key)}, Value={api_key_display}")
245
- print(f" Received gemini_model: Type={type(gemini_model)}, Value={gemini_model}")
246
  # --- END ENHANCED DEBUGGING LOGS ---
247
 
248
  is_logged_in = hf_profile is not None and hf_token is not None
249
  # Use bool() check for simplicity - handles None and "" correctly
250
  is_gemini_ready = bool(gemini_key) and bool(gemini_model)
251
 
252
- # --- CONTINUED DEBUGGING LOGS ---
253
- print(f" HF check: ({hf_profile is not None} and {hf_token is not None}) = {is_logged_in}")
254
- print(f" Gemini check: ({bool(gemini_key)} and {bool(gemini_model)}) = {is_gemini_ready}")
255
- print("--- END CONTINUED DEBUGGING LOGS ---")
256
-
257
  is_ready = is_logged_in and is_gemini_ready
258
- print(f"check_send_button_ready - HF Ready: {is_logged_in}, Gemini Ready: {is_gemini_ready}, Button Ready (boolean): {is_ready}")
259
  print("--- check_send_button_ready END ---\n")
260
 
261
- # FIXED: Call gr.update instead of gr.Button.update
262
  return gr.update(interactive=is_ready)
263
 
264
- # --- New wrapper function to handle the state updates and call the checker ---
265
- # This function takes the required state variables as inputs and calls the logic.
266
- # This function will be called by the .change() events of the state variables.
267
- def update_send_button_state(profile: gr.OAuthProfile | None, token: gr.OAuthToken | None, gemini_key: str | None, gemini_model: str | None) -> gr.update:
268
- """Wrapper function to read states and update button interactivity."""
269
- # Pass the received values directly to the core check function
270
- return check_send_button_ready(profile, token, gemini_key, gemini_model)
271
- # --- End of new wrapper function ---
272
-
273
 
274
  # This is the main generator function for the workflow, triggered by the 'Send' button
275
  # NOTE: This function MUST accept ALL state variables as inputs that it might need to modify or pass through.
276
  # It MUST also yield/return ALL state variables in the same order they appear in the `outputs` list of the `.click()` event.
277
- # MODIFIED: Input parameter names align with renamed states for clarity
278
- # MODIFIED: Output tuple includes renamed gemini state variables
279
- # REMOVED: *args, **kwargs from signature
280
  def ai_workflow_chat(
281
  message: str,
282
  history: list[dict],
@@ -297,7 +278,7 @@ def ai_workflow_chat(
297
  repo_name_state: str | None,
298
  generated_code_state: str | None,
299
  use_grounding_state: bool, # Value from use_grounding_checkbox
300
- # Absorb potential extra args passed by Gradio event listeners (e.g. old value, event data) - RE-ADDED for safety in generator context
301
  *args,
302
  **kwargs
303
  ) -> tuple[
@@ -331,6 +312,27 @@ def ai_workflow_chat(
331
  current_gemini_key = gemini_api_key_state
332
  current_gemini_model = gemini_model_state
333
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
334
 
335
  # Keep copies of potentially updated UI elements passed as inputs to update them later
336
  # These are the *current values* of the UI components as of the button click
@@ -349,6 +351,7 @@ def ai_workflow_chat(
349
  # This provides immediate feedback to the user while the AI processes
350
  # Ensure all state variables and UI outputs are yielded back in the correct order
351
  # Include gemini_api_key_state and gemini_model_state in the yield tuple
 
352
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
353
  attempts, app_desc, repo_name, generated_code, use_grounding,
354
  current_gemini_key, current_gemini_model) # Explicitly pass back current state values
@@ -358,20 +361,21 @@ def ai_workflow_chat(
358
 
359
  # Although button interactivity prevents reaching here without key/model,
360
  # the checks remain as a safeguard for the workflow logic itself.
 
361
  if not (hf_profile and hf_token):
362
  history = add_bot_message(history, "Workflow paused: Please log in to Hugging Face first.")
 
363
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
364
  attempts, app_desc, repo_name, generated_code, use_grounding,
365
- current_gemini_key, current_gemini_model) # Explicitly pass back current state values
366
  return # Stop workflow execution for this click
367
 
368
- # Check if API key is non-empty string and model is set
369
- # Use the local variables derived from state inputs
370
  if not (isinstance(current_gemini_key, str) and current_gemini_key != "" and current_gemini_model):
371
  history = add_bot_message(history, "Workflow cannot start: Please ensure your Gemini API key is entered and a model is selected.")
 
372
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
373
  attempts, app_desc, repo_name, generated_code, use_grounding,
374
- current_gemini_key, current_gemini_model) # Explicitly pass back current state values
375
  return # Stop workflow execution for this click
376
 
377
 
@@ -384,15 +388,10 @@ def ai_workflow_chat(
384
  create_match = re.search(r'create (?:a|an)? space called (\w+)', message, re.I)
385
 
386
  if reset_match:
387
- # Reset the workflow state and associated variables
388
  history = add_bot_message(history, "Workflow reset.")
389
- # Yield updated history and reset state variables to their initial values
390
- # Also reset UI outputs to their initial state
391
- # gemini_key and gemini_model are passed back with their *current* (likely valid) state
392
  yield (history, None, STATE_IDLE, "<p>No Space created yet.</p>", "", "", 0,
393
- None, None, None, False, # Reset use_grounding to default False, other states to None/default
394
- current_gemini_key, current_gemini_model) # Explicitly pass back current state values
395
- # No return needed after yield in this generator pattern; execution for this click ends here.
396
 
397
  elif generate_match:
398
  # User requested generation with description and name
@@ -403,11 +402,10 @@ def ai_workflow_chat(
403
  state = STATE_CREATING_SPACE
404
  repo_name = new_repo_name
405
  app_desc = new_app_desc
406
- # Yield updated history and state variables (pass UI outputs through)
407
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
408
  attempts, app_desc, repo_name, generated_code, use_grounding,
409
- current_gemini_key, current_gemini_model)
410
- # No return needed
411
 
412
  elif create_match:
413
  # User requested simple space creation with a name
@@ -415,30 +413,27 @@ def ai_workflow_chat(
415
  history = add_bot_message(history, f"Acknowledged: '{message}'. Starting workflow to create Space `{hf_profile.username}/{new_repo_name}`.")
416
  state = STATE_CREATING_SPACE # Transition state to creation
417
  repo_name = new_repo_name # Store the validated repo name
418
- # Yield updated history and state variables (pass UI outputs through)
419
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
420
  attempts, app_desc, repo_name, generated_code, use_grounding,
421
- current_gemini_key, current_gemini_model)
422
- # No return needed
423
 
424
  elif "create" in message.lower() and not repo_id:
425
  # User wants to create but didn't specify a name yet
426
  history = add_bot_message(history, "Okay, what should the Space be called? (e.g., `my-awesome-app`)")
427
  state = STATE_AWAITING_REPO_NAME # Transition to the state where we wait for the name
428
- # Yield updated history and state (pass UI outputs through)
429
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
430
  attempts, app_desc, repo_name, generated_code, use_grounding,
431
- current_gemini_key, current_gemini_model)
432
- # No return needed
433
 
434
  else:
435
  # Command not recognized in IDLE state
436
  history = add_bot_message(history, "Command not recognized. Try 'generate me a gradio app called myapp', or 'reset'.")
437
- # Yield updated history and current state (pass UI outputs through)
438
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
439
  attempts, app_desc, repo_name, generated_code, use_grounding,
440
- current_gemini_key, current_gemini_model)
441
- # No return needed
442
 
443
 
444
  elif state == STATE_AWAITING_REPO_NAME:
@@ -451,54 +446,41 @@ def ai_workflow_chat(
451
  # Stay in AWAITING_REPO_NAME state and yield message (pass UI outputs through)
452
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
453
  attempts, app_desc, repo_name, generated_code, use_grounding,
454
- current_gemini_key, current_gemini_model)
455
- # No return needed
456
 
457
  else:
458
  history = add_bot_message(history, f"Using Space name `{new_repo_name}`. Creating Space `{hf_profile.username}/{new_repo_name}`...")
459
  state = STATE_CREATING_SPACE # Transition state to creation
460
  repo_name = new_repo_name # Store the validated repo name
461
- # Yield updated history, state, and repo name. UI outputs remain unchanged for now.
462
- # The next click will proceed from the STATE_CREATING_SPACE block.
463
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
464
  attempts, app_desc, repo_name, generated_code, use_grounding,
465
- current_gemini_key, current_gemini_model)
466
- # No return needed
467
 
468
- # Note: Each 'elif' block below represents a distinct step in the workflow triggered
469
- # when the 'state' variable matches its condition on a button click.
470
 
471
  elif state == STATE_CREATING_SPACE:
472
  # Ensure repo_name is available (it should have been set in the previous step)
473
  if not repo_name:
474
  history = add_bot_message(history, "Internal error: Repo name missing for creation. Resetting.")
475
- # Reset relevant states and UI outputs on critical error
476
  yield (history, None, STATE_IDLE, "<p>Error creating space.</p>", "", "", 0,
477
- None, None, None, use_grounding,
478
- current_gemini_key, current_gemini_model) # Pass grounding state through
479
- # No return needed
480
-
481
  else:
482
  try:
483
- # Perform the action to create the Space on Hugging Face
484
  new_repo_id, iframe_html = create_space_action(repo_name, space_sdk, hf_profile, hf_token)
485
- updated_preview = iframe_html # Update the iframe content to show the new space
486
- repo_id = new_repo_id # Store the official repo_id
487
  history = add_bot_message(history, f"✅ Space `{repo_id}` created. Click 'Send' to generate and upload code.")
488
- state = STATE_GENERATING_CODE # Transition to the next state
489
- # Yield updated state variables and history, and the new iframe HTML
490
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
491
  attempts, app_desc, repo_name, generated_code, use_grounding,
492
- current_gemini_key, current_gemini_model) # Pass logs and grounding through
493
- # No return needed
494
-
495
  except Exception as e:
496
  history = add_bot_message(history, f"❌ Error creating space: {e}. Click 'reset'.")
497
- # Yield error message and reset state on failure
498
  yield (history, None, STATE_IDLE, "<p>Error creating space.</p>", "", "", 0,
499
- None, None, None, use_grounding,
500
- current_gemini_key, current_gemini_model) # Pass logs and grounding through
501
- # No return needed
502
 
503
 
504
  elif state == STATE_GENERATING_CODE:
@@ -515,42 +497,33 @@ Return **only** the python code block for `app.py`. Do not include any extra tex
515
  history = add_bot_message(history, f"🧠 Generating `{prompt_desc}` `{space_sdk}` app (`app.py`) code with Gemini...")
516
  if use_grounding:
517
  history = add_bot_message(history, "(Using Grounding with Google Search)")
518
- # Yield to show message before the potentially time-consuming API call
519
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
520
  attempts, app_desc, repo_name, generated_code, use_grounding,
521
- current_gemini_key, current_gemini_model)
522
 
523
- # Perform the Gemini API call to generate code, optionally using grounding
524
- # Use the current_gemini_key and current_gemini_model derived from state inputs
525
  code = call_gemini(prompt, current_gemini_key, current_gemini_model, use_grounding=use_grounding)
526
  code = code.strip()
527
- # Clean up common markdown code block formatting if present
528
- if code.startswith("```python"):
529
- code = code[len("```python"):].strip()
530
- if code.startswith("```"): # Handle generic code blocks too
531
- code = code[len("```"):].strip()
532
- if code.endswith("```"):
533
- code = code[:-len("```")].strip()
534
 
535
- if not code:
536
- raise ValueError("Gemini returned empty code.")
537
 
538
  history = add_bot_message(history, "✅ `app.py` code generated. Click 'Send' to upload.")
539
- state = STATE_UPLOADING_APP_PY # Transition to the upload state
540
- generated_code = code # Store the generated code in the state variable for the next step
541
- # Yield updated state variables and history (pass UI outputs and other states through)
542
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
543
  attempts, app_desc, repo_name, generated_code, use_grounding,
544
- current_gemini_key, current_gemini_model)
545
- # No return needed
546
 
547
  except Exception as e:
548
  history = add_bot_message(history, f"❌ Error generating code: {e}. Click 'reset'.")
549
- # Yield error message and reset state on failure
550
  yield (history, None, STATE_IDLE, updated_preview, updated_run, updated_build, 0,
551
- None, None, None, use_grounding,
552
- current_gemini_key, current_gemini_model)
553
- # No return needed
554
 
555
 
556
  elif state == STATE_UPLOADING_APP_PY:
@@ -559,44 +532,35 @@ Return **only** the python code block for `app.py`. Do not include any extra tex
559
  if not code_to_upload:
560
  history = add_bot_message(history, "Internal error: No code to upload. Resetting.")
561
  yield (history, None, STATE_IDLE, updated_preview, updated_run, updated_build, 0,
562
- None, None, None, use_grounding,
563
- current_gemini_key, current_gemini_model)
564
- # No return needed
565
-
566
  else:
567
  history = add_bot_message(history, "☁️ Uploading `app.py`...")
568
- # Yield to show message before the upload action (pass UI outputs and states through)
569
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
570
  attempts, app_desc, repo_name, generated_code, use_grounding,
571
- current_gemini_key, current_gemini_model)
572
-
573
  try:
574
- # Perform the file upload action
575
  upload_file_to_space_action(io.StringIO(code_to_upload), "app.py", repo_id, hf_profile, hf_token)
576
  history = add_bot_message(history, "✅ Uploaded `app.py`. Click 'Send' to generate requirements.")
577
- state = STATE_GENERATING_REQUIREMENTS # Transition state
578
- generated_code = None # Clear the stored code after use to free memory/state space
579
- # Yield updated state variables and history (pass UI outputs and other states through)
580
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
581
  attempts, app_desc, repo_name, generated_code, use_grounding,
582
- current_gemini_key, current_gemini_model)
583
- # No return needed
584
-
585
  except Exception as e:
586
  history = add_bot_message(history, f"❌ Error uploading `app.py`: {e}. Click 'reset'.")
587
- # Yield error message and reset state on failure
588
  yield (history, None, STATE_IDLE, updated_preview, updated_run, updated_build, 0,
589
- None, None, None, use_grounding,
590
- current_gemini_key, current_gemini_model)
591
- # No return needed
592
 
593
 
594
  elif state == STATE_GENERATING_REQUIREMENTS:
595
  history = add_bot_message(history, "📄 Generating `requirements.txt`...")
596
- # Yield to show message before generating requirements (pass UI outputs and states through)
597
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
598
  attempts, app_desc, repo_name, generated_code, use_grounding,
599
- current_gemini_key, current_gemini_model)
600
 
601
  # Logic to determine required packages based on SDK and keywords in the app description
602
  reqs_list = ["gradio"] if space_sdk == "gradio" else ["streamlit"]
@@ -639,8 +603,7 @@ Return **only** the python code block for `app.py`. Do not include any extra tex
639
  # Yield updated state variables and history (pass UI outputs and other states through)
640
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
641
  attempts, app_desc, repo_name, generated_code, use_grounding,
642
- current_gemini_key, current_gemini_model)
643
- # No return needed
644
 
645
 
646
  elif state == STATE_UPLOADING_REQUIREMENTS:
@@ -649,17 +612,13 @@ Return **only** the python code block for `app.py`. Do not include any extra tex
649
  if not reqs_content_to_upload:
650
  history = add_bot_message(history, "Internal error: No requirements content to upload. Resetting.")
651
  yield (history, None, STATE_IDLE, updated_preview, updated_run, updated_build, 0,
652
- None, None, None, use_grounding,
653
- current_gemini_key, current_gemini_model)
654
- # No return needed
655
-
656
  else:
657
  history = add_bot_message(history, "☁️ Uploading `requirements.txt`...")
658
  # Yield message before upload (pass UI outputs and states through)
659
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
660
  attempts, app_desc, repo_name, generated_code, use_grounding,
661
- current_gemini_key, current_gemini_model)
662
-
663
  try:
664
  # Perform requirements file upload
665
  upload_file_to_space_action(io.StringIO(reqs_content_to_upload), "requirements.txt", repo_id, hf_profile, hf_token)
@@ -669,23 +628,19 @@ Return **only** the python code block for `app.py`. Do not include any extra tex
669
  # Yield updated state variables and history (pass UI outputs and other states through)
670
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
671
  attempts, app_desc, repo_name, generated_code, use_grounding,
672
- current_gemini_key, current_gemini_model)
673
- # No return needed
674
-
675
  except Exception as e:
676
  history = add_bot_message(history, f"❌ Error uploading `requirements.txt`: {e}. Click 'reset'.")
677
  # Yield error message and reset state on failure
678
  yield (history, None, STATE_IDLE, updated_preview, updated_run, updated_build, 0,
679
- None, None, None, use_grounding,
680
- current_gemini_key, current_gemini_model)
681
- # No return needed
682
 
683
  elif state == STATE_GENERATING_README:
684
  history = add_bot_message(history, "📝 Generating `README.md`...")
685
  # Yield message before generating README (pass UI outputs and states through)
686
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
687
  attempts, app_desc, repo_name, generated_code, use_grounding,
688
- current_gemini_key, current_gemini_model)
689
 
690
  # Generate simple README content with Space metadata header
691
  readme_title = repo_name if repo_name else "My Awesome Space"
@@ -714,8 +669,7 @@ This Space was automatically generated by an AI workflow using Google Gemini and
714
  # Yield updated state variables and history (pass UI outputs and other states through)
715
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
716
  attempts, app_desc, repo_name, generated_code, use_grounding,
717
- current_gemini_key, current_gemini_model)
718
- # No return needed
719
 
720
 
721
  elif state == STATE_UPLOADING_README:
@@ -724,17 +678,13 @@ This Space was automatically generated by an AI workflow using Google Gemini and
724
  if not readme_content_to_upload:
725
  history = add_bot_message(history, "Internal error: No README content to upload. Resetting.")
726
  yield (history, None, STATE_IDLE, updated_preview, updated_run, updated_build, 0,
727
- None, None, None, use_grounding,
728
- current_gemini_key, current_gemini_model)
729
- # No return needed
730
-
731
  else:
732
  history = add_bot_message(history, "☁️ Uploading `README.md`...")
733
  # Yield message before upload (pass UI outputs and states through)
734
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
735
  attempts, app_desc, repo_name, generated_code, use_grounding,
736
- current_gemini_key, current_gemini_model)
737
-
738
  try:
739
  # Perform README file upload
740
  upload_file_to_space_action(io.StringIO(readme_content_to_upload), "README.md", repo_id, hf_profile, hf_token)
@@ -744,23 +694,19 @@ This Space was automatically generated by an AI workflow using Google Gemini and
744
  # Yield updated state variables and history (pass UI outputs and other states through)
745
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
746
  attempts, app_desc, repo_name, generated_code, use_grounding,
747
- current_gemini_key, current_gemini_model)
748
- # No return needed
749
-
750
  except Exception as e:
751
  history = add_bot_message(history, f"❌ Error uploading `README.md`: {e}. Click 'reset'.")
752
  # Yield error message and reset state on failure
753
  yield (history, None, STATE_IDLE, updated_preview, updated_run, updated_build, 0,
754
- None, None, None, use_grounding,
755
- current_gemini_key, current_gemini_model)
756
- # No return needed
757
 
758
  elif state == STATE_CHECKING_LOGS_BUILD:
759
  history = add_bot_message(history, "🔍 Fetching build logs...")
760
  # Yield message before fetching logs (which includes a delay) (pass UI outputs and states through)
761
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
762
  attempts, app_desc, repo_name, generated_code, use_grounding,
763
- current_gemini_key, current_gemini_model)
764
 
765
  # Fetch build logs from HF Space
766
  build_logs_text = get_build_logs_action(repo_id, hf_profile, hf_token)
@@ -773,8 +719,7 @@ This Space was automatically generated by an AI workflow using Google Gemini and
773
  # Yield updated state, logs, and variables
774
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
775
  attempts, app_desc, repo_name, generated_code, use_grounding,
776
- current_gemini_key, current_gemini_model)
777
- # No return needed
778
 
779
  else:
780
  history = add_bot_message(history, "✅ Build logs fetched. Click 'Send' to check container logs.")
@@ -782,8 +727,7 @@ This Space was automatically generated by an AI workflow using Google Gemini and
782
  # Yield updated state, logs, and variables
783
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
784
  attempts, app_desc, repo_name, generated_code, use_grounding,
785
- current_gemini_key, current_gemini_model)
786
- # No return needed
787
 
788
 
789
  elif state == STATE_CHECKING_LOGS_RUN:
@@ -791,7 +735,7 @@ This Space was automatically generated by an AI workflow using Google Gemini and
791
  # Yield message before fetching logs (includes a delay) (pass UI outputs and states through)
792
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
793
  attempts, app_desc, repo_name, generated_code, use_grounding,
794
- current_gemini_key, current_gemini_model)
795
 
796
  # Fetch container logs from HF Space
797
  container_logs_text = get_container_logs_action(repo_id, hf_profile, hf_token)
@@ -805,8 +749,7 @@ This Space was automatically generated by an AI workflow using Google Gemini and
805
  # Yield updated state, logs, attempts, and variables
806
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
807
  attempts, app_desc, repo_name, generated_code, use_grounding,
808
- current_gemini_key, current_gemini_model)
809
- # No return needed
810
 
811
  elif ("error" in updated_run.lower() or "exception" in updated_run.lower()) and attempts >= MAX_DEBUG_ATTEMPTS:
812
  # Max debug attempts reached
@@ -815,8 +758,7 @@ This Space was automatically generated by an AI workflow using Google Gemini and
815
  # Yield updated state, logs, attempts, and variables
816
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
817
  attempts, app_desc, repo_name, generated_code, use_grounding,
818
- current_gemini_key, current_gemini_model)
819
- # No return needed
820
 
821
  else:
822
  # No significant errors found in logs, assume success
@@ -825,8 +767,7 @@ This Space was automatically generated by an AI workflow using Google Gemini and
825
  # Yield updated state, logs, attempts, and variables
826
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
827
  attempts, app_desc, repo_name, generated_code, use_grounding,
828
- current_gemini_key, current_gemini_model)
829
- # No return needed
830
 
831
 
832
  elif state == STATE_DEBUGGING_CODE:
@@ -836,7 +777,7 @@ This Space was automatically generated by an AI workflow using Google Gemini and
836
  # Yield message before Gemini API call (pass UI outputs and states through)
837
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
838
  attempts, app_desc, repo_name, generated_code, use_grounding,
839
- current_gemini_key, current_gemini_model)
840
 
841
  # Construct prompt for Gemini including the container logs
842
  debug_prompt = f"""
@@ -873,16 +814,14 @@ Return **only** the python code block for app.py. Do not include any extra text,
873
  # Yield updated state, code, and variables (pass UI outputs and states through)
874
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
875
  attempts, app_desc, repo_name, generated_code, use_grounding,
876
- current_gemini_key, current_gemini_model)
877
- # No return needed
878
 
879
  except Exception as e:
880
  history = add_bot_message(history, f"❌ Error generating debug code: {e}. Click 'reset'.")
881
  # Yield error message and reset state on failure
882
  yield (history, None, STATE_IDLE, updated_preview, updated_run, updated_build, 0,
883
  None, None, None, use_grounding,
884
- current_gemini_key, current_gemini_model)
885
- # No return needed
886
 
887
  elif state == STATE_UPLOADING_FIXED_APP_PY:
888
  # Retrieve the fixed code from the state variable
@@ -890,16 +829,13 @@ Return **only** the python code block for app.py. Do not include any extra text,
890
  if not fixed_code_to_upload:
891
  history = add_bot_message(history, "Internal error: No fixed code available to upload. Resetting.")
892
  yield (history, None, STATE_IDLE, updated_preview, updated_run, updated_build, 0,
893
- None, None, None, use_grounding,
894
- current_gemini_key, current_gemini_model)
895
- # No return needed
896
-
897
  else:
898
  history = add_bot_message(history, "☁️ Uploading fixed `app.py`...")
899
  # Yield message before upload (pass UI outputs and states through)
900
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
901
  attempts, app_desc, repo_name, generated_code, use_grounding,
902
- current_gemini_key, current_gemini_model)
903
 
904
  try:
905
  # Perform the upload of the fixed app.py
@@ -910,24 +846,20 @@ Return **only** the python code block for app.py. Do not include any extra text,
910
  # Yield updated state, code, and variables (pass UI outputs and states through)
911
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
912
  attempts, app_desc, repo_name, generated_code, use_grounding,
913
- current_gemini_key, current_gemini_model)
914
- # No return needed
915
 
916
  except Exception as e:
917
  history = add_bot_message(history, f"❌ Error uploading fixed `app.py`: {e}. Click 'reset'.")
918
  # Yield error message and reset state on failure
919
  yield (history, None, STATE_IDLE, updated_preview, updated_run, updated_build, 0,
920
- None, None, None, use_grounding,
921
- current_gemini_key, current_gemini_model)
922
- # No return needed
923
 
924
  elif state == STATE_COMPLETE:
925
  # If in the complete state, the workflow is finished for this project.
926
  # Subsequent clicks just add user messages; we simply yield the current state.
927
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
928
  attempts, app_desc, repo_name, generated_code, use_grounding,
929
- current_gemini_key, current_gemini_model)
930
- # No return needed
931
 
932
 
933
  except Exception as e:
@@ -935,10 +867,10 @@ Return **only** the python code block for app.py. Do not include any extra text,
935
  error_message = f"Workflow step failed unexpectedly ({state}): {e}. Click 'Send' to re-attempt this step or 'reset'."
936
  history = add_bot_message(history, error_message)
937
  print(f"Critical Error in state {state}: {e}") # Log the error for debugging purposes
 
938
  yield (history, None, STATE_IDLE, updated_preview, updated_run, updated_build, 0,
939
  None, None, None, use_grounding,
940
- current_gemini_key, current_gemini_model) # Include use_grounding and Gemini states
941
- # No return needed after yield
942
 
943
 
944
  # --- Build the Gradio UI ---
@@ -948,9 +880,9 @@ with gr.Blocks(title="AI-Powered HF Space App Builder") as ai_builder_tab:
948
  # Define these first as they might be used in default values for components
949
  hf_profile = gr.State(None)
950
  hf_token = gr.State(None)
951
- # RENAMED: Initialize gemini_api_key_state to empty string
952
  gemini_api_key_state = gr.State("") # start with no key
953
- # RENAMED: Initialize gemini_model_state
954
  gemini_model_state = gr.State("gemini-1.5-flash") # Default selected model
955
 
956
  repo_id = gr.State(None) # Stores the ID of the created Space
@@ -975,7 +907,7 @@ with gr.Blocks(title="AI-Powered HF Space App Builder") as ai_builder_tab:
975
 
976
  gr.Markdown("## Google AI Studio / Gemini")
977
  # Define gemini_input and gemini_status before they are used in change handlers
978
- # CHANGED: Blank out textbox on load and update info text
979
  gemini_input = gr.Textbox(
980
  label="Your Google AI Studio API Key", # Changed label
981
  type="password", # Hides input for security
@@ -1021,7 +953,7 @@ with gr.Blocks(title="AI-Powered HF Space App Builder") as ai_builder_tab:
1021
  chatbot = gr.Chatbot(type='messages', label="AI Workflow Chat")
1022
  user_input = gr.Textbox(placeholder="Type your message…", interactive=True)
1023
  # Define send_btn here, BEFORE it's used in send_button_update_output
1024
- send_btn = gr.Button("Send") # Starts disabled by default (interactive=False)
1025
 
1026
 
1027
  # Define iframe, build_txt, run_txt after send_btn
@@ -1033,75 +965,73 @@ with gr.Blocks(title="AI-Powered HF Space App Builder") as ai_builder_tab:
1033
 
1034
  # --- Define Event Handlers and Chains AFTER all components and required lists are defined ---
1035
 
1036
- # Define the inputs used for checking prerequisites using the RENAMED states
1037
- # This list should be defined AFTER the state variables
1038
  send_button_interactive_binding_inputs = [
1039
  hf_profile,
1040
  hf_token,
1041
- gemini_api_key_state, # Use new state name
1042
- gemini_model_state # Use new state name
1043
  ]
1044
  # Define the output for updating the send button interactivity
1045
- # FIXED: Moved definition to *after* send_btn is defined
1046
  send_button_update_output = [send_btn]
1047
 
1048
 
1049
- # Trigger update_send_button_state whenever any prerequisite state changes
1050
- # This uses the new wrapper function which expects exactly 4 inputs.
1051
- # The inputs list ensures those 4 state values are passed.
1052
  hf_profile.change(
1053
- update_send_button_state, # Call the wrapper function
1054
  inputs=send_button_interactive_binding_inputs, # Pass all 4 prerequisite states
1055
  outputs=send_button_update_output, # Update only the send button
1056
  )
1057
  hf_token.change(
1058
- update_send_button_state, # Call the wrapper function
1059
  inputs=send_button_interactive_binding_inputs, # Pass all 4 prerequisite states
1060
  outputs=send_button_update_output, # Update only the send button
1061
  )
1062
  # gemini_input.change updates gemini_api_key_state, which triggers gemini_api_key_state.change
1063
  gemini_api_key_state.change(
1064
- update_send_button_state, # Call the wrapper function
1065
  inputs=send_button_interactive_binding_inputs, # Pass all 4 prerequisite states
1066
  outputs=send_button_update_output, # Update only the send button
1067
  )
1068
  # model_selector.change updates gemini_model_state, which triggers gemini_model_state.change
1069
  gemini_model_state.change(
1070
- update_send_button_state, # Call the wrapper function
1071
  inputs=send_button_interactive_binding_inputs, # Pass all 4 prerequisite states
1072
  outputs=send_button_update_output, # Update only the send button
1073
  )
1074
 
1075
 
1076
- # Handle login button click: Update profile/token state -> Their .change handlers trigger update_send_button_state
1077
  login_btn.click(
1078
- lambda x: (x[0], x[1]),
1079
  inputs=[login_btn],
1080
- outputs=[hf_profile, hf_token] # Updating these states will trigger their .change handlers
1081
  )
1082
 
1083
- # Handle Gemini Key Input change: Update key state -> Configure Gemini status -> State .change handler triggers update_send_button_state
1084
  gemini_input.change(
1085
- lambda k: k,
1086
  inputs=[gemini_input],
1087
- outputs=[gemini_api_key_state] # Updating this state will trigger its .change handler
1088
  ).then(
1089
- # Use RENAMED state variables as inputs to configure_gemini
1090
  configure_gemini,
1091
  inputs=[gemini_api_key_state, gemini_model_state],
1092
- outputs=[gemini_status] # Update Gemini status based on new key
1093
  )
1094
 
1095
- # Handle Gemini Model Selector change: Update model state -> Configure Gemini status -> State .change handler triggers update_send_button_state
1096
  model_selector.change(
1097
- lambda m: m,
1098
  inputs=[model_selector],
1099
- outputs=[gemini_model_state] # Updating this state will trigger its .change handler
1100
  ).then(
1101
- # Use RENAMED state variables as inputs to configure_gemini
1102
  configure_gemini,
1103
  inputs=[gemini_api_key_state, gemini_model_state],
1104
- outputs=[gemini_status] # Update Gemini status based on new model
1105
  )
1106
 
1107
 
@@ -1119,6 +1049,8 @@ with gr.Blocks(title="AI-Powered HF Space App Builder") as ai_builder_tab:
1119
  workflow.change(lambda s: s, inputs=workflow, outputs=status_text)
1120
 
1121
  # Link Repo ID State variable change to UI status display
 
 
1122
  repo_id.change(lambda r: r if r else "None", inputs=repo_id, outputs=repo_id_text)
1123
 
1124
 
@@ -1126,31 +1058,25 @@ with gr.Blocks(title="AI-Powered HF Space App Builder") as ai_builder_tab:
1126
  # This .click() event triggers the ai_workflow_chat generator function
1127
  # Inputs are read from UI components AND State variables
1128
  # Outputs are updated by the values yielded from the generator
1129
- # MODIFIED: Inputs use renamed gemini state variables
1130
- # MODIFIED: Outputs include renamed gemini state variables
1131
- # Added back *args, **kwargs to the generator function signature and yield for robustness,
1132
- # as the previous attempt suggested this might be necessary for state consistency within the generator's lifecycle.
1133
  send_btn.click(
1134
  ai_workflow_chat, # The generator function to run
1135
  inputs=[
1136
  user_input, chatbot, # UI component inputs (message, current chat history)
1137
  hf_profile, hf_token, # HF State variables
1138
- # Pass RENAMED gemini state variables as inputs
1139
- gemini_api_key_state, gemini_model_state,
1140
  repo_id, workflow, sdk_state, # Workflow State variables
1141
- # UI component inputs whose *current values* are needed by the generator
1142
  iframe, run_txt, build_txt, # UI component inputs (current values)
1143
  debug_attempts, app_description, repo_name_state, generated_code_state, # Other State variables
1144
  use_grounding_state # Grounding state input
1145
  ],
1146
  outputs=[
1147
- chatbot, # Update Chatbot with new messages
1148
- repo_id, workflow, # Update workflow State variables
1149
- iframe, run_txt, build_txt, # Update UI component outputs
1150
- debug_attempts, app_description, repo_name_state, generated_code_state, # Update other State variables
1151
- use_grounding_state, # Update the grounding state output
1152
- # Include RENAMED gemini state variables in outputs to ensure consistency
1153
- gemini_api_key_state, gemini_model_state
1154
  ]
1155
  ).success( # Chain a .success() event to run *after* the .click() handler completes without error
1156
  # Clear the user input textbox after the message is sent and processed
@@ -1164,20 +1090,18 @@ with gr.Blocks(title="AI-Powered HF Space App Builder") as ai_builder_tab:
1164
  # This chain runs once when the app loads
1165
  ai_builder_tab.load(
1166
  # Action 1: Show profile (loads cached login if available)
1167
- # This calls show_profile, which updates the login_status UI.
1168
- # The LoginButton component itself implicitly handles updating hf_profile/hf_token states on load if cached creds exist.
1169
  show_profile,
1170
  inputs=None,
1171
  outputs=login_status # Updates UI
1172
  ).then(
1173
  # Action 2: Configure Gemini using initial state (gemini_api_key_state is "", model_state is default)
1174
  configure_gemini,
1175
- inputs=[gemini_api_key_state, gemini_model_state], # Use RENAMED state variables as inputs
1176
  outputs=[gemini_status] # Update Gemini status display
1177
  ).then(
1178
  # Action 3: After initial load checks, update the button state based on initial states
1179
- # Use the new wrapper function here as well.
1180
- update_send_button_state,
1181
  inputs=send_button_interactive_binding_inputs, # Pass all 4 prerequisite states
1182
  outputs=send_button_update_output, # Update the send button
1183
  ).then(
 
229
  return [{"role": "assistant", "content": "Welcome! Please log in to Hugging Face and provide your Google AI Studio API key to start building Spaces. Once ready, type 'generate me a gradio app called myapp' or 'create' to begin."}]
230
 
231
  # Helper function to update send button interactivity based on prereqs
232
+ # Now takes explicit arguments, intended to be called with all necessary states.
 
 
 
233
  def check_send_button_ready(hf_profile: gr.OAuthProfile | None, hf_token: gr.OAuthToken | None, gemini_key: str | None, gemini_model: str | None) -> gr.update:
234
  """Checks if HF login and Gemini configuration are complete and returns update for button interactivity."""
235
  # --- START ENHANCED DEBUGGING LOGS ---
236
  print("\n--- check_send_button_ready START ---")
237
+ print(f" Received hf_profile: {hf_profile is not None}")
238
+ print(f" Received hf_token: {hf_token is not None}")
239
  # For api_key, print part of the key if not None/empty for verification
240
  api_key_display = gemini_key[:5] if isinstance(gemini_key, str) and gemini_key else ('Empty String' if isinstance(gemini_key, str) and gemini_key == "" else 'None')
241
+ print(f" Received gemini_key: Value starts with '{api_key_display}'")
242
+ print(f" Received gemini_model: {gemini_model}")
243
  # --- END ENHANCED DEBUGGING LOGS ---
244
 
245
  is_logged_in = hf_profile is not None and hf_token is not None
246
  # Use bool() check for simplicity - handles None and "" correctly
247
  is_gemini_ready = bool(gemini_key) and bool(gemini_model)
248
 
 
 
 
 
 
249
  is_ready = is_logged_in and is_gemini_ready
250
+ print(f"check_send_button_ready - HF Ready: {is_logged_in}, Gemini Ready: {is_gemini_ready}, Button Ready: {is_ready}")
251
  print("--- check_send_button_ready END ---\n")
252
 
 
253
  return gr.update(interactive=is_ready)
254
 
 
 
 
 
 
 
 
 
 
255
 
256
  # This is the main generator function for the workflow, triggered by the 'Send' button
257
  # NOTE: This function MUST accept ALL state variables as inputs that it might need to modify or pass through.
258
  # It MUST also yield/return ALL state variables in the same order they appear in the `outputs` list of the `.click()` event.
259
+ # Added back *args, **kwargs to the generator function signature and yield for robustness,
260
+ # as the previous attempt suggested this might be necessary for state consistency within the generator's lifecycle.
 
261
  def ai_workflow_chat(
262
  message: str,
263
  history: list[dict],
 
278
  repo_name_state: str | None,
279
  generated_code_state: str | None,
280
  use_grounding_state: bool, # Value from use_grounding_checkbox
281
+ # Absorb potential extra args passed by Gradio event listeners
282
  *args,
283
  **kwargs
284
  ) -> tuple[
 
312
  current_gemini_key = gemini_api_key_state
313
  current_gemini_model = gemini_model_state
314
 
315
+ # --- START DEBUGGING ai_workflow_chat inputs ---
316
+ print("\n--- ai_workflow_chat START (Inputs received) ---")
317
+ print(f" message: {message}")
318
+ print(f" history len: {len(history)}")
319
+ print(f" hf_profile: {hf_profile is not None}")
320
+ print(f" hf_token: {hf_token is not None}")
321
+ api_key_display = current_gemini_key[:5] if isinstance(current_gemini_key, str) and current_gemini_key else ('Empty String' if isinstance(current_gemini_key, str) and current_gemini_key == "" else 'None')
322
+ print(f" gemini_api_key_state: Value starts with '{api_key_display}'")
323
+ print(f" gemini_model_state: {current_gemini_model}")
324
+ print(f" repo_id_state: {repo_id_state}") # Check value here
325
+ print(f" workflow_state: {workflow_state}")
326
+ print(f" space_sdk: {space_sdk}")
327
+ print(f" use_grounding_state: {use_grounding_state}")
328
+ print(f" debug_attempts_state: {debug_attempts_state}")
329
+ print(f" app_description_state: {app_description_state}")
330
+ print(f" repo_name_state: {repo_name_state}")
331
+ print(f" generated_code_state: {'Present' if generated_code_state is not None else 'None'}")
332
+ # print(f" *args: {args}") # Optional: print extra args if needed
333
+ # print(f" **kwargs: {kwargs}") # Optional: print extra kwargs if needed
334
+ print("--- END DEBUGGING ai_workflow_chat inputs ---\n")
335
+
336
 
337
  # Keep copies of potentially updated UI elements passed as inputs to update them later
338
  # These are the *current values* of the UI components as of the button click
 
351
  # This provides immediate feedback to the user while the AI processes
352
  # Ensure all state variables and UI outputs are yielded back in the correct order
353
  # Include gemini_api_key_state and gemini_model_state in the yield tuple
354
+ # The yielded tuple must match the send_btn.click outputs list exactly.
355
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
356
  attempts, app_desc, repo_name, generated_code, use_grounding,
357
  current_gemini_key, current_gemini_model) # Explicitly pass back current state values
 
361
 
362
  # Although button interactivity prevents reaching here without key/model,
363
  # the checks remain as a safeguard for the workflow logic itself.
364
+ # Use the local variables derived from state inputs (current_gemini_key, current_gemini_model)
365
  if not (hf_profile and hf_token):
366
  history = add_bot_message(history, "Workflow paused: Please log in to Hugging Face first.")
367
+ # Re-yield state to update chat and keep current state values
368
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
369
  attempts, app_desc, repo_name, generated_code, use_grounding,
370
+ current_gemini_key, current_gemini_model)
371
  return # Stop workflow execution for this click
372
 
 
 
373
  if not (isinstance(current_gemini_key, str) and current_gemini_key != "" and current_gemini_model):
374
  history = add_bot_message(history, "Workflow cannot start: Please ensure your Gemini API key is entered and a model is selected.")
375
+ # Re-yield state to update chat and keep current state values
376
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
377
  attempts, app_desc, repo_name, generated_code, use_grounding,
378
+ current_gemini_key, current_gemini_model) # Correctly yielding back the received (likely empty/None) Gemini states
379
  return # Stop workflow execution for this click
380
 
381
 
 
388
  create_match = re.search(r'create (?:a|an)? space called (\w+)', message, re.I)
389
 
390
  if reset_match:
 
391
  history = add_bot_message(history, "Workflow reset.")
392
+ # Reset relevant states and UI outputs, passing through current Gemini state
 
 
393
  yield (history, None, STATE_IDLE, "<p>No Space created yet.</p>", "", "", 0,
394
+ None, None, None, False, current_gemini_key, current_gemini_model) # Correctly yielding back the received Gemini states
 
 
395
 
396
  elif generate_match:
397
  # User requested generation with description and name
 
402
  state = STATE_CREATING_SPACE
403
  repo_name = new_repo_name
404
  app_desc = new_app_desc
405
+ # Yield updated state variables, passing others through
406
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
407
  attempts, app_desc, repo_name, generated_code, use_grounding,
408
+ current_gemini_key, current_gemini_model) # Correctly yielding back the received Gemini states
 
409
 
410
  elif create_match:
411
  # User requested simple space creation with a name
 
413
  history = add_bot_message(history, f"Acknowledged: '{message}'. Starting workflow to create Space `{hf_profile.username}/{new_repo_name}`.")
414
  state = STATE_CREATING_SPACE # Transition state to creation
415
  repo_name = new_repo_name # Store the validated repo name
416
+ # Yield updated state variables, passing others through
417
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
418
  attempts, app_desc, repo_name, generated_code, use_grounding,
419
+ current_gemini_key, current_gemini_model) # Correctly yielding back the received Gemini states
 
420
 
421
  elif "create" in message.lower() and not repo_id:
422
  # User wants to create but didn't specify a name yet
423
  history = add_bot_message(history, "Okay, what should the Space be called? (e.g., `my-awesome-app`)")
424
  state = STATE_AWAITING_REPO_NAME # Transition to the state where we wait for the name
425
+ # Yield updated state, passing others through
426
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
427
  attempts, app_desc, repo_name, generated_code, use_grounding,
428
+ current_gemini_key, current_gemini_model) # Correctly yielding back the received Gemini states
 
429
 
430
  else:
431
  # Command not recognized in IDLE state
432
  history = add_bot_message(history, "Command not recognized. Try 'generate me a gradio app called myapp', or 'reset'.")
433
+ # Yield current state, passing others through
434
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
435
  attempts, app_desc, repo_name, generated_code, use_grounding,
436
+ current_gemini_key, current_gemini_model) # Correctly yielding back the received Gemini states
 
437
 
438
 
439
  elif state == STATE_AWAITING_REPO_NAME:
 
446
  # Stay in AWAITING_REPO_NAME state and yield message (pass UI outputs through)
447
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
448
  attempts, app_desc, repo_name, generated_code, use_grounding,
449
+ current_gemini_key, current_gemini_model) # Correctly yielding back the received Gemini states
 
450
 
451
  else:
452
  history = add_bot_message(history, f"Using Space name `{new_repo_name}`. Creating Space `{hf_profile.username}/{new_repo_name}`...")
453
  state = STATE_CREATING_SPACE # Transition state to creation
454
  repo_name = new_repo_name # Store the validated repo name
455
+ # Yield updated state variables, passing others through
 
456
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
457
  attempts, app_desc, repo_name, generated_code, use_grounding,
458
+ current_gemini_key, current_gemini_model) # Correctly yielding back the received Gemini states
 
459
 
 
 
460
 
461
  elif state == STATE_CREATING_SPACE:
462
  # Ensure repo_name is available (it should have been set in the previous step)
463
  if not repo_name:
464
  history = add_bot_message(history, "Internal error: Repo name missing for creation. Resetting.")
465
+ # Reset state on error, passing through current Gemini state
466
  yield (history, None, STATE_IDLE, "<p>Error creating space.</p>", "", "", 0,
467
+ None, None, None, use_grounding, current_gemini_key, current_gemini_model) # Correctly yielding back the received Gemini states
 
 
 
468
  else:
469
  try:
 
470
  new_repo_id, iframe_html = create_space_action(repo_name, space_sdk, hf_profile, hf_token)
471
+ updated_preview = iframe_html
472
+ repo_id = new_repo_id # Update repo_id state variable
473
  history = add_bot_message(history, f"✅ Space `{repo_id}` created. Click 'Send' to generate and upload code.")
474
+ state = STATE_GENERATING_CODE
475
+ # Yield updated state variables, passing others through
476
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
477
  attempts, app_desc, repo_name, generated_code, use_grounding,
478
+ current_gemini_key, current_gemini_model) # Correctly yielding back the received Gemini states
 
 
479
  except Exception as e:
480
  history = add_bot_message(history, f"❌ Error creating space: {e}. Click 'reset'.")
481
+ # Reset state on error, passing through current Gemini state
482
  yield (history, None, STATE_IDLE, "<p>Error creating space.</p>", "", "", 0,
483
+ None, None, None, use_grounding, current_gemini_key, current_gemini_model) # Correctly yielding back the received Gemini states
 
 
484
 
485
 
486
  elif state == STATE_GENERATING_CODE:
 
497
  history = add_bot_message(history, f"🧠 Generating `{prompt_desc}` `{space_sdk}` app (`app.py`) code with Gemini...")
498
  if use_grounding:
499
  history = add_bot_message(history, "(Using Grounding with Google Search)")
500
+ # Yield message before API call
501
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
502
  attempts, app_desc, repo_name, generated_code, use_grounding,
503
+ current_gemini_key, current_gemini_model) # Correctly yielding back the received Gemini states
504
 
 
 
505
  code = call_gemini(prompt, current_gemini_key, current_gemini_model, use_grounding=use_grounding)
506
  code = code.strip()
507
+ # Clean up markdown
508
+ if code.startswith("```python"): code = code[len("```python"):].strip()
509
+ if code.startswith("```"): code = code[len("```"):].strip()
510
+ if code.endswith("```"): code = code[:-len("```")].strip()
 
 
 
511
 
512
+ if not code: raise ValueError("Gemini returned empty code.")
 
513
 
514
  history = add_bot_message(history, "✅ `app.py` code generated. Click 'Send' to upload.")
515
+ state = STATE_UPLOADING_APP_PY
516
+ generated_code = code
517
+ # Yield updated state variables
518
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
519
  attempts, app_desc, repo_name, generated_code, use_grounding,
520
+ current_gemini_key, current_gemini_model) # Correctly yielding back the received Gemini states
 
521
 
522
  except Exception as e:
523
  history = add_bot_message(history, f"❌ Error generating code: {e}. Click 'reset'.")
524
+ # Reset state on error, passing through current Gemini state
525
  yield (history, None, STATE_IDLE, updated_preview, updated_run, updated_build, 0,
526
+ None, None, None, use_grounding, current_gemini_key, current_gemini_model) # Correctly yielding back the received Gemini states
 
 
527
 
528
 
529
  elif state == STATE_UPLOADING_APP_PY:
 
532
  if not code_to_upload:
533
  history = add_bot_message(history, "Internal error: No code to upload. Resetting.")
534
  yield (history, None, STATE_IDLE, updated_preview, updated_run, updated_build, 0,
535
+ None, None, None, use_grounding, current_gemini_key, current_gemini_model) # Correctly yielding back the received Gemini states
 
 
 
536
  else:
537
  history = add_bot_message(history, "☁️ Uploading `app.py`...")
538
+ # Yield message before upload
539
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
540
  attempts, app_desc, repo_name, generated_code, use_grounding,
541
+ current_gemini_key, current_gemini_model) # Correctly yielding back the received Gemini states
 
542
  try:
 
543
  upload_file_to_space_action(io.StringIO(code_to_upload), "app.py", repo_id, hf_profile, hf_token)
544
  history = add_bot_message(history, "✅ Uploaded `app.py`. Click 'Send' to generate requirements.")
545
+ state = STATE_GENERATING_REQUIREMENTS
546
+ generated_code = None
547
+ # Yield updated state variables
548
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
549
  attempts, app_desc, repo_name, generated_code, use_grounding,
550
+ current_gemini_key, current_gemini_model) # Correctly yielding back the received Gemini states
 
 
551
  except Exception as e:
552
  history = add_bot_message(history, f"❌ Error uploading `app.py`: {e}. Click 'reset'.")
553
+ # Reset state on error, passing through current Gemini state
554
  yield (history, None, STATE_IDLE, updated_preview, updated_run, updated_build, 0,
555
+ None, None, None, use_grounding, current_gemini_key, current_gemini_model) # Correctly yielding back the received Gemini states
 
 
556
 
557
 
558
  elif state == STATE_GENERATING_REQUIREMENTS:
559
  history = add_bot_message(history, "📄 Generating `requirements.txt`...")
560
+ # Yield message before generating requirements
561
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
562
  attempts, app_desc, repo_name, generated_code, use_grounding,
563
+ current_gemini_key, current_gemini_model) # Correctly yielding back the received Gemini states
564
 
565
  # Logic to determine required packages based on SDK and keywords in the app description
566
  reqs_list = ["gradio"] if space_sdk == "gradio" else ["streamlit"]
 
603
  # Yield updated state variables and history (pass UI outputs and other states through)
604
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
605
  attempts, app_desc, repo_name, generated_code, use_grounding,
606
+ current_gemini_key, current_gemini_model) # Correctly yielding back the received Gemini states
 
607
 
608
 
609
  elif state == STATE_UPLOADING_REQUIREMENTS:
 
612
  if not reqs_content_to_upload:
613
  history = add_bot_message(history, "Internal error: No requirements content to upload. Resetting.")
614
  yield (history, None, STATE_IDLE, updated_preview, updated_run, updated_build, 0,
615
+ None, None, None, use_grounding, current_gemini_key, current_gemini_model) # Correctly yielding back the received Gemini states
 
 
 
616
  else:
617
  history = add_bot_message(history, "☁️ Uploading `requirements.txt`...")
618
  # Yield message before upload (pass UI outputs and states through)
619
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
620
  attempts, app_desc, repo_name, generated_code, use_grounding,
621
+ current_gemini_key, current_gemini_model) # Correctly yielding back the received Gemini states
 
622
  try:
623
  # Perform requirements file upload
624
  upload_file_to_space_action(io.StringIO(reqs_content_to_upload), "requirements.txt", repo_id, hf_profile, hf_token)
 
628
  # Yield updated state variables and history (pass UI outputs and other states through)
629
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
630
  attempts, app_desc, repo_name, generated_code, use_grounding,
631
+ current_gemini_key, current_gemini_model) # Correctly yielding back the received Gemini states
 
 
632
  except Exception as e:
633
  history = add_bot_message(history, f"❌ Error uploading `requirements.txt`: {e}. Click 'reset'.")
634
  # Yield error message and reset state on failure
635
  yield (history, None, STATE_IDLE, updated_preview, updated_run, updated_build, 0,
636
+ None, None, None, use_grounding, current_gemini_key, current_gemini_model) # Correctly yielding back the received Gemini states
 
 
637
 
638
  elif state == STATE_GENERATING_README:
639
  history = add_bot_message(history, "📝 Generating `README.md`...")
640
  # Yield message before generating README (pass UI outputs and states through)
641
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
642
  attempts, app_desc, repo_name, generated_code, use_grounding,
643
+ current_gemini_key, current_gemini_model) # Correctly yielding back the received Gemini states
644
 
645
  # Generate simple README content with Space metadata header
646
  readme_title = repo_name if repo_name else "My Awesome Space"
 
669
  # Yield updated state variables and history (pass UI outputs and other states through)
670
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
671
  attempts, app_desc, repo_name, generated_code, use_grounding,
672
+ current_gemini_key, current_gemini_model) # Correctly yielding back the received Gemini states
 
673
 
674
 
675
  elif state == STATE_UPLOADING_README:
 
678
  if not readme_content_to_upload:
679
  history = add_bot_message(history, "Internal error: No README content to upload. Resetting.")
680
  yield (history, None, STATE_IDLE, updated_preview, updated_run, updated_build, 0,
681
+ None, None, None, use_grounding, current_gemini_key, current_gemini_model) # Correctly yielding back the received Gemini states
 
 
 
682
  else:
683
  history = add_bot_message(history, "☁️ Uploading `README.md`...")
684
  # Yield message before upload (pass UI outputs and states through)
685
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
686
  attempts, app_desc, repo_name, generated_code, use_grounding,
687
+ current_gemini_key, current_gemini_model) # Correctly yielding back the received Gemini states
 
688
  try:
689
  # Perform README file upload
690
  upload_file_to_space_action(io.StringIO(readme_content_to_upload), "README.md", repo_id, hf_profile, hf_token)
 
694
  # Yield updated state variables and history (pass UI outputs and other states through)
695
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
696
  attempts, app_desc, repo_name, generated_code, use_grounding,
697
+ current_gemini_key, current_gemini_model) # Correctly yielding back the received Gemini states
 
 
698
  except Exception as e:
699
  history = add_bot_message(history, f"❌ Error uploading `README.md`: {e}. Click 'reset'.")
700
  # Yield error message and reset state on failure
701
  yield (history, None, STATE_IDLE, updated_preview, updated_run, updated_build, 0,
702
+ None, None, None, use_grounding, current_gemini_key, current_gemini_model) # Correctly yielding back the received Gemini states
 
 
703
 
704
  elif state == STATE_CHECKING_LOGS_BUILD:
705
  history = add_bot_message(history, "🔍 Fetching build logs...")
706
  # Yield message before fetching logs (which includes a delay) (pass UI outputs and states through)
707
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
708
  attempts, app_desc, repo_name, generated_code, use_grounding,
709
+ current_gemini_key, current_gemini_model) # Correctly yielding back the received Gemini states
710
 
711
  # Fetch build logs from HF Space
712
  build_logs_text = get_build_logs_action(repo_id, hf_profile, hf_token)
 
719
  # Yield updated state, logs, and variables
720
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
721
  attempts, app_desc, repo_name, generated_code, use_grounding,
722
+ current_gemini_key, current_gemini_model) # Correctly yielding back the received Gemini states
 
723
 
724
  else:
725
  history = add_bot_message(history, "✅ Build logs fetched. Click 'Send' to check container logs.")
 
727
  # Yield updated state, logs, and variables
728
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
729
  attempts, app_desc, repo_name, generated_code, use_grounding,
730
+ current_gemini_key, current_gemini_model) # Correctly yielding back the received Gemini states
 
731
 
732
 
733
  elif state == STATE_CHECKING_LOGS_RUN:
 
735
  # Yield message before fetching logs (includes a delay) (pass UI outputs and states through)
736
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
737
  attempts, app_desc, repo_name, generated_code, use_grounding,
738
+ current_gemini_key, current_gemini_model) # Correctly yielding back the received Gemini states
739
 
740
  # Fetch container logs from HF Space
741
  container_logs_text = get_container_logs_action(repo_id, hf_profile, hf_token)
 
749
  # Yield updated state, logs, attempts, and variables
750
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
751
  attempts, app_desc, repo_name, generated_code, use_grounding,
752
+ current_gemini_key, current_gemini_model) # Correctly yielding back the received Gemini states
 
753
 
754
  elif ("error" in updated_run.lower() or "exception" in updated_run.lower()) and attempts >= MAX_DEBUG_ATTEMPTS:
755
  # Max debug attempts reached
 
758
  # Yield updated state, logs, attempts, and variables
759
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
760
  attempts, app_desc, repo_name, generated_code, use_grounding,
761
+ current_gemini_key, current_gemini_model) # Correctly yielding back the received Gemini states
 
762
 
763
  else:
764
  # No significant errors found in logs, assume success
 
767
  # Yield updated state, logs, attempts, and variables
768
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
769
  attempts, app_desc, repo_name, generated_code, use_grounding,
770
+ current_gemini_key, current_gemini_model) # Correctly yielding back the received Gemini states
 
771
 
772
 
773
  elif state == STATE_DEBUGGING_CODE:
 
777
  # Yield message before Gemini API call (pass UI outputs and states through)
778
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
779
  attempts, app_desc, repo_name, generated_code, use_grounding,
780
+ current_gemini_key, current_gemini_model) # Correctly yielding back the received Gemini states
781
 
782
  # Construct prompt for Gemini including the container logs
783
  debug_prompt = f"""
 
814
  # Yield updated state, code, and variables (pass UI outputs and states through)
815
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
816
  attempts, app_desc, repo_name, generated_code, use_grounding,
817
+ current_gemini_key, current_gemini_model) # Correctly yielding back the received Gemini states
 
818
 
819
  except Exception as e:
820
  history = add_bot_message(history, f"❌ Error generating debug code: {e}. Click 'reset'.")
821
  # Yield error message and reset state on failure
822
  yield (history, None, STATE_IDLE, updated_preview, updated_run, updated_build, 0,
823
  None, None, None, use_grounding,
824
+ current_gemini_key, current_gemini_model) # Correctly yielding back the received Gemini states
 
825
 
826
  elif state == STATE_UPLOADING_FIXED_APP_PY:
827
  # Retrieve the fixed code from the state variable
 
829
  if not fixed_code_to_upload:
830
  history = add_bot_message(history, "Internal error: No fixed code available to upload. Resetting.")
831
  yield (history, None, STATE_IDLE, updated_preview, updated_run, updated_build, 0,
832
+ None, None, None, use_grounding, current_gemini_key, current_gemini_model) # Correctly yielding back the received Gemini states
 
 
 
833
  else:
834
  history = add_bot_message(history, "☁️ Uploading fixed `app.py`...")
835
  # Yield message before upload (pass UI outputs and states through)
836
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
837
  attempts, app_desc, repo_name, generated_code, use_grounding,
838
+ current_gemini_key, current_gemini_model) # Correctly yielding back the received Gemini states
839
 
840
  try:
841
  # Perform the upload of the fixed app.py
 
846
  # Yield updated state, code, and variables (pass UI outputs and states through)
847
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
848
  attempts, app_desc, repo_name, generated_code, use_grounding,
849
+ current_gemini_key, current_gemini_model) # Correctly yielding back the received Gemini states
 
850
 
851
  except Exception as e:
852
  history = add_bot_message(history, f"❌ Error uploading fixed `app.py`: {e}. Click 'reset'.")
853
  # Yield error message and reset state on failure
854
  yield (history, None, STATE_IDLE, updated_preview, updated_run, updated_build, 0,
855
+ None, None, None, use_grounding, current_gemini_key, current_gemini_model) # Correctly yielding back the received Gemini states
 
 
856
 
857
  elif state == STATE_COMPLETE:
858
  # If in the complete state, the workflow is finished for this project.
859
  # Subsequent clicks just add user messages; we simply yield the current state.
860
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
861
  attempts, app_desc, repo_name, generated_code, use_grounding,
862
+ current_gemini_key, current_gemini_model) # Correctly yielding back the received Gemini states
 
863
 
864
 
865
  except Exception as e:
 
867
  error_message = f"Workflow step failed unexpectedly ({state}): {e}. Click 'Send' to re-attempt this step or 'reset'."
868
  history = add_bot_message(history, error_message)
869
  print(f"Critical Error in state {state}: {e}") # Log the error for debugging purposes
870
+ # On unexpected error, reset to IDLE, but pass through the current Gemini state
871
  yield (history, None, STATE_IDLE, updated_preview, updated_run, updated_build, 0,
872
  None, None, None, use_grounding,
873
+ current_gemini_key, current_gemini_model) # Correctly yielding back the received Gemini states
 
874
 
875
 
876
  # --- Build the Gradio UI ---
 
880
  # Define these first as they might be used in default values for components
881
  hf_profile = gr.State(None)
882
  hf_token = gr.State(None)
883
+ # Initialize gemini_api_key_state to empty string
884
  gemini_api_key_state = gr.State("") # start with no key
885
+ # Initialize gemini_model_state
886
  gemini_model_state = gr.State("gemini-1.5-flash") # Default selected model
887
 
888
  repo_id = gr.State(None) # Stores the ID of the created Space
 
907
 
908
  gr.Markdown("## Google AI Studio / Gemini")
909
  # Define gemini_input and gemini_status before they are used in change handlers
910
+ # Blank out textbox on load and update info text
911
  gemini_input = gr.Textbox(
912
  label="Your Google AI Studio API Key", # Changed label
913
  type="password", # Hides input for security
 
953
  chatbot = gr.Chatbot(type='messages', label="AI Workflow Chat")
954
  user_input = gr.Textbox(placeholder="Type your message…", interactive=True)
955
  # Define send_btn here, BEFORE it's used in send_button_update_output
956
+ send_btn = gr.Button("Send", interactive=False) # Start disabled by default
957
 
958
 
959
  # Define iframe, build_txt, run_txt after send_btn
 
965
 
966
  # --- Define Event Handlers and Chains AFTER all components and required lists are defined ---
967
 
968
+ # Define the inputs used for checking prerequisites
969
+ # This list provides the values to the check_send_button_ready function
970
  send_button_interactive_binding_inputs = [
971
  hf_profile,
972
  hf_token,
973
+ gemini_api_key_state,
974
+ gemini_model_state
975
  ]
976
  # Define the output for updating the send button interactivity
 
977
  send_button_update_output = [send_btn]
978
 
979
 
980
+ # Trigger check_send_button_ready whenever any prerequisite state changes
981
+ # Bind the check function directly. The inputs list passes the required state values.
 
982
  hf_profile.change(
983
+ check_send_button_ready, # Call the core check function directly
984
  inputs=send_button_interactive_binding_inputs, # Pass all 4 prerequisite states
985
  outputs=send_button_update_output, # Update only the send button
986
  )
987
  hf_token.change(
988
+ check_send_button_ready, # Call the core check function directly
989
  inputs=send_button_interactive_binding_inputs, # Pass all 4 prerequisite states
990
  outputs=send_button_update_output, # Update only the send button
991
  )
992
  # gemini_input.change updates gemini_api_key_state, which triggers gemini_api_key_state.change
993
  gemini_api_key_state.change(
994
+ check_send_button_ready, # Call the core check function directly
995
  inputs=send_button_interactive_binding_inputs, # Pass all 4 prerequisite states
996
  outputs=send_button_update_output, # Update only the send button
997
  )
998
  # model_selector.change updates gemini_model_state, which triggers gemini_model_state.change
999
  gemini_model_state.change(
1000
+ check_send_button_ready, # Call the core check function directly
1001
  inputs=send_button_interactive_binding_inputs, # Pass all 4 prerequisite states
1002
  outputs=send_button_update_output, # Update only the send button
1003
  )
1004
 
1005
 
1006
+ # Handle login button click: Update profile/token state -> Their .change handlers trigger check_send_button_ready
1007
  login_btn.click(
1008
+ lambda x: (x[0], x[1]), # Lambda takes the LoginButton output (profile, token tuple) and returns it
1009
  inputs=[login_btn],
1010
+ outputs=[hf_profile, hf_token] # Update state variables
1011
  )
1012
 
1013
+ # Handle Gemini Key Input change: Update key state -> Configure Gemini status -> State .change handler triggers check_send_button_ready
1014
  gemini_input.change(
1015
+ lambda k: k, # Lambda takes the textbox value and returns it
1016
  inputs=[gemini_input],
1017
+ outputs=[gemini_api_key_state] # Update state variable
1018
  ).then(
1019
+ # Configure Gemini using the updated state variables
1020
  configure_gemini,
1021
  inputs=[gemini_api_key_state, gemini_model_state],
1022
+ outputs=[gemini_status] # Update Gemini status display
1023
  )
1024
 
1025
+ # Handle Gemini Model Selector change: Update model state -> Configure Gemini status -> State .change handler triggers check_send_button_ready
1026
  model_selector.change(
1027
+ lambda m: m, # Lambda takes the radio value and returns it
1028
  inputs=[model_selector],
1029
+ outputs=[gemini_model_state] # Update state variable
1030
  ).then(
1031
+ # Configure Gemini using the updated state variables
1032
  configure_gemini,
1033
  inputs=[gemini_api_key_state, gemini_model_state],
1034
+ outputs=[gemini_status] # Update Gemini status display
1035
  )
1036
 
1037
 
 
1049
  workflow.change(lambda s: s, inputs=workflow, outputs=status_text)
1050
 
1051
  # Link Repo ID State variable change to UI status display
1052
+ # This binding seems correct and should update the Textbox with the value of repo_id state.
1053
+ # The API key appearing here means the API key value is somehow ending up *in* the repo_id state.
1054
  repo_id.change(lambda r: r if r else "None", inputs=repo_id, outputs=repo_id_text)
1055
 
1056
 
 
1058
  # This .click() event triggers the ai_workflow_chat generator function
1059
  # Inputs are read from UI components AND State variables
1060
  # Outputs are updated by the values yielded from the generator
1061
+ # Ensure inputs and outputs match the ai_workflow_chat signature and yield tuple EXACTLY.
 
 
 
1062
  send_btn.click(
1063
  ai_workflow_chat, # The generator function to run
1064
  inputs=[
1065
  user_input, chatbot, # UI component inputs (message, current chat history)
1066
  hf_profile, hf_token, # HF State variables
1067
+ gemini_api_key_state, gemini_model_state, # Gemini State variables
 
1068
  repo_id, workflow, sdk_state, # Workflow State variables
 
1069
  iframe, run_txt, build_txt, # UI component inputs (current values)
1070
  debug_attempts, app_description, repo_name_state, generated_code_state, # Other State variables
1071
  use_grounding_state # Grounding state input
1072
  ],
1073
  outputs=[
1074
+ chatbot, # Updates Chatbot
1075
+ repo_id, workflow, # Updates State variables (repo_id, workflow)
1076
+ iframe, run_txt, build_txt, # Updates UI components (iframe, logs)
1077
+ debug_attempts, app_description, repo_name_state, generated_code_state, # Updates other State variables
1078
+ use_grounding_state, # Updates Grounding state
1079
+ gemini_api_key_state, gemini_model_state # Updates Gemini State variables
 
1080
  ]
1081
  ).success( # Chain a .success() event to run *after* the .click() handler completes without error
1082
  # Clear the user input textbox after the message is sent and processed
 
1090
  # This chain runs once when the app loads
1091
  ai_builder_tab.load(
1092
  # Action 1: Show profile (loads cached login if available)
 
 
1093
  show_profile,
1094
  inputs=None,
1095
  outputs=login_status # Updates UI
1096
  ).then(
1097
  # Action 2: Configure Gemini using initial state (gemini_api_key_state is "", model_state is default)
1098
  configure_gemini,
1099
+ inputs=[gemini_api_key_state, gemini_model_state],
1100
  outputs=[gemini_status] # Update Gemini status display
1101
  ).then(
1102
  # Action 3: After initial load checks, update the button state based on initial states
1103
+ # Call check_send_button_ready directly on load with initial state values
1104
+ check_send_button_ready,
1105
  inputs=send_button_interactive_binding_inputs, # Pass all 4 prerequisite states
1106
  outputs=send_button_update_output, # Update the send button
1107
  ).then(