ouhenio commited on
Commit
12c6f3b
·
verified ·
1 Parent(s): 15ffb5b

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +174 -178
app.py CHANGED
@@ -1,213 +1,209 @@
1
  import gradio as gr
2
- import random
3
- import json
4
- import fastapi
5
- from fastapi import FastAPI, Request
6
- import os
7
  import argilla as rg
8
- from functools import lru_cache
 
9
  import time
10
- import asyncio
11
- from fastapi.responses import HTMLResponse
12
- from fastapi.staticfiles import StaticFiles
13
- from fastapi.middleware.gzip import GZipMiddleware
14
 
 
15
  client = rg.Argilla(
16
  api_url=os.getenv("ARGILLA_API_URL", ""),
17
  api_key=os.getenv("ARGILLA_API_KEY", "")
18
  )
19
 
20
- countries = {
21
- "Argentina": {
22
- "iso": "ARG",
23
- "emoji": "🇦🇷"
24
- },
25
- "Bolivia": {
26
- "iso": "BOL",
27
- "emoji": "🇧🇴"
28
- },
29
- "Chile": {
30
- "iso": "CHL",
31
- "emoji": "🇨🇱"
32
- },
33
- "Colombia": {
34
- "iso": "COL",
35
- "emoji": "🇨🇴"
36
- },
37
- "Costa Rica": {
38
- "iso": "CRI",
39
- "emoji": "🇨🇷"
40
- },
41
- "Cuba": {
42
- "iso": "CUB",
43
- "emoji": "🇨🇺"
44
- },
45
- "Ecuador": {
46
- "iso": "ECU",
47
- "emoji": "🇪🇨"
48
- },
49
- "El Salvador": {
50
- "iso": "SLV",
51
- "emoji": "🇸🇻"
52
- },
53
- "España": {
54
- "iso": "ESP",
55
- "emoji": "🇪🇸"
56
- },
57
- "Guatemala": {
58
- "iso": "GTM",
59
- "emoji": "🇬🇹"
60
- },
61
- "Honduras": {
62
- "iso": "HND",
63
- "emoji": "🇭🇳"
64
- },
65
- "México": {
66
- "iso": "MEX",
67
- "emoji": "🇲🇽"
68
- },
69
- "Nicaragua": {
70
- "iso": "NIC",
71
- "emoji": "🇳🇮"
72
- },
73
- "Panamá": {
74
- "iso": "PAN",
75
- "emoji": "🇵🇦"
76
- },
77
- "Paraguay": {
78
- "iso": "PRY",
79
- "emoji": "🇵🇾"
80
- },
81
- "Perú": {
82
- "iso": "PER",
83
- "emoji": "🇵🇪"
84
- },
85
- "Puerto Rico": {
86
- "iso": "PRI",
87
- "emoji": "🇵🇷"
88
- },
89
- "República Dominicana": {
90
- "iso": "DOM",
91
- "emoji": "🇩🇴"
92
- },
93
- "Uruguay": {
94
- "iso": "URY",
95
- "emoji": "🇺🇾"
96
- },
97
- "Venezuela": {
98
- "iso": "VEN",
99
- "emoji": "🇻🇪"
100
- }
101
- }
102
-
103
 
 
104
  @lru_cache(maxsize=32)
105
- def count_answers_per_space_cached(country: str, cache_buster: int):
106
- return count_answers_per_space(country)
107
 
108
- def count_answers_per_space(country: str):
109
- iso = countries[country]["iso"]
110
- emoji = countries[country]["emoji"]
111
-
112
- dataset_name = f"{emoji} {country} - {iso} - Responder"
113
 
114
- try:
115
- dataset = client.datasets(dataset_name)
116
- records = list(dataset.records(with_responses=True))
117
-
118
- total_questions = len(records)
119
-
120
- completed_questions = 0
121
- total_answers = 0
122
- # answers_per_user = {}
123
-
124
- for record in records:
125
- record = record.to_dict()
126
- responses = record["responses"]
127
- if record["status"] == "completed":
128
- # +1 completed questions
129
- completed_questions += 1
130
- if "answer_1" in responses:
131
- answers = responses["answer_1"]
132
- total_answers += len(answers)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
133
 
134
- # for answer in answers:
135
- # user_id = answer["user_id"]
136
- # answers_per_user[user_id] = answers_per_user.get(user_id, 0) + 1
137
-
138
- percentage_complete = (completed_questions / total_questions * 100) if total_questions > 0 else 0
139
-
140
- return {
141
- "name": country,
142
- "total_questions": total_questions,
143
- "answered_questions": completed_questions,
144
- "total_answers": total_answers,
145
- "percent": round(percentage_complete, 2),
146
- "documents": total_questions
147
- }
148
-
149
- except Exception as e:
150
- print(f"No dataset found for {dataset_name}: {e}")
151
- return {
152
- "name": country,
153
- "total_questions": 0,
154
- "answered_questions": 0,
155
- "total_answers": 0,
156
- "percent": 0,
157
- "documents": 0
158
  }
 
 
 
 
 
 
 
 
 
 
 
 
159
 
 
160
  app = FastAPI()
161
 
162
- # gzip compression middleware reduces transferred data size
163
- app.add_middleware(GZipMiddleware, minimum_size=1000)
164
-
165
- last_update_time = time.time()
166
- cached_html_content = None
167
 
168
- @app.get("/d3-map")
169
- async def serve_map(request: Request, refresh: bool = False):
170
- global last_update_time, cached_html_content
171
  current_time = time.time()
172
 
173
- # use cached content if available and not expired (5 minute cache)
174
- if cached_html_content and current_time - last_update_time < 300 and not refresh:
175
- return HTMLResponse(content=cached_html_content)
 
 
 
 
 
 
176
 
177
- cache_buster = int(current_time) # use current time to bust cache when refresh=True
 
 
 
 
 
178
 
179
- country_data = {}
180
- for country in countries.keys():
181
- country_data[countries[country]["iso"]] = count_answers_per_space_cached(country, cache_buster)
182
 
183
- country_data_json = json.dumps(country_data)
184
-
185
- with open('template.txt', 'r') as f:
186
- html_template = f.read()
187
-
188
- html_content = html_template.replace("COUNTRY_DATA_PLACEHOLDER", country_data_json)
189
-
190
- cached_html_content = html_content
191
- last_update_time = current_time
192
-
193
- return HTMLResponse(content=html_content)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
194
 
195
- def create_iframe(refresh=False):
196
- param = f"refresh={str(refresh).lower()}&t={random.randint(1, 10000)}"
197
- return f'<iframe src="/d3-map?{param}" style="width:100%; height:650px; border:none;"></iframe>'
 
 
 
198
 
199
- with gr.Blocks(theme=gr.themes.Soft(primary_hue="pink", secondary_hue="purple")) as demo:
200
- gr.Markdown("# Mapa anotación")
 
 
201
 
202
- iframe_output = gr.HTML(create_iframe())
 
203
 
204
- def refresh():
205
- return create_iframe(refresh=True)
 
206
 
207
- gr.Button("Actualizar Datos").click(fn=refresh, outputs=iframe_output)
 
 
 
 
 
 
 
 
 
 
 
208
 
 
209
  gr.mount_gradio_app(app, demo, path="/")
210
 
 
211
  if __name__ == "__main__":
212
  import uvicorn
213
  uvicorn.run(app, host="0.0.0.0", port=7860)
 
1
  import gradio as gr
 
 
 
 
 
2
  import argilla as rg
3
+ import pandas as pd
4
+ import os
5
  import time
6
+ from collections import defaultdict
7
+ from fastapi import FastAPI
8
+ from functools import lru_cache
 
9
 
10
+ # Initialize Argilla client with environment variables
11
  client = rg.Argilla(
12
  api_url=os.getenv("ARGILLA_API_URL", ""),
13
  api_key=os.getenv("ARGILLA_API_KEY", "")
14
  )
15
 
16
+ # Dataset information - list all the datasets to track
17
+ DATASETS = [
18
+ "🇪🇸 España - ESP - Responder",
19
+ # Add more datasets as needed
20
+ ]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21
 
22
+ # Cache results to avoid frequent API calls
23
  @lru_cache(maxsize=32)
24
+ def get_user_contributions_cached(cache_buster: int):
25
+ return get_user_contributions()
26
 
27
+ def get_user_contributions():
28
+ """Get contributions per user across all datasets"""
29
+ user_contributions = defaultdict(lambda: {"username": "", "contributions": 0, "datasets": {}})
30
+ user_id_to_username = {}
 
31
 
32
+ # Process each dataset
33
+ for dataset_name in DATASETS:
34
+ try:
35
+ print(f"Processing dataset: {dataset_name}")
36
+ dataset = client.datasets(dataset_name)
37
+ records = list(dataset.records(with_responses=True))
38
+
39
+ # Track contributions per user in this dataset
40
+ dataset_contributions = defaultdict(int)
41
+
42
+ for record in records:
43
+ record_dict = record.to_dict()
44
+ if "answer_1" in record_dict["responses"]:
45
+ for answer in record_dict["responses"]["answer_1"]:
46
+ if answer["user_id"]:
47
+ user_id = answer["user_id"]
48
+ dataset_contributions[user_id] += 1
49
+
50
+ # Get username if not already cached
51
+ if user_id not in user_id_to_username:
52
+ try:
53
+ user = client.users(id=user_id)
54
+ user_id_to_username[user_id] = user.username
55
+ except Exception as e:
56
+ print(f"Error getting username for {user_id}: {e}")
57
+ user_id_to_username[user_id] = f"User-{user_id[:8]}"
58
+
59
+ # Add dataset contributions to overall user stats
60
+ for user_id, count in dataset_contributions.items():
61
+ username = user_id_to_username.get(user_id, f"User-{user_id[:8]}")
62
+ user_contributions[user_id]["username"] = username
63
+ user_contributions[user_id]["contributions"] += count
64
+ user_contributions[user_id]["datasets"][dataset_name] = count
65
 
66
+ except Exception as e:
67
+ print(f"Error processing dataset {dataset_name}: {e}")
68
+
69
+ # Convert to dataframe for easier handling
70
+ rows = []
71
+ for user_id, data in user_contributions.items():
72
+ row = {
73
+ "Username": data["username"],
74
+ "Total Contributions": data["contributions"]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
75
  }
76
+ # Add individual dataset contributions
77
+ for dataset_name in DATASETS:
78
+ row[dataset_name] = data["datasets"].get(dataset_name, 0)
79
+ rows.append(row)
80
+
81
+ df = pd.DataFrame(rows)
82
+
83
+ # Sort by total contributions (descending)
84
+ if not df.empty:
85
+ df = df.sort_values("Total Contributions", ascending=False)
86
+
87
+ return df
88
 
89
+ # App setup
90
  app = FastAPI()
91
 
92
+ last_update_time = 0
93
+ cached_data = None
 
 
 
94
 
95
+ def create_leaderboard_ui():
96
+ """Create the leaderboard UI"""
97
+ global cached_data, last_update_time
98
  current_time = time.time()
99
 
100
+ # Use cached data if available and not expired (5 minute cache)
101
+ if cached_data is not None and current_time - last_update_time < 300:
102
+ df = cached_data
103
+ else:
104
+ # Fetch fresh data
105
+ cache_buster = int(current_time)
106
+ df = get_user_contributions_cached(cache_buster)
107
+ cached_data = df
108
+ last_update_time = current_time
109
 
110
+ # Add rank column
111
+ if not df.empty:
112
+ df = df.reset_index(drop=True)
113
+ df.index = df.index + 1
114
+ df = df.rename_axis("Rank")
115
+ df = df.reset_index()
116
 
117
+ # Format for better display
118
+ df_html = df.to_html(classes="leaderboard-table", border=0, index=False)
 
119
 
120
+ # Add some styling
121
+ styled_html = f"""
122
+ <div style="margin: 20px 0;">
123
+ <h2>🏆 Leaderboard of User Contributions</h2>
124
+ <p>Last updated: {time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(last_update_time))}</p>
125
+ <style>
126
+ .leaderboard-table {{
127
+ width: 100%;
128
+ border-collapse: collapse;
129
+ font-family: Arial, sans-serif;
130
+ }}
131
+ .leaderboard-table th {{
132
+ background-color: #f2f2f2;
133
+ color: #333;
134
+ font-weight: bold;
135
+ text-align: left;
136
+ padding: 12px;
137
+ border-bottom: 2px solid #ddd;
138
+ }}
139
+ .leaderboard-table td {{
140
+ padding: 10px 12px;
141
+ border-bottom: 1px solid #ddd;
142
+ }}
143
+ .leaderboard-table tr:nth-child(even) {{
144
+ background-color: #f9f9f9;
145
+ }}
146
+ .leaderboard-table tr:hover {{
147
+ background-color: #f1f1f1;
148
+ }}
149
+ .leaderboard-table tr:nth-child(1) td:first-child,
150
+ .leaderboard-table tr:nth-child(1) td:nth-child(2) {{
151
+ font-weight: bold;
152
+ color: gold;
153
+ }}
154
+ .leaderboard-table tr:nth-child(2) td:first-child,
155
+ .leaderboard-table tr:nth-child(2) td:nth-child(2) {{
156
+ font-weight: bold;
157
+ color: silver;
158
+ }}
159
+ .leaderboard-table tr:nth-child(3) td:first-child,
160
+ .leaderboard-table tr:nth-child(3) td:nth-child(2) {{
161
+ font-weight: bold;
162
+ color: #cd7f32; /* bronze */
163
+ }}
164
+ </style>
165
+ {df_html}
166
+ <p><small>Note: This leaderboard shows user contributions across all tracked datasets.</small></p>
167
+ </div>
168
+ """
169
+ return styled_html
170
 
171
+ def refresh_data():
172
+ """Force refresh of the data"""
173
+ global cached_data, last_update_time
174
+ cached_data = None
175
+ last_update_time = 0
176
+ return create_leaderboard_ui()
177
 
178
+ # Create Gradio interface
179
+ with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="indigo")) as demo:
180
+ gr.Markdown("# Contribution Leaderboard")
181
+ gr.Markdown("Track user contributions across datasets in real-time")
182
 
183
+ # Create leaderboard display
184
+ leaderboard_html = gr.HTML(create_leaderboard_ui)
185
 
186
+ # Add refresh button
187
+ refresh_btn = gr.Button("🔄 Refresh Data")
188
+ refresh_btn.click(fn=refresh_data, outputs=leaderboard_html)
189
 
190
+ # Additional information
191
+ with gr.Accordion("About this leaderboard", open=False):
192
+ gr.Markdown("""
193
+ This leaderboard tracks user contributions across multiple datasets.
194
+
195
+ ### How it works
196
+ - **Contributions**: Each response provided by a user counts as one contribution
197
+ - **Refresh**: Data is automatically cached for 5 minutes. Click the refresh button to update manually
198
+ - **Datasets tracked**:
199
+ - 🇪🇸 España - ESP - Responder
200
+ - [Add more datasets as needed]
201
+ """)
202
 
203
+ # Mount the Gradio app
204
  gr.mount_gradio_app(app, demo, path="/")
205
 
206
+ # Run the app
207
  if __name__ == "__main__":
208
  import uvicorn
209
  uvicorn.run(app, host="0.0.0.0", port=7860)