evijit HF Staff commited on
Commit
47e0cf9
·
verified ·
1 Parent(s): 0c6bf95

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +215 -75
app.py CHANGED
@@ -1,4 +1,4 @@
1
- # --- START OF FINAL, CORRECTED FILE app.py ---
2
 
3
  import gradio as gr
4
  import pandas as pd
@@ -16,52 +16,6 @@ HF_DATASET_ID = "evijit/orgstats_daily_data"
16
  TAG_FILTER_CHOICES = [ "Audio & Speech", "Time series", "Robotics", "Music", "Video", "Images", "Text", "Biomedical", "Sciences" ]
17
  PIPELINE_TAGS = [ 'text-generation', 'text-to-image', 'text-classification', 'text2text-generation', 'audio-to-audio', 'feature-extraction', 'image-classification', 'translation', 'reinforcement-learning', 'fill-mask', 'text-to-speech', 'automatic-speech-recognition', 'image-text-to-text', 'token-classification', 'sentence-similarity', 'question-answering', 'image-feature-extraction', 'summarization', 'zero-shot-image-classification', 'object-detection', 'image-segmentation', 'image-to-image', 'image-to-text', 'audio-classification', 'visual-question-answering', 'text-to-video', 'zero-shot-classification', 'depth-estimation', 'text-ranking', 'image-to-video', 'multiple-choice', 'unconditional-image-generation', 'video-classification', 'text-to-audio', 'time-series-forecasting', 'any-to-any', 'video-text-to-text', 'table-question-answering' ]
18
 
19
- # --- Custom HTML, CSS, and JavaScript for the Slider ---
20
- # Using a placeholder for the choices to be safely injected from Python
21
- custom_slider_js = """
22
- function createCustomSlider() {{
23
- const paramChoices = {js_param_choices}; // This will be replaced by Python
24
- const slider = document.getElementById('noui-slider-container');
25
- if (slider.noUiSlider) {{
26
- slider.noUiSlider.destroy();
27
- }}
28
- noUiSlider.create(slider, {{
29
- start: [0, paramChoices.length - 1],
30
- connect: true,
31
- step: 1,
32
- range: {{ 'min': 0, 'max': paramChoices.length - 1 }},
33
- pips: {{
34
- mode: 'values',
35
- values: Array.from(Array(paramChoices.length).keys()),
36
- density: 100 / (paramChoices.length - 1),
37
- format: {{ to: function(value) {{ return paramChoices[value]; }} }}
38
- }}
39
- }});
40
-
41
- const paramRangeStateInput = document.querySelector('#param-range-state-js textarea');
42
- slider.noUiSlider.on('update', function (values) {{
43
- const intValues = values.map(v => parseInt(v, 10));
44
- const newValue = JSON.stringify(intValues);
45
- if (paramRangeStateInput.value !== newValue) {{
46
- paramRangeStateInput.value = newValue;
47
- const event = new Event('input', {{ bubbles: true }});
48
- paramRangeStateInput.dispatchEvent(event);
49
- }}
50
- }});
51
-
52
- function highlightPips(values) {{
53
- const intValues = values.map(v => parseInt(v, 10));
54
- document.querySelectorAll('.noUi-value').forEach((pip, index) => {{
55
- const pipIsSelected = index >= intValues[0] && index <= intValues[1];
56
- pip.style.fontWeight = pipIsSelected ? 'bold' : 'normal';
57
- pip.style.color = pipIsSelected ? '#000' : '#777';
58
- }});
59
- }}
60
- slider.noUiSlider.on('update', highlightPips);
61
- highlightPips([0, paramChoices.length - 1]);
62
- }}
63
- """
64
-
65
  def load_models_data():
66
  overall_start_time = time.time()
67
  print(f"Attempting to load dataset from Hugging Face Hub: {HF_DATASET_ID}")
@@ -121,50 +75,226 @@ def create_treemap(treemap_data, count_by, title=None):
121
  fig.update_traces(textinfo="label+value+percent root", hovertemplate="<b>%{label}</b><br>%{value:,} " + count_by + "<br>%{percentRoot:.2%} of total<extra></extra>")
122
  return fig
123
 
 
124
  custom_head = """
125
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/noUiSlider/15.7.1/nouislider.min.css">
126
  <script src="https://cdnjs.cloudflare.com/ajax/libs/noUiSlider/15.7.1/nouislider.min.js"></script>
127
  """
128
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
129
  with gr.Blocks(title="🤗 ModelVerse Explorer", fill_width=True, head=custom_head) as demo:
130
  models_data_state = gr.State(pd.DataFrame())
131
  loading_complete_state = gr.State(False)
132
 
133
  with gr.Row():
134
  with gr.Column(scale=1):
135
- count_by_dropdown = gr.Dropdown(label="Metric", choices=[("Downloads (last 30 days)", "downloads"), ("Downloads (All Time)", "downloadsAllTime"), ("Likes", "likes")], value="downloads")
136
- filter_choice_radio = gr.Radio(label="Filter Type", choices=["None", "Tag Filter", "Pipeline Filter"], value="None")
137
- tag_filter_dropdown = gr.Dropdown(label="Select Tag", choices=TAG_FILTER_CHOICES, value=None, visible=False)
138
- pipeline_filter_dropdown = gr.Dropdown(label="Select Pipeline Tag", choices=PIPELINE_TAGS, value=None, visible=False)
 
139
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
140
  with gr.Group():
141
- gr.Markdown("<div style='font-weight: 500;'>Parameters</div>")
142
- gr.HTML("""
143
- <div id="noui-slider-container" style="margin: 2rem 1rem;"></div>
 
 
144
  <style>
145
- .noUi-value { font-size: 12px; }
146
- .noUi-pips-horizontal { padding: 10px 0; height: 50px; }
147
- .noUi-connect { background: #333; }
148
- .noUi-handle { border-radius: 50%; width: 20px; height: 20px; right: -10px; top: -7px; box-shadow: none; border: 2px solid #333; background: #FFF; cursor: pointer; }
149
- .noUi-handle:focus { outline: none; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
150
  </style>
151
  """)
152
- param_range_state_js = gr.Textbox(value=PARAM_CHOICES_DEFAULT_INDICES_JSON, visible=False, elem_id="param-range-state-js")
 
 
 
 
 
 
 
 
 
 
 
 
153
 
154
- top_k_dropdown = gr.Dropdown(label="Number of Top Organizations", choices=TOP_K_CHOICES, value=25)
155
- skip_orgs_textbox = gr.Textbox(label="Organizations to Skip (comma-separated)", value="TheBloke,MaziyarPanahi,unsloth,modularai,Gensyn,bartowski")
156
- generate_plot_button = gr.Button(value="Generate Plot", variant="primary", interactive=False)
 
 
 
 
 
 
 
157
 
158
  with gr.Column(scale=3):
159
  plot_output = gr.Plot()
160
  status_message_md = gr.Markdown("Initializing...")
161
  data_info_md = gr.Markdown("")
162
 
163
- def _update_button_interactivity(is_loaded_flag): return gr.update(interactive=is_loaded_flag)
164
- loading_complete_state.change(fn=_update_button_interactivity, inputs=loading_complete_state, outputs=generate_plot_button)
 
 
 
 
 
 
 
165
 
166
- def _toggle_filters_visibility(choice): return gr.update(visible=choice == "Tag Filter"), gr.update(visible=choice == "Pipeline Filter")
167
- filter_choice_radio.change(fn=_toggle_filters_visibility, inputs=filter_choice_radio, outputs=[tag_filter_dropdown, pipeline_filter_dropdown])
 
 
 
 
 
 
 
 
 
168
 
169
  def ui_load_data_controller(progress=gr.Progress()):
170
  progress(0, desc=f"Loading dataset '{HF_DATASET_ID}'...")
@@ -199,7 +329,11 @@ with gr.Blocks(title="🤗 ModelVerse Explorer", fill_width=True, head=custom_he
199
  pipeline_to_use = pipeline_choice if filter_type == "Pipeline Filter" else None
200
  orgs_to_skip = [org.strip() for org in skip_orgs_input.split(',') if org.strip()]
201
 
202
- param_range_indices = json.loads(param_range_json)
 
 
 
 
203
  min_label = PARAM_CHOICES[int(param_range_indices[0])]
204
  max_label = PARAM_CHOICES[int(param_range_indices[1])]
205
  param_labels_for_filtering = [min_label, max_label]
@@ -219,20 +353,26 @@ with gr.Blocks(title="🤗 ModelVerse Explorer", fill_width=True, head=custom_he
219
  plot_stats_md = f"## Plot Statistics\n- **Models shown**: {total_items_in_plot:,}\n- **Total {metric_choice}**: {int(total_value_in_plot):,}"
220
  return plotly_fig, plot_stats_md
221
 
222
- # --- FINAL FIX: Use the `js` parameter in demo.load() instead of the deprecated `_js` in .then() ---
223
- # We also safely format the Python list into a JS array using json.dumps
224
- final_js = custom_slider_js.format(js_param_choices=json.dumps(PARAM_CHOICES))
225
  demo.load(
226
  fn=ui_load_data_controller,
227
  inputs=[],
228
- outputs=[models_data_state, loading_complete_state, data_info_md, status_message_md],
229
- js=f"() => {{ {final_js} }}" # Wrap the JS in a function to be executed on load
 
 
 
 
 
 
 
230
  )
231
 
 
232
  generate_plot_button.click(
233
  fn=ui_generate_plot_controller,
234
  inputs=[count_by_dropdown, filter_choice_radio, tag_filter_dropdown, pipeline_filter_dropdown,
235
- param_range_state_js, top_k_dropdown, skip_orgs_textbox, models_data_state],
236
  outputs=[plot_output, status_message_md]
237
  )
238
 
@@ -240,4 +380,4 @@ if __name__ == "__main__":
240
  print(f"Application starting...")
241
  demo.queue().launch()
242
 
243
- # --- END OF FINAL, CORRECTED FILE app.py ---
 
1
+ # --- START OF FIXED FILE app.py ---
2
 
3
  import gradio as gr
4
  import pandas as pd
 
16
  TAG_FILTER_CHOICES = [ "Audio & Speech", "Time series", "Robotics", "Music", "Video", "Images", "Text", "Biomedical", "Sciences" ]
17
  PIPELINE_TAGS = [ 'text-generation', 'text-to-image', 'text-classification', 'text2text-generation', 'audio-to-audio', 'feature-extraction', 'image-classification', 'translation', 'reinforcement-learning', 'fill-mask', 'text-to-speech', 'automatic-speech-recognition', 'image-text-to-text', 'token-classification', 'sentence-similarity', 'question-answering', 'image-feature-extraction', 'summarization', 'zero-shot-image-classification', 'object-detection', 'image-segmentation', 'image-to-image', 'image-to-text', 'audio-classification', 'visual-question-answering', 'text-to-video', 'zero-shot-classification', 'depth-estimation', 'text-ranking', 'image-to-video', 'multiple-choice', 'unconditional-image-generation', 'video-classification', 'text-to-audio', 'time-series-forecasting', 'any-to-any', 'video-text-to-text', 'table-question-answering' ]
18
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
  def load_models_data():
20
  overall_start_time = time.time()
21
  print(f"Attempting to load dataset from Hugging Face Hub: {HF_DATASET_ID}")
 
75
  fig.update_traces(textinfo="label+value+percent root", hovertemplate="<b>%{label}</b><br>%{value:,} " + count_by + "<br>%{percentRoot:.2%} of total<extra></extra>")
76
  return fig
77
 
78
+ # Custom head with noUiSlider CSS and JS
79
  custom_head = """
80
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/noUiSlider/15.7.1/nouislider.min.css">
81
  <script src="https://cdnjs.cloudflare.com/ajax/libs/noUiSlider/15.7.1/nouislider.min.js"></script>
82
  """
83
 
84
+ # JavaScript for creating the slider - this will be injected properly
85
+ def create_slider_js():
86
+ return f"""
87
+ function initializeSlider() {{
88
+ const paramChoices = {json.dumps(PARAM_CHOICES)};
89
+ const sliderContainer = document.getElementById('param-slider');
90
+ const hiddenInput = document.querySelector('#param-range-hidden input');
91
+
92
+ if (!sliderContainer || !hiddenInput) {{
93
+ console.log('Slider elements not found, retrying...');
94
+ setTimeout(initializeSlider, 100);
95
+ return;
96
+ }}
97
+
98
+ // Clear any existing slider
99
+ if (sliderContainer.noUiSlider) {{
100
+ sliderContainer.noUiSlider.destroy();
101
+ }}
102
+
103
+ // Create the slider
104
+ noUiSlider.create(sliderContainer, {{
105
+ start: [0, paramChoices.length - 1],
106
+ connect: true,
107
+ step: 1,
108
+ range: {{
109
+ 'min': 0,
110
+ 'max': paramChoices.length - 1
111
+ }},
112
+ pips: {{
113
+ mode: 'values',
114
+ values: Array.from({{length: paramChoices.length}}, (_, i) => i),
115
+ density: 100 / (paramChoices.length - 1),
116
+ format: {{
117
+ to: function(value) {{
118
+ return paramChoices[Math.round(value)];
119
+ }}
120
+ }}
121
+ }}
122
+ }});
123
+
124
+ // Update hidden input when slider changes
125
+ sliderContainer.noUiSlider.on('update', function(values) {{
126
+ const indices = values.map(v => Math.round(parseFloat(v)));
127
+ hiddenInput.value = JSON.stringify(indices);
128
+ hiddenInput.dispatchEvent(new Event('input', {{ bubbles: true }}));
129
+
130
+ // Highlight selected range
131
+ document.querySelectorAll('.noUi-value').forEach((pip, index) => {{
132
+ const isSelected = index >= indices[0] && index <= indices[1];
133
+ pip.style.fontWeight = isSelected ? 'bold' : 'normal';
134
+ pip.style.color = isSelected ? '#2563eb' : '#6b7280';
135
+ }});
136
+ }});
137
+
138
+ // Initial highlight
139
+ document.querySelectorAll('.noUi-value').forEach((pip, index) => {{
140
+ const isSelected = index >= 0 && index <= paramChoices.length - 1;
141
+ pip.style.fontWeight = isSelected ? 'bold' : 'normal';
142
+ pip.style.color = isSelected ? '#2563eb' : '#6b7280';
143
+ }});
144
+
145
+ console.log('Slider initialized successfully');
146
+ }}
147
+
148
+ // Initialize when DOM is ready
149
+ if (document.readyState === 'loading') {{
150
+ document.addEventListener('DOMContentLoaded', initializeSlider);
151
+ }} else {{
152
+ initializeSlider();
153
+ }}
154
+ """
155
+
156
  with gr.Blocks(title="🤗 ModelVerse Explorer", fill_width=True, head=custom_head) as demo:
157
  models_data_state = gr.State(pd.DataFrame())
158
  loading_complete_state = gr.State(False)
159
 
160
  with gr.Row():
161
  with gr.Column(scale=1):
162
+ count_by_dropdown = gr.Dropdown(
163
+ label="Metric",
164
+ choices=[("Downloads (last 30 days)", "downloads"), ("Downloads (All Time)", "downloadsAllTime"), ("Likes", "likes")],
165
+ value="downloads"
166
+ )
167
 
168
+ filter_choice_radio = gr.Radio(
169
+ label="Filter Type",
170
+ choices=["None", "Tag Filter", "Pipeline Filter"],
171
+ value="None"
172
+ )
173
+
174
+ tag_filter_dropdown = gr.Dropdown(
175
+ label="Select Tag",
176
+ choices=TAG_FILTER_CHOICES,
177
+ value=None,
178
+ visible=False
179
+ )
180
+
181
+ pipeline_filter_dropdown = gr.Dropdown(
182
+ label="Select Pipeline Tag",
183
+ choices=PIPELINE_TAGS,
184
+ value=None,
185
+ visible=False
186
+ )
187
+
188
+ # Parameter range slider section
189
  with gr.Group():
190
+ gr.Markdown("### Parameters")
191
+
192
+ # Custom HTML for the slider
193
+ gr.HTML(f"""
194
+ <div id="param-slider" style="margin: 20px 10px 60px 10px; height: 20px;"></div>
195
  <style>
196
+ #param-slider {{
197
+ height: 20px;
198
+ }}
199
+ .noUi-target {{
200
+ background: #f1f5f9;
201
+ border-radius: 10px;
202
+ border: 1px solid #e2e8f0;
203
+ box-shadow: none;
204
+ }}
205
+ .noUi-connect {{
206
+ background: #3b82f6;
207
+ border-radius: 10px;
208
+ }}
209
+ .noUi-handle {{
210
+ width: 20px;
211
+ height: 20px;
212
+ right: -10px;
213
+ top: -5px;
214
+ background: white;
215
+ border: 2px solid #3b82f6;
216
+ border-radius: 50%;
217
+ box-shadow: 0 2px 4px rgba(0,0,0,0.1);
218
+ cursor: pointer;
219
+ }}
220
+ .noUi-handle:before,
221
+ .noUi-handle:after {{
222
+ display: none;
223
+ }}
224
+ .noUi-handle:focus {{
225
+ outline: none;
226
+ }}
227
+ .noUi-pips {{
228
+ color: #6b7280;
229
+ font-size: 12px;
230
+ }}
231
+ .noUi-pips-horizontal {{
232
+ padding: 10px 0;
233
+ height: 60px;
234
+ }}
235
+ .noUi-value {{
236
+ font-size: 11px;
237
+ padding-top: 5px;
238
+ cursor: pointer;
239
+ }}
240
+ .noUi-marker-horizontal.noUi-marker {{
241
+ background: #e2e8f0;
242
+ height: 5px;
243
+ width: 1px;
244
+ }}
245
  </style>
246
  """)
247
+
248
+ # Hidden input to store slider values
249
+ param_range_hidden = gr.Textbox(
250
+ value=PARAM_CHOICES_DEFAULT_INDICES_JSON,
251
+ visible=False,
252
+ elem_id="param-range-hidden"
253
+ )
254
+
255
+ top_k_dropdown = gr.Dropdown(
256
+ label="Number of Top Organizations",
257
+ choices=TOP_K_CHOICES,
258
+ value=25
259
+ )
260
 
261
+ skip_orgs_textbox = gr.Textbox(
262
+ label="Organizations to Skip (comma-separated)",
263
+ value="TheBloke,MaziyarPanahi,unsloth,modularai,Gensyn,bartowski"
264
+ )
265
+
266
+ generate_plot_button = gr.Button(
267
+ value="Generate Plot",
268
+ variant="primary",
269
+ interactive=False
270
+ )
271
 
272
  with gr.Column(scale=3):
273
  plot_output = gr.Plot()
274
  status_message_md = gr.Markdown("Initializing...")
275
  data_info_md = gr.Markdown("")
276
 
277
+ # Event handlers
278
+ def _update_button_interactivity(is_loaded_flag):
279
+ return gr.update(interactive=is_loaded_flag)
280
+
281
+ loading_complete_state.change(
282
+ fn=_update_button_interactivity,
283
+ inputs=loading_complete_state,
284
+ outputs=generate_plot_button
285
+ )
286
 
287
+ def _toggle_filters_visibility(choice):
288
+ return (
289
+ gr.update(visible=choice == "Tag Filter"),
290
+ gr.update(visible=choice == "Pipeline Filter")
291
+ )
292
+
293
+ filter_choice_radio.change(
294
+ fn=_toggle_filters_visibility,
295
+ inputs=filter_choice_radio,
296
+ outputs=[tag_filter_dropdown, pipeline_filter_dropdown]
297
+ )
298
 
299
  def ui_load_data_controller(progress=gr.Progress()):
300
  progress(0, desc=f"Loading dataset '{HF_DATASET_ID}'...")
 
329
  pipeline_to_use = pipeline_choice if filter_type == "Pipeline Filter" else None
330
  orgs_to_skip = [org.strip() for org in skip_orgs_input.split(',') if org.strip()]
331
 
332
+ try:
333
+ param_range_indices = json.loads(param_range_json)
334
+ except:
335
+ param_range_indices = [0, len(PARAM_CHOICES) - 1]
336
+
337
  min_label = PARAM_CHOICES[int(param_range_indices[0])]
338
  max_label = PARAM_CHOICES[int(param_range_indices[1])]
339
  param_labels_for_filtering = [min_label, max_label]
 
353
  plot_stats_md = f"## Plot Statistics\n- **Models shown**: {total_items_in_plot:,}\n- **Total {metric_choice}**: {int(total_value_in_plot):,}"
354
  return plotly_fig, plot_stats_md
355
 
356
+ # Load data on startup and initialize slider
 
 
357
  demo.load(
358
  fn=ui_load_data_controller,
359
  inputs=[],
360
+ outputs=[models_data_state, loading_complete_state, data_info_md, status_message_md]
361
+ )
362
+
363
+ # Initialize slider after page loads
364
+ demo.load(
365
+ fn=lambda: None,
366
+ inputs=[],
367
+ outputs=[],
368
+ js=create_slider_js()
369
  )
370
 
371
+ # Generate plot button click handler
372
  generate_plot_button.click(
373
  fn=ui_generate_plot_controller,
374
  inputs=[count_by_dropdown, filter_choice_radio, tag_filter_dropdown, pipeline_filter_dropdown,
375
+ param_range_hidden, top_k_dropdown, skip_orgs_textbox, models_data_state],
376
  outputs=[plot_output, status_message_md]
377
  )
378
 
 
380
  print(f"Application starting...")
381
  demo.queue().launch()
382
 
383
+ # --- END OF FIXED FILE