wuhp commited on
Commit
a8fc748
·
verified ·
1 Parent(s): 965bae1

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +109 -69
app.py CHANGED
@@ -394,9 +394,14 @@ def orchestrate_development(client, project_state, config, oauth_token_token):
394
  current_task = project_state['current_task']
395
 
396
  # Add current task to history for UI visibility (if not already added by previous step)
397
- if not project_state['chat_history'] or project_state['chat_history'][-1].get('content', '').strip() != f"➡️ Task: {current_task}".strip():
 
 
 
 
398
  project_state['chat_history'].append({"role": "assistant", "content": f"➡️ Task: {current_task}"})
399
 
 
400
  step_successful = True # Flag to track if the current step completed without error
401
 
402
  if current_task == 'PLANNING':
@@ -404,24 +409,32 @@ def orchestrate_development(client, project_state, config, oauth_token_token):
404
  if step_successful:
405
  # Add plan to chat history for user (done inside run_planner now?) - moved to run_planner
406
  project_state['current_task'] = 'CODING - Initial Implementation' # Move to coding after planning
 
 
 
 
407
  else:
408
  project_state['current_task'] = 'FAILED' # Planning failed
409
 
410
 
411
  elif current_task.startswith('CODING'):
412
- # Ensure the main app file exists before coding if it's the first coding step (or first after syntax error)
413
- if project_state['attempt_count'] == 0 or 'Syntax Errors' in project_state.get('feedback', ''):
414
- if project_state['main_app_file'] not in project_state['files']:
415
- project_state['files'][project_state['main_app_file']] = f"# Initial {project_state['sdk_choice']} app file\n" # Start with a basic stub
416
- if project_state['sdk_choice'] == 'gradio':
417
- project_state['files'][project_state['main_app_file']] += "import gradio as gr\n\n# Define a simple interface\n# For example: gr.Interface(...).launch()\n"
418
- elif project_state['sdk_choice'] == 'streamlit':
419
- project_state['files'][project_state['main_app_file']] += "import streamlit as st\n\n# Your Streamlit app starts here\n# For example: st.write('Hello, world!')\n"
420
- # Also ensure requirements.txt and README are stubbed if they don't exist
421
- if 'requirements.txt' not in project_state['files']:
422
- project_state['files']['requirements.txt'] = "pandas\n" + ("streamlit\n" if project_state['sdk_choice']=="streamlit" else "gradio\n") + "google-generativeai\nhuggingface-hub\n"
423
- if 'README.md' not in project_state['files']:
424
- readme_content = f"""---
 
 
 
 
425
  title: {project_state['repo_id']}
426
  emoji: 🐢
427
  sdk: {project_state['sdk_choice']}
@@ -438,7 +451,7 @@ This is an auto-generated HF Space.
438
  **Plan:**
439
  {project_state['plan']}
440
  """
441
- project_state['files']['README.md'] = readme_content
442
 
443
 
444
  step_successful = run_codegen(client, project_state, config)
@@ -449,7 +462,7 @@ This is an auto-generated HF Space.
449
  # Code-gen failed (syntax error, parsing issue, etc.)
450
  # The failure is handled within run_codegen by setting status_message and feedback
451
  # We'll try debugging/coding again in the next attempt loop iteration if attempts allow
452
- print("Code-Gen step failed.")
453
  # attempt_count is incremented AFTER debugging phase analyses results
454
  project_state['current_task'] = 'DEBUGGING' # Go to debugging to analyze the failure
455
 
@@ -490,13 +503,15 @@ This is an auto-generated HF Space.
490
  # Wait a moment for build to start
491
  time.sleep(5) # Initial wait
492
  wait_time = 5
493
- max_log_wait = 90 # Maximum total time to wait for logs in this step (increased slightly)
494
  elapsed_log_wait = 0
495
  logs_fetched = False
496
  iframe_checked = False
497
 
498
  project_state['status_message'] = "Fetching logs and checking iframe..."
499
- project_state['chat_history'].append({"role": "assistant", "content": project_state['status_message']})
 
 
500
 
501
 
502
  while elapsed_log_wait < max_log_wait:
@@ -508,7 +523,8 @@ This is an auto-generated HF Space.
508
  logs_fetched = True
509
 
510
  # Only check iframe once logs indicate something might be running, or after a delay
511
- if elapsed_log_wait > 10: # Don't check immediately
 
512
  project_state['iframe_ok'] = check_iframe(project_state['iframe_url'])
513
  iframe_checked = True
514
  else:
@@ -518,14 +534,16 @@ This is an auto-generated HF Space.
518
  print(f"Log/Iframe check at {elapsed_log_wait}s. Build logs len: {len(build_logs)}, Run logs len: {len(run_logs)}, Iframe OK: {project_state['iframe_ok']}")
519
 
520
  # Conditions to proceed to debugging:
521
- # 1. Iframe is OK (app is running and accessible)
522
  # 2. Build logs show errors (need debugging ASAP)
523
  # 3. Max wait time is almost reached (proceed with whatever logs we have)
524
  # 4. Build logs exist and indicate *some* progress (e.g., contain "Building" or sufficient length)
 
525
  if project_state['iframe_ok'] or \
526
  "ERROR" in build_logs.upper() or "FATAL" in build_logs.upper() or \
527
  elapsed_log_wait >= max_log_wait - wait_time or \
528
- ("Building" in build_logs or len(build_logs) > 100) and logs_fetched: # Heuristic for build progress
 
529
  break # Exit the log fetching wait loop
530
  else:
531
  print(f"Logs or iframe not ready. Waiting {wait_time}s...")
@@ -541,16 +559,16 @@ This is an auto-generated HF Space.
541
  wait_time = min(wait_time * 1.5, 20)
542
 
543
 
 
544
  if logs_fetched or iframe_checked: # Proceed if we got logs OR checked the iframe
545
  project_state['status_message'] = "Logs fetched and iframe checked (or timeout reached)."
546
- project_state['chat_history'].append({"role": "assistant", "content": project_state['status_message']})
547
- project_state['current_task'] = 'DEBUGGING' # Move to debugging to analyze logs
548
  else:
549
- step_successful = False
550
- project_state['status'] = 'Failed' # Failed to fetch logs/check iframe within timeout after retries
551
- project_state['status_message'] = "ERROR: Failed to fetch logs or check iframe within timeout after multiple retries."
552
- project_state['chat_history'].append({"role": "assistant", "content": project_state['status_message']})
553
- project_state['current_task'] = 'FINISHED' # End process
 
554
 
555
 
556
  elif current_task == 'DEBUGGING':
@@ -564,23 +582,17 @@ This is an auto-generated HF Space.
564
  # Analyze feedback to decide next step
565
  feedback = project_state['feedback']
566
  iframe_ok = project_state.get('iframe_ok', False)
567
- # Re-check logs just before making the decision for freshest info if possible
568
- # This might add latency, skipping for now, rely on logs fetched in LOGGING step
569
- # build_logs = fetch_logs(project_state['repo_id'], "build", oauth_token_token)
570
- # run_logs = fetch_logs(project_state['repo_id'], "run", oauth_token_token)
571
- # error_types = classify_errors(build_logs + '\n' + run_logs)
572
- # project_state['logs']['build'] = build_logs # Update state with freshest logs
573
- # project_state['logs']['run'] = run_logs
574
-
575
  error_types = classify_errors(project_state['logs'].get('build', '') + '\n' + project_state['logs'].get('run', ''))
576
 
577
-
578
  print(f"Debug Analysis - Feedback: {feedback[:100]}... | Iframe OK: {iframe_ok} | Errors: {error_types}")
579
 
580
 
581
- if "All clear. Project appears complete." in feedback or \
582
- (iframe_ok and error_types == "none" and "ERROR" not in feedback.upper()):
583
- # Debugger says it's clear OR iframe is working AND no errors reported in logs AND no ERROR in feedback
 
 
 
584
  project_state['status'] = 'Complete'
585
  project_state['current_task'] = 'FINISHED'
586
  project_state['status_message'] = "Debug Agent reports clear. Project appears complete."
@@ -606,7 +618,7 @@ This is an auto-generated HF Space.
606
 
607
  elif current_task == 'FINISHED':
608
  # Exit the main loop
609
- pass # Loop condition handles exit
610
 
611
  else:
612
  # Unknown task
@@ -622,9 +634,14 @@ This is an auto-generated HF Space.
622
  # the orchestrator logic above should handle transition to FAILED or DEBUGGING.
623
  # This check acts as a safeguard.
624
  if not step_successful and project_state['status'] == 'In Progress':
 
 
 
 
625
  project_state['status'] = 'Failed'
626
- project_state['status_message'] = project_state.get('status_message', f'An error occurred during task: {current_task}')
627
- project_state['current_task'] = 'FINISHED' # End process
 
628
 
629
 
630
  # --- End of Orchestration Loop ---
@@ -638,6 +655,7 @@ This is an auto-generated HF Space.
638
 
639
  # Add final outcome message to history if not already the last message
640
  final_outcome_message = f"**Project Outcome:** {project_state['status']} - {project_state['status_message']}"
 
641
  if not project_state['chat_history'] or project_state['chat_history'][-1].get('content', '').strip() != final_outcome_message.strip():
642
  project_state['chat_history'].append({"role": "assistant", "content": final_outcome_message})
643
 
@@ -664,8 +682,10 @@ This is an auto-generated HF Space.
664
 
665
  # --- MAIN HANDLER (Called by Gradio) ---
666
 
 
667
  def handle_user_message(
668
- history, # This is the list of messages in the Gradio Chatbot
 
669
  sdk_choice: str,
670
  gemini_api_key: str,
671
  grounding_enabled: bool,
@@ -674,16 +694,17 @@ def handle_user_message(
674
  profile: gr.OAuthProfile | None,
675
  oauth_token: gr.OAuthToken | None # We need the token object
676
  ):
677
- # Append the user's message to the history immediately for display
678
- # Gradio's Chatbot usually handles this automatically, but explicitly ensures it's present
679
- # before we start the orchestration.
680
- # Check if the last message is the current user input to avoid duplication on submit/click
681
- if not history or history[-1].get("content") != user_in.value: # Assuming user_in is accessible or passed
682
- # This logic is tricky with Gradio's submit button.
683
- # The default Chatbot behavior on submit/click is to add the user message.
684
- # So, history *should* already contain the new user message.
685
- # Let's rely on Gradio's standard behavior.
686
- pass
 
687
 
688
  if not profile or not oauth_token or not oauth_token.token:
689
  # Append error message to history for display
@@ -695,6 +716,11 @@ def handle_user_message(
695
  error_history = history + [{"role":"assistant","content":"⚠️ Please provide your Gemini API Key."}]
696
  return error_history, "", "", "<p>Please provide API Key.</p>", "API Key required."
697
 
 
 
 
 
 
698
 
699
  client = genai.Client(api_key=gemini_api_key)
700
  repo_id = f"{profile.username}/{profile.username}-auto-space"
@@ -702,14 +728,8 @@ def handle_user_message(
702
  sdk_version = get_sdk_version(sdk_choice)
703
  code_fn = "app.py" if sdk_choice == "gradio" else "streamlit_app.py" # Standard main file name convention
704
 
705
- # Get the user's latest prompt from the history
706
- # Assume the last message in history is the user's new prompt because Gradio added it
707
- user_prompt = history[-1]['content'] if history and history[-1].get("role") == "user" else "No prompt provided."
708
-
709
- if user_prompt == "No prompt provided." or user_prompt.strip() == "":
710
- # Handle empty prompt case
711
- empty_prompt_history = history + [{"role":"assistant","content":"Please enter requirements for the application."}]
712
- return empty_prompt_history, "", "", "<p>Enter requirements.</p>", "Waiting for prompt."
713
 
714
 
715
  # Initialize project state for this development session
@@ -762,7 +782,7 @@ with gr.Blocks(title="HF Space Auto‑Builder (Team AI)") as demo:
762
 
763
  with gr.Row():
764
  with gr.Column(scale=1):
765
- # --- LOGIN BUTTON / PROFILE & MODEL LISTING (FIXED) ---
766
  login_btn = gr.LoginButton(variant="huggingface", size="lg")
767
  status_md = gr.Markdown("*Not logged in.*")
768
  models_md = gr.Markdown()
@@ -784,7 +804,7 @@ with gr.Blocks(title="HF Space Auto‑Builder (Team AI)") as demo:
784
  outputs=models_md,
785
  api_name="login_models"
786
  )
787
- # --- END FIX ---
788
 
789
 
790
  gr.Markdown("---")
@@ -812,17 +832,37 @@ with gr.Blocks(title="HF Space Auto‑Builder (Team AI)") as demo:
812
  preview = gr.HTML("<p>App preview will load here when available.</p>")
813
 
814
 
815
- # Update the button click handler
816
- # It will now return the updated chatbot history, logs, preview, and the project status
817
- # Inputs=None allows Gradio to inject profile/token from login_btn
818
  send_btn.click(
819
  fn=handle_user_message,
820
- inputs=[chatbot, sdk_choice, api_key, grounding, temp, max_tokens, login_btn, login_btn], # Keep login_btn twice for profile and token objects
 
 
 
 
 
 
 
 
 
 
821
  outputs=[chatbot, build_box, run_box, preview, project_status_md]
822
  )
 
 
823
  user_in.submit(
824
  fn=handle_user_message,
825
- inputs=[chatbot, sdk_choice, api_key, grounding, temp, max_tokens, login_btn, login_btn], # Keep login_btn twice
 
 
 
 
 
 
 
 
 
 
826
  outputs=[chatbot, build_box, run_box, preview, project_status_md]
827
  )
828
 
 
394
  current_task = project_state['current_task']
395
 
396
  # Add current task to history for UI visibility (if not already added by previous step)
397
+ # Avoid adding duplicate "➡️ Task" messages immediately
398
+ if not project_state['chat_history'] or (
399
+ project_state['chat_history'][-1].get('content', '').strip().replace('➡️ Task: ', '') != current_task.strip().replace('➡️ Task: ', '')
400
+ or not project_state['chat_history'][-1].get('content', '').startswith('➡️ Task:')
401
+ ):
402
  project_state['chat_history'].append({"role": "assistant", "content": f"➡️ Task: {current_task}"})
403
 
404
+
405
  step_successful = True # Flag to track if the current step completed without error
406
 
407
  if current_task == 'PLANNING':
 
409
  if step_successful:
410
  # Add plan to chat history for user (done inside run_planner now?) - moved to run_planner
411
  project_state['current_task'] = 'CODING - Initial Implementation' # Move to coding after planning
412
+ # Add plan to chat history if it wasn't added by run_planner (depends on its implementation)
413
+ if project_state['plan'] and not any("**Plan:**" in msg['content'] for msg in project_state['chat_history']):
414
+ project_state['chat_history'].append({"role": "assistant", "content": f"**Plan:**\n{project_state['plan']}"})
415
+
416
  else:
417
  project_state['current_task'] = 'FAILED' # Planning failed
418
 
419
 
420
  elif current_task.startswith('CODING'):
421
+ # Ensure minimum files exist before asking CodeGen to code
422
+ # This happens once at the start of the first coding task
423
+ if project_state['attempt_count'] == 0 and project_state['current_task'] == 'CODING - Initial Implementation':
424
+ # Add initial stub files if they don't exist
425
+ if project_state['main_app_file'] not in project_state['files']:
426
+ project_state['files'][project_state['main_app_file']] = f"# Initial {project_state['sdk_choice']} app file\n" # Start with a basic stub
427
+ if project_state['sdk_choice'] == 'gradio':
428
+ project_state['files'][project_state['main_app_file']] += "import gradio as gr\n\n# Define a simple interface\n# For example: gr.Interface(...).launch()\n"
429
+ elif project_state['sdk_choice'] == 'streamlit':
430
+ project_state['files'][project_state['main_app_file']] += "import streamlit as st\n\n# Your Streamlit app starts here\n# For example: st.write('Hello, world!')\n"
431
+
432
+ if 'requirements.txt' not in project_state['files']:
433
+ req_content = "pandas\n" + ("streamlit\n" if project_state['sdk_choice']=="streamlit" else "gradio\n") + "google-generativeai\nhuggingface-hub\n"
434
+ project_state['files']['requirements.txt'] = req_content
435
+
436
+ if 'README.md' not in project_state['files']:
437
+ readme_content = f"""---
438
  title: {project_state['repo_id']}
439
  emoji: 🐢
440
  sdk: {project_state['sdk_choice']}
 
451
  **Plan:**
452
  {project_state['plan']}
453
  """
454
+ project_state['files']['README.md'] = readme_content
455
 
456
 
457
  step_successful = run_codegen(client, project_state, config)
 
462
  # Code-gen failed (syntax error, parsing issue, etc.)
463
  # The failure is handled within run_codegen by setting status_message and feedback
464
  # We'll try debugging/coding again in the next attempt loop iteration if attempts allow
465
+ print("Code-Gen step failed. Moving to Debugging.")
466
  # attempt_count is incremented AFTER debugging phase analyses results
467
  project_state['current_task'] = 'DEBUGGING' # Go to debugging to analyze the failure
468
 
 
503
  # Wait a moment for build to start
504
  time.sleep(5) # Initial wait
505
  wait_time = 5
506
+ max_log_wait = 120 # Maximum total time to wait for logs in this step (increased slightly more)
507
  elapsed_log_wait = 0
508
  logs_fetched = False
509
  iframe_checked = False
510
 
511
  project_state['status_message'] = "Fetching logs and checking iframe..."
512
+ # Check if the message is already the last one to avoid spamming
513
+ if not project_state['chat_history'] or project_state['chat_history'][-1].get('content', '').strip() != project_state['status_message'].strip():
514
+ project_state['chat_history'].append({"role": "assistant", "content": project_state['status_message']})
515
 
516
 
517
  while elapsed_log_wait < max_log_wait:
 
523
  logs_fetched = True
524
 
525
  # Only check iframe once logs indicate something might be running, or after a delay
526
+ # Check iframe more frequently after initial wait
527
+ if elapsed_log_wait > 10 or len(run_logs) > 0:
528
  project_state['iframe_ok'] = check_iframe(project_state['iframe_url'])
529
  iframe_checked = True
530
  else:
 
534
  print(f"Log/Iframe check at {elapsed_log_wait}s. Build logs len: {len(build_logs)}, Run logs len: {len(run_logs)}, Iframe OK: {project_state['iframe_ok']}")
535
 
536
  # Conditions to proceed to debugging:
537
+ # 1. Iframe is OK (app is running and accessible) - strongest signal
538
  # 2. Build logs show errors (need debugging ASAP)
539
  # 3. Max wait time is almost reached (proceed with whatever logs we have)
540
  # 4. Build logs exist and indicate *some* progress (e.g., contain "Building" or sufficient length)
541
+ # 5. Run logs exist (app is at least trying to run)
542
  if project_state['iframe_ok'] or \
543
  "ERROR" in build_logs.upper() or "FATAL" in build_logs.upper() or \
544
  elapsed_log_wait >= max_log_wait - wait_time or \
545
+ ("Building" in build_logs or len(build_logs) > 100) and logs_fetched or \
546
+ len(run_logs) > 0:
547
  break # Exit the log fetching wait loop
548
  else:
549
  print(f"Logs or iframe not ready. Waiting {wait_time}s...")
 
559
  wait_time = min(wait_time * 1.5, 20)
560
 
561
 
562
+ # Update status message after the wait loop
563
  if logs_fetched or iframe_checked: # Proceed if we got logs OR checked the iframe
564
  project_state['status_message'] = "Logs fetched and iframe checked (or timeout reached)."
 
 
565
  else:
566
+ project_state['status_message'] = "Warning: Could not fetch logs or check iframe status within timeout." # Use Warning status message
567
+ step_successful = False # Indicate that this step didn't fully succeed
568
+
569
+
570
+ project_state['chat_history'].append({"role": "assistant", "content": project_state['status_message']})
571
+ project_state['current_task'] = 'DEBUGGING' # Always move to debugging after attempting to log/check
572
 
573
 
574
  elif current_task == 'DEBUGGING':
 
582
  # Analyze feedback to decide next step
583
  feedback = project_state['feedback']
584
  iframe_ok = project_state.get('iframe_ok', False)
 
 
 
 
 
 
 
 
585
  error_types = classify_errors(project_state['logs'].get('build', '') + '\n' + project_state['logs'].get('run', ''))
586
 
 
587
  print(f"Debug Analysis - Feedback: {feedback[:100]}... | Iframe OK: {iframe_ok} | Errors: {error_types}")
588
 
589
 
590
+ # Decision Logic:
591
+ # 1. Success? Debugger says clear AND iframe works AND no/minor errors in logs
592
+ is_complete = ("All clear. Project appears complete." in feedback) or \
593
+ (iframe_ok and error_types == "none" and "ERROR" not in feedback.upper() and len(project_state['logs'].get('run', '')) > 0) # Appears to run and no errors
594
+
595
+ if is_complete:
596
  project_state['status'] = 'Complete'
597
  project_state['current_task'] = 'FINISHED'
598
  project_state['status_message'] = "Debug Agent reports clear. Project appears complete."
 
618
 
619
  elif current_task == 'FINISHED':
620
  # Exit the main loop
621
+ break # Loop condition handles exit
622
 
623
  else:
624
  # Unknown task
 
634
  # the orchestrator logic above should handle transition to FAILED or DEBUGGING.
635
  # This check acts as a safeguard.
636
  if not step_successful and project_state['status'] == 'In Progress':
637
+ # This case might occur if a sub-function returns False but doesn't set status='Failed'
638
+ # The logic above *should* set status_message and transition away from the failed task,
639
+ # but this ensures the overall loop exits if something goes wrong.
640
+ print(f"Orchestration step '{current_task}' failed, but status is still 'In Progress'. Forcing Failure.")
641
  project_state['status'] = 'Failed'
642
+ project_state['status_message'] = project_state.get('status_message', f'An unexpected error caused task failure: {current_task}')
643
+ project_state['chat_history'].append({"role": "assistant", "content": project_state['status_message']})
644
+ project_state['current_task'] = 'FINISHED'
645
 
646
 
647
  # --- End of Orchestration Loop ---
 
655
 
656
  # Add final outcome message to history if not already the last message
657
  final_outcome_message = f"**Project Outcome:** {project_state['status']} - {project_state['status_message']}"
658
+ # Prevent adding duplicate messages if they were already added inside the loop
659
  if not project_state['chat_history'] or project_state['chat_history'][-1].get('content', '').strip() != final_outcome_message.strip():
660
  project_state['chat_history'].append({"role": "assistant", "content": final_outcome_message})
661
 
 
682
 
683
  # --- MAIN HANDLER (Called by Gradio) ---
684
 
685
+ # Updated signature to include user_input
686
  def handle_user_message(
687
+ history, # This is the list of messages in the Gradio Chatbot (from previous turns)
688
+ user_input: str, # <--- The *new* text input from the user_in textbox
689
  sdk_choice: str,
690
  gemini_api_key: str,
691
  grounding_enabled: bool,
 
694
  profile: gr.OAuthProfile | None,
695
  oauth_token: gr.OAuthToken | None # We need the token object
696
  ):
697
+ # The user_input is already the new prompt.
698
+ # We need to add it to the history list here at the beginning,
699
+ # as Gradio's Chatbot expects the handler to return the *updated* history.
700
+ # Check if the last message is *not* a user message or is empty to avoid duplicates
701
+ # (Gradio's default Chatbot adds the user message automatically on submit,
702
+ # but explicit handling here is safer if using user_in separately)
703
+ if not history or history[-1].get("role") != "user" or history[-1].get("content") != user_input:
704
+ history.append({"role": "user", "content": user_input})
705
+ # Note: If Gradio Chatbot already adds the message, this might cause duplicates.
706
+ # In typical chatbot+textbox setup, the textbox value is passed explicitly,
707
+ # and the handler is responsible for appending it to the history.
708
 
709
  if not profile or not oauth_token or not oauth_token.token:
710
  # Append error message to history for display
 
716
  error_history = history + [{"role":"assistant","content":"⚠️ Please provide your Gemini API Key."}]
717
  return error_history, "", "", "<p>Please provide API Key.</p>", "API Key required."
718
 
719
+ if not user_input or user_input.strip() == "":
720
+ # Handle empty prompt case - the prompt is now the user_input parameter
721
+ empty_prompt_history = history + [{"role":"assistant","content":"Please enter requirements for the application."}]
722
+ return empty_prompt_history, "", "", "<p>Enter requirements.</p>", "Waiting for prompt."
723
+
724
 
725
  client = genai.Client(api_key=gemini_api_key)
726
  repo_id = f"{profile.username}/{profile.username}-auto-space"
 
728
  sdk_version = get_sdk_version(sdk_choice)
729
  code_fn = "app.py" if sdk_choice == "gradio" else "streamlit_app.py" # Standard main file name convention
730
 
731
+ # The user's latest prompt is the user_input parameter
732
+ user_prompt = user_input
 
 
 
 
 
 
733
 
734
 
735
  # Initialize project state for this development session
 
782
 
783
  with gr.Row():
784
  with gr.Column(scale=1):
785
+ # --- LOGIN BUTTON / PROFILE & MODEL LISTING ---
786
  login_btn = gr.LoginButton(variant="huggingface", size="lg")
787
  status_md = gr.Markdown("*Not logged in.*")
788
  models_md = gr.Markdown()
 
804
  outputs=models_md,
805
  api_name="login_models"
806
  )
807
+ # --- END LOGIN FIX ---
808
 
809
 
810
  gr.Markdown("---")
 
832
  preview = gr.HTML("<p>App preview will load here when available.</p>")
833
 
834
 
835
+ # Update the button click handler - ADD user_in to inputs
 
 
836
  send_btn.click(
837
  fn=handle_user_message,
838
+ inputs=[
839
+ chatbot, # history (passed automatically by chatbot)
840
+ user_in, # <-- user_input (pass the textbox component)
841
+ sdk_choice,
842
+ api_key,
843
+ grounding,
844
+ temp,
845
+ max_tokens,
846
+ login_btn, # profile (passed automatically by LoginButton)
847
+ login_btn # oauth_token (passed automatically by LoginButton)
848
+ ],
849
  outputs=[chatbot, build_box, run_box, preview, project_status_md]
850
  )
851
+
852
+ # Update the submit handler - ADD user_in to inputs
853
  user_in.submit(
854
  fn=handle_user_message,
855
+ inputs=[
856
+ chatbot, # history
857
+ user_in, # <-- user_input
858
+ sdk_choice,
859
+ api_key,
860
+ grounding,
861
+ temp,
862
+ max_tokens,
863
+ login_btn,
864
+ login_btn
865
+ ],
866
  outputs=[chatbot, build_box, run_box, preview, project_status_md]
867
  )
868