broadfield-dev commited on
Commit
8eba441
·
verified ·
1 Parent(s): adc8c7b

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +55 -269
app.py CHANGED
@@ -24,7 +24,7 @@ from build_logic import (
24
  build_logic_create_pull_request,
25
  build_logic_add_comment,
26
  build_logic_like_space,
27
- build_logic_create_space
28
  )
29
 
30
  from model_logic import (
@@ -95,10 +95,10 @@ If no code or actions are requested, respond conversationally and help the user
95
 
96
  def escape_html_for_markdown(text):
97
  if not isinstance(text, str): return ""
98
- return text.replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;")
99
 
100
  def _infer_lang_from_filename(filename):
101
- if not filename: return "plaintext"
102
  if '.' in filename:
103
  ext = filename.split('.')[-1].lower()
104
  mapping = {
@@ -110,17 +110,17 @@ def _infer_lang_from_filename(filename):
110
  'c': 'c', 'h': 'c', 'cpp': 'cpp', 'hpp': 'cpp', 'cs': 'csharp', 'java': 'java',
111
  'rb': 'ruby', 'php': 'php', 'go': 'go', 'rs': 'rust', 'swift': 'swift', 'kt': 'kotlin', 'kts': 'kotlin',
112
  'sql': 'sql', 'dockerfile': 'docker', 'tf': 'terraform', 'hcl': 'terraform',
113
- 'txt': 'plaintext', 'log': 'plaintext', 'ini': 'ini', 'conf': 'plaintext', 'cfg': 'plaintext',
114
- 'csv': 'plaintext', 'tsv': 'tsv', 'err': 'plaintext',
115
- '.env': 'plaintext', '.gitignore': 'plaintext', '.npmrc': 'plaintext', '.gitattributes': 'plaintext',
116
  'makefile': 'makefile',
117
  }
118
- return mapping.get(ext, "plaintext")
119
  base_filename = os.path.basename(filename)
120
  if base_filename == 'Dockerfile': return 'docker'
121
  if base_filename == 'Makefile': return 'makefile'
122
- if base_filename.startswith('.'): return 'plaintext'
123
- return "plaintext"
124
 
125
  def _clean_filename(filename_line_content):
126
  text = filename_line_content.strip()
@@ -141,7 +141,7 @@ def _parse_and_update_state_cache(latest_bot_message_content, current_files_stat
141
 
142
  structure_match = structure_pattern.search(content)
143
  if structure_match:
144
- structure_block_state = {"filename": "File Structure (from AI)", "language": structure_match.group("struct_lang") or "plaintext", "code": structure_match.group("structure_code").strip(), "is_binary": False, "is_structure_block": True}
145
 
146
  current_message_proposed_filenames = []
147
  for match in file_pattern.finditer(content):
@@ -200,7 +200,7 @@ def _export_selected_logic(selected_filenames, space_line_name_for_md, parsed_bl
200
  if block.get('is_binary') or content.startswith(("[Binary file", "[Error loading content:", "[Binary or Skipped file]")):
201
  output_lines.append(content)
202
  else:
203
- lang = block.get('language', 'plaintext') or 'plaintext'
204
  output_lines.extend([f"{bbb}{lang}", content, bbb])
205
  output_lines.append("")
206
  exported_content_count += 1
@@ -257,7 +257,7 @@ def _generate_ui_outputs_from_cache(owner, space_name):
257
  if block.get('is_binary') or content.startswith(("[Binary file", "[Error loading content:", "[Binary or Skipped file]")):
258
  preview_md_lines.append(f"\n`{escape_html_for_markdown(content.strip())}`\n")
259
  else:
260
- lang = block.get('language', 'plaintext') or 'plaintext'
261
  preview_md_lines.append(f"\n{bbb}{lang}\n{content.strip()}\n{bbb}\n")
262
  preview_md_val = "\n".join(preview_md_lines)
263
 
@@ -265,7 +265,7 @@ def _generate_ui_outputs_from_cache(owner, space_name):
265
 
266
  def generate_and_stage_changes(ai_response_content, current_files_state, hf_owner_name, hf_repo_name):
267
  changeset = []
268
- current_files_dict = {f["filename"]: f for f in current_files_state if not f.get("is_structure_block")}
269
  ai_parsed_md = build_logic_parse_markdown(ai_response_content)
270
  ai_proposed_files_list = ai_parsed_md.get("files", [])
271
  ai_proposed_files_dict = {f["path"]: f for f in ai_proposed_files_list}
@@ -411,6 +411,7 @@ def generate_and_stage_changes(ai_response_content, current_files_state, hf_owne
411
  print(f"Warning: Cannot stage LIKE_SPACE action, no Space currently loaded.")
412
  changeset.append({"type": "Error", "message": "Cannot like space, no Space currently loaded."})
413
 
 
414
  for file_info in ai_proposed_files_list:
415
  filename = file_info["path"]
416
  proposed_content = file_info["content"]
@@ -593,8 +594,8 @@ def handle_confirm_changes(hf_api_key, owner_name, space_name, changeset):
593
 
594
  _status = "Applying changes..."
595
  yield _status, gr.update(visible=False), gr.update(visible=False), gr.update(visible=False), gr.update(value="*Applying changes...*")
596
- # Dummy yields for components that might be updated later in the generator
597
- yield gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update()
598
 
599
  if not changeset:
600
  return "No changes to apply.", gr.update(visible=False), gr.update(visible=False), gr.update(visible=False), gr.update(value="No changes were staged.")
@@ -614,7 +615,7 @@ def handle_confirm_changes(hf_api_key, owner_name, space_name, changeset):
614
  private=change.get("private", False)
615
  )
616
  _status_reload = f"{status_message} | Attempting to load the new Space [{change['target_repo_id']}]..."
617
- yield gr.update(value=_status_reload)
618
 
619
  target_repo_id = change['target_repo_id']
620
  new_owner, new_space_name = target_repo_id.split('/', 1) if '/' in target_repo_id else (None, target_repo_id)
@@ -683,6 +684,7 @@ def handle_confirm_changes(hf_api_key, owner_name, space_name, changeset):
683
  gr.update(value="*Runtime status unavailable for new space.*")
684
  )
685
 
 
686
  else:
687
  final_overall_status = "Duplicate Action Error: Invalid duplicate changeset format."
688
  _formatted, _detected, _download = _generate_ui_outputs_from_cache(owner_name, space_name)
@@ -707,6 +709,7 @@ def handle_confirm_changes(hf_api_key, owner_name, space_name, changeset):
707
  status_message = build_logic_delete_space(hf_api_key, delete_owner, delete_space)
708
  final_overall_status = status_message
709
  if "Successfully" in status_message:
 
710
  parsed_code_blocks_state_cache = []
711
  _formatted, _detected, _download = _generate_ui_outputs_from_cache(None, None)
712
  owner_update = gr.update(value="")
@@ -741,10 +744,8 @@ def handle_confirm_changes(hf_api_key, owner_name, space_name, changeset):
741
  if change['type'] == 'CREATE_SPACE':
742
  repo_id_to_create = change.get('repo_id')
743
  if repo_id_to_create:
744
- msg = build_logic_create_space(hf_api_key, repo_id_to_create.split('/')[1], repo_id_to_create.split('/')[0] if '/' in repo_id_to_create else None, change.get('sdk', 'gradio'), "", change.get('private', False)) # Note: Manual create requires markdown, passing empty string
745
  action_status_messages.append(f"CREATE_SPACE: {msg}")
746
- # If creation was successful, potentially update the UI fields? No, AI might create a *different* space.
747
- # Just report success/failure. The AI can propose loading it next.
748
  else:
749
  action_status_messages.append("CREATE_SPACE Error: Target repo_id not specified.")
750
  elif change['type'] == 'SET_PRIVACY':
@@ -805,7 +806,7 @@ def handle_confirm_changes(hf_api_key, owner_name, space_name, changeset):
805
  if not final_overall_status: final_overall_status = "No operations were applied."
806
 
807
  _status_reload = f"{final_overall_status} | Reloading Space state..."
808
- yield gr.update(value=_status_reload)
809
 
810
  refreshed_file_list = []
811
  reload_error = None
@@ -880,15 +881,17 @@ def update_models_dropdown(provider_select):
880
  selected_value = default_model if default_model in models else (models[0] if models else None)
881
  return gr.update(choices=models, value=selected_value)
882
 
883
- def handle_detect_user(hf_api_key_ui, owner_name_ui):
884
  _status = "Detecting user from token..."
885
- # Yield initial state to show loading status and clear potentially outdated owner/spaces list
886
- yield gr.update(value=_status), gr.update(value=""), gr.update(value="*Listing spaces...*")
 
887
 
888
  token, token_err = build_logic_get_api_token(hf_api_key_ui)
889
  if token_err:
890
  _status = f"Detection Error: {token_err}"
891
- yield gr.update(value=_status), gr.update(), gr.update(value="*Could not list spaces due to token error.*")
 
892
  return
893
 
894
  try:
@@ -898,7 +901,6 @@ def handle_detect_user(hf_api_key_ui, owner_name_ui):
898
  _status = f"User detected: {owner_name}"
899
  owner_update = gr.update(value=owner_name)
900
 
901
- # Immediately trigger listing spaces using the detected owner
902
  list_spaces_md, list_err = build_logic_list_user_spaces(hf_api_key=token, owner=owner_name)
903
  if list_err:
904
  list_spaces_update = gr.update(value=f"List Spaces Error: {list_err}")
@@ -906,14 +908,15 @@ def handle_detect_user(hf_api_key_ui, owner_name_ui):
906
  else:
907
  list_spaces_update = gr.update(value=list_spaces_md)
908
 
909
- yield gr.update(value=_status), owner_update, list_spaces_update
 
910
 
911
  except Exception as e:
912
  _status = f"Detection Error: Could not detect user from token: {e}"
913
  print(f"Error in handle_detect_user: {e}")
914
  import traceback
915
  traceback.print_exc()
916
- yield gr.update(value=_status), gr.update(), gr.update(value="*Could not list spaces due to user detection error.*")
917
 
918
 
919
  def handle_load_existing_space(hf_api_key_ui, ui_owner_name, ui_space_name):
@@ -924,7 +927,7 @@ def handle_load_existing_space(hf_api_key_ui, ui_owner_name, ui_space_name):
924
  _changeset_clear = []
925
  _changeset_summary_clear = "*No changes proposed.*"
926
  _confirm_ui_hidden = gr.update(visible=False)
927
- _list_spaces_display_clear = gr.update() # Don't clear list spaces display on load, it's controlled by its own button
928
  _target_owner_clear, _target_space_clear, _target_private_clear = gr.update(value=""), gr.update(value=""), gr.update(value=False)
929
 
930
 
@@ -934,34 +937,34 @@ def handle_load_existing_space(hf_api_key_ui, ui_owner_name, ui_space_name):
934
  _iframe_html_update, _download_btn_update, gr.update(value=_build_status_clear),
935
  gr.update(value=_edit_status_clear), gr.update(value=_runtime_status_clear),
936
  _changeset_clear, gr.update(value=_changeset_summary_clear), _confirm_ui_hidden, _confirm_ui_hidden, _confirm_ui_hidden,
937
- _list_spaces_display_clear, _target_owner_clear, _target_space_clear, _target_private_clear
938
  )
939
 
940
  owner_to_use = ui_owner_name
941
  token, token_err = build_logic_get_api_token(hf_api_key_ui)
942
  if token_err:
943
  _status_val = f"Load Error: {token_err}"
944
- yield gr.update(value=_status_val),
945
  return
946
  if not owner_to_use:
947
  try:
948
  user_info = build_logic_whoami(token=token)
949
  owner_to_use = user_info.get('name')
950
  if not owner_to_use: raise Exception("Could not find user name from token.")
951
- yield gr.update(value=owner_to_use), gr.update(value=f"Loading Space: {owner_to_use}/{ui_space_name} (Auto-detected owner)...")
952
  except Exception as e:
953
  _status_val = f"Load Error: Error auto-detecting owner: {e}"
954
- yield gr.update(value=_status_val),
955
  return
956
 
957
  if not owner_to_use or not ui_space_name:
958
  _status_val = "Load Error: Owner and Space Name are required."
959
- yield gr.update(value=_status_val),
960
  return
961
 
962
  sdk, file_list, err = get_space_repository_info(hf_api_key_ui, ui_space_name, owner_to_use)
963
 
964
- yield gr.update(value=owner_to_use), gr.update(value=ui_space_name),
965
 
966
  if err:
967
  _status_val = f"Load Error: {err}"
@@ -972,7 +975,8 @@ def handle_load_existing_space(hf_api_key_ui, ui_owner_name, ui_space_name):
972
  gr.update(visible=False, choices=[], value=None),
973
  gr.update(), gr.update(),
974
  gr.update(value=None, visible=False),
975
- _download, gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update()
 
976
  )
977
  return
978
 
@@ -1006,7 +1010,8 @@ def handle_load_existing_space(hf_api_key_ui, ui_owner_name, ui_space_name):
1006
  file_browser_update,
1007
  gr.update(), gr.update(),
1008
  iframe_update,
1009
- _download, gr.update(), gr.update(), gr.update(value=runtime_status_md), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update()
 
1010
  )
1011
 
1012
  def handle_build_space_button(hf_api_key_ui, ui_space_name_part, ui_owner_name_part, space_sdk_ui, is_private_ui, formatted_markdown_content):
@@ -1024,7 +1029,7 @@ def handle_build_space_button(hf_api_key_ui, ui_space_name_part, ui_owner_name_p
1024
 
1025
  if not ui_space_name_part or "/" in ui_space_name_part:
1026
  _build_status = f"Build Error: Invalid Space Name '{ui_space_name_part}'."
1027
- yield gr.update(value=_build_status),
1028
  return
1029
 
1030
  parsed_content = build_logic_parse_markdown(formatted_markdown_content)
@@ -1038,13 +1043,13 @@ def handle_build_space_button(hf_api_key_ui, ui_space_name_part, ui_owner_name_p
1038
 
1039
  if not manual_changeset:
1040
  _build_status = "Build Error: No target space specified or no files parsed from markdown."
1041
- yield gr.update(value=_build_status),
1042
  return
1043
 
1044
  token, token_err = build_logic_get_api_token(hf_api_key_ui)
1045
  if token_err:
1046
  _build_status = f"Build Error: API Token Error: {token_err}"
1047
- yield gr.update(value=_build_status),
1048
  return
1049
  api = HfApi(token=token)
1050
  repo_id_target = f"{ui_owner_name_part}/{ui_space_name_part}"
@@ -1056,10 +1061,10 @@ def handle_build_space_button(hf_api_key_ui, ui_space_name_part, ui_owner_name_p
1056
  except HfHubHTTPError as e_http:
1057
  build_status_messages.append(f"CREATE_SPACE HTTP Error ({e_http.response.status_code if e_http.response else 'N/A'}): {e_http.response.text if e_http.response else str(e_http)}. Check logs.")
1058
  if e_http.response and e_http.response.status_code in (401, 403):
1059
- _build_status = f"Build Error: {build_status_messages[-1]}. Cannot proceed with file upload."; yield gr.update(value=_build_status); return
1060
  except Exception as e:
1061
  build_status_messages.append(f"CREATE_SPACE Error: {e}")
1062
- _build_status = f"Build Error: {build_status_messages[-1]}. Cannot proceed with file upload."; yield gr.update(value=_build_status); return
1063
 
1064
 
1065
  file_changes_only_changeset = [{"type": "CREATE_FILE", "path": f["path"], "content": f["content"], "lang": _infer_lang_from_filename(f["path"])} for f in proposed_files_list]
@@ -1125,11 +1130,11 @@ def handle_build_space_button(hf_api_key_ui, ui_space_name_part, ui_owner_name_p
1125
 
1126
  def handle_load_file_for_editing(hf_api_key_ui, ui_space_name_part, ui_owner_name_part, selected_file_path):
1127
  if not selected_file_path:
1128
- return "", "Select a file.", "", gr.update(language="plaintext")
1129
 
1130
  content, err = get_space_file_content(hf_api_key_ui, ui_space_name_part, ui_owner_name_part, selected_file_path)
1131
  if err:
1132
- return "", f"Load Error: {err}", "", gr.update(language="plaintext")
1133
 
1134
  lang = _infer_lang_from_filename(selected_file_path)
1135
  commit_msg = f"Update {selected_file_path}"
@@ -1172,9 +1177,9 @@ def handle_commit_file_changes(hf_api_key_ui, ui_space_name_part, ui_owner_name_
1172
 
1173
  def handle_delete_file(hf_api_key_ui, ui_space_name_part, ui_owner_name_part, file_to_delete_path):
1174
  if not ui_owner_name_part or not ui_space_name_part:
1175
- return "Delete Error: Cannot delete file. Please load a space first.", gr.update(), "", "", "plaintext", gr.update(), gr.update(), gr.update()
1176
  if not file_to_delete_path:
1177
- return "Delete Error: No file selected to delete.", gr.update(), "", "", "plaintext", gr.update(), gr.update(), gr.update()
1178
 
1179
  status_msg = build_logic_delete_space_file(hf_api_key_ui, ui_space_name_part, ui_owner_name_part, file_to_delete_path)
1180
 
@@ -1188,7 +1193,7 @@ def handle_delete_file(hf_api_key_ui, ui_space_name_part, ui_owner_name_part, fi
1188
  parsed_code_blocks_state_cache = [b for b in parsed_code_blocks_state_cache if b["filename"] != file_to_delete_path]
1189
  file_content_editor_update = gr.update(value="")
1190
  commit_message_update = gr.update(value="")
1191
- editor_lang_update = gr.update(language="plaintext")
1192
  file_list, _ = list_space_files_for_browsing(hf_api_key_ui, ui_space_name_part, ui_owner_name_part)
1193
  file_browser_update = gr.update(choices=sorted(file_list or []), value=None)
1194
 
@@ -1286,7 +1291,6 @@ def handle_manual_duplicate_space(hf_api_key_ui, source_owner, source_space_name
1286
  return "Duplicate Error: Target Owner and Target Space Name are required.", gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update()
1287
  if "/" in target_space_name:
1288
  return "Duplicate Error: Target Space Name should not contain '/'. Use Target Owner field for the owner part.", gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update()
1289
- global parsed_code_blocks_state_cache
1290
 
1291
 
1292
  source_repo_id = f"{source_owner}/{source_space_name}"
@@ -1300,7 +1304,7 @@ def handle_manual_duplicate_space(hf_api_key_ui, source_owner, source_space_name
1300
  status_msg = f"Duplication Result: {result_message}"
1301
 
1302
  _status_reload = f"{status_msg} | Attempting to load the new Space [{target_repo_id}]..."
1303
- yield gr.update(value=_status_reload)
1304
 
1305
  new_owner = target_owner
1306
  new_space_name = target_space_name
@@ -1309,6 +1313,7 @@ def handle_manual_duplicate_space(hf_api_key_ui, source_owner, source_space_name
1309
 
1310
  if err_list:
1311
  reload_error = f"Error reloading file list after duplication: {err_list}"
 
1312
  parsed_code_blocks_state_cache = []
1313
  _file_browser_update = gr.update(visible=False, choices=[], value=None)
1314
  _iframe_html_update = gr.update(value=None, visible=False)
@@ -1320,6 +1325,7 @@ def handle_manual_duplicate_space(hf_api_key_ui, source_owner, source_space_name
1320
  is_binary = lang == "binary" or (err_get is not None)
1321
  code = f"[Error loading content: {err_get}]" if err_get else (content or "")
1322
  loaded_files.append({"filename": file_path, "code": code, "language": lang, "is_binary": is_binary, "is_structure_block": False})
 
1323
  parsed_code_blocks_state_cache = loaded_files
1324
 
1325
  _file_browser_update = gr.update(visible=True, choices=sorted([f["filename"] for f in parsed_code_blocks_state_cache if not f.get("is_structure_block")] or []), value=None)
@@ -1345,224 +1351,4 @@ def handle_manual_duplicate_space(hf_api_key_ui, source_owner, source_space_name
1345
  owner_update, space_update,
1346
  gr.update(value=_formatted), gr.update(value=_detected), _download,
1347
  _file_browser_update, _iframe_html_update, gr.update(value=runtime_status_md)
1348
- )
1349
-
1350
-
1351
- custom_theme = gr.themes.Base(primary_hue="teal", secondary_hue="purple", neutral_hue="zinc", text_size="sm", spacing_size="md", radius_size="sm", font=["System UI", "sans-serif"])
1352
- custom_css = """
1353
- body { background: linear-gradient(to bottom right, #2c3e50, #34495e); color: #ecf0f1; }
1354
- .gradio-container { background: transparent !important; }
1355
- .gr-box, .gr-panel, .gr-pill { background-color: rgba(44, 62, 80, 0.8) !important; border-color: rgba(189, 195, 199, 0.2) !important; }
1356
- .gr-textbox, .gr-dropdown, .gr-button, .gr-code, .gr-chat-message { border-color: rgba(189, 195, 199, 0.3) !important; background-color: rgba(52, 73, 94, 0.9) !important; color: #ecf0f1 !important; }
1357
- .gr-button.gr-button-primary { background-color: #1abc9c !important; color: white !important; border-color: #16a085 !important; }
1358
- .gr-button.gr-button-secondary { background-color: #9b59b6 !important; color: white !important; border-color: #8e44ad !important; }
1359
- .gr-button.gr-button-stop { background-color: #e74c3c !important; color: white !important; border-color: #c0392b !important; }
1360
- .gr-markdown { background-color: rgba(44, 62, 80, 0.7) !important; padding: 10px; border-radius: 5px; overflow-x: auto; }
1361
- .gr-markdown h1, .gr-markdown h2, .gr-markdown h3, .gr-markdown h4, .gr-markdown h5, .gr-markdown h6 { color: #ecf0f1 !important; border-bottom-color: rgba(189, 195, 199, 0.3) !important; }
1362
- .gr-markdown pre code { background-color: rgba(52, 73, 94, 0.95) !important; border-color: rgba(189, 195, 199, 0.3) !important; }
1363
- .gr-chatbot { background-color: rgba(44, 62, 80, 0.7) !important; border-color: rgba(189, 195, 199, 0.2) !important; }
1364
- .gr-chatbot .message { background-color: rgba(52, 73, 94, 0.9) !important; color: #ecf0f1 !important; border-color: rgba(189, 195, 199, 0.3) !important; }
1365
- .gr-chatbot .message.user { background-color: rgba(46, 204, 113, 0.9) !important; color: black !important; }
1366
- .gradio-container .gr-accordion { border-color: rgba(189, 195, 199, 0.3) !important; }
1367
- .gradio-container .gr-accordion.closed { background-color: rgba(52, 73, 94, 0.9) !important; }
1368
- .gradio-container .gr-accordion.open { background-color: rgba(44, 62, 80, 0.8) !important; }
1369
-
1370
- """
1371
-
1372
- with gr.Blocks(theme=custom_theme, css=custom_css) as demo:
1373
- changeset_state = gr.State([])
1374
-
1375
- gr.Markdown("# 🤖 AI-Powered Hugging Face Space Commander")
1376
- gr.Markdown("Use an AI assistant to create, modify, build, and manage your Hugging Face Spaces directly from this interface.")
1377
- gr.Markdown("## ❗ This will cause changes to your huggingface spaces if you give it your Huggingface Key")
1378
- gr.Markdown("⚒ Under Development - Use with Caution")
1379
-
1380
-
1381
- with gr.Sidebar():
1382
- with gr.Column(scale=1):
1383
- with gr.Accordion("⚙️ Configuration", open=True):
1384
- hf_api_key_input = gr.Textbox(label="Hugging Face Token", type="password", placeholder="hf_... (uses env var HF_TOKEN if empty)")
1385
- owner_name_input = gr.Textbox(label="HF Owner Name", placeholder="e.g., your-username")
1386
- space_name_input = gr.Textbox(label="HF Space Name", value="")
1387
- load_space_button = gr.Button("🔄 Load Existing Space", variant="secondary")
1388
- detect_user_button = gr.Button("👤 Detect User from Token", variant="secondary")
1389
-
1390
-
1391
- with gr.Accordion("🤖 AI Model Settings", open=True):
1392
- available_providers = get_available_providers()
1393
- default_provider = 'Groq'
1394
- if default_provider not in available_providers:
1395
- default_provider = available_providers[0] if available_providers else None
1396
- elif len(available_providers) < 3:
1397
- default_provider = available_providers[0] if available_providers else None
1398
-
1399
- initial_models = get_models_for_provider(default_provider) if default_provider else []
1400
- initial_model = get_default_model_for_provider(default_provider) if default_provider else None
1401
- if initial_model not in initial_models:
1402
- initial_model = initial_models[0] if initial_models else None
1403
-
1404
- provider_select = gr.Dropdown(
1405
- label="AI Provider",
1406
- choices=available_providers,
1407
- value=default_provider,
1408
- allow_custom_value=False
1409
- )
1410
- model_select = gr.Dropdown(
1411
- label="AI Model",
1412
- choices=initial_models,
1413
- value=initial_model,
1414
- allow_custom_value=False
1415
- )
1416
- provider_api_key_input = gr.Textbox(label="Model Provider API Key (Optional)", type="password", placeholder="sk_... (overrides backend settings)")
1417
- system_prompt_input = gr.Textbox(label="System Prompt", lines=10, value=DEFAULT_SYSTEM_PROMPT, elem_id="system-prompt")
1418
-
1419
- with gr.Accordion("🗄️ Space Management", open=True):
1420
- gr.Markdown("### Manual Actions")
1421
- with gr.Group():
1422
- gr.Markdown("Duplicate Current Space To:")
1423
- target_owner_input = gr.Textbox(label="Target Owner Name", placeholder="e.g., new-username")
1424
- target_space_name_input = gr.Textbox(label="Target Space Name", placeholder="e.g., new-space")
1425
- target_private_checkbox = gr.Checkbox(label="Make Target Private", value=False)
1426
- duplicate_space_button = gr.Button("📂 Duplicate Space", variant="secondary")
1427
-
1428
- gr.Markdown("---")
1429
- gr.Markdown("### List Spaces")
1430
- list_spaces_button = gr.Button("📄 List My Spaces", variant="secondary")
1431
- list_spaces_display = gr.Markdown("*List of spaces will appear here.*")
1432
-
1433
-
1434
- with gr.Column(scale=2):
1435
- gr.Markdown("## 💬 AI Assistant Chat")
1436
- chatbot_display = gr.Chatbot(label="AI Chat", height=500, bubble_full_width=False, avatar_images=(None))
1437
- with gr.Row():
1438
- chat_message_input = gr.Textbox(show_label=False, placeholder="Your Message...", scale=7)
1439
- send_chat_button = gr.Button("Send", variant="primary", scale=1)
1440
- status_output = gr.Textbox(label="Last Action Status", interactive=False, value="Ready.")
1441
-
1442
- with gr.Accordion("📝 Proposed Changes (Pending Confirmation)", open=False, visible=False) as confirm_accordion:
1443
- changeset_display = gr.Markdown("*No changes proposed.*")
1444
- with gr.Row():
1445
- confirm_button = gr.Button("✅ Confirm & Apply Changes", variant="primary", visible=False)
1446
- cancel_button = gr.Button("❌ Cancel", variant="stop", visible=False)
1447
-
1448
- with gr.Tabs():
1449
- with gr.TabItem("📝 Generated Markdown & Build"):
1450
- with gr.Row():
1451
- with gr.Column(scale=2):
1452
- formatted_space_output_display = gr.Textbox(label="Current Space Definition (Generated Markdown)", lines=20, interactive=True, value="*Load or create a space to see its definition.*")
1453
- download_button = gr.DownloadButton(label="Download .md", interactive=False)
1454
- with gr.Column(scale=1):
1455
- gr.Markdown("### Manual Build & Status")
1456
- space_sdk_select = gr.Dropdown(label="Space SDK", choices=["gradio", "streamlit", "docker", "static"], value="gradio", interactive=True)
1457
- space_private_checkbox = gr.Checkbox(label="Make Space Private", value=False, interactive=True)
1458
- build_space_button = gr.Button("🚀 Build / Update Space from Markdown", variant="primary")
1459
- build_status_display = gr.Textbox(label="Manual Build/Update Status", interactive=False, value="*Manual build status...*")
1460
- gr.Markdown("---")
1461
- refresh_status_button = gr.Button("🔄 Refresh Runtime/Repo Status")
1462
- space_runtime_status_display = gr.Markdown("*Runtime/Repo status will appear here.*")
1463
-
1464
- with gr.TabItem("🔍 Files Preview"):
1465
- detected_files_preview = gr.Markdown(value="*A preview of the latest file versions will appear here.*")
1466
-
1467
- with gr.TabItem("✏️ Live File Editor & Preview"):
1468
- with gr.Row():
1469
- with gr.Column(scale=1):
1470
- gr.Markdown("### Live Editor")
1471
- file_browser_dropdown = gr.Dropdown(label="Select File in Space", choices=[], interactive=True)
1472
- file_content_editor = gr.Code(label="File Content Editor", language="python", lines=15, interactive=True, value="")
1473
- commit_message_input = gr.Textbox(label="Commit Message", placeholder="e.g., Updated app.py", interactive=True, value="")
1474
- with gr.Row():
1475
- update_file_button = gr.Button("Commit Changes", variant="primary", interactive=True)
1476
- delete_file_button = gr.Button("🗑️ Delete Selected File", variant="stop", interactive=True)
1477
- edit_status_display = gr.Textbox(label="File Edit/Delete Status", interactive=False, value="")
1478
- with gr.Column(scale=1):
1479
- gr.Markdown("### Live Space Preview")
1480
- space_iframe_display = gr.HTML(value="", visible=True)
1481
-
1482
-
1483
- provider_select.change(update_models_dropdown, inputs=provider_select, outputs=model_select)
1484
-
1485
- chat_inputs = [
1486
- chat_message_input, chatbot_display, hf_api_key_input,
1487
- provider_api_key_input, provider_select, model_select, system_prompt_input,
1488
- owner_name_input, space_name_input
1489
- ]
1490
- chat_outputs = [
1491
- chat_message_input, chatbot_display, status_output,
1492
- detected_files_preview, formatted_space_output_display, download_button,
1493
- changeset_state, changeset_display, confirm_accordion, confirm_button, cancel_button
1494
- ]
1495
- send_chat_button.click(handle_chat_submit, inputs=chat_inputs, outputs=chat_outputs)
1496
- chat_message_input.submit(handle_chat_submit, inputs=chat_inputs, outputs=chat_outputs)
1497
-
1498
- confirm_inputs = [hf_api_key_input, owner_name_input, space_name_input, changeset_state]
1499
- confirm_outputs = [
1500
- status_output, formatted_space_output_display, detected_files_preview, download_button,
1501
- confirm_accordion, confirm_button, cancel_button, changeset_state, changeset_display,
1502
- owner_name_input, space_name_input, file_browser_dropdown, space_iframe_display, space_runtime_status_display
1503
- ]
1504
- confirm_button.click(handle_confirm_changes, inputs=confirm_inputs, outputs=confirm_outputs)
1505
-
1506
- cancel_outputs = [
1507
- status_output, changeset_state, changeset_display,
1508
- confirm_accordion, confirm_button, cancel_button
1509
- ]
1510
- cancel_button.click(handle_cancel_changes, inputs=None, outputs=cancel_outputs)
1511
-
1512
- load_space_outputs = [
1513
- formatted_space_output_display, detected_files_preview, status_output,
1514
- file_browser_dropdown, owner_name_input, space_name_input,
1515
- space_iframe_display, download_button, build_status_display,
1516
- edit_status_display, space_runtime_status_display,
1517
- changeset_state, changeset_display, confirm_accordion, confirm_button, cancel_button,
1518
- list_spaces_display, target_owner_input, target_space_name_input, target_private_checkbox
1519
- ]
1520
- load_space_button.click(
1521
- fn=handle_load_existing_space,
1522
- inputs=[hf_api_key_input, owner_name_input, space_name_input],
1523
- outputs=load_space_outputs
1524
- )
1525
-
1526
- detect_user_outputs = [status_output, owner_name_input, list_spaces_display]
1527
- detect_user_button.click(fn=handle_detect_user, inputs=[hf_api_key_input, owner_name_input], outputs=detect_user_outputs)
1528
-
1529
- build_outputs = [
1530
- build_status_display, space_iframe_display, file_browser_dropdown,
1531
- owner_name_input, space_name_input,
1532
- changeset_state, changeset_display, confirm_accordion, confirm_button, cancel_button,
1533
- formatted_space_output_display, detected_files_preview, download_button, space_runtime_status_display
1534
- ]
1535
- build_inputs = [
1536
- hf_api_key_input, space_name_input, owner_name_input, space_sdk_select,
1537
- space_private_checkbox, formatted_space_output_display
1538
- ]
1539
- build_space_button.click(fn=handle_build_space_button, inputs=build_inputs, outputs=build_outputs)
1540
-
1541
- file_edit_load_outputs = [file_content_editor, edit_status_display, commit_message_input, file_content_editor]
1542
- file_browser_dropdown.change(fn=handle_load_file_for_editing, inputs=[hf_api_key_input, space_name_input, owner_name_input, file_browser_dropdown], outputs=file_edit_load_outputs)
1543
-
1544
- commit_file_outputs = [edit_status_display, file_browser_dropdown, formatted_space_output_display, detected_files_preview, download_button]
1545
- update_file_button.click(fn=handle_commit_file_changes, inputs=[hf_api_key_input, space_name_input, owner_name_input, file_browser_dropdown, file_content_editor, commit_message_input], outputs=commit_file_outputs)
1546
-
1547
- delete_file_outputs = [
1548
- edit_status_display, file_browser_dropdown,
1549
- file_content_editor, commit_message_input, file_content_editor,
1550
- formatted_space_output_display, detected_files_preview, download_button
1551
- ]
1552
- delete_file_button.click(fn=handle_delete_file, inputs=[hf_api_key_input, space_name_input, owner_name_input, file_browser_dropdown], outputs=delete_file_outputs)
1553
-
1554
- refresh_status_button.click(fn=handle_refresh_space_status, inputs=[hf_api_key_input, owner_name_input, space_name_input], outputs=[space_runtime_status_display])
1555
-
1556
- manual_duplicate_inputs = [hf_api_key_input, owner_name_input, space_name_input, target_owner_input, target_space_name_input, target_private_checkbox]
1557
- manual_duplicate_outputs = [
1558
- status_output, owner_name_input, space_name_input,
1559
- formatted_space_output_display, detected_files_preview, download_button,
1560
- file_browser_dropdown, space_iframe_display, space_runtime_status_display
1561
- ]
1562
- duplicate_space_button.click(fn=handle_manual_duplicate_space, inputs=manual_duplicate_inputs, outputs=manual_duplicate_outputs)
1563
-
1564
- list_spaces_button.click(fn=handle_list_spaces, inputs=[hf_api_key_input, owner_name_input], outputs=[list_spaces_display])
1565
-
1566
-
1567
- if __name__ == "__main__":
1568
- demo.launch(debug=False, mcp_server=True)
 
24
  build_logic_create_pull_request,
25
  build_logic_add_comment,
26
  build_logic_like_space,
27
+ build_logic_create_space
28
  )
29
 
30
  from model_logic import (
 
95
 
96
  def escape_html_for_markdown(text):
97
  if not isinstance(text, str): return ""
98
+ return text.replace("&", "&").replace("<", "<").replace(">", ">")
99
 
100
  def _infer_lang_from_filename(filename):
101
+ if not filename: return "text" # Changed from "plaintext" to "text" for gr.Code compatibility
102
  if '.' in filename:
103
  ext = filename.split('.')[-1].lower()
104
  mapping = {
 
110
  'c': 'c', 'h': 'c', 'cpp': 'cpp', 'hpp': 'cpp', 'cs': 'csharp', 'java': 'java',
111
  'rb': 'ruby', 'php': 'php', 'go': 'go', 'rs': 'rust', 'swift': 'swift', 'kt': 'kotlin', 'kts': 'kotlin',
112
  'sql': 'sql', 'dockerfile': 'docker', 'tf': 'terraform', 'hcl': 'terraform',
113
+ 'txt': 'text', 'log': 'text', 'ini': 'ini', 'conf': 'text', 'cfg': 'text', # Changed plaintext to text
114
+ 'csv': 'text', 'tsv': 'text', 'err': 'text', # Changed plaintext to text
115
+ '.env': 'text', '.gitignore': 'text', '.npmrc': 'text', '.gitattributes': 'text', # Changed plaintext to text
116
  'makefile': 'makefile',
117
  }
118
+ return mapping.get(ext, "text") # Changed default to text
119
  base_filename = os.path.basename(filename)
120
  if base_filename == 'Dockerfile': return 'docker'
121
  if base_filename == 'Makefile': return 'makefile'
122
+ if base_filename.startswith('.'): return 'text' # Changed plaintext to text
123
+ return "text" # Changed default to text
124
 
125
  def _clean_filename(filename_line_content):
126
  text = filename_line_content.strip()
 
141
 
142
  structure_match = structure_pattern.search(content)
143
  if structure_match:
144
+ structure_block_state = {"filename": "File Structure (from AI)", "language": structure_match.group("struct_lang") or "text", "code": structure_match.group("structure_code").strip(), "is_binary": False, "is_structure_block": True} # Changed plaintext to text
145
 
146
  current_message_proposed_filenames = []
147
  for match in file_pattern.finditer(content):
 
200
  if block.get('is_binary') or content.startswith(("[Binary file", "[Error loading content:", "[Binary or Skipped file]")):
201
  output_lines.append(content)
202
  else:
203
+ lang = block.get('language', 'text') or 'text' # Changed plaintext to text
204
  output_lines.extend([f"{bbb}{lang}", content, bbb])
205
  output_lines.append("")
206
  exported_content_count += 1
 
257
  if block.get('is_binary') or content.startswith(("[Binary file", "[Error loading content:", "[Binary or Skipped file]")):
258
  preview_md_lines.append(f"\n`{escape_html_for_markdown(content.strip())}`\n")
259
  else:
260
+ lang = block.get('language', 'text') or 'text' # Changed plaintext to text
261
  preview_md_lines.append(f"\n{bbb}{lang}\n{content.strip()}\n{bbb}\n")
262
  preview_md_val = "\n".join(preview_md_lines)
263
 
 
265
 
266
  def generate_and_stage_changes(ai_response_content, current_files_state, hf_owner_name, hf_repo_name):
267
  changeset = []
268
+ current_files_dict = {f["filename"]: f.copy() for f in current_files_state if not f.get("is_structure_block")}
269
  ai_parsed_md = build_logic_parse_markdown(ai_response_content)
270
  ai_proposed_files_list = ai_parsed_md.get("files", [])
271
  ai_proposed_files_dict = {f["path"]: f for f in ai_proposed_files_list}
 
411
  print(f"Warning: Cannot stage LIKE_SPACE action, no Space currently loaded.")
412
  changeset.append({"type": "Error", "message": "Cannot like space, no Space currently loaded."})
413
 
414
+
415
  for file_info in ai_proposed_files_list:
416
  filename = file_info["path"]
417
  proposed_content = file_info["content"]
 
594
 
595
  _status = "Applying changes..."
596
  yield _status, gr.update(visible=False), gr.update(visible=False), gr.update(visible=False), gr.update(value="*Applying changes...*")
597
+ # Explicitly yield None for the other 15 outputs initially
598
+ yield None, None, None, None, None, None, None, None, None, None, None, None, None, None, None # Ensure 16 None values
599
 
600
  if not changeset:
601
  return "No changes to apply.", gr.update(visible=False), gr.update(visible=False), gr.update(visible=False), gr.update(value="No changes were staged.")
 
615
  private=change.get("private", False)
616
  )
617
  _status_reload = f"{status_message} | Attempting to load the new Space [{change['target_repo_id']}]..."
618
+ yield gr.update(value=_status_reload), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update()
619
 
620
  target_repo_id = change['target_repo_id']
621
  new_owner, new_space_name = target_repo_id.split('/', 1) if '/' in target_repo_id else (None, target_repo_id)
 
684
  gr.update(value="*Runtime status unavailable for new space.*")
685
  )
686
 
687
+
688
  else:
689
  final_overall_status = "Duplicate Action Error: Invalid duplicate changeset format."
690
  _formatted, _detected, _download = _generate_ui_outputs_from_cache(owner_name, space_name)
 
709
  status_message = build_logic_delete_space(hf_api_key, delete_owner, delete_space)
710
  final_overall_status = status_message
711
  if "Successfully" in status_message:
712
+ global parsed_code_blocks_state_cache
713
  parsed_code_blocks_state_cache = []
714
  _formatted, _detected, _download = _generate_ui_outputs_from_cache(None, None)
715
  owner_update = gr.update(value="")
 
744
  if change['type'] == 'CREATE_SPACE':
745
  repo_id_to_create = change.get('repo_id')
746
  if repo_id_to_create:
747
+ msg = build_logic_create_space(hf_api_key, repo_id_to_create.split('/')[1], repo_id_to_create.split('/')[0] if '/' in repo_id_to_create else None, change.get('sdk', 'gradio'), "", change.get('private', False))
748
  action_status_messages.append(f"CREATE_SPACE: {msg}")
 
 
749
  else:
750
  action_status_messages.append("CREATE_SPACE Error: Target repo_id not specified.")
751
  elif change['type'] == 'SET_PRIVACY':
 
806
  if not final_overall_status: final_overall_status = "No operations were applied."
807
 
808
  _status_reload = f"{final_overall_status} | Reloading Space state..."
809
+ yield gr.update(value=_status_reload), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update() # Yield status
810
 
811
  refreshed_file_list = []
812
  reload_error = None
 
881
  selected_value = default_model if default_model in models else (models[0] if models else None)
882
  return gr.update(choices=models, value=selected_value)
883
 
884
+ def handle_detect_user_and_list_spaces(hf_api_key_ui):
885
  _status = "Detecting user from token..."
886
+ # Yield initial state: update status, clear owner/space fields, clear list display, clear duplicate fields
887
+ yield (gr.update(value=_status), gr.update(value=""), gr.update(value=""), gr.update(value="*Listing spaces...*"), gr.update(visible=False, choices=[], value=None), gr.update(value=None, visible=False), gr.update(value=""), gr.update(value=""), gr.update(value="*Manual build status...*"), gr.update(value="*Select a file...*"), gr.update(value="*Runtime/Repo status will appear here.*"), [], gr.update(value="*No changes proposed.*"), gr.update(visible=False), gr.update(visible=False), gr.update(visible=False), gr.update(value=""), gr.update(value=""), gr.update(value=False))
888
+
889
 
890
  token, token_err = build_logic_get_api_token(hf_api_key_ui)
891
  if token_err:
892
  _status = f"Detection Error: {token_err}"
893
+ # Yield error status, keep fields cleared, update list display error
894
+ yield (gr.update(value=_status), gr.update(), gr.update(), gr.update(value="*Could not list spaces due to token error.*"), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update())
895
  return
896
 
897
  try:
 
901
  _status = f"User detected: {owner_name}"
902
  owner_update = gr.update(value=owner_name)
903
 
 
904
  list_spaces_md, list_err = build_logic_list_user_spaces(hf_api_key=token, owner=owner_name)
905
  if list_err:
906
  list_spaces_update = gr.update(value=f"List Spaces Error: {list_err}")
 
908
  else:
909
  list_spaces_update = gr.update(value=list_spaces_md)
910
 
911
+ yield (gr.update(value=_status), owner_update, gr.update(value=""), list_spaces_update, gr.update(visible=False, choices=[], value=None), gr.update(value=None, visible=False), gr.update(value=""), gr.update(value=""), gr.update(value="*Manual build status...*"), gr.update(value="*Select a file...*"), gr.update(value="*Runtime/Repo status will appear here.*"), [], gr.update(value="*No changes proposed.*"), gr.update(visible=False), gr.update(visible=False), gr.update(visible=False), gr.update(value=""), gr.update(value=""), gr.update(value=False))
912
+
913
 
914
  except Exception as e:
915
  _status = f"Detection Error: Could not detect user from token: {e}"
916
  print(f"Error in handle_detect_user: {e}")
917
  import traceback
918
  traceback.print_exc()
919
+ yield (gr.update(value=_status), gr.update(), gr.update(), gr.update(value="*Could not list spaces due to user detection error.*"), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update())
920
 
921
 
922
  def handle_load_existing_space(hf_api_key_ui, ui_owner_name, ui_space_name):
 
927
  _changeset_clear = []
928
  _changeset_summary_clear = "*No changes proposed.*"
929
  _confirm_ui_hidden = gr.update(visible=False)
930
+ _list_spaces_display_placeholder = "*List of spaces will appear here.*"
931
  _target_owner_clear, _target_space_clear, _target_private_clear = gr.update(value=""), gr.update(value=""), gr.update(value=False)
932
 
933
 
 
937
  _iframe_html_update, _download_btn_update, gr.update(value=_build_status_clear),
938
  gr.update(value=_edit_status_clear), gr.update(value=_runtime_status_clear),
939
  _changeset_clear, gr.update(value=_changeset_summary_clear), _confirm_ui_hidden, _confirm_ui_hidden, _confirm_ui_hidden,
940
+ gr.update(value=_list_spaces_display_placeholder), _target_owner_clear, _target_space_clear, _target_private_clear
941
  )
942
 
943
  owner_to_use = ui_owner_name
944
  token, token_err = build_logic_get_api_token(hf_api_key_ui)
945
  if token_err:
946
  _status_val = f"Load Error: {token_err}"
947
+ yield (gr.update(value=_status_val), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update())
948
  return
949
  if not owner_to_use:
950
  try:
951
  user_info = build_logic_whoami(token=token)
952
  owner_to_use = user_info.get('name')
953
  if not owner_to_use: raise Exception("Could not find user name from token.")
954
+ yield gr.update(value=owner_to_use), gr.update(value=f"Loading Space: {owner_to_use}/{ui_space_name} (Auto-detected owner)..."), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update()
955
  except Exception as e:
956
  _status_val = f"Load Error: Error auto-detecting owner: {e}"
957
+ yield (gr.update(value=_status_val), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update())
958
  return
959
 
960
  if not owner_to_use or not ui_space_name:
961
  _status_val = "Load Error: Owner and Space Name are required."
962
+ yield (gr.update(value=_status_val), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update())
963
  return
964
 
965
  sdk, file_list, err = get_space_repository_info(hf_api_key_ui, ui_space_name, owner_to_use)
966
 
967
+ yield gr.update(value=owner_to_use), gr.update(value=ui_space_name), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update()
968
 
969
  if err:
970
  _status_val = f"Load Error: {err}"
 
975
  gr.update(visible=False, choices=[], value=None),
976
  gr.update(), gr.update(),
977
  gr.update(value=None, visible=False),
978
+ _download, gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(),
979
+ gr.update(value=_list_spaces_display_placeholder), gr.update(value=""), gr.update(value=""), gr.update(value=False)
980
  )
981
  return
982
 
 
1010
  file_browser_update,
1011
  gr.update(), gr.update(),
1012
  iframe_update,
1013
+ _download, gr.update(), gr.update(), gr.update(value=runtime_status_md), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(),
1014
+ gr.update(value=_list_spaces_display_placeholder), gr.update(value=""), gr.update(value=""), gr.update(value=False)
1015
  )
1016
 
1017
  def handle_build_space_button(hf_api_key_ui, ui_space_name_part, ui_owner_name_part, space_sdk_ui, is_private_ui, formatted_markdown_content):
 
1029
 
1030
  if not ui_space_name_part or "/" in ui_space_name_part:
1031
  _build_status = f"Build Error: Invalid Space Name '{ui_space_name_part}'."
1032
+ yield gr.update(value=_build_status), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update()
1033
  return
1034
 
1035
  parsed_content = build_logic_parse_markdown(formatted_markdown_content)
 
1043
 
1044
  if not manual_changeset:
1045
  _build_status = "Build Error: No target space specified or no files parsed from markdown."
1046
+ yield gr.update(value=_build_status), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update()
1047
  return
1048
 
1049
  token, token_err = build_logic_get_api_token(hf_api_key_ui)
1050
  if token_err:
1051
  _build_status = f"Build Error: API Token Error: {token_err}"
1052
+ yield gr.update(value=_build_status), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update()
1053
  return
1054
  api = HfApi(token=token)
1055
  repo_id_target = f"{ui_owner_name_part}/{ui_space_name_part}"
 
1061
  except HfHubHTTPError as e_http:
1062
  build_status_messages.append(f"CREATE_SPACE HTTP Error ({e_http.response.status_code if e_http.response else 'N/A'}): {e_http.response.text if e_http.response else str(e_http)}. Check logs.")
1063
  if e_http.response and e_http.response.status_code in (401, 403):
1064
+ _build_status = f"Build Error: {build_status_messages[-1]}. Cannot proceed with file upload."; yield gr.update(value=_build_status), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(); return
1065
  except Exception as e:
1066
  build_status_messages.append(f"CREATE_SPACE Error: {e}")
1067
+ _build_status = f"Build Error: {build_status_messages[-1]}. Cannot proceed with file upload."; yield gr.update(value=_build_status), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(); return
1068
 
1069
 
1070
  file_changes_only_changeset = [{"type": "CREATE_FILE", "path": f["path"], "content": f["content"], "lang": _infer_lang_from_filename(f["path"])} for f in proposed_files_list]
 
1130
 
1131
  def handle_load_file_for_editing(hf_api_key_ui, ui_space_name_part, ui_owner_name_part, selected_file_path):
1132
  if not selected_file_path:
1133
+ return "", "Select a file.", "", gr.update(language="text") # Changed plaintext to text
1134
 
1135
  content, err = get_space_file_content(hf_api_key_ui, ui_space_name_part, ui_owner_name_part, selected_file_path)
1136
  if err:
1137
+ return "", f"Load Error: {err}", "", gr.update(language="text") # Changed plaintext to text
1138
 
1139
  lang = _infer_lang_from_filename(selected_file_path)
1140
  commit_msg = f"Update {selected_file_path}"
 
1177
 
1178
  def handle_delete_file(hf_api_key_ui, ui_space_name_part, ui_owner_name_part, file_to_delete_path):
1179
  if not ui_owner_name_part or not ui_space_name_part:
1180
+ return "Delete Error: Cannot delete file. Please load a space first.", gr.update(), "", "", "text", gr.update(), gr.update(), gr.update() # Changed plaintext to text
1181
  if not file_to_delete_path:
1182
+ return "Delete Error: No file selected to delete.", gr.update(), "", "", "text", gr.update(), gr.update(), gr.update() # Changed plaintext to text
1183
 
1184
  status_msg = build_logic_delete_space_file(hf_api_key_ui, ui_space_name_part, ui_owner_name_part, file_to_delete_path)
1185
 
 
1193
  parsed_code_blocks_state_cache = [b for b in parsed_code_blocks_state_cache if b["filename"] != file_to_delete_path]
1194
  file_content_editor_update = gr.update(value="")
1195
  commit_message_update = gr.update(value="")
1196
+ editor_lang_update = gr.update(language="text") # Changed plaintext to text
1197
  file_list, _ = list_space_files_for_browsing(hf_api_key_ui, ui_space_name_part, ui_owner_name_part)
1198
  file_browser_update = gr.update(choices=sorted(file_list or []), value=None)
1199
 
 
1291
  return "Duplicate Error: Target Owner and Target Space Name are required.", gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update()
1292
  if "/" in target_space_name:
1293
  return "Duplicate Error: Target Space Name should not contain '/'. Use Target Owner field for the owner part.", gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update()
 
1294
 
1295
 
1296
  source_repo_id = f"{source_owner}/{source_space_name}"
 
1304
  status_msg = f"Duplication Result: {result_message}"
1305
 
1306
  _status_reload = f"{status_msg} | Attempting to load the new Space [{target_repo_id}]..."
1307
+ yield gr.update(value=_status_reload), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update()
1308
 
1309
  new_owner = target_owner
1310
  new_space_name = target_space_name
 
1313
 
1314
  if err_list:
1315
  reload_error = f"Error reloading file list after duplication: {err_list}"
1316
+ global parsed_code_blocks_state_cache
1317
  parsed_code_blocks_state_cache = []
1318
  _file_browser_update = gr.update(visible=False, choices=[], value=None)
1319
  _iframe_html_update = gr.update(value=None, visible=False)
 
1325
  is_binary = lang == "binary" or (err_get is not None)
1326
  code = f"[Error loading content: {err_get}]" if err_get else (content or "")
1327
  loaded_files.append({"filename": file_path, "code": code, "language": lang, "is_binary": is_binary, "is_structure_block": False})
1328
+ global parsed_code_blocks_state_cache
1329
  parsed_code_blocks_state_cache = loaded_files
1330
 
1331
  _file_browser_update = gr.update(visible=True, choices=sorted([f["filename"] for f in parsed_code_blocks_state_cache if not f.get("is_structure_block")] or []), value=None)
 
1351
  owner_update, space_update,
1352
  gr.update(value=_formatted), gr.update(value=_detected), _download,
1353
  _file_browser_update, _iframe_html_update, gr.update(value=runtime_status_md)
1354
+ )