yonigozlan HF Staff commited on
Commit
2225a22
·
1 Parent(s): 45f6190

update app

Browse files
Files changed (1) hide show
  1. app.py +166 -28
app.py CHANGED
@@ -7,7 +7,6 @@ import glob
7
  import os
8
  import re
9
  import sys
10
- import threading
11
  import time
12
  import webbrowser
13
  from datetime import datetime
@@ -906,13 +905,15 @@ def create_timeline_template():
906
  }
907
 
908
  .header {
909
- background: rgba(255, 255, 255, 0.95);
910
  backdrop-filter: blur(10px);
911
- padding: 0.5rem 1.5rem;
912
  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
 
913
  position: sticky;
914
  top: 0;
915
  z-index: 100;
 
916
  }
917
 
918
  .header h1 {
@@ -928,17 +929,67 @@ def create_timeline_template():
928
  margin: 0;
929
  }
930
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
931
  .controls {
932
  background: rgba(255, 255, 255, 0.9);
933
  backdrop-filter: blur(10px);
934
  padding: 0.4rem 1rem;
935
- margin: 0.3rem 2rem;
936
  border-radius: 8px;
937
  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.06);
938
  display: flex;
939
- gap: 0.5rem;
940
  align-items: start;
941
- flex-wrap: wrap;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
942
  }
943
 
944
  .input-group {
@@ -970,8 +1021,9 @@ def create_timeline_template():
970
  }
971
 
972
  .modality-group {
973
- flex: 1.5;
974
- min-width: 200px;
 
975
  }
976
 
977
  .modality-filters {
@@ -988,8 +1040,8 @@ def create_timeline_template():
988
  }
989
 
990
  .task-group {
991
- flex: 4;
992
- min-width: 400px;
993
  }
994
 
995
  .task-filters {
@@ -1499,10 +1551,10 @@ def create_timeline_template():
1499
 
1500
  /* Expanded card styles */
1501
  .timeline-label.expanded {
1502
- max-width: 450px !important;
1503
- min-width: 350px !important;
1504
- width: 450px !important;
1505
- min-height: 300px !important;
1506
  text-align: left;
1507
  z-index: 9999 !important; /* Much higher than all other elements */
1508
  transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
@@ -1533,6 +1585,9 @@ def create_timeline_template():
1533
  color: #1f2937;
1534
  border-bottom: 1px solid rgba(0, 0, 0, 0.1);
1535
  padding-bottom: 0.3rem;
 
 
 
1536
  }
1537
 
1538
  .timeline-label .model-description {
@@ -1786,8 +1841,8 @@ def create_timeline_template():
1786
 
1787
  .date-input-group {
1788
  display: flex;
1789
- flex-direction: column;
1790
- gap: 0.3rem;
1791
  align-items: center;
1792
  }
1793
 
@@ -1795,7 +1850,7 @@ def create_timeline_template():
1795
  font-size: 0.7rem;
1796
  color: #4a5568;
1797
  font-weight: 600;
1798
- text-align: center;
1799
  }
1800
 
1801
  .date-input-group input {
@@ -1895,10 +1950,12 @@ def create_timeline_template():
1895
  <body>
1896
  <div class="header">
1897
  <h1>🤗 Transformers Models Timeline</h1>
1898
- <p>Interactive timeline showing when models were added to the Hugging Face Transformers library</p>
1899
  </div>
1900
 
1901
- <div class="controls">
 
 
1902
  <div class="input-group modality-group">
1903
  <label>Modalities</label>
1904
  <div class="modality-filters" id="modalityFilters">
@@ -1927,6 +1984,7 @@ def create_timeline_template():
1927
  </button>
1928
  </div>
1929
  </div>
 
1930
  </div>
1931
 
1932
  <div class="timeline-container">
@@ -1977,6 +2035,7 @@ def create_timeline_template():
1977
  let timelineOffset = 0;
1978
  let timelineWidth = 0;
1979
  let containerWidth = 0;
 
1980
  let isDragging = false;
1981
  let startX = 0;
1982
  let startOffset = 0;
@@ -2018,6 +2077,31 @@ def create_timeline_template():
2018
  allModels = data.models;
2019
  currentModels = data.models;
2020
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2021
  updateStats(data.total_count, data.filtered_count);
2022
  renderTimeline(currentModels);
2023
 
@@ -2877,10 +2961,72 @@ def create_timeline_template():
2877
  if (!e.target.closest('.timeline-label')) {
2878
  document.querySelectorAll('.timeline-label.expanded').forEach(label => {
2879
  label.classList.remove('expanded');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2880
  });
2881
  }
2882
  });
 
 
 
2883
  });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2884
  </script>
2885
  </body>
2886
  </html>"""
@@ -2892,7 +3038,7 @@ def create_timeline_template():
2892
  def open_browser():
2893
  """Open the browser after a short delay."""
2894
  time.sleep(1.5)
2895
- webbrowser.open("http://localhost:7860")
2896
 
2897
 
2898
  def main():
@@ -2916,14 +3062,6 @@ def main():
2916
  else:
2917
  print(f"✅ Found {len(models)} models with release dates")
2918
 
2919
- print("\n🚀 Starting timeline server...")
2920
- print("📱 Opening in browser...")
2921
- print("🌐 Access at: http://localhost:7860")
2922
- print("🛑 Press Ctrl+C to stop")
2923
-
2924
- # Start browser opening in background
2925
- threading.Thread(target=open_browser, daemon=True).start()
2926
-
2927
  # Run Flask app
2928
  try:
2929
  app.run(host="0.0.0.0", port=7860, debug=False)
 
7
  import os
8
  import re
9
  import sys
 
10
  import time
11
  import webbrowser
12
  from datetime import datetime
 
905
  }
906
 
907
  .header {
908
+ background: rgba(255, 255, 255, 0.9);
909
  backdrop-filter: blur(10px);
910
+ padding: 0.8rem 1.5rem;
911
  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
912
+ border-bottom: 1px solid rgba(255, 255, 255, 0.5);
913
  position: sticky;
914
  top: 0;
915
  z-index: 100;
916
+ margin: 0 0 0.3rem 0;
917
  }
918
 
919
  .header h1 {
 
929
  margin: 0;
930
  }
931
 
932
+ .controls-wrapper {
933
+ margin: 0.3rem 2rem;
934
+ }
935
+
936
+ .controls-toggle {
937
+ position: absolute;
938
+ left: 8px;
939
+ right: 8px;
940
+ top: 8px;
941
+ z-index: 2;
942
+ display: inline-flex;
943
+ align-items: center;
944
+ justify-content: center;
945
+ width: 28px;
946
+ height: 28px;
947
+ font-size: 0.9rem;
948
+ border-radius: 999px;
949
+ border: 1px solid #e5e7eb;
950
+ background: #ffffff;
951
+ color: #374151;
952
+ cursor: pointer;
953
+ transition: all 0.2s ease;
954
+ box-shadow: 0 2px 8px rgba(0,0,0,0.06);
955
+ }
956
+
957
+ .controls-toggle:hover {
958
+ transform: translateY(-1px);
959
+ box-shadow: 0 4px 14px rgba(0,0,0,0.1);
960
+ }
961
+
962
  .controls {
963
  background: rgba(255, 255, 255, 0.9);
964
  backdrop-filter: blur(10px);
965
  padding: 0.4rem 1rem;
 
966
  border-radius: 8px;
967
  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.06);
968
  display: flex;
969
+ gap: 0.8rem;
970
  align-items: start;
971
+ flex-wrap: nowrap;
972
+ overflow: hidden;
973
+ transition: max-height 0.25s ease, opacity 0.2s ease;
974
+ position: relative;
975
+ padding-left: 2.4rem; /* space for the left toggle button */
976
+ max-height: none; /* will be set dynamically */
977
+ }
978
+
979
+ .controls.collapsed {
980
+ opacity: 1;
981
+ }
982
+
983
+ /* Blur fade to hint there is more content when collapsed */
984
+ .controls.collapsed::after {
985
+ content: '';
986
+ position: absolute;
987
+ left: 0;
988
+ right: 0;
989
+ bottom: 0;
990
+ height: 26px;
991
+ background: linear-gradient(to bottom, rgba(255,255,255,0), rgba(255,255,255,0.94) 60%, rgba(255,255,255,1));
992
+ pointer-events: none;
993
  }
994
 
995
  .input-group {
 
1021
  }
1022
 
1023
  .modality-group {
1024
+ flex: 22%;
1025
+ min-width: 220px;
1026
+ padding-left: 8px; /* add small spacing from collapse arrow */
1027
  }
1028
 
1029
  .modality-filters {
 
1040
  }
1041
 
1042
  .task-group {
1043
+ flex: 78%;
1044
+ min-width: 520px;
1045
  }
1046
 
1047
  .task-filters {
 
1551
 
1552
  /* Expanded card styles */
1553
  .timeline-label.expanded {
1554
+ max-width: 500px !important;
1555
+ min-width: 400px !important;
1556
+ width: 500px !important;
1557
+ min-height: 250px !important;
1558
  text-align: left;
1559
  z-index: 9999 !important; /* Much higher than all other elements */
1560
  transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
 
1585
  color: #1f2937;
1586
  border-bottom: 1px solid rgba(0, 0, 0, 0.1);
1587
  padding-bottom: 0.3rem;
1588
+ white-space: nowrap;
1589
+ overflow: hidden;
1590
+ text-overflow: ellipsis;
1591
  }
1592
 
1593
  .timeline-label .model-description {
 
1841
 
1842
  .date-input-group {
1843
  display: flex;
1844
+ flex-direction: row;
1845
+ gap: 0.5rem;
1846
  align-items: center;
1847
  }
1848
 
 
1850
  font-size: 0.7rem;
1851
  color: #4a5568;
1852
  font-weight: 600;
1853
+ white-space: nowrap;
1854
  }
1855
 
1856
  .date-input-group input {
 
1950
  <body>
1951
  <div class="header">
1952
  <h1>🤗 Transformers Models Timeline</h1>
1953
+ <p>Interactive timeline to explore models supported by the Hugging Face Transformers library!</p>
1954
  </div>
1955
 
1956
+ <div class="controls-wrapper">
1957
+ <div class="controls" id="filtersPanel">
1958
+ <button id="toggleFilters" class="controls-toggle" type="button" aria-label="Toggle filters" onclick="toggleFilters()">▾</button>
1959
  <div class="input-group modality-group">
1960
  <label>Modalities</label>
1961
  <div class="modality-filters" id="modalityFilters">
 
1984
  </button>
1985
  </div>
1986
  </div>
1987
+ </div>
1988
  </div>
1989
 
1990
  <div class="timeline-container">
 
2035
  let timelineOffset = 0;
2036
  let timelineWidth = 0;
2037
  let containerWidth = 0;
2038
+ let dateInitialized = false; // initialize date inputs once from data
2039
  let isDragging = false;
2040
  let startX = 0;
2041
  let startOffset = 0;
 
2077
  allModels = data.models;
2078
  currentModels = data.models;
2079
 
2080
+ // Initialize date inputs to min/max once (based on current data)
2081
+ if (!dateInitialized && currentModels && currentModels.length > 0) {
2082
+ const validDates = currentModels
2083
+ .map(m => m.transformers_date)
2084
+ .filter(d => !!d)
2085
+ .sort();
2086
+ if (validDates.length > 0) {
2087
+ const minDate = validDates[0];
2088
+ const maxDate = validDates[validDates.length - 1];
2089
+ const startEl = document.getElementById('startDate');
2090
+ const endEl = document.getElementById('endDate');
2091
+ if (startEl) {
2092
+ startEl.min = minDate;
2093
+ startEl.max = maxDate;
2094
+ if (!startEl.value) startEl.value = minDate;
2095
+ }
2096
+ if (endEl) {
2097
+ endEl.min = minDate;
2098
+ endEl.max = maxDate;
2099
+ if (!endEl.value) endEl.value = maxDate;
2100
+ }
2101
+ dateInitialized = true;
2102
+ }
2103
+ }
2104
+
2105
  updateStats(data.total_count, data.filtered_count);
2106
  renderTimeline(currentModels);
2107
 
 
2961
  if (!e.target.closest('.timeline-label')) {
2962
  document.querySelectorAll('.timeline-label.expanded').forEach(label => {
2963
  label.classList.remove('expanded');
2964
+
2965
+ // Restore compact content
2966
+ setTimeout(() => {
2967
+ label.innerHTML = `
2968
+ <div class="model-title">${label.dataset.modelName}</div>
2969
+ <div class="timeline-date">${label.dataset.modelDate}</div>
2970
+ `;
2971
+
2972
+ // Reset positioning after content change
2973
+ setTimeout(() => {
2974
+ label.style.top = '';
2975
+ label.style.bottom = '';
2976
+ label.parentElement.style.zIndex = '';
2977
+ }, 50);
2978
+ }, 50);
2979
  });
2980
  }
2981
  });
2982
+
2983
+ // Initialize filters collapsible panel
2984
+ initFiltersCollapsible();
2985
  });
2986
+
2987
+ function initFiltersCollapsible() {
2988
+ const panel = document.getElementById('filtersPanel');
2989
+ const btn = document.getElementById('toggleFilters');
2990
+ if (!panel || !btn) return;
2991
+
2992
+ // Restore persisted state, default to collapsed
2993
+ const saved = localStorage.getItem('filtersCollapsed');
2994
+ if (saved === 'false') {
2995
+ // Set natural max-height to allow animation on first collapse
2996
+ panel.style.maxHeight = panel.scrollHeight + 'px';
2997
+ btn.textContent = '▾';
2998
+ } else {
2999
+ // set partial height (~2 rows) when collapsed (default state)
3000
+ const partial = 74; // pixels to show when collapsed
3001
+ panel.style.maxHeight = partial + 'px';
3002
+ panel.classList.add('collapsed');
3003
+ btn.textContent = '▸';
3004
+ }
3005
+ }
3006
+
3007
+ function toggleFilters() {
3008
+ const panel = document.getElementById('filtersPanel');
3009
+ const btn = document.getElementById('toggleFilters');
3010
+ if (!panel || !btn) return;
3011
+
3012
+ const isCollapsed = panel.classList.contains('collapsed');
3013
+ if (isCollapsed) {
3014
+ // expand to full content height
3015
+ panel.classList.remove('collapsed');
3016
+ panel.style.maxHeight = panel.scrollHeight + 'px';
3017
+ btn.textContent = '▾';
3018
+ localStorage.setItem('filtersCollapsed', 'false');
3019
+ } else {
3020
+ // collapse to partial height (show a hint of content)
3021
+ panel.style.maxHeight = panel.scrollHeight + 'px'; // set current height
3022
+ void panel.offsetHeight; // reflow
3023
+ panel.classList.add('collapsed');
3024
+ const partial = 74; // pixels to show when collapsed
3025
+ panel.style.maxHeight = partial + 'px';
3026
+ btn.textContent = '▸';
3027
+ localStorage.setItem('filtersCollapsed', 'true');
3028
+ }
3029
+ }
3030
  </script>
3031
  </body>
3032
  </html>"""
 
3038
  def open_browser():
3039
  """Open the browser after a short delay."""
3040
  time.sleep(1.5)
3041
+ webbrowser.open("http://localhost:5000")
3042
 
3043
 
3044
  def main():
 
3062
  else:
3063
  print(f"✅ Found {len(models)} models with release dates")
3064
 
 
 
 
 
 
 
 
 
3065
  # Run Flask app
3066
  try:
3067
  app.run(host="0.0.0.0", port=7860, debug=False)