Luigi commited on
Commit
68d2790
Β·
1 Parent(s): c732f74

feat: add dynamic model search for custom GGUF loader

Browse files

- Add model_search_results dropdown to show matching GGUF models from HF
- Implement search_models_dynamic() to search as user types (2+ chars)
- Add on_model_selected_from_search() to auto-fill repo and discover files
- Connect event handlers: custom_repo_id.change triggers search
- Connect event handlers: model_search_results.change triggers file discovery
- Show model metadata: params, downloads in search results
- Keep manual 'Discover Files' button as backup option

Files changed (1) hide show
  1. app.py +109 -5
app.py CHANGED
@@ -1673,20 +1673,30 @@ def create_interface():
1673
 
1674
  custom_repo_id = gr.Textbox(
1675
  label="HuggingFace Repo ID",
1676
- placeholder="e.g., unsloth/DeepSeek-R1-Distill-Qwen-7B-GGUF",
1677
- info="Enter repository ID (format: username/model-name). Popular models will be suggested as you type.",
1678
  interactive=True,
1679
  )
1680
 
 
 
 
 
 
 
 
 
 
 
1681
  # Hidden fields to store discovered file data
1682
  custom_repo_files = gr.State([])
1683
 
1684
  # File dropdown (populated after repo discovery)
1685
  custom_file_dropdown = gr.Dropdown(
1686
- label="Available GGUF Files",
1687
  choices=[],
1688
  value=None,
1689
- info="Files will be auto-discovered when you stop typing (alphabetically sorted)",
1690
  interactive=True,
1691
  visible=True,
1692
  )
@@ -1999,7 +2009,101 @@ def create_interface():
1999
  gr.update(visible=True, value="βœ… Files discovered! Select one and click 'Load Selected Model'")
2000
  )
2001
 
2002
- # Manual discover button
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2003
  discover_btn.click(
2004
  fn=discover_custom_files,
2005
  inputs=[custom_repo_id],
 
1673
 
1674
  custom_repo_id = gr.Textbox(
1675
  label="HuggingFace Repo ID",
1676
+ placeholder="e.g., unsloth/DeepSeek-R1-Distill-Qwen-7B-GGUF or type to search...",
1677
+ info="Type model name to search GGUF models on HF, or paste full repo ID",
1678
  interactive=True,
1679
  )
1680
 
1681
+ # Search results dropdown (shows matching models from HF)
1682
+ model_search_results = gr.Dropdown(
1683
+ label="πŸ” Search Results - Select a Model",
1684
+ choices=[],
1685
+ value=None,
1686
+ info="Matching GGUF models from HuggingFace Hub will appear here as you type",
1687
+ interactive=True,
1688
+ visible=True,
1689
+ )
1690
+
1691
  # Hidden fields to store discovered file data
1692
  custom_repo_files = gr.State([])
1693
 
1694
  # File dropdown (populated after repo discovery)
1695
  custom_file_dropdown = gr.Dropdown(
1696
+ label="πŸ“¦ Available GGUF Files - Select Precision",
1697
  choices=[],
1698
  value=None,
1699
+ info="GGUF files from selected repo (alphabetically sorted)",
1700
  interactive=True,
1701
  visible=True,
1702
  )
 
2009
  gr.update(visible=True, value="βœ… Files discovered! Select one and click 'Load Selected Model'")
2010
  )
2011
 
2012
+ # ==========================================
2013
+ # DYNAMIC MODEL SEARCH - New Feature
2014
+ # ==========================================
2015
+
2016
+ def search_models_dynamic(query):
2017
+ """Search for GGUF models as user types."""
2018
+ if not query or len(query) < 2:
2019
+ # Clear search results if query too short
2020
+ return gr.update(choices=[], value=None)
2021
+
2022
+ # Search popular GGUF models from cache
2023
+ matches = search_gguf_models(query, limit=10)
2024
+
2025
+ if not matches:
2026
+ # No matches found
2027
+ return gr.update(choices=["No matching models found"], value=None)
2028
+
2029
+ # Format choices with metadata
2030
+ choices = []
2031
+ for m in matches:
2032
+ repo_id = m["repo_id"]
2033
+ params = m.get("params", "Unknown")
2034
+ downloads = m.get("downloads", 0)
2035
+ # Format downloads
2036
+ if downloads >= 1000000:
2037
+ dl_str = f"{downloads/1000000:.1f}M"
2038
+ elif downloads >= 1000:
2039
+ dl_str = f"{downloads/1000:.1f}K"
2040
+ else:
2041
+ dl_str = str(downloads)
2042
+
2043
+ display = f"{repo_id} | {params} params | ⬇️ {dl_str}"
2044
+ choices.append((display, repo_id))
2045
+
2046
+ return gr.update(choices=choices, value=None)
2047
+
2048
+ # Auto-search as user types (with small delay via change event)
2049
+ custom_repo_id.change(
2050
+ fn=search_models_dynamic,
2051
+ inputs=[custom_repo_id],
2052
+ outputs=[model_search_results],
2053
+ )
2054
+
2055
+ def on_model_selected_from_search(selected_repo):
2056
+ """Handle when user selects a model from search results."""
2057
+ if not selected_repo or selected_repo == "No matching models found":
2058
+ return (
2059
+ gr.update(value=""),
2060
+ gr.update(choices=[], value=None),
2061
+ gr.update(visible=True, value="Please select a model from search results"),
2062
+ [],
2063
+ )
2064
+
2065
+ # Auto-discover files for selected repo
2066
+ # First show searching status
2067
+ yield (
2068
+ gr.update(value=selected_repo),
2069
+ gr.update(choices=["Searching..."], value=None, interactive=False),
2070
+ gr.update(visible=True, value="πŸ” Discovering GGUF files..."),
2071
+ [],
2072
+ )
2073
+
2074
+ files, error = list_repo_gguf_files(selected_repo)
2075
+
2076
+ if error:
2077
+ yield (
2078
+ gr.update(value=selected_repo),
2079
+ gr.update(choices=[], value=None, interactive=True),
2080
+ gr.update(visible=True, value=f"❌ {error}"),
2081
+ [],
2082
+ )
2083
+ elif not files:
2084
+ yield (
2085
+ gr.update(value=selected_repo),
2086
+ gr.update(choices=[], value=None, interactive=True),
2087
+ gr.update(visible=True, value="❌ No GGUF files found in this repository"),
2088
+ [],
2089
+ )
2090
+ else:
2091
+ choices = [format_file_choice(f) for f in files]
2092
+ yield (
2093
+ gr.update(value=selected_repo),
2094
+ gr.update(choices=choices, value=choices[0] if choices else None, interactive=True),
2095
+ gr.update(visible=True, value=f"βœ… Found {len(files)} GGUF files! Select precision and click 'Load Selected Model'"),
2096
+ files,
2097
+ )
2098
+
2099
+ # When user selects from search results, auto-fill repo and discover files
2100
+ model_search_results.change(
2101
+ fn=on_model_selected_from_search,
2102
+ inputs=[model_search_results],
2103
+ outputs=[custom_repo_id, custom_file_dropdown, custom_status, custom_repo_files],
2104
+ )
2105
+
2106
+ # Manual discover button (kept as backup)
2107
  discover_btn.click(
2108
  fn=discover_custom_files,
2109
  inputs=[custom_repo_id],