wuhp commited on
Commit
373e394
·
verified ·
1 Parent(s): 7d5e931

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +149 -141
app.py CHANGED
@@ -12,8 +12,7 @@ from google.generativeai import types # Import types for configuration and tools
12
  from huggingface_hub import create_repo, list_models, upload_file, constants
13
  from huggingface_hub.utils import build_hf_headers, get_session, hf_raise_for_status
14
 
15
- # Add debugging print to check environment variable immediately
16
- print(f"Attempting to read GOOGLE_API_KEY from environment: {os.environ.get('GOOGLE_API_KEY')}")
17
 
18
 
19
  # --- Helper functions for Hugging Face integration ---
@@ -139,6 +138,7 @@ def get_container_logs_action(repo_id, profile, token):
139
 
140
  def configure_gemini(api_key: str | None, model_name: str | None) -> str:
141
  """Configures the Gemini API and checks if the model is accessible."""
 
142
  if not api_key:
143
  return "⚠️ Gemini API key is not set."
144
  if not model_name:
@@ -157,7 +157,7 @@ def configure_gemini(api_key: str | None, model_name: str | None) -> str:
157
  def call_gemini(prompt: str, api_key: str, model_name: str, use_grounding: bool = False) -> str:
158
  """Calls the Gemini API with a given prompt, optionally using grounding."""
159
  # This check is crucial - it will raise an error *before* the API call if prereqs aren't met
160
- if not api_key or not model_name:
161
  raise ValueError("Gemini API key or model not set.")
162
  try:
163
  genai.configure(api_key=api_key)
@@ -222,6 +222,7 @@ def add_bot_message(history: list[dict], bot_message: str) -> list[dict]:
222
 
223
  # Add an initial welcome message to the chatbot (defined outside Blocks to be called by load chain)
224
  def greet():
 
225
  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."}]
226
 
227
  # Helper function to update send button interactivity based on prereqs
@@ -234,16 +235,19 @@ def check_send_button_ready(profile: gr.OAuthProfile | None, token: gr.OAuthToke
234
  print(f" Received profile type: {type(profile)}, is None: {profile is None}")
235
  print(f" Received token type: {type(token)}, is None: {token is None}")
236
  # For api_key, print part of the key if not None for verification, be careful with full key
237
- print(f" Received api_key is None: {api_key is None}, first 5 chars: {api_key[:5] if api_key else 'N/A'}")
 
 
238
  print(f" Received model_name: {model_name}")
239
  # --- END ENHANCED DEBUGGING LOGS ---
240
 
241
  is_logged_in = profile is not None and token is not None
242
- is_gemini_ready = api_key is not None and model_name is not None
 
243
 
244
  # --- CONTINUED DEBUGGING LOGS ---
245
  print(f" HF check: {profile is not None} and {token is not None} = {is_logged_in}")
246
- print(f" Gemini check: {api_key is not None} and {model_name is not None} = {is_gemini_ready}")
247
  # --- END CONTINUED DEBUGGING LOGS ---
248
 
249
  is_ready = is_logged_in and is_gemini_ready
@@ -261,8 +265,11 @@ def ai_workflow_chat(
261
  history: list[dict],
262
  hf_profile: gr.OAuthProfile | None,
263
  hf_token: gr.OAuthToken | None,
264
- gemini_api_key: str | None,
265
- gemini_model: str | None,
 
 
 
266
  repo_id_state: str | None,
267
  workflow_state: str,
268
  space_sdk: str,
@@ -290,8 +297,7 @@ def ai_workflow_chat(
290
  str | None, # 8: Updated repo name (for repo_name_state state)
291
  str | None, # 9: Updated generated code (for generated_code_state state)
292
  bool, # 10: Updated use_grounding_state (for use_grounding_state state)
293
- str | None, # 11: Updated gemini_key state (Explicitly yield key)
294
- str | None, # 12: Updated gemini_model state (Explicitly yield model)
295
  ]:
296
  """
297
  Generator function to handle the AI workflow state machine.
@@ -322,35 +328,32 @@ def ai_workflow_chat(
322
  # Yield immediately to update the chat UI with the user's message
323
  # This provides immediate feedback to the user while the AI processes
324
  # Ensure all state variables and UI outputs are yielded back in the correct order
325
- # INCLUDE gemini_api_key and gemini_model in the yield tuple
326
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
327
- attempts, app_desc, repo_name, generated_code, use_grounding, gemini_api_key, gemini_model)
328
 
329
  try:
330
  # --- State Machine Logic based on the current 'state' variable ---
331
 
332
- if state == STATE_IDLE:
333
- # Check workflow prerequisites before starting any workflow actions
334
- # The Send button should already be disabled if these aren't met, but double-check
335
- # Note: These checks here are for the *workflow logic*, not the button interactivity logic.
336
- # The button state is controlled by check_send_button_ready and the .then chains.
337
- if not (hf_profile and hf_token):
338
- # This case should ideally not be reachable if the button is correctly disabled
339
- history = add_bot_message(history, "Workflow paused: Please log in to Hugging Face first.")
340
- # INCLUDE gemini_api_key and gemini_model in the yield tuple
341
- yield (history, repo_id, state, updated_preview, updated_run, updated_build,
342
- attempts, app_desc, repo_name, generated_code, use_grounding, gemini_api_key, gemini_model)
343
- return # Stop workflow execution for this click
344
 
345
- if not (gemini_api_key and gemini_model):
346
- # This case should also ideally not be reachable if the button is correctly disabled
347
- history = add_bot_message(history, "Workflow cannot start: Please ensure your Gemini API key is entered and a model is selected.")
348
- # INCLUDE gemini_api_key and gemini_model in the yield tuple
349
- yield (history, repo_id, state, updated_preview, updated_run, updated_build,
350
- attempts, app_desc, repo_name, generated_code, use_grounding, gemini_api_key, gemini_model)
351
- return # Stop workflow execution for this click
352
 
353
 
 
354
  # Look for specific commands in the user's message
355
  reset_match = "reset" in message.lower()
356
  # Capture app description AND repo name using regex
@@ -363,9 +366,9 @@ def ai_workflow_chat(
363
  history = add_bot_message(history, "Workflow reset.")
364
  # Yield updated history and reset state variables to their initial values
365
  # Also reset UI outputs to their initial state
366
- # INCLUDE gemini_api_key and gemini_model in the yield tuple (pass current values through)
367
  yield (history, None, STATE_IDLE, "<p>No Space created yet.</p>", "", "", 0,
368
- None, None, None, False, gemini_api_key, gemini_model) # Reset use_grounding to default False, and other states to None/default
369
  # No return needed after yield in this generator pattern; execution for this click ends here.
370
 
371
  elif generate_match:
@@ -378,9 +381,9 @@ def ai_workflow_chat(
378
  repo_name = new_repo_name
379
  app_desc = new_app_desc
380
  # Yield updated history and state variables (pass UI outputs through)
381
- # INCLUDE gemini_api_key and gemini_model in the yield tuple
382
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
383
- attempts, app_desc, repo_name, generated_code, use_grounding, gemini_api_key, gemini_model)
384
  # No return needed
385
 
386
  elif create_match:
@@ -390,9 +393,9 @@ def ai_workflow_chat(
390
  state = STATE_CREATING_SPACE # Transition state to creation
391
  repo_name = new_repo_name # Store the validated repo name
392
  # Yield updated history and state variables (pass UI outputs through)
393
- # INCLUDE gemini_api_key and gemini_model in the yield tuple
394
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
395
- attempts, app_desc, repo_name, generated_code, use_grounding, gemini_api_key, gemini_model)
396
  # No return needed
397
 
398
  elif "create" in message.lower() and not repo_id:
@@ -400,18 +403,18 @@ def ai_workflow_chat(
400
  history = add_bot_message(history, "Okay, what should the Space be called? (e.g., `my-awesome-app`)")
401
  state = STATE_AWAITING_REPO_NAME # Transition to the state where we wait for the name
402
  # Yield updated history and state (pass UI outputs through)
403
- # INCLUDE gemini_api_key and gemini_model in the yield tuple
404
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
405
- attempts, app_desc, repo_name, generated_code, use_grounding, gemini_api_key, gemini_model)
406
  # No return needed
407
 
408
  else:
409
  # Command not recognized in IDLE state
410
  history = add_bot_message(history, "Command not recognized. Try 'generate me a gradio app called myapp', or 'reset'.")
411
  # Yield updated history and current state (pass UI outputs through)
412
- # INCLUDE gemini_api_key and gemini_model in the yield tuple
413
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
414
- attempts, app_desc, repo_name, generated_code, use_grounding, gemini_api_key, gemini_model)
415
  # No return needed
416
 
417
 
@@ -423,9 +426,9 @@ def ai_workflow_chat(
423
  if not new_repo_name or re.search(r'[^a-zA-Z0-9_-]', new_repo_name) or len(new_repo_name) > 100:
424
  history = add_bot_message(history, "Invalid name. Please provide a single word/slug for the Space name (letters, numbers, underscores, hyphens only, max 100 chars).")
425
  # Stay in AWAITING_REPO_NAME state and yield message (pass UI outputs through)
426
- # INCLUDE gemini_api_key and gemini_model in the yield tuple
427
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
428
- attempts, app_desc, repo_name, generated_code, use_grounding, gemini_api_key, gemini_model)
429
  # No return needed
430
 
431
  else:
@@ -434,9 +437,9 @@ def ai_workflow_chat(
434
  repo_name = new_repo_name # Store the validated repo name
435
  # Yield updated history, state, and repo name. UI outputs remain unchanged for now.
436
  # The next click will proceed from the STATE_CREATING_SPACE block.
437
- # INCLUDE gemini_api_key and gemini_model in the yield tuple
438
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
439
- attempts, app_desc, repo_name, generated_code, use_grounding, gemini_api_key, gemini_model)
440
  # No return needed
441
 
442
  # Note: Each 'elif' block below represents a distinct step in the workflow triggered
@@ -447,9 +450,9 @@ def ai_workflow_chat(
447
  if not repo_name:
448
  history = add_bot_message(history, "Internal error: Repo name missing for creation. Resetting.")
449
  # Reset relevant states and UI outputs on critical error
450
- # INCLUDE gemini_api_key and gemini_model in the yield tuple (pass current values through)
451
  yield (history, None, STATE_IDLE, "<p>Error creating space.</p>", "", "", 0,
452
- None, None, None, use_grounding, gemini_api_key, gemini_model) # Pass grounding state through
453
  # No return needed
454
 
455
  else:
@@ -461,17 +464,17 @@ def ai_workflow_chat(
461
  history = add_bot_message(history, f"✅ Space `{repo_id}` created. Click 'Send' to generate and upload code.")
462
  state = STATE_GENERATING_CODE # Transition to the next state
463
  # Yield updated state variables and history, and the new iframe HTML
464
- # INCLUDE gemini_api_key and gemini_model in the yield tuple
465
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
466
- attempts, app_desc, repo_name, generated_code, use_grounding, gemini_api_key, gemini_model) # Pass logs and grounding through
467
  # No return needed
468
 
469
  except Exception as e:
470
  history = add_bot_message(history, f"❌ Error creating space: {e}. Click 'reset'.")
471
  # Yield error message and reset state on failure
472
- # INCLUDE gemini_api_key and gemini_model in the yield tuple (pass current values through)
473
  yield (history, None, STATE_IDLE, "<p>Error creating space.</p>", "", "", 0,
474
- None, None, None, use_grounding, gemini_api_key, gemini_model) # Pass logs and grounding through
475
  # No return needed
476
 
477
 
@@ -490,11 +493,12 @@ Return **only** the python code block for `app.py`. Do not include any extra tex
490
  if use_grounding:
491
  history = add_bot_message(history, "(Using Grounding with Google Search)")
492
  # Yield to show message before the potentially time-consuming API call
493
- # INCLUDE gemini_api_key and gemini_model in the yield tuple
494
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
495
- attempts, app_desc, repo_name, generated_code, use_grounding, gemini_api_key, gemini_model)
496
 
497
  # Perform the Gemini API call to generate code, optionally using grounding
 
498
  code = call_gemini(prompt, gemini_api_key, gemini_model, use_grounding=use_grounding)
499
  code = code.strip()
500
  # Clean up common markdown code block formatting if present
@@ -512,17 +516,17 @@ Return **only** the python code block for `app.py`. Do not include any extra tex
512
  state = STATE_UPLOADING_APP_PY # Transition to the upload state
513
  generated_code = code # Store the generated code in the state variable for the next step
514
  # Yield updated state variables and history (pass UI outputs and other states through)
515
- # INCLUDE gemini_api_key and gemini_model in the yield tuple
516
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
517
- attempts, app_desc, repo_name, generated_code, use_grounding, gemini_api_key, gemini_model)
518
  # No return needed
519
 
520
  except Exception as e:
521
  history = add_bot_message(history, f"❌ Error generating code: {e}. Click 'reset'.")
522
  # Yield error message and reset state on failure
523
- # INCLUDE gemini_api_key and gemini_model in the yield tuple (pass current values through)
524
  yield (history, None, STATE_IDLE, updated_preview, updated_run, updated_build, 0,
525
- None, None, None, use_grounding, gemini_api_key, gemini_model)
526
  # No return needed
527
 
528
 
@@ -531,17 +535,17 @@ Return **only** the python code block for `app.py`. Do not include any extra tex
531
  code_to_upload = generated_code
532
  if not code_to_upload:
533
  history = add_bot_message(history, "Internal error: No code to upload. Resetting.")
534
- # INCLUDE gemini_api_key and gemini_model in the yield tuple (pass current values through)
535
  yield (history, None, STATE_IDLE, updated_preview, updated_run, updated_build, 0,
536
- None, None, None, use_grounding, gemini_api_key, gemini_model)
537
  # No return needed
538
 
539
  else:
540
  history = add_bot_message(history, "☁️ Uploading `app.py`...")
541
  # Yield to show message before the upload action (pass UI outputs and states through)
542
- # INCLUDE gemini_api_key and gemini_model in the yield tuple
543
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
544
- attempts, app_desc, repo_name, generated_code, use_grounding, gemini_api_key, gemini_model)
545
 
546
  try:
547
  # Perform the file upload action
@@ -550,26 +554,26 @@ Return **only** the python code block for `app.py`. Do not include any extra tex
550
  state = STATE_GENERATING_REQUIREMENTS # Transition state
551
  generated_code = None # Clear the stored code after use to free memory/state space
552
  # Yield updated state variables and history (pass UI outputs and other states through)
553
- # INCLUDE gemini_api_key and gemini_model in the yield tuple
554
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
555
- attempts, app_desc, repo_name, generated_code, use_grounding, gemini_api_key, gemini_model)
556
  # No return needed
557
 
558
  except Exception as e:
559
  history = add_bot_message(history, f"❌ Error uploading `app.py`: {e}. Click 'reset'.")
560
  # Yield error message and reset state on failure
561
- # INCLUDE gemini_api_key and gemini_model in the yield tuple (pass current values through)
562
  yield (history, None, STATE_IDLE, updated_preview, updated_run, updated_build, 0,
563
- None, None, None, use_grounding, gemini_api_key, gemini_model)
564
  # No return needed
565
 
566
 
567
  elif state == STATE_GENERATING_REQUIREMENTS:
568
  history = add_bot_message(history, "📄 Generating `requirements.txt`...")
569
  # Yield to show message before generating requirements (pass UI outputs and states through)
570
- # INCLUDE gemini_api_key and gemini_model in the yield tuple
571
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
572
- attempts, app_desc, repo_name, generated_code, use_grounding, gemini_api_key, gemini_model)
573
 
574
  # Logic to determine required packages based on SDK and keywords in the app description
575
  reqs_list = ["gradio"] if space_sdk == "gradio" else ["streamlit"]
@@ -610,9 +614,9 @@ Return **only** the python code block for `app.py`. Do not include any extra tex
610
  state = STATE_UPLOADING_REQUIREMENTS # Transition state
611
  generated_code = reqs_content # Store requirements content
612
  # Yield updated state variables and history (pass UI outputs and other states through)
613
- # INCLUDE gemini_api_key and gemini_model in the yield tuple
614
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
615
- attempts, app_desc, repo_name, generated_code, use_grounding, gemini_api_key, gemini_model)
616
  # No return needed
617
 
618
 
@@ -621,17 +625,17 @@ Return **only** the python code block for `app.py`. Do not include any extra tex
621
  reqs_content_to_upload = generated_code
622
  if not reqs_content_to_upload:
623
  history = add_bot_message(history, "Internal error: No requirements content to upload. Resetting.")
624
- # INCLUDE gemini_api_key and gemini_model in the yield tuple (pass current values through)
625
  yield (history, None, STATE_IDLE, updated_preview, updated_run, updated_build, 0,
626
- None, None, None, use_grounding, gemini_api_key, gemini_model)
627
  # No return needed
628
 
629
  else:
630
  history = add_bot_message(history, "☁️ Uploading `requirements.txt`...")
631
  # Yield message before upload (pass UI outputs and states through)
632
- # INCLUDE gemini_api_key and gemini_model in the yield tuple
633
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
634
- attempts, app_desc, repo_name, generated_code, use_grounding, gemini_api_key, gemini_model)
635
 
636
  try:
637
  # Perform requirements file upload
@@ -640,25 +644,25 @@ Return **only** the python code block for `app.py`. Do not include any extra tex
640
  state = STATE_GENERATING_README # Transition state
641
  generated_code = None # Clear content after use
642
  # Yield updated state variables and history (pass UI outputs and other states through)
643
- # INCLUDE gemini_api_key and gemini_model in the yield tuple
644
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
645
- attempts, app_desc, repo_name, generated_code, use_grounding, gemini_api_key, gemini_model)
646
  # No return needed
647
 
648
  except Exception as e:
649
  history = add_bot_message(history, f"❌ Error uploading `requirements.txt`: {e}. Click 'reset'.")
650
  # Yield error message and reset state on failure
651
- # INCLUDE gemini_api_key and gemini_model in the yield tuple (pass current values through)
652
  yield (history, None, STATE_IDLE, updated_preview, updated_run, updated_build, 0,
653
- None, None, None, use_grounding, gemini_api_key, gemini_model)
654
  # No return needed
655
 
656
  elif state == STATE_GENERATING_README:
657
  history = add_bot_message(history, "📝 Generating `README.md`...")
658
  # Yield message before generating README (pass UI outputs and states through)
659
- # INCLUDE gemini_api_key and gemini_model in the yield tuple
660
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
661
- attempts, app_desc, repo_name, generated_code, use_grounding, gemini_api_key, gemini_model)
662
 
663
  # Generate simple README content with Space metadata header
664
  readme_title = repo_name if repo_name else "My Awesome Space"
@@ -685,9 +689,9 @@ This Space was automatically generated by an AI workflow using Google Gemini and
685
  state = STATE_UPLOADING_README # Transition state
686
  generated_code = readme_content # Store README content
687
  # Yield updated state variables and history (pass UI outputs and other states through)
688
- # INCLUDE gemini_api_key and gemini_model in the yield tuple
689
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
690
- attempts, app_desc, repo_name, generated_code, use_grounding, gemini_api_key, gemini_model)
691
  # No return needed
692
 
693
 
@@ -696,17 +700,17 @@ This Space was automatically generated by an AI workflow using Google Gemini and
696
  readme_content_to_upload = generated_code
697
  if not readme_content_to_upload:
698
  history = add_bot_message(history, "Internal error: No README content to upload. Resetting.")
699
- # INCLUDE gemini_api_key and gemini_model in the yield tuple (pass current values through)
700
  yield (history, None, STATE_IDLE, updated_preview, updated_run, updated_build, 0,
701
- None, None, None, use_grounding, gemini_api_key, gemini_model)
702
  # No return needed
703
 
704
  else:
705
  history = add_bot_message(history, "☁️ Uploading `README.md`...")
706
  # Yield message before upload (pass UI outputs and states through)
707
- # INCLUDE gemini_api_key and gemini_model in the yield tuple
708
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
709
- attempts, app_desc, repo_name, generated_code, use_grounding, gemini_api_key, gemini_model)
710
 
711
  try:
712
  # Perform README file upload
@@ -715,25 +719,25 @@ This Space was automatically generated by an AI workflow using Google Gemini and
715
  state = STATE_CHECKING_LOGS_BUILD # Transition to checking build logs
716
  generated_code = None # Clear content after use
717
  # Yield updated state variables and history (pass UI outputs and other states through)
718
- # INCLUDE gemini_api_key and gemini_model in the yield tuple
719
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
720
- attempts, app_desc, repo_name, generated_code, use_grounding, gemini_api_key, gemini_model)
721
  # No return needed
722
 
723
  except Exception as e:
724
  history = add_bot_message(history, f"❌ Error uploading `README.md`: {e}. Click 'reset'.")
725
  # Yield error message and reset state on failure
726
- # INCLUDE gemini_api_key and gemini_model in the yield tuple (pass current values through)
727
  yield (history, None, STATE_IDLE, updated_preview, updated_run, updated_build, 0,
728
- None, None, None, use_grounding, gemini_api_key, gemini_model)
729
  # No return needed
730
 
731
  elif state == STATE_CHECKING_LOGS_BUILD:
732
  history = add_bot_message(history, "🔍 Fetching build logs...")
733
  # Yield message before fetching logs (which includes a delay) (pass UI outputs and states through)
734
- # INCLUDE gemini_api_key and gemini_model in the yield tuple
735
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
736
- attempts, app_desc, repo_name, generated_code, use_grounding, gemini_api_key, gemini_model)
737
 
738
  # Fetch build logs from HF Space
739
  build_logs_text = get_build_logs_action(repo_id, hf_profile, hf_token)
@@ -744,27 +748,27 @@ This Space was automatically generated by an AI workflow using Google Gemini and
744
  history = add_bot_message(history, "⚠️ Build logs indicate potential issues. Please inspect above. Click 'Send' to check container logs (app might still start despite build warnings).")
745
  state = STATE_CHECKING_LOGS_RUN # Transition even on build error, to see if container starts
746
  # Yield updated state, logs, and variables
747
- # INCLUDE gemini_api_key and gemini_model in the yield tuple
748
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
749
- attempts, app_desc, repo_name, generated_code, use_grounding, gemini_api_key, gemini_model)
750
  # No return needed
751
 
752
  else:
753
  history = add_bot_message(history, "✅ Build logs fetched. Click 'Send' to check container logs.")
754
  state = STATE_CHECKING_LOGS_RUN # Transition to next log check
755
  # Yield updated state, logs, and variables
756
- # INCLUDE gemini_api_key and gemini_model in the yield tuple
757
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
758
- attempts, app_desc, repo_name, generated_code, use_grounding, gemini_api_key, gemini_model)
759
  # No return needed
760
 
761
 
762
  elif state == STATE_CHECKING_LOGS_RUN:
763
  history = add_bot_message(history, "🔍 Fetching container logs...")
764
  # Yield message before fetching logs (includes a delay) (pass UI outputs and states through)
765
- # INCLUDE gemini_api_key and gemini_model in the yield tuple
766
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
767
- attempts, app_desc, repo_name, generated_code, use_grounding, gemini_api_key, gemini_model)
768
 
769
  # Fetch container logs from HF Space
770
  container_logs_text = get_container_logs_action(repo_id, hf_profile, hf_token)
@@ -776,9 +780,9 @@ This Space was automatically generated by an AI workflow using Google Gemini and
776
  history = add_bot_message(history, f"❌ Errors detected in container logs. Attempting debug fix #{attempts}/{MAX_DEBUG_ATTEMPTS}. Click 'Send' to proceed.")
777
  state = STATE_DEBUGGING_CODE # Transition to the debugging state
778
  # Yield updated state, logs, attempts, and variables
779
- # INCLUDE gemini_api_key and gemini_model in the yield tuple
780
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
781
- attempts, app_desc, repo_name, generated_code, use_grounding, gemini_api_key, gemini_model)
782
  # No return needed
783
 
784
  elif ("error" in updated_run.lower() or "exception" in updated_run.lower()) and attempts >= MAX_DEBUG_ATTEMPTS:
@@ -786,9 +790,9 @@ This Space was automatically generated by an AI workflow using Google Gemini and
786
  history = add_bot_message(history, f"❌ Errors detected in container logs. Max debug attempts ({MAX_DEBUG_ATTEMPTS}) reached. Please inspect logs manually or click 'reset'.")
787
  state = STATE_COMPLETE # Workflow ends on failure after attempts
788
  # Yield updated state, logs, attempts, and variables
789
- # INCLUDE gemini_api_key and gemini_model in the yield tuple
790
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
791
- attempts, app_desc, repo_name, generated_code, use_grounding, gemini_api_key, gemini_model)
792
  # No return needed
793
 
794
  else:
@@ -796,9 +800,9 @@ This Space was automatically generated by an AI workflow using Google Gemini and
796
  history = add_bot_message(history, "✅ App appears to be running successfully! Check the iframe above. Click 'reset' to start a new project.")
797
  state = STATE_COMPLETE # Workflow ends on success
798
  # Yield updated state, logs, attempts, and variables
799
- # INCLUDE gemini_api_key and gemini_model in the yield tuple
800
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
801
- attempts, app_desc, repo_name, generated_code, use_grounding, gemini_api_key, gemini_model)
802
  # No return needed
803
 
804
 
@@ -807,9 +811,9 @@ This Space was automatically generated by an AI workflow using Google Gemini and
807
  if use_grounding:
808
  history = add_bot_message(history, "(Using Grounding with Google Search)")
809
  # Yield message before Gemini API call (pass UI outputs and states through)
810
- # INCLUDE gemini_api_key and gemini_model in the yield tuple
811
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
812
- attempts, app_desc, repo_name, generated_code, use_grounding, gemini_api_key, gemini_model)
813
 
814
  # Construct prompt for Gemini including the container logs
815
  debug_prompt = f"""
@@ -826,6 +830,7 @@ Return **only** the python code block for app.py. Do not include any extra text,
826
  # Call Gemini to generate the corrected code, optionally using grounding
827
  # Note: Grounding might be less effective for debugging based *only* on logs,
828
  # but we include the option as requested.
 
829
  fix_code = call_gemini(debug_prompt, gemini_api_key, gemini_model, use_grounding=use_grounding)
830
  fix_code = fix_code.strip()
831
  # Clean up potential markdown formatting
@@ -843,17 +848,17 @@ Return **only** the python code block for app.py. Do not include any extra text,
843
  state = STATE_UPLOADING_FIXED_APP_PY # Transition to the upload state for the fix
844
  generated_code = fix_code # Store the generated fix code
845
  # Yield updated state, code, and variables (pass UI outputs and states through)
846
- # INCLUDE gemini_api_key and gemini_model in the yield tuple
847
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
848
- attempts, app_desc, repo_name, generated_code, use_grounding, gemini_api_key, gemini_model)
849
  # No return needed
850
 
851
  except Exception as e:
852
  history = add_bot_message(history, f"❌ Error generating debug code: {e}. Click 'reset'.")
853
  # Yield error message and reset state on failure
854
- # INCLUDE gemini_api_key and gemini_model in the yield tuple (pass current values through)
855
  yield (history, None, STATE_IDLE, updated_preview, updated_run, updated_build, 0,
856
- None, None, None, use_grounding, gemini_api_key, gemini_model)
857
  # No return needed
858
 
859
  elif state == STATE_UPLOADING_FIXED_APP_PY:
@@ -861,17 +866,17 @@ Return **only** the python code block for app.py. Do not include any extra text,
861
  fixed_code_to_upload = generated_code
862
  if not fixed_code_to_upload:
863
  history = add_bot_message(history, "Internal error: No fixed code available to upload. Resetting.")
864
- # INCLUDE gemini_api_key and gemini_model in the yield tuple (pass current values through)
865
  yield (history, None, STATE_IDLE, updated_preview, updated_run, updated_build, 0,
866
- None, None, None, use_grounding, gemini_api_key, gemini_model)
867
  # No return needed
868
 
869
  else:
870
  history = add_bot_message(history, "☁️ Uploading fixed `app.py`...")
871
  # Yield message before upload (pass UI outputs and states through)
872
- # INCLUDE gemini_api_key and gemini_model in the yield tuple
873
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
874
- attempts, app_desc, repo_name, generated_code, use_grounding, gemini_api_key, gemini_model)
875
 
876
  try:
877
  # Perform the upload of the fixed app.py
@@ -880,25 +885,25 @@ Return **only** the python code block for app.py. Do not include any extra text,
880
  state = STATE_CHECKING_LOGS_RUN # Go back to checking run logs after uploading the fix
881
  generated_code = None # Clear code after use
882
  # Yield updated state, code, and variables (pass UI outputs and states through)
883
- # INCLUDE gemini_api_key and gemini_model in the yield tuple
884
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
885
- attempts, app_desc, repo_name, generated_code, use_grounding, gemini_api_key, gemini_model)
886
  # No return needed
887
 
888
  except Exception as e:
889
  history = add_bot_message(history, f"❌ Error uploading fixed `app.py`: {e}. Click 'reset'.")
890
  # Yield error message and reset state on failure
891
- # INCLUDE gemini_api_key and gemini_model in the yield tuple (pass current values through)
892
  yield (history, None, STATE_IDLE, updated_preview, updated_run, updated_build, 0,
893
- None, None, None, use_grounding, gemini_api_key, gemini_model)
894
  # No return needed
895
 
896
  elif state == STATE_COMPLETE:
897
  # If in the complete state, the workflow is finished for this project.
898
  # Subsequent clicks just add user messages; we simply yield the current state.
899
- # INCLUDE gemini_api_key and gemini_model in the yield tuple
900
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
901
- attempts, app_desc, repo_name, generated_code, use_grounding, gemini_api_key, gemini_model)
902
  # No return needed
903
 
904
 
@@ -908,9 +913,9 @@ Return **only** the python code block for app.py. Do not include any extra text,
908
  history = add_bot_message(history, error_message)
909
  print(f"Critical Error in state {state}: {e}") # Log the error for debugging purposes
910
  # Yield an error state and reset essential workflow variables on critical failure
911
- # INCLUDE gemini_api_key and gemini_model in the yield tuple (pass current values through)
912
  yield (history, None, STATE_IDLE, updated_preview, updated_run, updated_build, 0,
913
- None, None, None, use_grounding, gemini_api_key, gemini_model) # Include use_grounding
914
  # No return needed after yield
915
 
916
 
@@ -921,8 +926,8 @@ with gr.Blocks(title="AI-Powered HF Space App Builder") as ai_builder_tab:
921
  # Define these first as they might be used in default values for components
922
  hf_profile = gr.State(None)
923
  hf_token = gr.State(None)
924
- # FIX: Initialize gemini_key state from env var on load
925
- gemini_key = gr.State(os.environ.get("GOOGLE_API_KEY"))
926
  gemini_model = gr.State("gemini-1.5-flash") # Default selected model
927
  repo_id = gr.State(None) # Stores the ID of the created Space
928
  workflow = gr.State(STATE_IDLE) # Stores the current state of the AI workflow
@@ -945,12 +950,13 @@ with gr.Blocks(title="AI-Powered HF Space App Builder") as ai_builder_tab:
945
 
946
  gr.Markdown("## Google AI Studio / Gemini")
947
  # Define gemini_input and gemini_status before they are used in change handlers
 
948
  gemini_input = gr.Textbox(
949
- label="API Key",
950
  type="password", # Hides input for security
951
  interactive=True,
952
- value=os.environ.get("GOOGLE_API_KEY"), # Pre-fill if GOOGLE_API_KEY env var is set
953
- info="Get your key from Google AI Studio"
954
  )
955
  gemini_status = gr.Markdown("") # Display Gemini configuration status
956
 
@@ -1020,10 +1026,11 @@ with gr.Blocks(title="AI-Powered HF Space App Builder") as ai_builder_tab:
1020
  )
1021
 
1022
  # Handle Gemini Key Input change: Update key state -> Configure Gemini status -> Check prereqs and update button interactivity
 
1023
  gemini_input.change(
1024
- lambda k: k, inputs=[gemini_input], outputs=[gemini_key] # Update gemini_key state
1025
  ).then(
1026
- configure_gemini, inputs=[gemini_key, gemini_model], outputs=[gemini_status] # Update Gemini status
1027
  ).then(
1028
  # Call the update function and bind its output to the button component
1029
  check_send_button_ready,
@@ -1032,10 +1039,11 @@ with gr.Blocks(title="AI-Powered HF Space App Builder") as ai_builder_tab:
1032
  )
1033
 
1034
  # Handle Gemini Model Selector change: Update model state -> Configure Gemini status -> Check prereqs and update button interactivity
 
1035
  model_selector.change(
1036
- lambda m: m, inputs=[model_selector], outputs=[gemini_model] # Update gemini_model state
1037
  ).then(
1038
- configure_gemini, inputs=[gemini_key, gemini_model], outputs=[gemini_status] # Update Gemini status
1039
  ).then(
1040
  # Call the update function and bind its output to the button component
1041
  check_send_button_ready,
@@ -1069,21 +1077,21 @@ with gr.Blocks(title="AI-Powered HF Space App Builder") as ai_builder_tab:
1069
  inputs=[
1070
  user_input, chatbot, # UI component inputs (message, current chat history)
1071
  hf_profile, hf_token, # HF State variables
1072
- gemini_key, gemini_model, # Gemini State variables
 
1073
  repo_id, workflow, sdk_state, # Workflow State variables
1074
  # UI component inputs whose *current values* are needed by the generator
1075
- # These are NOT State variables with the same names
1076
- iframe, run_txt, build_txt,
1077
  debug_attempts, app_description, repo_name_state, generated_code_state, # Other State variables
1078
- use_grounding_state # Add the new grounding state input
1079
  ],
1080
  outputs=[
1081
  chatbot, # Update Chatbot with new messages
1082
  repo_id, workflow, # Update workflow State variables
1083
  iframe, run_txt, build_txt, # Update UI component outputs
1084
  debug_attempts, app_description, repo_name_state, generated_code_state, # Update other State variables
1085
- use_grounding_state, # Update the grounding state output (generators must yield/return all state they modify/pass through)
1086
- gemini_key, gemini_model # ADDED: Explicitly yield and update Gemini states
1087
  ]
1088
  ).success( # Chain a .success() event to run *after* the .click() handler completes without error
1089
  # Clear the user input textbox after the message is sent and processed
@@ -1101,15 +1109,15 @@ with gr.Blocks(title="AI-Powered HF Space App Builder") as ai_builder_tab:
1101
  inputs=None,
1102
  outputs=login_status # Update login status markdown
1103
  ).then(
1104
- # Action 2: Configure Gemini using the initial state values (from env var if set)
1105
- # This uses the *initial* value of gemini_key and gemini_model state variables
1106
  configure_gemini,
1107
  inputs=[gemini_key, gemini_model],
1108
  outputs=[gemini_status] # Update Gemini status display
1109
  ).then(
1110
- # Action 3: Check prereqs and update send button interactivity based on initial states
1111
- # This uses the *initial* values of hf_profile, hf_token, gemini_key, and gemini_model states
1112
- check_send_button_ready, # Use the updated helper function
1113
  inputs=send_button_interactive_binding_inputs,
1114
  outputs=[send_btn] # Update button interactivity using gr.update return value
1115
  ).then(
 
12
  from huggingface_hub import create_repo, list_models, upload_file, constants
13
  from huggingface_hub.utils import build_hf_headers, get_session, hf_raise_for_status
14
 
15
+ # Removed the debugging print that attempts to read GOOGLE_API_KEY from environment
 
16
 
17
 
18
  # --- Helper functions for Hugging Face integration ---
 
138
 
139
  def configure_gemini(api_key: str | None, model_name: str | None) -> str:
140
  """Configures the Gemini API and checks if the model is accessible."""
141
+ # Check for empty string "" as well as None
142
  if not api_key:
143
  return "⚠️ Gemini API key is not set."
144
  if not model_name:
 
157
  def call_gemini(prompt: str, api_key: str, model_name: str, use_grounding: bool = False) -> str:
158
  """Calls the Gemini API with a given prompt, optionally using grounding."""
159
  # This check is crucial - it will raise an error *before* the API call if prereqs aren't met
160
+ if not api_key or not model_name: # Check for empty string "" as well as None
161
  raise ValueError("Gemini API key or model not set.")
162
  try:
163
  genai.configure(api_key=api_key)
 
222
 
223
  # Add an initial welcome message to the chatbot (defined outside Blocks to be called by load chain)
224
  def greet():
225
+ # Updated welcome message to reflect the change in API key handling
226
  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."}]
227
 
228
  # Helper function to update send button interactivity based on prereqs
 
235
  print(f" Received profile type: {type(profile)}, is None: {profile is None}")
236
  print(f" Received token type: {type(token)}, is None: {token is None}")
237
  # For api_key, print part of the key if not None for verification, be careful with full key
238
+ # Also check for empty string for printing
239
+ api_key_display = api_key[:5] if api_key else ('Empty String' if isinstance(api_key, str) and api_key == "" else 'N/A')
240
+ print(f" Received api_key is None: {api_key is None}, is Empty String: {api_key == '' if isinstance(api_key, str) else 'N/A'}, first 5 chars or status: {api_key_display}")
241
  print(f" Received model_name: {model_name}")
242
  # --- END ENHANCED DEBUGGING LOGS ---
243
 
244
  is_logged_in = profile is not None and token is not None
245
+ # Gemini is ready if api_key is a non-empty string AND model_name is set
246
+ is_gemini_ready = isinstance(api_key, str) and api_key != "" and model_name is not None
247
 
248
  # --- CONTINUED DEBUGGING LOGS ---
249
  print(f" HF check: {profile is not None} and {token is not None} = {is_logged_in}")
250
+ print(f" Gemini check: {isinstance(api_key, str)} and {api_key != ''} and {model_name is not None} = {is_gemini_ready}")
251
  # --- END CONTINUED DEBUGGING LOGS ---
252
 
253
  is_ready = is_logged_in and is_gemini_ready
 
265
  history: list[dict],
266
  hf_profile: gr.OAuthProfile | None,
267
  hf_token: gr.OAuthToken | None,
268
+ # gemini_api_key and gemini_model are inputs, but their *state* is managed by change handlers,
269
+ # so we don't yield them back in this version. They are read from the state at the start
270
+ # of the function call.
271
+ gemini_api_key: str | None, # Read key from state
272
+ gemini_model: str | None, # Read model from state
273
  repo_id_state: str | None,
274
  workflow_state: str,
275
  space_sdk: str,
 
297
  str | None, # 8: Updated repo name (for repo_name_state state)
298
  str | None, # 9: Updated generated code (for generated_code_state state)
299
  bool, # 10: Updated use_grounding_state (for use_grounding_state state)
300
+ # gemini_key, gemini_model removed from outputs based on new key handling strategy
 
301
  ]:
302
  """
303
  Generator function to handle the AI workflow state machine.
 
328
  # Yield immediately to update the chat UI with the user's message
329
  # This provides immediate feedback to the user while the AI processes
330
  # Ensure all state variables and UI outputs are yielded back in the correct order
331
+ # NOTE: gemini_key and gemini_model are NOT yielded back
332
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
333
+ attempts, app_desc, repo_name, generated_code, use_grounding)
334
 
335
  try:
336
  # --- State Machine Logic based on the current 'state' variable ---
337
 
338
+ # Although button interactivity prevents reaching here without key/model,
339
+ # the checks remain as a safeguard for the workflow logic itself.
340
+ if not (hf_profile and hf_token):
341
+ history = add_bot_message(history, "Workflow paused: Please log in to Hugging Face first.")
342
+ # NOTE: gemini_key and gemini_model are NOT yielded back
343
+ yield (history, repo_id, state, updated_preview, updated_run, updated_build,
344
+ attempts, app_desc, repo_name, generated_code, use_grounding)
345
+ return # Stop workflow execution for this click
 
 
 
 
346
 
347
+ # Check if API key is non-empty string and model is set
348
+ if not (isinstance(gemini_api_key, str) and gemini_api_key != "" and gemini_model):
349
+ history = add_bot_message(history, "Workflow cannot start: Please ensure your Gemini API key is entered and a model is selected.")
350
+ # NOTE: gemini_key and gemini_model are NOT yielded back
351
+ yield (history, repo_id, state, updated_preview, updated_run, updated_build,
352
+ attempts, app_desc, repo_name, generated_code, use_grounding)
353
+ return # Stop workflow execution for this click
354
 
355
 
356
+ if state == STATE_IDLE:
357
  # Look for specific commands in the user's message
358
  reset_match = "reset" in message.lower()
359
  # Capture app description AND repo name using regex
 
366
  history = add_bot_message(history, "Workflow reset.")
367
  # Yield updated history and reset state variables to their initial values
368
  # Also reset UI outputs to their initial state
369
+ # NOTE: gemini_key and gemini_model are NOT yielded back (they are managed by change handlers)
370
  yield (history, None, STATE_IDLE, "<p>No Space created yet.</p>", "", "", 0,
371
+ None, None, None, False) # Reset use_grounding to default False, and other states to None/default
372
  # No return needed after yield in this generator pattern; execution for this click ends here.
373
 
374
  elif generate_match:
 
381
  repo_name = new_repo_name
382
  app_desc = new_app_desc
383
  # Yield updated history and state variables (pass UI outputs through)
384
+ # NOTE: gemini_key and gemini_model are NOT yielded back
385
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
386
+ attempts, app_desc, repo_name, generated_code, use_grounding)
387
  # No return needed
388
 
389
  elif create_match:
 
393
  state = STATE_CREATING_SPACE # Transition state to creation
394
  repo_name = new_repo_name # Store the validated repo name
395
  # Yield updated history and state variables (pass UI outputs through)
396
+ # NOTE: gemini_key and gemini_model are NOT yielded back
397
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
398
+ attempts, app_desc, repo_name, generated_code, use_grounding)
399
  # No return needed
400
 
401
  elif "create" in message.lower() and not repo_id:
 
403
  history = add_bot_message(history, "Okay, what should the Space be called? (e.g., `my-awesome-app`)")
404
  state = STATE_AWAITING_REPO_NAME # Transition to the state where we wait for the name
405
  # Yield updated history and state (pass UI outputs through)
406
+ # NOTE: gemini_key and gemini_model are NOT yielded back
407
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
408
+ attempts, app_desc, repo_name, generated_code, use_grounding)
409
  # No return needed
410
 
411
  else:
412
  # Command not recognized in IDLE state
413
  history = add_bot_message(history, "Command not recognized. Try 'generate me a gradio app called myapp', or 'reset'.")
414
  # Yield updated history and current state (pass UI outputs through)
415
+ # NOTE: gemini_key and gemini_model are NOT yielded back
416
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
417
+ attempts, app_desc, repo_name, generated_code, use_grounding)
418
  # No return needed
419
 
420
 
 
426
  if not new_repo_name or re.search(r'[^a-zA-Z0-9_-]', new_repo_name) or len(new_repo_name) > 100:
427
  history = add_bot_message(history, "Invalid name. Please provide a single word/slug for the Space name (letters, numbers, underscores, hyphens only, max 100 chars).")
428
  # Stay in AWAITING_REPO_NAME state and yield message (pass UI outputs through)
429
+ # NOTE: gemini_key and gemini_model are NOT yielded back
430
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
431
+ attempts, app_desc, repo_name, generated_code, use_grounding)
432
  # No return needed
433
 
434
  else:
 
437
  repo_name = new_repo_name # Store the validated repo name
438
  # Yield updated history, state, and repo name. UI outputs remain unchanged for now.
439
  # The next click will proceed from the STATE_CREATING_SPACE block.
440
+ # NOTE: gemini_key and gemini_model are NOT yielded back
441
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
442
+ attempts, app_desc, repo_name, generated_code, use_grounding)
443
  # No return needed
444
 
445
  # Note: Each 'elif' block below represents a distinct step in the workflow triggered
 
450
  if not repo_name:
451
  history = add_bot_message(history, "Internal error: Repo name missing for creation. Resetting.")
452
  # Reset relevant states and UI outputs on critical error
453
+ # NOTE: gemini_key and gemini_model are NOT yielded back
454
  yield (history, None, STATE_IDLE, "<p>Error creating space.</p>", "", "", 0,
455
+ None, None, None, use_grounding) # Pass grounding state through
456
  # No return needed
457
 
458
  else:
 
464
  history = add_bot_message(history, f"✅ Space `{repo_id}` created. Click 'Send' to generate and upload code.")
465
  state = STATE_GENERATING_CODE # Transition to the next state
466
  # Yield updated state variables and history, and the new iframe HTML
467
+ # NOTE: gemini_key and gemini_model are NOT yielded back
468
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
469
+ attempts, app_desc, repo_name, generated_code, use_grounding) # Pass logs and grounding through
470
  # No return needed
471
 
472
  except Exception as e:
473
  history = add_bot_message(history, f"❌ Error creating space: {e}. Click 'reset'.")
474
  # Yield error message and reset state on failure
475
+ # NOTE: gemini_key and gemini_model are NOT yielded back
476
  yield (history, None, STATE_IDLE, "<p>Error creating space.</p>", "", "", 0,
477
+ None, None, None, use_grounding) # Pass logs and grounding through
478
  # No return needed
479
 
480
 
 
493
  if use_grounding:
494
  history = add_bot_message(history, "(Using Grounding with Google Search)")
495
  # Yield to show message before the potentially time-consuming API call
496
+ # NOTE: gemini_key and gemini_model are NOT yielded back
497
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
498
+ attempts, app_desc, repo_name, generated_code, use_grounding)
499
 
500
  # Perform the Gemini API call to generate code, optionally using grounding
501
+ # Use the gemini_api_key and gemini_model inputs directly (which come from state)
502
  code = call_gemini(prompt, gemini_api_key, gemini_model, use_grounding=use_grounding)
503
  code = code.strip()
504
  # Clean up common markdown code block formatting if present
 
516
  state = STATE_UPLOADING_APP_PY # Transition to the upload state
517
  generated_code = code # Store the generated code in the state variable for the next step
518
  # Yield updated state variables and history (pass UI outputs and other states through)
519
+ # NOTE: gemini_key and gemini_model are NOT yielded back
520
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
521
+ attempts, app_desc, repo_name, generated_code, use_grounding)
522
  # No return needed
523
 
524
  except Exception as e:
525
  history = add_bot_message(history, f"❌ Error generating code: {e}. Click 'reset'.")
526
  # Yield error message and reset state on failure
527
+ # NOTE: gemini_key and gemini_model are NOT yielded back
528
  yield (history, None, STATE_IDLE, updated_preview, updated_run, updated_build, 0,
529
+ None, None, None, use_grounding)
530
  # No return needed
531
 
532
 
 
535
  code_to_upload = generated_code
536
  if not code_to_upload:
537
  history = add_bot_message(history, "Internal error: No code to upload. Resetting.")
538
+ # NOTE: gemini_key and gemini_model are NOT yielded back
539
  yield (history, None, STATE_IDLE, updated_preview, updated_run, updated_build, 0,
540
+ None, None, None, use_grounding)
541
  # No return needed
542
 
543
  else:
544
  history = add_bot_message(history, "☁️ Uploading `app.py`...")
545
  # Yield to show message before the upload action (pass UI outputs and states through)
546
+ # NOTE: gemini_key and gemini_model are NOT yielded back
547
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
548
+ attempts, app_desc, repo_name, generated_code, use_grounding)
549
 
550
  try:
551
  # Perform the file upload action
 
554
  state = STATE_GENERATING_REQUIREMENTS # Transition state
555
  generated_code = None # Clear the stored code after use to free memory/state space
556
  # Yield updated state variables and history (pass UI outputs and other states through)
557
+ # NOTE: gemini_key and gemini_model are NOT yielded back
558
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
559
+ attempts, app_desc, repo_name, generated_code, use_grounding)
560
  # No return needed
561
 
562
  except Exception as e:
563
  history = add_bot_message(history, f"❌ Error uploading `app.py`: {e}. Click 'reset'.")
564
  # Yield error message and reset state on failure
565
+ # NOTE: gemini_key and gemini_model are NOT yielded back
566
  yield (history, None, STATE_IDLE, updated_preview, updated_run, updated_build, 0,
567
+ None, None, None, use_grounding)
568
  # No return needed
569
 
570
 
571
  elif state == STATE_GENERATING_REQUIREMENTS:
572
  history = add_bot_message(history, "📄 Generating `requirements.txt`...")
573
  # Yield to show message before generating requirements (pass UI outputs and states through)
574
+ # NOTE: gemini_key and gemini_model are NOT yielded back
575
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
576
+ attempts, app_desc, repo_name, generated_code, use_grounding)
577
 
578
  # Logic to determine required packages based on SDK and keywords in the app description
579
  reqs_list = ["gradio"] if space_sdk == "gradio" else ["streamlit"]
 
614
  state = STATE_UPLOADING_REQUIREMENTS # Transition state
615
  generated_code = reqs_content # Store requirements content
616
  # Yield updated state variables and history (pass UI outputs and other states through)
617
+ # NOTE: gemini_key and gemini_model are NOT yielded back
618
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
619
+ attempts, app_desc, repo_name, generated_code, use_grounding)
620
  # No return needed
621
 
622
 
 
625
  reqs_content_to_upload = generated_code
626
  if not reqs_content_to_upload:
627
  history = add_bot_message(history, "Internal error: No requirements content to upload. Resetting.")
628
+ # NOTE: gemini_key and gemini_model are NOT yielded back
629
  yield (history, None, STATE_IDLE, updated_preview, updated_run, updated_build, 0,
630
+ None, None, None, use_grounding)
631
  # No return needed
632
 
633
  else:
634
  history = add_bot_message(history, "☁️ Uploading `requirements.txt`...")
635
  # Yield message before upload (pass UI outputs and states through)
636
+ # NOTE: gemini_key and gemini_model are NOT yielded back
637
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
638
+ attempts, app_desc, repo_name, generated_code, use_grounding)
639
 
640
  try:
641
  # Perform requirements file upload
 
644
  state = STATE_GENERATING_README # Transition state
645
  generated_code = None # Clear content after use
646
  # Yield updated state variables and history (pass UI outputs and other states through)
647
+ # NOTE: gemini_key and gemini_model are NOT yielded back
648
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
649
+ attempts, app_desc, repo_name, generated_code, use_grounding)
650
  # No return needed
651
 
652
  except Exception as e:
653
  history = add_bot_message(history, f"❌ Error uploading `requirements.txt`: {e}. Click 'reset'.")
654
  # Yield error message and reset state on failure
655
+ # NOTE: gemini_key and gemini_model are NOT yielded back
656
  yield (history, None, STATE_IDLE, updated_preview, updated_run, updated_build, 0,
657
+ None, None, None, use_grounding)
658
  # No return needed
659
 
660
  elif state == STATE_GENERATING_README:
661
  history = add_bot_message(history, "📝 Generating `README.md`...")
662
  # Yield message before generating README (pass UI outputs and states through)
663
+ # NOTE: gemini_key and gemini_model are NOT yielded back
664
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
665
+ attempts, app_desc, repo_name, generated_code, use_grounding)
666
 
667
  # Generate simple README content with Space metadata header
668
  readme_title = repo_name if repo_name else "My Awesome Space"
 
689
  state = STATE_UPLOADING_README # Transition state
690
  generated_code = readme_content # Store README content
691
  # Yield updated state variables and history (pass UI outputs and other states through)
692
+ # NOTE: gemini_key and gemini_model are NOT yielded back
693
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
694
+ attempts, app_desc, repo_name, generated_code, use_grounding)
695
  # No return needed
696
 
697
 
 
700
  readme_content_to_upload = generated_code
701
  if not readme_content_to_upload:
702
  history = add_bot_message(history, "Internal error: No README content to upload. Resetting.")
703
+ # NOTE: gemini_key and gemini_model are NOT yielded back
704
  yield (history, None, STATE_IDLE, updated_preview, updated_run, updated_build, 0,
705
+ None, None, None, use_grounding)
706
  # No return needed
707
 
708
  else:
709
  history = add_bot_message(history, "☁️ Uploading `README.md`...")
710
  # Yield message before upload (pass UI outputs and states through)
711
+ # NOTE: gemini_key and gemini_model are NOT yielded back
712
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
713
+ attempts, app_desc, repo_name, generated_code, use_grounding)
714
 
715
  try:
716
  # Perform README file upload
 
719
  state = STATE_CHECKING_LOGS_BUILD # Transition to checking build logs
720
  generated_code = None # Clear content after use
721
  # Yield updated state variables and history (pass UI outputs and other states through)
722
+ # NOTE: gemini_key and gemini_model are NOT yielded back
723
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
724
+ attempts, app_desc, repo_name, generated_code, use_grounding)
725
  # No return needed
726
 
727
  except Exception as e:
728
  history = add_bot_message(history, f"❌ Error uploading `README.md`: {e}. Click 'reset'.")
729
  # Yield error message and reset state on failure
730
+ # NOTE: gemini_key and gemini_model are NOT yielded back
731
  yield (history, None, STATE_IDLE, updated_preview, updated_run, updated_build, 0,
732
+ None, None, None, use_grounding)
733
  # No return needed
734
 
735
  elif state == STATE_CHECKING_LOGS_BUILD:
736
  history = add_bot_message(history, "🔍 Fetching build logs...")
737
  # Yield message before fetching logs (which includes a delay) (pass UI outputs and states through)
738
+ # NOTE: gemini_key and gemini_model are NOT yielded back
739
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
740
+ attempts, app_desc, repo_name, generated_code, use_grounding)
741
 
742
  # Fetch build logs from HF Space
743
  build_logs_text = get_build_logs_action(repo_id, hf_profile, hf_token)
 
748
  history = add_bot_message(history, "⚠️ Build logs indicate potential issues. Please inspect above. Click 'Send' to check container logs (app might still start despite build warnings).")
749
  state = STATE_CHECKING_LOGS_RUN # Transition even on build error, to see if container starts
750
  # Yield updated state, logs, and variables
751
+ # NOTE: gemini_key and gemini_model are NOT yielded back
752
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
753
+ attempts, app_desc, repo_name, generated_code, use_grounding)
754
  # No return needed
755
 
756
  else:
757
  history = add_bot_message(history, "✅ Build logs fetched. Click 'Send' to check container logs.")
758
  state = STATE_CHECKING_LOGS_RUN # Transition to next log check
759
  # Yield updated state, logs, and variables
760
+ # NOTE: gemini_key and gemini_model are NOT yielded back
761
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
762
+ attempts, app_desc, repo_name, generated_code, use_grounding)
763
  # No return needed
764
 
765
 
766
  elif state == STATE_CHECKING_LOGS_RUN:
767
  history = add_bot_message(history, "🔍 Fetching container logs...")
768
  # Yield message before fetching logs (includes a delay) (pass UI outputs and states through)
769
+ # NOTE: gemini_key and gemini_model are NOT yielded back
770
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
771
+ attempts, app_desc, repo_name, generated_code, use_grounding)
772
 
773
  # Fetch container logs from HF Space
774
  container_logs_text = get_container_logs_action(repo_id, hf_profile, hf_token)
 
780
  history = add_bot_message(history, f"❌ Errors detected in container logs. Attempting debug fix #{attempts}/{MAX_DEBUG_ATTEMPTS}. Click 'Send' to proceed.")
781
  state = STATE_DEBUGGING_CODE # Transition to the debugging state
782
  # Yield updated state, logs, attempts, and variables
783
+ # NOTE: gemini_key and gemini_model are NOT yielded back
784
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
785
+ attempts, app_desc, repo_name, generated_code, use_grounding)
786
  # No return needed
787
 
788
  elif ("error" in updated_run.lower() or "exception" in updated_run.lower()) and attempts >= MAX_DEBUG_ATTEMPTS:
 
790
  history = add_bot_message(history, f"❌ Errors detected in container logs. Max debug attempts ({MAX_DEBUG_ATTEMPTS}) reached. Please inspect logs manually or click 'reset'.")
791
  state = STATE_COMPLETE # Workflow ends on failure after attempts
792
  # Yield updated state, logs, attempts, and variables
793
+ # NOTE: gemini_key and gemini_model are NOT yielded back
794
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
795
+ attempts, app_desc, repo_name, generated_code, use_grounding)
796
  # No return needed
797
 
798
  else:
 
800
  history = add_bot_message(history, "✅ App appears to be running successfully! Check the iframe above. Click 'reset' to start a new project.")
801
  state = STATE_COMPLETE # Workflow ends on success
802
  # Yield updated state, logs, attempts, and variables
803
+ # NOTE: gemini_key and gemini_model are NOT yielded back
804
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
805
+ attempts, app_desc, repo_name, generated_code, use_grounding)
806
  # No return needed
807
 
808
 
 
811
  if use_grounding:
812
  history = add_bot_message(history, "(Using Grounding with Google Search)")
813
  # Yield message before Gemini API call (pass UI outputs and states through)
814
+ # NOTE: gemini_key and gemini_model are NOT yielded back
815
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
816
+ attempts, app_desc, repo_name, generated_code, use_grounding)
817
 
818
  # Construct prompt for Gemini including the container logs
819
  debug_prompt = f"""
 
830
  # Call Gemini to generate the corrected code, optionally using grounding
831
  # Note: Grounding might be less effective for debugging based *only* on logs,
832
  # but we include the option as requested.
833
+ # Use the gemini_api_key and gemini_model inputs directly (which come from state)
834
  fix_code = call_gemini(debug_prompt, gemini_api_key, gemini_model, use_grounding=use_grounding)
835
  fix_code = fix_code.strip()
836
  # Clean up potential markdown formatting
 
848
  state = STATE_UPLOADING_FIXED_APP_PY # Transition to the upload state for the fix
849
  generated_code = fix_code # Store the generated fix code
850
  # Yield updated state, code, and variables (pass UI outputs and states through)
851
+ # NOTE: gemini_key and gemini_model are NOT yielded back
852
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
853
+ attempts, app_desc, repo_name, generated_code, use_grounding)
854
  # No return needed
855
 
856
  except Exception as e:
857
  history = add_bot_message(history, f"❌ Error generating debug code: {e}. Click 'reset'.")
858
  # Yield error message and reset state on failure
859
+ # NOTE: gemini_key and gemini_model are NOT yielded back
860
  yield (history, None, STATE_IDLE, updated_preview, updated_run, updated_build, 0,
861
+ None, None, None, use_grounding)
862
  # No return needed
863
 
864
  elif state == STATE_UPLOADING_FIXED_APP_PY:
 
866
  fixed_code_to_upload = generated_code
867
  if not fixed_code_to_upload:
868
  history = add_bot_message(history, "Internal error: No fixed code available to upload. Resetting.")
869
+ # NOTE: gemini_key and gemini_model are NOT yielded back
870
  yield (history, None, STATE_IDLE, updated_preview, updated_run, updated_build, 0,
871
+ None, None, None, use_grounding)
872
  # No return needed
873
 
874
  else:
875
  history = add_bot_message(history, "☁️ Uploading fixed `app.py`...")
876
  # Yield message before upload (pass UI outputs and states through)
877
+ # NOTE: gemini_key and gemini_model are NOT yielded back
878
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
879
+ attempts, app_desc, repo_name, generated_code, use_grounding)
880
 
881
  try:
882
  # Perform the upload of the fixed app.py
 
885
  state = STATE_CHECKING_LOGS_RUN # Go back to checking run logs after uploading the fix
886
  generated_code = None # Clear code after use
887
  # Yield updated state, code, and variables (pass UI outputs and states through)
888
+ # NOTE: gemini_key and gemini_model are NOT yielded back
889
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
890
+ attempts, app_desc, repo_name, generated_code, use_grounding)
891
  # No return needed
892
 
893
  except Exception as e:
894
  history = add_bot_message(history, f"❌ Error uploading fixed `app.py`: {e}. Click 'reset'.")
895
  # Yield error message and reset state on failure
896
+ # NOTE: gemini_key and gemini_model are NOT yielded back
897
  yield (history, None, STATE_IDLE, updated_preview, updated_run, updated_build, 0,
898
+ None, None, None, use_grounding)
899
  # No return needed
900
 
901
  elif state == STATE_COMPLETE:
902
  # If in the complete state, the workflow is finished for this project.
903
  # Subsequent clicks just add user messages; we simply yield the current state.
904
+ # NOTE: gemini_key and gemini_model are NOT yielded back
905
  yield (history, repo_id, state, updated_preview, updated_run, updated_build,
906
+ attempts, app_desc, repo_name, generated_code, use_grounding)
907
  # No return needed
908
 
909
 
 
913
  history = add_bot_message(history, error_message)
914
  print(f"Critical Error in state {state}: {e}") # Log the error for debugging purposes
915
  # Yield an error state and reset essential workflow variables on critical failure
916
+ # NOTE: gemini_key and gemini_model are NOT yielded back
917
  yield (history, None, STATE_IDLE, updated_preview, updated_run, updated_build, 0,
918
+ None, None, None, use_grounding) # Include use_grounding
919
  # No return needed after yield
920
 
921
 
 
926
  # Define these first as they might be used in default values for components
927
  hf_profile = gr.State(None)
928
  hf_token = gr.State(None)
929
+ # CHANGED: Initialize gemini_key state to empty string, not from env var
930
+ gemini_key = gr.State("") # start with no key
931
  gemini_model = gr.State("gemini-1.5-flash") # Default selected model
932
  repo_id = gr.State(None) # Stores the ID of the created Space
933
  workflow = gr.State(STATE_IDLE) # Stores the current state of the AI workflow
 
950
 
951
  gr.Markdown("## Google AI Studio / Gemini")
952
  # Define gemini_input and gemini_status before they are used in change handlers
953
+ # CHANGED: Blank out textbox on load and update info text
954
  gemini_input = gr.Textbox(
955
+ label="Your Google AI Studio API Key", # Changed label
956
  type="password", # Hides input for security
957
  interactive=True,
958
+ value="", # Don't pre-fill from env var
959
+ info="Enter your own key here" # Updated info text
960
  )
961
  gemini_status = gr.Markdown("") # Display Gemini configuration status
962
 
 
1026
  )
1027
 
1028
  # Handle Gemini Key Input change: Update key state -> Configure Gemini status -> Check prereqs and update button interactivity
1029
+ # This chain is crucial for the new key handling logic
1030
  gemini_input.change(
1031
+ lambda k: k, inputs=[gemini_input], outputs=[gemini_key] # Update gemini_key state with textbox value
1032
  ).then(
1033
+ configure_gemini, inputs=[gemini_key, gemini_model], outputs=[gemini_status] # Update Gemini status based on new key
1034
  ).then(
1035
  # Call the update function and bind its output to the button component
1036
  check_send_button_ready,
 
1039
  )
1040
 
1041
  # Handle Gemini Model Selector change: Update model state -> Configure Gemini status -> Check prereqs and update button interactivity
1042
+ # This chain is crucial for the new key handling logic
1043
  model_selector.change(
1044
+ lambda m: m, inputs=[model_selector], outputs=[gemini_model] # Update gemini_model state with selected model
1045
  ).then(
1046
+ configure_gemini, inputs=[gemini_key, gemini_model], outputs=[gemini_status] # Update Gemini status based on new model
1047
  ).then(
1048
  # Call the update function and bind its output to the button component
1049
  check_send_button_ready,
 
1077
  inputs=[
1078
  user_input, chatbot, # UI component inputs (message, current chat history)
1079
  hf_profile, hf_token, # HF State variables
1080
+ # Pass gemini_key and gemini_model as inputs (their state is read here)
1081
+ gemini_key, gemini_model,
1082
  repo_id, workflow, sdk_state, # Workflow State variables
1083
  # UI component inputs whose *current values* are needed by the generator
1084
+ iframe, run_txt, build_txt, # UI component inputs (current values)
 
1085
  debug_attempts, app_description, repo_name_state, generated_code_state, # Other State variables
1086
+ use_grounding_state # Grounding state input
1087
  ],
1088
  outputs=[
1089
  chatbot, # Update Chatbot with new messages
1090
  repo_id, workflow, # Update workflow State variables
1091
  iframe, run_txt, build_txt, # Update UI component outputs
1092
  debug_attempts, app_description, repo_name_state, generated_code_state, # Update other State variables
1093
+ use_grounding_state # Update the grounding state output
1094
+ # REMOVED: gemini_key, gemini_model from outputs
1095
  ]
1096
  ).success( # Chain a .success() event to run *after* the .click() handler completes without error
1097
  # Clear the user input textbox after the message is sent and processed
 
1109
  inputs=None,
1110
  outputs=login_status # Update login status markdown
1111
  ).then(
1112
+ # Action 2: Configure Gemini using the initial state values.
1113
+ # Since gemini_key state starts as "", this will initially show a "key is not set" message.
1114
  configure_gemini,
1115
  inputs=[gemini_key, gemini_model],
1116
  outputs=[gemini_status] # Update Gemini status display
1117
  ).then(
1118
+ # Action 3: Check prereqs and update send button interactivity based on initial states.
1119
+ # Since gemini_key state starts as "", button will initially be disabled.
1120
+ check_send_button_ready,
1121
  inputs=send_button_interactive_binding_inputs,
1122
  outputs=[send_btn] # Update button interactivity using gr.update return value
1123
  ).then(