Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -34,6 +34,30 @@ def cached_list_items(username, kind):
|
|
| 34 |
return []
|
| 35 |
|
| 36 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 37 |
# Rate limiting
|
| 38 |
class RateLimiter:
|
| 39 |
def __init__(self, calls_per_second=10):
|
|
@@ -180,37 +204,99 @@ def make_calendar_heatmap(df, title, year):
|
|
| 180 |
# Sidebar
|
| 181 |
with st.sidebar:
|
| 182 |
st.title("π€ Contributor")
|
| 183 |
-
|
| 184 |
-
|
| 185 |
-
|
| 186 |
-
|
| 187 |
-
|
| 188 |
-
|
| 189 |
-
|
| 190 |
-
|
| 191 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 192 |
year_options = list(range(datetime.now().year, 2017, -1))
|
| 193 |
-
selected_year = st.selectbox("
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 194 |
|
| 195 |
# Main Content
|
| 196 |
st.title("π€ Hugging Face Contributions")
|
| 197 |
if username:
|
| 198 |
-
with st.spinner("Fetching commit data..."):
|
| 199 |
# Create a dictionary to store commits by type
|
| 200 |
commits_by_type = {}
|
| 201 |
commit_counts_by_type = {}
|
| 202 |
-
|
| 203 |
-
#
|
| 204 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 205 |
try:
|
| 206 |
items = cached_list_items(username, kind)
|
| 207 |
repo_ids = [item.id for item in items]
|
|
|
|
|
|
|
| 208 |
|
| 209 |
# Process repos in chunks
|
| 210 |
chunk_size = 5
|
| 211 |
total_commits = 0
|
| 212 |
all_commit_dates = []
|
| 213 |
|
|
|
|
| 214 |
for i in range(0, len(repo_ids), chunk_size):
|
| 215 |
chunk = repo_ids[i:i + chunk_size]
|
| 216 |
with ThreadPoolExecutor(max_workers=min(5, len(chunk))) as executor:
|
|
@@ -223,6 +309,13 @@ if username:
|
|
| 223 |
if repo_commits:
|
| 224 |
all_commit_dates.extend(repo_commits)
|
| 225 |
total_commits += repo_count
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 226 |
|
| 227 |
commits_by_type[kind] = all_commit_dates
|
| 228 |
commit_counts_by_type[kind] = total_commits
|
|
@@ -236,7 +329,20 @@ if username:
|
|
| 236 |
total_commits = sum(commit_counts_by_type.values())
|
| 237 |
|
| 238 |
st.subheader(f"{username}'s Activity in {selected_year}")
|
| 239 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 240 |
|
| 241 |
# Create DataFrame for all commits
|
| 242 |
all_commits = []
|
|
@@ -248,26 +354,30 @@ if username:
|
|
| 248 |
|
| 249 |
make_calendar_heatmap(all_df, "All Commits", selected_year)
|
| 250 |
|
| 251 |
-
# Metrics and heatmaps for each type
|
| 252 |
-
|
| 253 |
-
|
| 254 |
-
|
| 255 |
-
(
|
| 256 |
-
(
|
| 257 |
-
|
| 258 |
-
|
| 259 |
-
|
| 260 |
-
|
| 261 |
-
|
| 262 |
-
|
| 263 |
-
|
| 264 |
-
|
| 265 |
-
df_kind =
|
| 266 |
-
|
| 267 |
-
|
| 268 |
-
|
| 269 |
-
|
| 270 |
-
|
| 271 |
-
|
| 272 |
-
|
| 273 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 34 |
return []
|
| 35 |
|
| 36 |
|
| 37 |
+
# Function to fetch trending model repositories
|
| 38 |
+
@lru_cache(maxsize=1)
|
| 39 |
+
def get_trending_accounts(limit=100):
|
| 40 |
+
try:
|
| 41 |
+
# Fetch trending models, datasets, and spaces
|
| 42 |
+
trending_models = list(api.list_models(sort="trending", limit=limit))
|
| 43 |
+
trending_datasets = list(api.list_datasets(sort="trending", limit=limit))
|
| 44 |
+
trending_spaces = list(api.list_spaces(sort="trending", limit=limit))
|
| 45 |
+
|
| 46 |
+
# Extract unique authors
|
| 47 |
+
authors = set()
|
| 48 |
+
for item in trending_models + trending_datasets + trending_spaces:
|
| 49 |
+
if hasattr(item, "author"):
|
| 50 |
+
authors.add(item.author)
|
| 51 |
+
elif hasattr(item, "id") and "/" in item.id:
|
| 52 |
+
authors.add(item.id.split("/")[0])
|
| 53 |
+
|
| 54 |
+
# Return sorted list of unique authors
|
| 55 |
+
return sorted(list(authors))[:limit]
|
| 56 |
+
except Exception as e:
|
| 57 |
+
st.error(f"Error fetching trending accounts: {str(e)}")
|
| 58 |
+
return ["ritvik77", "facebook", "google", "stabilityai", "Salesforce", "tiiuae", "bigscience"]
|
| 59 |
+
|
| 60 |
+
|
| 61 |
# Rate limiting
|
| 62 |
class RateLimiter:
|
| 63 |
def __init__(self, calls_per_second=10):
|
|
|
|
| 204 |
# Sidebar
|
| 205 |
with st.sidebar:
|
| 206 |
st.title("π€ Contributor")
|
| 207 |
+
|
| 208 |
+
# Fetch trending accounts with a loading spinner
|
| 209 |
+
with st.spinner("Loading top trending accounts..."):
|
| 210 |
+
trending_accounts = get_trending_accounts(limit=100)
|
| 211 |
+
|
| 212 |
+
# Create a tab interface for selection method
|
| 213 |
+
tab1, tab2 = st.tabs(["Top 100 Trending", "Custom User"])
|
| 214 |
+
|
| 215 |
+
with tab1:
|
| 216 |
+
# Show trending accounts list with search filter
|
| 217 |
+
st.subheader("π₯ Top Trending Accounts")
|
| 218 |
+
search_filter = st.text_input("Filter accounts", key="trending_filter")
|
| 219 |
+
|
| 220 |
+
# Filter accounts based on search
|
| 221 |
+
filtered_accounts = [acc for acc in trending_accounts if search_filter.lower() in acc.lower()] if search_filter else trending_accounts
|
| 222 |
+
|
| 223 |
+
# Show account count
|
| 224 |
+
st.caption(f"Showing {len(filtered_accounts)} accounts")
|
| 225 |
+
|
| 226 |
+
# Create a scrollable container for the accounts list
|
| 227 |
+
account_container = st.container()
|
| 228 |
+
with account_container:
|
| 229 |
+
selected_trending = st.selectbox(
|
| 230 |
+
"Select trending account",
|
| 231 |
+
options=filtered_accounts,
|
| 232 |
+
index=0 if filtered_accounts else None,
|
| 233 |
+
key="trending_selectbox"
|
| 234 |
+
)
|
| 235 |
+
|
| 236 |
+
if selected_trending:
|
| 237 |
+
username = selected_trending
|
| 238 |
+
|
| 239 |
+
with tab2:
|
| 240 |
+
st.subheader("π Custom Account")
|
| 241 |
+
default_accounts = ["ritvik77", "facebook", "google", "stabilityai", "Salesforce", "tiiuae", "bigscience"]
|
| 242 |
+
custom_account = st.selectbox(
|
| 243 |
+
"Select or type a username",
|
| 244 |
+
options=default_accounts,
|
| 245 |
+
index=0
|
| 246 |
+
)
|
| 247 |
+
st.markdown("<div style='text-align: center; margin: 10px 0;'>OR</div>", unsafe_allow_html=True)
|
| 248 |
+
custom = st.text_input("", placeholder="Enter custom username/org")
|
| 249 |
+
if custom.strip():
|
| 250 |
+
username = custom.strip()
|
| 251 |
+
elif tab2._active and not tab1._active: # Only set if tab2 is active
|
| 252 |
+
username = custom_account
|
| 253 |
+
|
| 254 |
+
# Year selection (outside tabs to always be visible)
|
| 255 |
+
st.subheader("ποΈ Time Period")
|
| 256 |
year_options = list(range(datetime.now().year, 2017, -1))
|
| 257 |
+
selected_year = st.selectbox("Select Year", options=year_options)
|
| 258 |
+
|
| 259 |
+
# Additional options for customization
|
| 260 |
+
st.subheader("βοΈ Display Options")
|
| 261 |
+
show_models = st.checkbox("Show Models", value=True)
|
| 262 |
+
show_datasets = st.checkbox("Show Datasets", value=True)
|
| 263 |
+
show_spaces = st.checkbox("Show Spaces", value=True)
|
| 264 |
|
| 265 |
# Main Content
|
| 266 |
st.title("π€ Hugging Face Contributions")
|
| 267 |
if username:
|
| 268 |
+
with st.spinner(f"Fetching commit data for {username}..."):
|
| 269 |
# Create a dictionary to store commits by type
|
| 270 |
commits_by_type = {}
|
| 271 |
commit_counts_by_type = {}
|
| 272 |
+
|
| 273 |
+
# Determine which types to fetch based on checkboxes
|
| 274 |
+
types_to_fetch = []
|
| 275 |
+
if show_models:
|
| 276 |
+
types_to_fetch.append("model")
|
| 277 |
+
if show_datasets:
|
| 278 |
+
types_to_fetch.append("dataset")
|
| 279 |
+
if show_spaces:
|
| 280 |
+
types_to_fetch.append("space")
|
| 281 |
+
|
| 282 |
+
if not types_to_fetch:
|
| 283 |
+
st.warning("Please select at least one content type to display (Models, Datasets, or Spaces)")
|
| 284 |
+
st.stop()
|
| 285 |
+
|
| 286 |
+
# Fetch commits for each selected type
|
| 287 |
+
for kind in types_to_fetch:
|
| 288 |
try:
|
| 289 |
items = cached_list_items(username, kind)
|
| 290 |
repo_ids = [item.id for item in items]
|
| 291 |
+
|
| 292 |
+
st.info(f"Found {len(repo_ids)} {kind}s for {username}")
|
| 293 |
|
| 294 |
# Process repos in chunks
|
| 295 |
chunk_size = 5
|
| 296 |
total_commits = 0
|
| 297 |
all_commit_dates = []
|
| 298 |
|
| 299 |
+
progress_bar = st.progress(0)
|
| 300 |
for i in range(0, len(repo_ids), chunk_size):
|
| 301 |
chunk = repo_ids[i:i + chunk_size]
|
| 302 |
with ThreadPoolExecutor(max_workers=min(5, len(chunk))) as executor:
|
|
|
|
| 309 |
if repo_commits:
|
| 310 |
all_commit_dates.extend(repo_commits)
|
| 311 |
total_commits += repo_count
|
| 312 |
+
|
| 313 |
+
# Update progress
|
| 314 |
+
progress = min(1.0, (i + len(chunk)) / max(1, len(repo_ids)))
|
| 315 |
+
progress_bar.progress(progress)
|
| 316 |
+
|
| 317 |
+
# Complete progress
|
| 318 |
+
progress_bar.progress(1.0)
|
| 319 |
|
| 320 |
commits_by_type[kind] = all_commit_dates
|
| 321 |
commit_counts_by_type[kind] = total_commits
|
|
|
|
| 329 |
total_commits = sum(commit_counts_by_type.values())
|
| 330 |
|
| 331 |
st.subheader(f"{username}'s Activity in {selected_year}")
|
| 332 |
+
|
| 333 |
+
# Profile information
|
| 334 |
+
profile_col1, profile_col2 = st.columns([1, 3])
|
| 335 |
+
with profile_col1:
|
| 336 |
+
# Try to get avatar
|
| 337 |
+
try:
|
| 338 |
+
avatar_url = f"https://huggingface.co/avatars/{username}"
|
| 339 |
+
st.image(avatar_url, width=150)
|
| 340 |
+
except:
|
| 341 |
+
st.info("No profile image available")
|
| 342 |
+
|
| 343 |
+
with profile_col2:
|
| 344 |
+
st.metric("Total Commits", total_commits)
|
| 345 |
+
st.markdown(f"[View Profile on Hugging Face](https://huggingface.co/{username})")
|
| 346 |
|
| 347 |
# Create DataFrame for all commits
|
| 348 |
all_commits = []
|
|
|
|
| 354 |
|
| 355 |
make_calendar_heatmap(all_df, "All Commits", selected_year)
|
| 356 |
|
| 357 |
+
# Metrics and heatmaps for each selected type
|
| 358 |
+
cols = st.columns(len(types_to_fetch)) if types_to_fetch else st.columns(1)
|
| 359 |
+
|
| 360 |
+
for i, (kind, emoji, label) in enumerate([
|
| 361 |
+
("model", "π§ ", "Models"),
|
| 362 |
+
("dataset", "π¦", "Datasets"),
|
| 363 |
+
("space", "π", "Spaces")
|
| 364 |
+
]):
|
| 365 |
+
if kind in types_to_fetch:
|
| 366 |
+
with cols[types_to_fetch.index(kind)]:
|
| 367 |
+
try:
|
| 368 |
+
total = len(cached_list_items(username, kind))
|
| 369 |
+
commits = commits_by_type.get(kind, [])
|
| 370 |
+
commit_count = commit_counts_by_type.get(kind, 0)
|
| 371 |
+
df_kind = pd.DataFrame(commits, columns=["date"])
|
| 372 |
+
if not df_kind.empty:
|
| 373 |
+
df_kind = df_kind.drop_duplicates() # Remove any duplicate dates
|
| 374 |
+
st.metric(f"{emoji} {label}", total)
|
| 375 |
+
st.metric(f"Commits in {selected_year}", commit_count)
|
| 376 |
+
make_calendar_heatmap(df_kind, f"{label} Commits", selected_year)
|
| 377 |
+
except Exception as e:
|
| 378 |
+
st.warning(f"Error processing {label}: {str(e)}")
|
| 379 |
+
st.metric(f"{emoji} {label}", 0)
|
| 380 |
+
st.metric(f"Commits in {selected_year}", 0)
|
| 381 |
+
make_calendar_heatmap(pd.DataFrame(), f"{label} Commits", selected_year)
|
| 382 |
+
else:
|
| 383 |
+
st.info("Please select an account from the sidebar to view contributions.")
|