evijit HF Staff commited on
Commit
97da54a
·
verified ·
1 Parent(s): afd7356

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +90 -60
app.py CHANGED
@@ -1,4 +1,4 @@
1
- # --- START OF FILE app.py ---
2
 
3
  import gradio as gr
4
  import pandas as pd
@@ -7,10 +7,10 @@ import time
7
  from datasets import load_dataset # Import the datasets library
8
 
9
  # --- Constants ---
10
- MODEL_SIZE_RANGES = {
11
- "Small (<1GB)": (0, 1), "Medium (1-5GB)": (1, 5), "Large (5-20GB)": (5, 20),
12
- "X-Large (20-50GB)": (20, 50), "XX-Large (>50GB)": (50, float('inf'))
13
- }
14
 
15
  # The Hugging Face dataset ID to load.
16
  HF_DATASET_ID = "evijit/orgstats_daily_data"
@@ -42,44 +42,40 @@ def load_models_data():
42
  overall_start_time = time.time()
43
  print(f"Attempting to load dataset from Hugging Face Hub: {HF_DATASET_ID}")
44
 
45
- # These are the columns expected to be in the pre-processed dataset.
46
  expected_cols = [
47
  'id', 'downloads', 'downloadsAllTime', 'likes', 'pipeline_tag', 'tags', 'params',
48
- 'size_category', 'organization', 'has_audio', 'has_speech', 'has_music',
49
  'has_robot', 'has_bio', 'has_med', 'has_series', 'has_video', 'has_image',
50
  'has_text', 'has_science', 'is_audio_speech', 'is_biomed',
51
  'data_download_timestamp'
52
  ]
53
 
54
  try:
55
- # Load the dataset using the datasets library
56
- # It will be cached locally after the first run.
57
  dataset_dict = load_dataset(HF_DATASET_ID)
58
 
59
  if not dataset_dict:
60
  raise ValueError(f"Dataset '{HF_DATASET_ID}' loaded but appears empty.")
61
 
62
- # Get the name of the first split (e.g., 'train')
63
  split_name = list(dataset_dict.keys())[0]
64
  print(f"Using dataset split: '{split_name}'. Converting to Pandas.")
65
-
66
- # Convert the dataset object to a Pandas DataFrame
67
  df = dataset_dict[split_name].to_pandas()
68
-
69
  elapsed = time.time() - overall_start_time
70
 
71
- # Validate that the loaded data has the columns we expect.
72
  missing_cols = [col for col in expected_cols if col not in df.columns]
73
  if missing_cols:
74
- raise ValueError(f"Loaded dataset is missing expected columns: {missing_cols}.")
75
-
76
- # --- Diagnostic for 'has_robot' after loading ---
77
- if 'has_robot' in df.columns:
78
- robot_count = df['has_robot'].sum()
79
- print(f"DIAGNOSTIC (Dataset Load): 'has_robot' column found. Number of True values: {robot_count}")
 
 
 
80
  else:
81
- print("DIAGNOSTIC (Dataset Load): 'has_robot' column NOT FOUND.")
82
- # --- End Diagnostic ---
 
83
 
84
  msg = f"Successfully loaded dataset '{HF_DATASET_ID}' (split: {split_name}) from HF Hub in {elapsed:.2f}s. Shape: {df.shape}"
85
  print(msg)
@@ -90,8 +86,24 @@ def load_models_data():
90
  print(err_msg)
91
  return pd.DataFrame(), False, err_msg
92
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
93
 
94
- def make_treemap_data(df, count_by, top_k=25, tag_filter=None, pipeline_filter=None, size_filter=None, skip_orgs=None):
 
95
  if df is None or df.empty: return pd.DataFrame()
96
  filtered_df = df.copy()
97
  col_map = { "Audio & Speech": "is_audio_speech", "Music": "has_music", "Robotics": "has_robot",
@@ -107,16 +119,26 @@ def make_treemap_data(df, count_by, top_k=25, tag_filter=None, pipeline_filter=N
107
 
108
  if pipeline_filter:
109
  if "pipeline_tag" in filtered_df.columns:
110
- # Ensure the comparison works even if pipeline_tag has NaNs or mixed types
111
  filtered_df = filtered_df[filtered_df["pipeline_tag"].astype(str) == pipeline_filter]
112
  else:
113
  print(f"Warning: 'pipeline_tag' column not found for filtering.")
114
 
115
- if size_filter and size_filter != "None" and size_filter in MODEL_SIZE_RANGES.keys():
116
- if 'size_category' in filtered_df.columns:
117
- filtered_df = filtered_df[filtered_df['size_category'] == size_filter]
118
- else:
119
- print("Warning: 'size_category' column not found for filtering.")
 
 
 
 
 
 
 
 
 
 
 
120
 
121
  if skip_orgs and len(skip_orgs) > 0:
122
  if "organization" in filtered_df.columns:
@@ -126,20 +148,16 @@ def make_treemap_data(df, count_by, top_k=25, tag_filter=None, pipeline_filter=N
126
 
127
  if filtered_df.empty: return pd.DataFrame()
128
 
129
- # Ensure the metric column is numeric and handle potential missing values
130
  if count_by not in filtered_df.columns:
131
  print(f"Warning: Metric column '{count_by}' not found. Using 0.")
132
  filtered_df[count_by] = 0.0
133
  filtered_df[count_by] = pd.to_numeric(filtered_df[count_by], errors="coerce").fillna(0.0)
134
 
135
- # Group and get top organizations
136
  org_totals = filtered_df.groupby("organization")[count_by].sum().nlargest(top_k, keep='first')
137
  top_orgs_list = org_totals.index.tolist()
138
 
139
- # Prepare data for treemap
140
  treemap_data = filtered_df[filtered_df["organization"].isin(top_orgs_list)][["id", "organization", count_by]].copy()
141
  treemap_data["root"] = "models"
142
- # Ensure numeric again for the final slice
143
  treemap_data[count_by] = pd.to_numeric(treemap_data[count_by], errors="coerce").fillna(0.0)
144
  return treemap_data
145
 
@@ -168,7 +186,19 @@ with gr.Blocks(title="HuggingFace Model Explorer", fill_width=True) as demo:
168
  filter_choice_radio = gr.Radio(label="Filter Type", choices=["None", "Tag Filter", "Pipeline Filter"], value="None")
169
  tag_filter_dropdown = gr.Dropdown(label="Select Tag", choices=TAG_FILTER_CHOICES, value=None, visible=False)
170
  pipeline_filter_dropdown = gr.Dropdown(label="Select Pipeline Tag", choices=PIPELINE_TAGS, value=None, visible=False)
171
- size_filter_dropdown = gr.Dropdown(label="Model Size Filter", choices=["None"] + list(MODEL_SIZE_RANGES.keys()), value="None")
 
 
 
 
 
 
 
 
 
 
 
 
172
  top_k_slider = gr.Slider(label="Number of Top Organizations", minimum=5, maximum=50, value=25, step=5)
173
  skip_orgs_textbox = gr.Textbox(label="Organizations to Skip (comma-separated)", value="TheBloke,MaziyarPanahi,unsloth,modularai,Gensyn,bartowski")
174
  generate_plot_button = gr.Button(value="Generate Plot", variant="primary", interactive=False)
@@ -178,6 +208,20 @@ with gr.Blocks(title="HuggingFace Model Explorer", fill_width=True) as demo:
178
  status_message_md = gr.Markdown("Initializing...")
179
  data_info_md = gr.Markdown("")
180
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
181
  def _update_button_interactivity(is_loaded_flag):
182
  return gr.update(interactive=is_loaded_flag)
183
  loading_complete_state.change(fn=_update_button_interactivity, inputs=loading_complete_state, outputs=generate_plot_button)
@@ -193,37 +237,24 @@ with gr.Blocks(title="HuggingFace Model Explorer", fill_width=True) as demo:
193
  data_info_text = ""
194
  current_df = pd.DataFrame()
195
  load_success_flag = False
196
- data_as_of_date_display = "N/A"
197
  try:
198
- # Call the load function that uses the datasets library.
199
  current_df, load_success_flag, status_msg_from_load = load_models_data()
200
  if load_success_flag:
201
  progress(0.9, desc="Processing loaded data...")
202
- # Get the data timestamp from the loaded file
203
  if 'data_download_timestamp' in current_df.columns and not current_df.empty and pd.notna(current_df['data_download_timestamp'].iloc[0]):
204
- timestamp_from_parquet = pd.to_datetime(current_df['data_download_timestamp'].iloc[0])
205
- # Ensure the timestamp is timezone-aware for consistent formatting
206
- if timestamp_from_parquet.tzinfo is None:
207
- timestamp_from_parquet = timestamp_from_parquet.tz_localize('UTC')
208
  data_as_of_date_display = timestamp_from_parquet.strftime('%B %d, %Y, %H:%M:%S %Z')
209
  else:
210
  data_as_of_date_display = "Pre-processed (date unavailable)"
211
 
212
- # Create summary text for the UI
213
- size_dist_lines = []
214
- if 'size_category' in current_df.columns:
215
- for cat in MODEL_SIZE_RANGES.keys():
216
- count = (current_df['size_category'] == cat).sum()
217
- size_dist_lines.append(f" - {cat}: {count:,} models")
218
- else: size_dist_lines.append(" - Size category information not available.")
219
- size_dist = "\n".join(size_dist_lines)
220
-
221
  data_info_text = (f"### Data Information\n"
222
  f"- Source: `{HF_DATASET_ID}`\n"
223
  f"- Overall Status: {status_msg_from_load}\n"
224
  f"- Total models loaded: {len(current_df):,}\n"
225
- f"- Data as of: {data_as_of_date_display}\n"
226
- f"- Size categories:\n{size_dist}")
227
 
228
  status_msg_ui = "Data loaded successfully. Ready to generate plot."
229
  else:
@@ -236,8 +267,9 @@ with gr.Blocks(title="HuggingFace Model Explorer", fill_width=True) as demo:
236
  load_success_flag = False
237
  return current_df, load_success_flag, data_info_text, status_msg_ui
238
 
 
239
  def ui_generate_plot_controller(metric_choice, filter_type, tag_choice, pipeline_choice,
240
- size_choice, k_orgs, skip_orgs_input, df_current_models, progress=gr.Progress()):
241
  if df_current_models is None or df_current_models.empty:
242
  empty_fig = create_treemap(pd.DataFrame(), metric_choice, "Error: Model Data Not Loaded")
243
  error_msg = "Model data is not loaded or is empty. Please wait for data to load."
@@ -248,11 +280,10 @@ with gr.Blocks(title="HuggingFace Model Explorer", fill_width=True) as demo:
248
 
249
  tag_to_use = tag_choice if filter_type == "Tag Filter" else None
250
  pipeline_to_use = pipeline_choice if filter_type == "Pipeline Filter" else None
251
- size_to_use = size_choice if size_choice != "None" else None
252
  orgs_to_skip = [org.strip() for org in skip_orgs_input.split(',') if org.strip()] if skip_orgs_input else []
253
 
254
-
255
- treemap_df = make_treemap_data(df_current_models, metric_choice, k_orgs, tag_to_use, pipeline_to_use, size_to_use, orgs_to_skip)
256
 
257
  progress(0.7, desc="Generating Plotly visualization...")
258
 
@@ -269,23 +300,22 @@ with gr.Blocks(title="HuggingFace Model Explorer", fill_width=True) as demo:
269
 
270
  return plotly_fig, plot_stats_md
271
 
272
- # On app load, call the controller to fetch data using the datasets library.
273
  demo.load(
274
  fn=ui_load_data_controller,
275
  inputs=[],
276
  outputs=[models_data_state, loading_complete_state, data_info_md, status_message_md]
277
  )
278
 
 
279
  generate_plot_button.click(
280
  fn=ui_generate_plot_controller,
281
  inputs=[count_by_dropdown, filter_choice_radio, tag_filter_dropdown, pipeline_filter_dropdown,
282
- size_filter_dropdown, top_k_slider, skip_orgs_textbox, models_data_state],
283
  outputs=[plot_output, status_message_md]
284
  )
285
 
286
  if __name__ == "__main__":
287
  print(f"Application starting. Data will be loaded from Hugging Face dataset: {HF_DATASET_ID}")
288
- # Increase the queue size for potentially busy traffic if hosted
289
  demo.queue().launch()
290
 
291
- # --- END OF FILE app.py ---
 
1
+ # --- START OF MODIFIED FILE app.py ---
2
 
3
  import gradio as gr
4
  import pandas as pd
 
7
  from datasets import load_dataset # Import the datasets library
8
 
9
  # --- Constants ---
10
+ # REMOVED the old MODEL_SIZE_RANGES dictionary.
11
+ # NEW: Define the discrete steps for the parameter range slider.
12
+ PARAM_CHOICES = ['< 1B', '1B', '5B', '12B', '32B', '64B', '128B', '256B', '> 500B']
13
+ PARAM_CHOICES_DEFAULT = [PARAM_CHOICES[0], PARAM_CHOICES[-1]]
14
 
15
  # The Hugging Face dataset ID to load.
16
  HF_DATASET_ID = "evijit/orgstats_daily_data"
 
42
  overall_start_time = time.time()
43
  print(f"Attempting to load dataset from Hugging Face Hub: {HF_DATASET_ID}")
44
 
 
45
  expected_cols = [
46
  'id', 'downloads', 'downloadsAllTime', 'likes', 'pipeline_tag', 'tags', 'params',
47
+ 'organization', 'has_audio', 'has_speech', 'has_music',
48
  'has_robot', 'has_bio', 'has_med', 'has_series', 'has_video', 'has_image',
49
  'has_text', 'has_science', 'is_audio_speech', 'is_biomed',
50
  'data_download_timestamp'
51
  ]
52
 
53
  try:
 
 
54
  dataset_dict = load_dataset(HF_DATASET_ID)
55
 
56
  if not dataset_dict:
57
  raise ValueError(f"Dataset '{HF_DATASET_ID}' loaded but appears empty.")
58
 
 
59
  split_name = list(dataset_dict.keys())[0]
60
  print(f"Using dataset split: '{split_name}'. Converting to Pandas.")
 
 
61
  df = dataset_dict[split_name].to_pandas()
 
62
  elapsed = time.time() - overall_start_time
63
 
 
64
  missing_cols = [col for col in expected_cols if col not in df.columns]
65
  if missing_cols:
66
+ # The 'params' column is crucial for the new slider.
67
+ if 'params' in missing_cols:
68
+ raise ValueError(f"FATAL: Loaded dataset is missing the crucial 'params' column.")
69
+ print(f"Warning: Loaded dataset is missing some expected columns: {missing_cols}.")
70
+
71
+ # Ensure 'params' column is numeric, coercing errors to NaN and then filling with 0.
72
+ # This is important for filtering. Assumes params are in billions.
73
+ if 'params' in df.columns:
74
+ df['params'] = pd.to_numeric(df['params'], errors='coerce').fillna(0)
75
  else:
76
+ # If 'params' is missing after all, create a dummy column to prevent crashes.
77
+ df['params'] = 0
78
+ print("CRITICAL WARNING: 'params' column not found in data. Parameter filtering will not work.")
79
 
80
  msg = f"Successfully loaded dataset '{HF_DATASET_ID}' (split: {split_name}) from HF Hub in {elapsed:.2f}s. Shape: {df.shape}"
81
  print(msg)
 
86
  print(err_msg)
87
  return pd.DataFrame(), False, err_msg
88
 
89
+ # --- NEW: Helper function to parse slider labels into numerical values ---
90
+ def get_param_range_values(param_range_labels):
91
+ """Converts a list of two string labels from the slider into a numerical min/max tuple."""
92
+ if not param_range_labels or len(param_range_labels) != 2:
93
+ return None, None
94
+
95
+ min_label, max_label = param_range_labels
96
+
97
+ # Min value logic: '< 1B' becomes 0, otherwise parse the number.
98
+ min_val = 0.0 if '<' in min_label else float(min_label.replace('B', ''))
99
+
100
+ # Max value logic: '> 500B' becomes infinity, otherwise parse the number.
101
+ max_val = float('inf') if '>' in max_label else float(max_label.replace('B', ''))
102
+
103
+ return min_val, max_val
104
 
105
+ # --- MODIFIED: Function signature and filtering logic updated for parameter range ---
106
+ def make_treemap_data(df, count_by, top_k=25, tag_filter=None, pipeline_filter=None, param_range=None, skip_orgs=None):
107
  if df is None or df.empty: return pd.DataFrame()
108
  filtered_df = df.copy()
109
  col_map = { "Audio & Speech": "is_audio_speech", "Music": "has_music", "Robotics": "has_robot",
 
119
 
120
  if pipeline_filter:
121
  if "pipeline_tag" in filtered_df.columns:
 
122
  filtered_df = filtered_df[filtered_df["pipeline_tag"].astype(str) == pipeline_filter]
123
  else:
124
  print(f"Warning: 'pipeline_tag' column not found for filtering.")
125
 
126
+ # --- MODIFIED: Filtering logic now uses the numerical parameter range ---
127
+ if param_range:
128
+ min_params, max_params = get_param_range_values(param_range)
129
+ is_default_range = (param_range == PARAM_CHOICES_DEFAULT)
130
+
131
+ # Only filter if the range is not the default full range
132
+ if not is_default_range and 'params' in filtered_df.columns:
133
+ # The 'params' column is in billions, so the values match our slider
134
+ if min_params is not None:
135
+ filtered_df = filtered_df[filtered_df['params'] >= min_params]
136
+ if max_params is not None and max_params != float('inf'):
137
+ # The upper bound is exclusive, e.g., 5B to 64B is [5, 64)
138
+ filtered_df = filtered_df[filtered_df['params'] < max_params]
139
+ elif 'params' not in filtered_df.columns:
140
+ print("Warning: 'params' column not found for filtering.")
141
+
142
 
143
  if skip_orgs and len(skip_orgs) > 0:
144
  if "organization" in filtered_df.columns:
 
148
 
149
  if filtered_df.empty: return pd.DataFrame()
150
 
 
151
  if count_by not in filtered_df.columns:
152
  print(f"Warning: Metric column '{count_by}' not found. Using 0.")
153
  filtered_df[count_by] = 0.0
154
  filtered_df[count_by] = pd.to_numeric(filtered_df[count_by], errors="coerce").fillna(0.0)
155
 
 
156
  org_totals = filtered_df.groupby("organization")[count_by].sum().nlargest(top_k, keep='first')
157
  top_orgs_list = org_totals.index.tolist()
158
 
 
159
  treemap_data = filtered_df[filtered_df["organization"].isin(top_orgs_list)][["id", "organization", count_by]].copy()
160
  treemap_data["root"] = "models"
 
161
  treemap_data[count_by] = pd.to_numeric(treemap_data[count_by], errors="coerce").fillna(0.0)
162
  return treemap_data
163
 
 
186
  filter_choice_radio = gr.Radio(label="Filter Type", choices=["None", "Tag Filter", "Pipeline Filter"], value="None")
187
  tag_filter_dropdown = gr.Dropdown(label="Select Tag", choices=TAG_FILTER_CHOICES, value=None, visible=False)
188
  pipeline_filter_dropdown = gr.Dropdown(label="Select Pipeline Tag", choices=PIPELINE_TAGS, value=None, visible=False)
189
+
190
+ # --- MODIFIED: Replaced Dropdown with RangeSlider and a Reset Button ---
191
+ with gr.Group():
192
+ with gr.Row():
193
+ gr.Markdown("<div style='padding-top: 10px; font-weight: 500;'>Parameters</div>")
194
+ reset_params_button = gr.Button("🔄 Reset", visible=False, size="sm", min_width=80)
195
+ param_range_slider = gr.RangeSlider(
196
+ label=None, # Label is handled by Markdown above
197
+ choices=PARAM_CHOICES,
198
+ value=PARAM_CHOICES_DEFAULT,
199
+ )
200
+ # --- END OF MODIFICATION ---
201
+
202
  top_k_slider = gr.Slider(label="Number of Top Organizations", minimum=5, maximum=50, value=25, step=5)
203
  skip_orgs_textbox = gr.Textbox(label="Organizations to Skip (comma-separated)", value="TheBloke,MaziyarPanahi,unsloth,modularai,Gensyn,bartowski")
204
  generate_plot_button = gr.Button(value="Generate Plot", variant="primary", interactive=False)
 
208
  status_message_md = gr.Markdown("Initializing...")
209
  data_info_md = gr.Markdown("")
210
 
211
+ # --- NEW: Event handlers for the new parameter slider and reset button ---
212
+ def _update_reset_button_visibility(current_range):
213
+ """Shows the reset button only if the slider is not at its default full range."""
214
+ is_default = (current_range == PARAM_CHOICES_DEFAULT)
215
+ return gr.update(visible=not is_default)
216
+
217
+ def _reset_param_slider_and_button():
218
+ """Resets the slider to its default value and hides the reset button."""
219
+ return gr.update(value=PARAM_CHOICES_DEFAULT), gr.update(visible=False)
220
+
221
+ param_range_slider.release(fn=_update_reset_button_visibility, inputs=param_range_slider, outputs=reset_params_button)
222
+ reset_params_button.click(fn=_reset_param_slider_and_button, outputs=[param_range_slider, reset_params_button])
223
+ # --- END OF NEW EVENT HANDLERS ---
224
+
225
  def _update_button_interactivity(is_loaded_flag):
226
  return gr.update(interactive=is_loaded_flag)
227
  loading_complete_state.change(fn=_update_button_interactivity, inputs=loading_complete_state, outputs=generate_plot_button)
 
237
  data_info_text = ""
238
  current_df = pd.DataFrame()
239
  load_success_flag = False
 
240
  try:
 
241
  current_df, load_success_flag, status_msg_from_load = load_models_data()
242
  if load_success_flag:
243
  progress(0.9, desc="Processing loaded data...")
 
244
  if 'data_download_timestamp' in current_df.columns and not current_df.empty and pd.notna(current_df['data_download_timestamp'].iloc[0]):
245
+ timestamp_from_parquet = pd.to_datetime(current_df['data_download_timestamp'].iloc[0]).tz_localize('UTC')
 
 
 
246
  data_as_of_date_display = timestamp_from_parquet.strftime('%B %d, %Y, %H:%M:%S %Z')
247
  else:
248
  data_as_of_date_display = "Pre-processed (date unavailable)"
249
 
250
+ # --- MODIFIED: Removed the old size category distribution text ---
251
+ param_count = (current_df['params'] > 0).sum() if 'params' in current_df.columns else 0
 
 
 
 
 
 
 
252
  data_info_text = (f"### Data Information\n"
253
  f"- Source: `{HF_DATASET_ID}`\n"
254
  f"- Overall Status: {status_msg_from_load}\n"
255
  f"- Total models loaded: {len(current_df):,}\n"
256
+ f"- Models with parameter counts: {param_count:,}\n"
257
+ f"- Data as of: {data_as_of_date_display}\n")
258
 
259
  status_msg_ui = "Data loaded successfully. Ready to generate plot."
260
  else:
 
267
  load_success_flag = False
268
  return current_df, load_success_flag, data_info_text, status_msg_ui
269
 
270
+ # --- MODIFIED: Updated controller signature and logic to handle new slider ---
271
  def ui_generate_plot_controller(metric_choice, filter_type, tag_choice, pipeline_choice,
272
+ param_range_choice, k_orgs, skip_orgs_input, df_current_models, progress=gr.Progress()):
273
  if df_current_models is None or df_current_models.empty:
274
  empty_fig = create_treemap(pd.DataFrame(), metric_choice, "Error: Model Data Not Loaded")
275
  error_msg = "Model data is not loaded or is empty. Please wait for data to load."
 
280
 
281
  tag_to_use = tag_choice if filter_type == "Tag Filter" else None
282
  pipeline_to_use = pipeline_choice if filter_type == "Pipeline Filter" else None
 
283
  orgs_to_skip = [org.strip() for org in skip_orgs_input.split(',') if org.strip()] if skip_orgs_input else []
284
 
285
+ # Pass the param_range_choice directly to make_treemap_data
286
+ treemap_df = make_treemap_data(df_current_models, metric_choice, k_orgs, tag_to_use, pipeline_to_use, param_range_choice, orgs_to_skip)
287
 
288
  progress(0.7, desc="Generating Plotly visualization...")
289
 
 
300
 
301
  return plotly_fig, plot_stats_md
302
 
 
303
  demo.load(
304
  fn=ui_load_data_controller,
305
  inputs=[],
306
  outputs=[models_data_state, loading_complete_state, data_info_md, status_message_md]
307
  )
308
 
309
+ # --- MODIFIED: Updated the inputs list for the click event ---
310
  generate_plot_button.click(
311
  fn=ui_generate_plot_controller,
312
  inputs=[count_by_dropdown, filter_choice_radio, tag_filter_dropdown, pipeline_filter_dropdown,
313
+ param_range_slider, top_k_slider, skip_orgs_textbox, models_data_state],
314
  outputs=[plot_output, status_message_md]
315
  )
316
 
317
  if __name__ == "__main__":
318
  print(f"Application starting. Data will be loaded from Hugging Face dataset: {HF_DATASET_ID}")
 
319
  demo.queue().launch()
320
 
321
+ # --- END OF MODIFIED FILE app.py ---