Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
@@ -9,21 +9,20 @@ def create_reranking_interface(task_data):
|
|
9 |
results = {"task_name": task_data["task_name"], "task_type": "reranking", "annotations": []}
|
10 |
completed_samples = {s["id"]: False for s in samples}
|
11 |
|
12 |
-
#
|
13 |
-
|
14 |
|
15 |
-
def save_ranking(sample_id
|
16 |
"""Save the current document ordering as rankings."""
|
17 |
try:
|
18 |
-
if not
|
19 |
return "⚠️ No document ordering found", f"Progress: {sum(completed_samples.values())}/{len(samples)}"
|
20 |
|
21 |
-
# Convert document positions to rankings
|
22 |
-
#
|
23 |
rankings = []
|
24 |
-
for i in
|
25 |
-
|
26 |
-
rankings.append(doc_idx + 1) # Convert to 1-based ranks
|
27 |
|
28 |
# Store this annotation in memory
|
29 |
existing_idx = next((i for i, a in enumerate(results["annotations"]) if a["sample_id"] == sample_id), None)
|
@@ -53,159 +52,19 @@ def create_reranking_interface(task_data):
|
|
53 |
# Return specific error message
|
54 |
return f"Error: {str(e)}", f"Progress: {sum(completed_samples.values())}/{len(samples)}"
|
55 |
|
56 |
-
def
|
57 |
-
|
58 |
-
|
59 |
-
if not sample:
|
60 |
-
return [], "", "Query not found", f"Progress: {sum(completed_samples.values())}/{len(samples)}"
|
61 |
-
|
62 |
-
# Get the documents for this sample
|
63 |
-
docs = sample["candidates"]
|
64 |
-
|
65 |
-
# Initialize the document order (0, 1, 2, ..., n-1)
|
66 |
-
doc_order = list(range(len(docs)))
|
67 |
-
|
68 |
-
# Check if this sample has already been annotated to restore ordering
|
69 |
-
existing_annotation = next((a for a in results["annotations"] if a["sample_id"] == sample_id), None)
|
70 |
-
if existing_annotation and "rankings" in existing_annotation:
|
71 |
-
# Convert rankings back to positions
|
72 |
-
# If document 0 has rank 3, it should be in position 2
|
73 |
-
sorted_positions = []
|
74 |
-
for i in range(len(existing_annotation["rankings"])):
|
75 |
-
rank = existing_annotation["rankings"][i]
|
76 |
-
sorted_positions.append((i, rank))
|
77 |
-
|
78 |
-
# Sort by rank (ascending)
|
79 |
-
sorted_positions.sort(key=lambda x: x[1])
|
80 |
-
|
81 |
-
# Extract the original indices in their ranked order
|
82 |
-
doc_order = [pos[0] for pos in sorted_positions]
|
83 |
-
|
84 |
-
# Current sample query
|
85 |
-
query = sample["query"]
|
86 |
-
|
87 |
-
# Status message
|
88 |
-
status = f"Viewing query {samples.index(sample) + 1} of {len(samples)}"
|
89 |
-
if completed_samples[sample_id]:
|
90 |
-
status += " (already completed)"
|
91 |
-
|
92 |
-
return doc_order, query, status, f"Progress: {sum(completed_samples.values())}/{len(samples)}"
|
93 |
-
|
94 |
-
def move_document(doc_order, doc_idx, direction):
|
95 |
-
"""Move a document up or down in the order."""
|
96 |
-
if not doc_order:
|
97 |
-
return doc_order
|
98 |
-
|
99 |
-
# Create a copy of the order to avoid reference issues
|
100 |
-
new_order = doc_order.copy()
|
101 |
-
|
102 |
-
# Find the current position of the document in the order
|
103 |
-
current_pos = new_order.index(doc_idx)
|
104 |
-
|
105 |
-
# Calculate the new position
|
106 |
-
if direction == "up" and current_pos > 0:
|
107 |
# Swap with the document above
|
108 |
-
|
109 |
-
|
110 |
-
# Swap with the document below
|
111 |
-
new_order[current_pos], new_order[current_pos + 1] = new_order[current_pos + 1], new_order[current_pos]
|
112 |
-
|
113 |
-
return new_order
|
114 |
|
115 |
-
def
|
116 |
-
|
117 |
-
|
118 |
-
|
119 |
-
|
120 |
-
|
121 |
-
docs = sample["candidates"]
|
122 |
-
|
123 |
-
# Build HTML for the document list
|
124 |
-
html = "<div class='document-list'>"
|
125 |
-
|
126 |
-
for pos, doc_idx in enumerate(doc_order):
|
127 |
-
if doc_idx < len(docs):
|
128 |
-
doc_text = docs[doc_idx]
|
129 |
-
|
130 |
-
# Calculate the rank (position + 1)
|
131 |
-
rank = pos + 1
|
132 |
-
|
133 |
-
# Create a container for each document with buttons and rank
|
134 |
-
html += f"""
|
135 |
-
<div class='document-item' id='doc-{doc_idx}'>
|
136 |
-
<div class='document-controls'>
|
137 |
-
<div class='rank-display'>Rank: {rank}</div>
|
138 |
-
<button class='move-up-btn' onclick='moveDocument({doc_idx}, "up")'>↑ Move Up</button>
|
139 |
-
<button class='move-down-btn' onclick='moveDocument({doc_idx}, "down")'>↓ Move Down</button>
|
140 |
-
</div>
|
141 |
-
<div class='document-content'>
|
142 |
-
<p><strong>Document {doc_idx + 1}:</strong> {doc_text}</p>
|
143 |
-
</div>
|
144 |
-
</div>
|
145 |
-
"""
|
146 |
-
|
147 |
-
html += "</div>"
|
148 |
-
|
149 |
-
# Add custom CSS
|
150 |
-
html += """
|
151 |
-
<style>
|
152 |
-
.document-list {
|
153 |
-
display: flex;
|
154 |
-
flex-direction: column;
|
155 |
-
gap: 10px;
|
156 |
-
}
|
157 |
-
.document-item {
|
158 |
-
border: 1px solid #ddd;
|
159 |
-
border-radius: 8px;
|
160 |
-
padding: 15px;
|
161 |
-
background-color: #f9f9f9;
|
162 |
-
display: flex;
|
163 |
-
flex-direction: column;
|
164 |
-
}
|
165 |
-
.document-controls {
|
166 |
-
display: flex;
|
167 |
-
align-items: center;
|
168 |
-
gap: 10px;
|
169 |
-
margin-bottom: 10px;
|
170 |
-
}
|
171 |
-
.rank-display {
|
172 |
-
font-weight: bold;
|
173 |
-
min-width: 80px;
|
174 |
-
}
|
175 |
-
.document-content {
|
176 |
-
padding: 5px;
|
177 |
-
background-color: white;
|
178 |
-
border-radius: 4px;
|
179 |
-
}
|
180 |
-
button {
|
181 |
-
padding: 5px 10px;
|
182 |
-
border-radius: 4px;
|
183 |
-
border: 1px solid #ccc;
|
184 |
-
cursor: pointer;
|
185 |
-
}
|
186 |
-
.move-up-btn {
|
187 |
-
background-color: #e0f7fa;
|
188 |
-
}
|
189 |
-
.move-down-btn {
|
190 |
-
background-color: #fff3e0;
|
191 |
-
}
|
192 |
-
</style>
|
193 |
-
"""
|
194 |
-
|
195 |
-
# Add JavaScript to handle button clicks
|
196 |
-
html += """
|
197 |
-
<script>
|
198 |
-
function moveDocument(docIdx, direction) {
|
199 |
-
// Call the Python function via Gradio's API
|
200 |
-
const event = new CustomEvent('move-document', {
|
201 |
-
detail: { docIdx: docIdx, direction: direction }
|
202 |
-
});
|
203 |
-
document.dispatchEvent(event);
|
204 |
-
}
|
205 |
-
</script>
|
206 |
-
"""
|
207 |
-
|
208 |
-
return gr.HTML.update(value=html)
|
209 |
|
210 |
with gr.Blocks(theme=gr.themes.Soft()) as demo:
|
211 |
gr.Markdown(f"# {task_data['task_name']} - Human Reranking Evaluation")
|
@@ -238,15 +97,76 @@ def create_reranking_interface(task_data):
|
|
238 |
|
239 |
gr.Markdown("## Documents (Arrange in order of relevance, most relevant at top):")
|
240 |
|
241 |
-
#
|
242 |
-
|
243 |
|
244 |
-
#
|
245 |
-
|
246 |
-
|
247 |
-
|
248 |
-
|
249 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
250 |
|
251 |
with gr.Row():
|
252 |
prev_btn = gr.Button("← Previous Query", size="sm")
|
@@ -255,82 +175,67 @@ def create_reranking_interface(task_data):
|
|
255 |
|
256 |
save_btn = gr.Button("💾 Save All Results", variant="secondary")
|
257 |
|
258 |
-
# Initialize the document
|
259 |
-
|
260 |
-
current_document_order.value = doc_order
|
261 |
-
query_text.value = query_val
|
262 |
status_box.value = status_val
|
263 |
progress_text.value = progress_val
|
264 |
|
265 |
-
#
|
266 |
-
|
267 |
-
|
268 |
-
# Connect events for up/down buttons (these are triggered by JavaScript)
|
269 |
-
def doc_move_handler(doc_idx, direction, current_order, sample_id):
|
270 |
-
new_order = move_document(current_order, doc_idx, direction)
|
271 |
-
html_update = render_documents(new_order, sample_id)
|
272 |
-
return new_order, html_update
|
273 |
-
|
274 |
-
up_btn.click(
|
275 |
-
doc_move_handler,
|
276 |
-
inputs=[doc_index, gr.Textbox(value="up"), current_document_order, current_sample_id],
|
277 |
-
outputs=[current_document_order, document_list]
|
278 |
-
)
|
279 |
-
|
280 |
-
down_btn.click(
|
281 |
-
doc_move_handler,
|
282 |
-
inputs=[doc_index, gr.Textbox(value="down"), current_document_order, current_sample_id],
|
283 |
-
outputs=[current_document_order, document_list]
|
284 |
-
)
|
285 |
-
|
286 |
-
# Load a sample and update the interface
|
287 |
-
def load_sample(sample_id):
|
288 |
-
doc_order, query_val, status_val, progress_val = initialize_documents(sample_id)
|
289 |
-
html_update = render_documents(doc_order, sample_id)
|
290 |
-
return doc_order, query_val, html_update, status_val, progress_val
|
291 |
-
|
292 |
-
# Navigation events
|
293 |
-
def nav_sample(current_id, direction):
|
294 |
-
"""Navigate to the previous or next sample."""
|
295 |
current_sample = next((s for s in samples if s["id"] == current_id), None)
|
296 |
if not current_sample:
|
297 |
return current_id
|
298 |
|
299 |
current_idx = samples.index(current_sample)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
300 |
|
301 |
-
|
|
|
302 |
next_sample = samples[current_idx + 1]
|
303 |
return next_sample["id"]
|
304 |
-
elif direction == "prev" and current_idx > 0:
|
305 |
-
prev_sample = samples[current_idx - 1]
|
306 |
-
return prev_sample["id"]
|
307 |
-
|
308 |
return current_id
|
309 |
|
310 |
-
|
311 |
-
|
|
|
312 |
inputs=[current_sample_id],
|
313 |
outputs=[current_sample_id]
|
314 |
).then(
|
315 |
-
|
316 |
inputs=[current_sample_id],
|
317 |
-
outputs=[
|
|
|
|
|
|
|
|
|
318 |
)
|
319 |
|
320 |
-
|
321 |
-
|
322 |
inputs=[current_sample_id],
|
323 |
outputs=[current_sample_id]
|
324 |
).then(
|
325 |
-
|
326 |
inputs=[current_sample_id],
|
327 |
-
outputs=[
|
|
|
|
|
|
|
|
|
328 |
)
|
329 |
|
330 |
-
# Submit
|
331 |
submit_btn.click(
|
332 |
save_ranking,
|
333 |
-
inputs=[current_sample_id
|
334 |
outputs=[status_box, progress_text]
|
335 |
)
|
336 |
|
|
|
9 |
results = {"task_name": task_data["task_name"], "task_type": "reranking", "annotations": []}
|
10 |
completed_samples = {s["id"]: False for s in samples}
|
11 |
|
12 |
+
# Store the current document order for the active sample
|
13 |
+
current_order = []
|
14 |
|
15 |
+
def save_ranking(sample_id):
|
16 |
"""Save the current document ordering as rankings."""
|
17 |
try:
|
18 |
+
if not current_order:
|
19 |
return "⚠️ No document ordering found", f"Progress: {sum(completed_samples.values())}/{len(samples)}"
|
20 |
|
21 |
+
# Convert document positions to rankings (position in list -> document's rank)
|
22 |
+
# First document (position 0) gets rank 1, etc.
|
23 |
rankings = []
|
24 |
+
for i, doc_idx in enumerate(current_order):
|
25 |
+
rankings.append(i + 1) # Convert to 1-based ranks
|
|
|
26 |
|
27 |
# Store this annotation in memory
|
28 |
existing_idx = next((i for i, a in enumerate(results["annotations"]) if a["sample_id"] == sample_id), None)
|
|
|
52 |
# Return specific error message
|
53 |
return f"Error: {str(e)}", f"Progress: {sum(completed_samples.values())}/{len(samples)}"
|
54 |
|
55 |
+
def move_document_up(idx):
|
56 |
+
nonlocal current_order
|
57 |
+
if idx > 0:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
58 |
# Swap with the document above
|
59 |
+
current_order[idx], current_order[idx-1] = current_order[idx-1], current_order[idx]
|
60 |
+
return gr.update(value=f"Moved document up: {idx}")
|
|
|
|
|
|
|
|
|
61 |
|
62 |
+
def move_document_down(idx):
|
63 |
+
nonlocal current_order
|
64 |
+
if idx < len(current_order) - 1:
|
65 |
+
# Swap with the document below
|
66 |
+
current_order[idx], current_order[idx+1] = current_order[idx+1], current_order[idx]
|
67 |
+
return gr.update(value=f"Moved document down: {idx}")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
68 |
|
69 |
with gr.Blocks(theme=gr.themes.Soft()) as demo:
|
70 |
gr.Markdown(f"# {task_data['task_name']} - Human Reranking Evaluation")
|
|
|
97 |
|
98 |
gr.Markdown("## Documents (Arrange in order of relevance, most relevant at top):")
|
99 |
|
100 |
+
# Create simple document list with move up/down buttons
|
101 |
+
document_containers = []
|
102 |
|
103 |
+
# Function to initialize the document list for a sample
|
104 |
+
def initialize_document_list(sample_id):
|
105 |
+
nonlocal current_order
|
106 |
+
|
107 |
+
sample = next((s for s in samples if s["id"] == sample_id), None)
|
108 |
+
if not sample:
|
109 |
+
return "Query not found", f"Progress: {sum(completed_samples.values())}/{len(samples)}"
|
110 |
+
|
111 |
+
# Get the documents for this sample
|
112 |
+
docs = sample["candidates"]
|
113 |
+
|
114 |
+
# Initialize document order (0, 1, 2, ..., n-1)
|
115 |
+
current_order = list(range(len(docs)))
|
116 |
+
|
117 |
+
# Check if this sample has already been annotated to restore ordering
|
118 |
+
existing_annotation = next((a for a in results["annotations"] if a["sample_id"] == sample_id), None)
|
119 |
+
if existing_annotation and "rankings" in existing_annotation:
|
120 |
+
# Sort documents based on previous rankings
|
121 |
+
# This is a simplified version that just keeps the original order for now
|
122 |
+
pass
|
123 |
+
|
124 |
+
# Update UI
|
125 |
+
for i, doc_idx in enumerate(current_order):
|
126 |
+
if i < len(document_containers) and doc_idx < len(docs):
|
127 |
+
document_containers[i].value = f"Document {doc_idx+1} (Rank: {i+1}): {docs[doc_idx]}"
|
128 |
+
|
129 |
+
# Status message
|
130 |
+
status = f"Viewing query {samples.index(sample) + 1} of {len(samples)}"
|
131 |
+
if completed_samples[sample_id]:
|
132 |
+
status += " (already completed)"
|
133 |
+
|
134 |
+
return status, f"Progress: {sum(completed_samples.values())}/{len(samples)}"
|
135 |
+
|
136 |
+
# Create document display containers with up/down buttons
|
137 |
+
with gr.Column():
|
138 |
+
for i in range(10): # Assuming max 10 documents per sample
|
139 |
+
with gr.Group():
|
140 |
+
with gr.Row():
|
141 |
+
doc_text = gr.Textbox(label=f"Document {i+1}", interactive=False)
|
142 |
+
document_containers.append(doc_text)
|
143 |
+
|
144 |
+
with gr.Row():
|
145 |
+
up_btn = gr.Button(f"⬆️ Move Up", size="sm")
|
146 |
+
down_btn = gr.Button(f"⬇️ Move Down", size="sm")
|
147 |
+
|
148 |
+
# Connect the up/down buttons
|
149 |
+
up_btn.click(
|
150 |
+
lambda idx=i: move_document_up(idx),
|
151 |
+
inputs=[],
|
152 |
+
outputs=[status_box]
|
153 |
+
).then(
|
154 |
+
lambda: [gr.update(value=f"Document {current_order[j]+1} (Rank: {j+1}): {samples[0]['candidates'][current_order[j]]}")
|
155 |
+
for j in range(len(current_order))],
|
156 |
+
inputs=[],
|
157 |
+
outputs=document_containers[:len(current_order)]
|
158 |
+
)
|
159 |
+
|
160 |
+
down_btn.click(
|
161 |
+
lambda idx=i: move_document_down(idx),
|
162 |
+
inputs=[],
|
163 |
+
outputs=[status_box]
|
164 |
+
).then(
|
165 |
+
lambda: [gr.update(value=f"Document {current_order[j]+1} (Rank: {j+1}): {samples[0]['candidates'][current_order[j]]}")
|
166 |
+
for j in range(len(current_order))],
|
167 |
+
inputs=[],
|
168 |
+
outputs=document_containers[:len(current_order)]
|
169 |
+
)
|
170 |
|
171 |
with gr.Row():
|
172 |
prev_btn = gr.Button("← Previous Query", size="sm")
|
|
|
175 |
|
176 |
save_btn = gr.Button("💾 Save All Results", variant="secondary")
|
177 |
|
178 |
+
# Initialize the document list for the first sample
|
179 |
+
status_val, progress_val = initialize_document_list(samples[0]["id"])
|
|
|
|
|
180 |
status_box.value = status_val
|
181 |
progress_text.value = progress_val
|
182 |
|
183 |
+
# Navigation functions
|
184 |
+
def nav_to_prev(current_id):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
185 |
current_sample = next((s for s in samples if s["id"] == current_id), None)
|
186 |
if not current_sample:
|
187 |
return current_id
|
188 |
|
189 |
current_idx = samples.index(current_sample)
|
190 |
+
if current_idx > 0:
|
191 |
+
prev_sample = samples[current_idx - 1]
|
192 |
+
return prev_sample["id"]
|
193 |
+
return current_id
|
194 |
+
|
195 |
+
def nav_to_next(current_id):
|
196 |
+
current_sample = next((s for s in samples if s["id"] == current_id), None)
|
197 |
+
if not current_sample:
|
198 |
+
return current_id
|
199 |
|
200 |
+
current_idx = samples.index(current_sample)
|
201 |
+
if current_idx < len(samples) - 1:
|
202 |
next_sample = samples[current_idx + 1]
|
203 |
return next_sample["id"]
|
|
|
|
|
|
|
|
|
204 |
return current_id
|
205 |
|
206 |
+
# Connect navigation buttons
|
207 |
+
prev_btn.click(
|
208 |
+
nav_to_prev,
|
209 |
inputs=[current_sample_id],
|
210 |
outputs=[current_sample_id]
|
211 |
).then(
|
212 |
+
lambda id: initialize_document_list(id),
|
213 |
inputs=[current_sample_id],
|
214 |
+
outputs=[status_box, progress_text]
|
215 |
+
).then(
|
216 |
+
lambda id: next((s["query"] for s in samples if s["id"] == id), ""),
|
217 |
+
inputs=[current_sample_id],
|
218 |
+
outputs=[query_text]
|
219 |
)
|
220 |
|
221 |
+
next_btn.click(
|
222 |
+
nav_to_next,
|
223 |
inputs=[current_sample_id],
|
224 |
outputs=[current_sample_id]
|
225 |
).then(
|
226 |
+
lambda id: initialize_document_list(id),
|
227 |
inputs=[current_sample_id],
|
228 |
+
outputs=[status_box, progress_text]
|
229 |
+
).then(
|
230 |
+
lambda id: next((s["query"] for s in samples if s["id"] == id), ""),
|
231 |
+
inputs=[current_sample_id],
|
232 |
+
outputs=[query_text]
|
233 |
)
|
234 |
|
235 |
+
# Submit button
|
236 |
submit_btn.click(
|
237 |
save_ranking,
|
238 |
+
inputs=[current_sample_id],
|
239 |
outputs=[status_box, progress_text]
|
240 |
)
|
241 |
|