emsesc commited on
Commit
da7a067
·
1 Parent(s): 36502d8

fix toggle & caching issue

Browse files
Files changed (2) hide show
  1. app.py +210 -174
  2. graphs/leaderboard.py +45 -1
app.py CHANGED
@@ -11,12 +11,57 @@ app = Dash()
11
  server = app.server
12
 
13
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14
  # Query for most recent date in all_downloads
15
  def get_last_updated():
16
  try:
17
- result = con.execute(
18
- "SELECT MAX(time) as max_time FROM all_downloads"
19
- ).fetchdf()
 
 
 
20
  max_time = result["max_time"].iloc[0]
21
  if pd.isnull(max_time):
22
  return "N/A"
@@ -26,30 +71,6 @@ def get_last_updated():
26
  return "N/A"
27
 
28
 
29
- def load_parquet_to_duckdb(con, parquet_url, view_name):
30
- """
31
- Loads a parquet file from a remote URL into DuckDB as a view.
32
- Returns (start_dt, end_dt) for the 'time' column.
33
- """
34
- # Install and load httpfs extension for remote file access
35
- con.execute("INSTALL httpfs;")
36
- con.execute("LOAD httpfs;")
37
-
38
- # Create a view that references the remote parquet file
39
- con.execute(f"""
40
- CREATE OR REPLACE VIEW {view_name} AS
41
- SELECT * FROM read_parquet('{parquet_url}')
42
- """)
43
-
44
- # Get time range for slider
45
- time_range = con.execute(
46
- f"SELECT MIN(time) as min_time, MAX(time) as max_time FROM {view_name}"
47
- ).fetchdf()
48
- start_dt = pd.to_datetime(time_range["min_time"].iloc[0])
49
- end_dt = pd.to_datetime(time_range["max_time"].iloc[0])
50
- return start_dt, end_dt
51
-
52
-
53
  # DuckDB connection (global)
54
  con = duckdb.connect(database=":memory:", read_only=False)
55
 
@@ -66,12 +87,14 @@ print(f"Attempting to connect to dataset from Hugging Face Hub: {HF_DATASET_ID}"
66
  try:
67
  overall_start_time = time.time()
68
 
69
- # Load both parquet files as views
70
- start_dt, end_dt = load_parquet_to_duckdb(con, hf_parquet_url_1, "all_downloads")
71
- # Example: load a second parquet file as another view
72
- start_dt2, end_dt2 = load_parquet_to_duckdb(
73
- con, hf_parquet_url_2, "one_year_rolling"
74
- )
 
 
75
 
76
  msg = f"Successfully connected to datasets in {time.time() - overall_start_time:.2f}s."
77
  print(msg)
@@ -753,151 +776,164 @@ def _get_filtered_top_n_from_duckdb(
753
  - percent_of_total (percent of total across all returned model deltas)
754
  """
755
 
756
- # Compute date window (if slider_value provided, use it; otherwise cover full range)
757
- if slider_value and len(slider_value) == 2:
758
- start = pd.to_datetime(slider_value[0], unit="s")
759
- end = pd.to_datetime(slider_value[1], unit="s")
760
- else:
761
- start = pd.to_datetime("1970-01-01")
762
- end = end_dt # defined near top of file when parquet was loaded
763
-
764
- start_str = str(start)
765
- end_str = str(end)
766
-
767
- # If grouping by country, transform some country values
768
- if group_col == "org_country_single":
769
- group_expr = """CASE
770
- WHEN org_country_single IN ('HF', 'United States of America') THEN 'United States of America'
771
- WHEN org_country_single IN ('International', 'Online', 'Online?') THEN 'International/Online'
772
- ELSE org_country_single
773
- END"""
774
- else:
775
- group_expr = group_col
776
 
777
- # Derived-author requires author->country lookup; build separate SQL for that case
778
- if group_col == "derived_author":
779
- query = f"""
780
- WITH base_data AS (
781
- SELECT
782
- {group_expr} AS group_key,
783
- CASE
784
- WHEN org_country_single IN ('HF', 'United States of America') THEN 'United States of America'
785
- WHEN org_country_single IN ('International', 'Online', 'Online?') THEN 'International/Online'
786
- ELSE org_country_single
787
- END AS org_country_single,
788
- author,
789
- derived_author,
790
- merged_country_groups_single,
791
- merged_modality,
792
- model,
793
- time,
794
- downloadsAllTime
795
- FROM {view}
796
- ),
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
797
 
798
- author_country_lookup AS (
799
- SELECT DISTINCT
800
- author,
801
- FIRST_VALUE(org_country_single) OVER (PARTITION BY author ORDER BY downloadsAllTime DESC) AS author_country
802
- FROM base_data
803
- WHERE author IS NOT NULL
804
- ),
805
 
806
- model_metrics AS (
807
- SELECT
808
- model,
809
- group_key,
810
- ANY_VALUE(org_country_single) AS org_country_single,
811
- ANY_VALUE(author) AS author,
812
- ANY_VALUE(derived_author) AS derived_author,
813
- ANY_VALUE(merged_country_groups_single) AS merged_country_groups_single,
814
- ANY_VALUE(merged_modality) AS merged_modality,
815
- COALESCE(MAX(CASE WHEN time <= '{end_str}' THEN downloadsAllTime END), 0)
816
- - COALESCE(MAX(CASE WHEN time < '{start_str}' THEN downloadsAllTime END), 0)
817
- AS total_downloads
818
- FROM base_data
819
- GROUP BY model, group_key
820
- ),
821
 
822
- total_downloads_cte AS (
823
- SELECT SUM(total_downloads) AS total_downloads_all FROM model_metrics
824
- )
825
 
826
- SELECT
827
- mm.model,
828
- mm.group_key,
829
- COALESCE(acl.author_country, mm.org_country_single) AS org_country_single,
830
- mm.author,
831
- mm.derived_author,
832
- mm.merged_country_groups_single,
833
- mm.merged_modality,
834
- mm.total_downloads,
835
- CASE WHEN td.total_downloads_all = 0 THEN 0 ELSE ROUND(mm.total_downloads * 100.0 / td.total_downloads_all, 2) END AS percent_of_total
836
- FROM model_metrics mm
837
- LEFT JOIN author_country_lookup acl ON mm.group_key = acl.author
838
- CROSS JOIN total_downloads_cte td
839
- WHERE mm.total_downloads > 0
840
- ORDER BY mm.total_downloads DESC
841
- LIMIT {top_n * 10};
842
- """
843
- else:
844
- query = f"""
845
- WITH base_data AS (
846
  SELECT
847
- {group_expr} AS group_key,
848
- CASE
849
- WHEN org_country_single IN ('HF', 'United States of America') THEN 'United States of America'
850
- WHEN org_country_single IN ('International', 'Online', 'Online?') THEN 'International/Online'
851
- ELSE org_country_single
852
- END AS org_country_single,
853
- author,
854
- derived_author,
855
- merged_country_groups_single,
856
- merged_modality,
857
- model,
858
- time,
859
- downloadsAllTime
860
- FROM {view}
861
- ),
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
862
 
863
- model_metrics AS (
864
- SELECT
865
- model,
866
- group_key,
867
- ANY_VALUE(org_country_single) AS org_country_single,
868
- ANY_VALUE(author) AS author,
869
- ANY_VALUE(derived_author) AS derived_author,
870
- ANY_VALUE(merged_country_groups_single) AS merged_country_groups_single,
871
- ANY_VALUE(merged_modality) AS merged_modality,
872
- COALESCE(MAX(CASE WHEN time <= '{end_str}' THEN downloadsAllTime END), 0)
873
- - COALESCE(MAX(CASE WHEN time < '{start_str}' THEN downloadsAllTime END), 0)
874
- AS total_downloads
875
- FROM base_data
876
- GROUP BY model, group_key
877
- ),
878
 
879
- total_downloads_cte AS (
880
- SELECT SUM(total_downloads) AS total_downloads_all FROM model_metrics
881
- )
882
 
883
- SELECT
884
- mm.model,
885
- mm.group_key,
886
- mm.org_country_single,
887
- mm.author,
888
- mm.derived_author,
889
- mm.merged_country_groups_single,
890
- mm.merged_modality,
891
- mm.total_downloads,
892
- CASE WHEN td.total_downloads_all = 0 THEN 0 ELSE ROUND(mm.total_downloads * 100.0 / td.total_downloads_all, 2) END AS percent_of_total
893
- FROM model_metrics mm
894
- CROSS JOIN total_downloads_cte td
895
- WHERE mm.total_downloads > 0
896
- ORDER BY mm.total_downloads DESC
897
- LIMIT {top_n * 10};
898
- """
899
-
900
- return con.execute(query).fetchdf()
 
 
 
 
901
 
902
 
903
  def _leaderboard_callback_logic(
@@ -991,7 +1027,7 @@ def update_top_countries(
991
  default_label="▼ Show Top 50",
992
  chip_color="#F0F9FF",
993
  view=selected_view,
994
- derived_author_toggle=(attribution_type == "uploader"),
995
  )
996
 
997
 
@@ -1007,8 +1043,8 @@ def update_top_countries(
1007
  def update_top_developers(
1008
  n_clicks, slider_value, selected_view, attribution_type, current_label
1009
  ):
1010
- # Use derived_author if attribution_type == "uploader", else author
1011
- group_col = "derived_author" if attribution_type == "uploader" else "author"
1012
  return _leaderboard_callback_logic(
1013
  n_clicks,
1014
  slider_value,
@@ -1018,7 +1054,7 @@ def update_top_developers(
1018
  default_label="▼ Show Top 50",
1019
  chip_color="#F0F9FF",
1020
  view=selected_view,
1021
- derived_author_toggle=(attribution_type == "uploader"),
1022
  )
1023
 
1024
 
@@ -1043,7 +1079,7 @@ def update_top_models(
1043
  default_label="▼ Show More",
1044
  chip_color="#F0F9FF",
1045
  view=selected_view,
1046
- derived_author_toggle=(attribution_type == "uploader"),
1047
  )
1048
 
1049
 
 
11
  server = app.server
12
 
13
 
14
+ # Add dataset URLs (used by the helper to create views)
15
+ HF_DATASET_ID = "mmpr/open_model_evolution_data"
16
+ hf_parquet_url_1 = "https://huggingface.co/datasets/emsesc/open_model_evolution_data/resolve/main/all_downloads_with_annotations.parquet"
17
+ hf_parquet_url_2 = "https://huggingface.co/datasets/emsesc/open_model_evolution_data/resolve/main/one_year_rolling.parquet"
18
+
19
+ # Helper: create a fresh in-memory DuckDB connection and (re)create parquet-backed views.
20
+ def create_fresh_duckdb_with_views():
21
+ """
22
+ Returns a fresh in-memory DuckDB connection with httpfs enabled and the
23
+ all_downloads / one_year_rolling views created from the remote parquet URLs.
24
+ Caller must close the returned connection.
25
+ """
26
+ local_con = duckdb.connect(database=":memory:", read_only=False)
27
+ try:
28
+ # try to install/load httpfs if necessary; ignore errors if preinstalled
29
+ try:
30
+ local_con.execute("INSTALL httpfs;")
31
+ local_con.execute("LOAD httpfs;")
32
+ except Exception:
33
+ pass
34
+
35
+ # keep HF Spaces behavior consistent
36
+ try:
37
+ local_con.execute("SET enable_http_metadata_cache = false;")
38
+ local_con.execute("SET enable_object_cache = false;")
39
+ except Exception:
40
+ pass
41
+
42
+ # create views referencing remote parquet files
43
+ local_con.execute(f"""
44
+ CREATE OR REPLACE VIEW all_downloads AS
45
+ SELECT * FROM read_parquet('{hf_parquet_url_1}')
46
+ """)
47
+ local_con.execute(f"""
48
+ CREATE OR REPLACE VIEW one_year_rolling AS
49
+ SELECT * FROM read_parquet('{hf_parquet_url_2}')
50
+ """)
51
+ except Exception:
52
+ # If view creation fails, ensure connection is still returned for caller to handle/close
53
+ pass
54
+ return local_con
55
+
56
  # Query for most recent date in all_downloads
57
  def get_last_updated():
58
  try:
59
+ conn = create_fresh_duckdb_with_views()
60
+ try:
61
+ result = conn.execute("SELECT MAX(time) as max_time FROM all_downloads").fetchdf()
62
+ finally:
63
+ conn.close()
64
+
65
  max_time = result["max_time"].iloc[0]
66
  if pd.isnull(max_time):
67
  return "N/A"
 
71
  return "N/A"
72
 
73
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
74
  # DuckDB connection (global)
75
  con = duckdb.connect(database=":memory:", read_only=False)
76
 
 
87
  try:
88
  overall_start_time = time.time()
89
 
90
+ # Create fresh connection, views, and read start/end time
91
+ conn = create_fresh_duckdb_with_views()
92
+ try:
93
+ time_range = conn.execute("SELECT MIN(time) as min_time, MAX(time) as max_time FROM all_downloads").fetchdf()
94
+ start_dt = pd.to_datetime(time_range["min_time"].iloc[0])
95
+ end_dt = pd.to_datetime(time_range["max_time"].iloc[0])
96
+ finally:
97
+ conn.close()
98
 
99
  msg = f"Successfully connected to datasets in {time.time() - overall_start_time:.2f}s."
100
  print(msg)
 
776
  - percent_of_total (percent of total across all returned model deltas)
777
  """
778
 
779
+ # Create a fresh connection and load parquet-backed views for each call
780
+ local_con = create_fresh_duckdb_with_views()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
781
 
782
+ try:
783
+ # Compute date window (if slider_value provided, use it; otherwise cover full range)
784
+ if slider_value and len(slider_value) == 2:
785
+ start = pd.to_datetime(slider_value[0], unit="s")
786
+ end = pd.to_datetime(slider_value[1], unit="s")
787
+ else:
788
+ start = pd.to_datetime("1970-01-01")
789
+ # keep previous behavior if end_dt exists
790
+ try:
791
+ end_local = end_dt # may be defined from initial load
792
+ except NameError:
793
+ end_local = pd.Timestamp.now()
794
+ end = end_local
795
+
796
+ start_str = str(start)
797
+ end_str = str(end)
798
+
799
+ # If grouping by country, transform some country values
800
+ if group_col == "org_country_single":
801
+ group_expr = """CASE
802
+ WHEN org_country_single IN ('HF', 'United States of America') THEN 'United States of America'
803
+ WHEN org_country_single IN ('International', 'Online', 'Online?') THEN 'International/Online'
804
+ ELSE org_country_single
805
+ END"""
806
+ else:
807
+ group_expr = group_col
808
+
809
+ # Derived-author requires author->country lookup; build separate SQL for that case
810
+ if group_col == "derived_author":
811
+ query = f"""
812
+ WITH base_data AS (
813
+ SELECT
814
+ {group_expr} AS group_key,
815
+ CASE
816
+ WHEN org_country_single IN ('HF', 'United States of America') THEN 'United States of America'
817
+ WHEN org_country_single IN ('International', 'Online', 'Online?') THEN 'International/Online'
818
+ ELSE org_country_single
819
+ END AS org_country_single,
820
+ author,
821
+ derived_author,
822
+ merged_country_groups_single,
823
+ merged_modality,
824
+ model,
825
+ time,
826
+ downloadsAllTime
827
+ FROM {view}
828
+ ),
829
 
830
+ author_country_lookup AS (
831
+ SELECT DISTINCT
832
+ author,
833
+ FIRST_VALUE(org_country_single) OVER (PARTITION BY author ORDER BY downloadsAllTime DESC) AS author_country
834
+ FROM base_data
835
+ WHERE author IS NOT NULL
836
+ ),
837
 
838
+ model_metrics AS (
839
+ SELECT
840
+ model,
841
+ group_key,
842
+ ANY_VALUE(org_country_single) AS org_country_single,
843
+ ANY_VALUE(author) AS author,
844
+ ANY_VALUE(derived_author) AS derived_author,
845
+ ANY_VALUE(merged_country_groups_single) AS merged_country_groups_single,
846
+ ANY_VALUE(merged_modality) AS merged_modality,
847
+ COALESCE(MAX(CASE WHEN time <= '{end_str}' THEN downloadsAllTime END), 0)
848
+ - COALESCE(MAX(CASE WHEN time < '{start_str}' THEN downloadsAllTime END), 0)
849
+ AS total_downloads
850
+ FROM base_data
851
+ GROUP BY model, group_key
852
+ ),
853
 
854
+ total_downloads_cte AS (
855
+ SELECT SUM(total_downloads) AS total_downloads_all FROM model_metrics
856
+ )
857
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
858
  SELECT
859
+ mm.model,
860
+ mm.group_key,
861
+ COALESCE(acl.author_country, mm.org_country_single) AS org_country_single,
862
+ mm.author,
863
+ mm.derived_author,
864
+ mm.merged_country_groups_single,
865
+ mm.merged_modality,
866
+ mm.total_downloads,
867
+ CASE WHEN td.total_downloads_all = 0 THEN 0 ELSE ROUND(mm.total_downloads * 100.0 / td.total_downloads_all, 2) END AS percent_of_total
868
+ FROM model_metrics mm
869
+ LEFT JOIN author_country_lookup acl ON mm.group_key = acl.author
870
+ CROSS JOIN total_downloads_cte td
871
+ WHERE mm.total_downloads > 0
872
+ ORDER BY mm.total_downloads DESC
873
+ LIMIT {top_n * 10};
874
+ """
875
+ else:
876
+ query = f"""
877
+ WITH base_data AS (
878
+ SELECT
879
+ {group_expr} AS group_key,
880
+ CASE
881
+ WHEN org_country_single IN ('HF', 'United States of America') THEN 'United States of America'
882
+ WHEN org_country_single IN ('International', 'Online', 'Online?') THEN 'International/Online'
883
+ ELSE org_country_single
884
+ END AS org_country_single,
885
+ author,
886
+ derived_author,
887
+ merged_country_groups_single,
888
+ merged_modality,
889
+ model,
890
+ time,
891
+ downloadsAllTime
892
+ FROM {view}
893
+ ),
894
 
895
+ model_metrics AS (
896
+ SELECT
897
+ model,
898
+ group_key,
899
+ ANY_VALUE(org_country_single) AS org_country_single,
900
+ ANY_VALUE(author) AS author,
901
+ ANY_VALUE(derived_author) AS derived_author,
902
+ ANY_VALUE(merged_country_groups_single) AS merged_country_groups_single,
903
+ ANY_VALUE(merged_modality) AS merged_modality,
904
+ COALESCE(MAX(CASE WHEN time <= '{end_str}' THEN downloadsAllTime END), 0)
905
+ - COALESCE(MAX(CASE WHEN time < '{start_str}' THEN downloadsAllTime END), 0)
906
+ AS total_downloads
907
+ FROM base_data
908
+ GROUP BY model, group_key
909
+ ),
910
 
911
+ total_downloads_cte AS (
912
+ SELECT SUM(total_downloads) AS total_downloads_all FROM model_metrics
913
+ )
914
 
915
+ SELECT
916
+ mm.model,
917
+ mm.group_key,
918
+ mm.org_country_single,
919
+ mm.author,
920
+ mm.derived_author,
921
+ mm.merged_country_groups_single,
922
+ mm.merged_modality,
923
+ mm.total_downloads,
924
+ CASE WHEN td.total_downloads_all = 0 THEN 0 ELSE ROUND(mm.total_downloads * 100.0 / td.total_downloads_all, 2) END AS percent_of_total
925
+ FROM model_metrics mm
926
+ CROSS JOIN total_downloads_cte td
927
+ WHERE mm.total_downloads > 0
928
+ ORDER BY mm.total_downloads DESC
929
+ LIMIT {top_n * 10};
930
+ """
931
+
932
+ # execute using the fresh local connection
933
+ result_df = local_con.execute(query).fetchdf()
934
+ return result_df
935
+ finally:
936
+ local_con.close()
937
 
938
 
939
  def _leaderboard_callback_logic(
 
1027
  default_label="▼ Show Top 50",
1028
  chip_color="#F0F9FF",
1029
  view=selected_view,
1030
+ derived_author_toggle=(attribution_type == "original_creator"),
1031
  )
1032
 
1033
 
 
1043
  def update_top_developers(
1044
  n_clicks, slider_value, selected_view, attribution_type, current_label
1045
  ):
1046
+ # Use derived_author if attribution_type == "original_creator", else author
1047
+ group_col = "derived_author" if attribution_type == "original_creator" else "author"
1048
  return _leaderboard_callback_logic(
1049
  n_clicks,
1050
  slider_value,
 
1054
  default_label="▼ Show Top 50",
1055
  chip_color="#F0F9FF",
1056
  view=selected_view,
1057
+ derived_author_toggle=(attribution_type == "original_creator"),
1058
  )
1059
 
1060
 
 
1079
  default_label="▼ Show More",
1080
  chip_color="#F0F9FF",
1081
  view=selected_view,
1082
+ derived_author_toggle=(attribution_type == "original_creator"),
1083
  )
1084
 
1085
 
graphs/leaderboard.py CHANGED
@@ -4,6 +4,7 @@ from dash_iconify import DashIconify
4
  import dash_mantine_components as dmc
5
  import base64
6
  import countryflag
 
7
 
8
  button_style = {
9
  "display": "inline-block",
@@ -458,12 +459,51 @@ def get_top_n_leaderboard(filtered_df, group_col, top_n=10, derived_author_toggl
458
  return display_for_render, download_top
459
 
460
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
461
  def get_top_n_from_duckdb(
462
  con, group_col, top_n=10, time_filter=None, view="all_downloads"
463
  ):
464
  """
465
  Query DuckDB directly to get model-level rows with per-model total_downloads (delta or full)
466
  Returns rows similar to _get_filtered_top_n_from_duckdb in app.py.
 
 
467
  """
468
  # Compute date window
469
  if time_filter and len(time_filter) == 2:
@@ -610,11 +650,15 @@ def get_top_n_from_duckdb(
610
  LIMIT {top_n * 10};
611
  """
612
 
 
 
613
  try:
614
- return con.execute(query).fetchdf()
615
  except Exception as e:
616
  print(f"Error querying DuckDB: {e}")
617
  return pd.DataFrame()
 
 
618
 
619
 
620
  def format_large_number(n):
 
4
  import dash_mantine_components as dmc
5
  import base64
6
  import countryflag
7
+ import duckdb
8
 
9
  button_style = {
10
  "display": "inline-block",
 
459
  return display_for_render, download_top
460
 
461
 
462
+ # Add dataset URLs used to create views when running queries from this module
463
+ hf_parquet_url_1 = "https://huggingface.co/datasets/emsesc/open_model_evolution_data/resolve/main/all_downloads_with_annotations.parquet"
464
+ hf_parquet_url_2 = "https://huggingface.co/datasets/emsesc/open_model_evolution_data/resolve/main/one_year_rolling.parquet"
465
+
466
+
467
+ def create_fresh_duckdb_with_views():
468
+ """
469
+ Returns a fresh in-memory DuckDB connection with httpfs enabled and the
470
+ all_downloads / one_year_rolling views created from the remote parquet URLs.
471
+ Caller must close the returned connection.
472
+ """
473
+ local_con = duckdb.connect(database=":memory:", read_only=False)
474
+ try:
475
+ try:
476
+ local_con.execute("INSTALL httpfs;")
477
+ local_con.execute("LOAD httpfs;")
478
+ except Exception:
479
+ pass
480
+ try:
481
+ local_con.execute("SET enable_http_metadata_cache = false;")
482
+ local_con.execute("SET enable_object_cache = false;")
483
+ except Exception:
484
+ pass
485
+
486
+ local_con.execute(f"""
487
+ CREATE OR REPLACE VIEW all_downloads AS
488
+ SELECT * FROM read_parquet('{hf_parquet_url_1}')
489
+ """)
490
+ local_con.execute(f"""
491
+ CREATE OR REPLACE VIEW one_year_rolling AS
492
+ SELECT * FROM read_parquet('{hf_parquet_url_2}')
493
+ """)
494
+ except Exception:
495
+ pass
496
+ return local_con
497
+
498
+
499
  def get_top_n_from_duckdb(
500
  con, group_col, top_n=10, time_filter=None, view="all_downloads"
501
  ):
502
  """
503
  Query DuckDB directly to get model-level rows with per-model total_downloads (delta or full)
504
  Returns rows similar to _get_filtered_top_n_from_duckdb in app.py.
505
+ NOTE: This function now opens a fresh DuckDB connection internally and ignores
506
+ any external connection passed in. Keep signature for compatibility.
507
  """
508
  # Compute date window
509
  if time_filter and len(time_filter) == 2:
 
650
  LIMIT {top_n * 10};
651
  """
652
 
653
+ # Open a fresh in-memory connection that creates the views, run the query, close.
654
+ conn_local = create_fresh_duckdb_with_views()
655
  try:
656
+ return conn_local.execute(query).fetchdf()
657
  except Exception as e:
658
  print(f"Error querying DuckDB: {e}")
659
  return pd.DataFrame()
660
+ finally:
661
+ conn_local.close()
662
 
663
 
664
  def format_large_number(n):