Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
@@ -141,95 +141,135 @@ def create_reranking_interface(task_data):
|
|
141 |
save_btn = gr.Button("💾 Save All Results", variant="secondary")
|
142 |
|
143 |
js_code = """
|
144 |
-
<script src
|
145 |
<script>
|
146 |
-
function
|
147 |
-
|
148 |
-
|
149 |
-
|
150 |
-
|
151 |
-
|
152 |
-
|
153 |
-
setTimeout(initializeSortableForApp, 200);
|
154 |
-
return;
|
155 |
-
}
|
156 |
-
if (container.sortableInstance) {
|
157 |
-
return;
|
158 |
-
}
|
159 |
-
container.sortableInstance = new Sortable(container, {
|
160 |
-
animation: 150,
|
161 |
-
ghostClass: "sortable-ghost",
|
162 |
-
onEnd: function() {
|
163 |
-
updateRanksAndSyncState();
|
164 |
}
|
165 |
-
|
166 |
-
|
167 |
-
|
168 |
-
|
169 |
-
|
170 |
-
|
171 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
172 |
|
173 |
-
|
174 |
-
|
175 |
-
|
176 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
177 |
}
|
178 |
|
179 |
-
|
180 |
-
|
181 |
-
const rankBadge = item.querySelector('.rank-badge');
|
182 |
-
if (rankBadge) rankBadge.textContent = (index + 1);
|
183 |
-
item.className = item.className.replace(/rank-bg-\d+/g, '').trim();
|
184 |
-
item.classList.add(`rank-bg-${index + 1}`);
|
185 |
-
const docId = parseInt(item.getAttribute('data-doc-id'));
|
186 |
-
order.push(docId);
|
187 |
-
});
|
188 |
|
189 |
-
const
|
190 |
-
if (
|
191 |
-
|
192 |
-
const
|
193 |
-
|
194 |
-
|
195 |
-
|
196 |
-
|
197 |
-
|
198 |
-
if (targetNode) {
|
199 |
-
const config = { childList: true, subtree: true };
|
200 |
-
const callback = function(mutationsList, observer) {
|
201 |
-
for(const mutation of mutationsList) {
|
202 |
-
if (mutation.type === 'childList') {
|
203 |
-
if (document.getElementById('sortable-container')){
|
204 |
-
initializeSortableForApp();
|
205 |
}
|
206 |
}
|
207 |
-
}
|
208 |
-
|
209 |
-
|
210 |
-
|
211 |
-
}
|
212 |
-
|
213 |
-
setTimeout(initializeSortableForApp, 500);
|
214 |
-
|
215 |
</script>
|
216 |
<style>
|
217 |
-
.sortable-container {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
218 |
.sortable-item {
|
219 |
-
padding:
|
220 |
-
|
221 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
222 |
}
|
223 |
-
.sortable-item:hover { background-color: #f8f9fa; }
|
224 |
-
.sortable-ghost { background-color: #d3e3fd !important; border-style: dashed !important; opacity: 0.6; }
|
225 |
-
.sortable-chosen { cursor: grabbing; }
|
226 |
.rank-badge {
|
227 |
-
display: flex;
|
228 |
-
|
229 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
230 |
flex-shrink: 0;
|
231 |
}
|
232 |
-
.doc-content {
|
|
|
|
|
|
|
|
|
233 |
.rank-bg-1 .rank-badge { background-color: #198754; }
|
234 |
.rank-bg-2 .rank-badge { background-color: #20c997; }
|
235 |
.rank-bg-3 .rank-badge { background-color: #ffc107; color: #333; }
|
|
|
141 |
save_btn = gr.Button("💾 Save All Results", variant="secondary")
|
142 |
|
143 |
js_code = """
|
144 |
+
<script src="https://cdn.jsdelivr.net/npm/sortablejs@1.15.0/Sortable.min.js"></script>
|
145 |
<script>
|
146 |
+
document.addEventListener('DOMContentLoaded', function() {
|
147 |
+
function initializeSortable() {
|
148 |
+
const container = document.getElementById('sortable-container');
|
149 |
+
if (!container) {
|
150 |
+
console.log('Container not found, retrying...');
|
151 |
+
setTimeout(initializeSortable, 200);
|
152 |
+
return;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
153 |
}
|
154 |
+
|
155 |
+
if (typeof Sortable === 'undefined') {
|
156 |
+
console.log('Sortable not loaded, retrying...');
|
157 |
+
setTimeout(initializeSortable, 200);
|
158 |
+
return;
|
159 |
+
}
|
160 |
+
|
161 |
+
if (container.sortableInstance) {
|
162 |
+
return;
|
163 |
+
}
|
164 |
+
|
165 |
+
container.sortableInstance = new Sortable(container, {
|
166 |
+
animation: 150,
|
167 |
+
ghostClass: "sortable-ghost",
|
168 |
+
onEnd: function() {
|
169 |
+
updateRanksAndSyncState();
|
170 |
+
}
|
171 |
+
});
|
172 |
+
|
173 |
+
updateRanksAndSyncState();
|
174 |
+
}
|
175 |
|
176 |
+
function updateRanksAndSyncState() {
|
177 |
+
const container = document.getElementById('sortable-container');
|
178 |
+
if (!container) return;
|
179 |
+
|
180 |
+
const items = container.querySelectorAll('.sortable-item');
|
181 |
+
const orderInput = document.querySelector('#current-order textarea');
|
182 |
+
if (!orderInput) return;
|
183 |
+
|
184 |
+
const order = [];
|
185 |
+
items.forEach((item, index) => {
|
186 |
+
const rankBadge = item.querySelector('.rank-badge');
|
187 |
+
if (rankBadge) rankBadge.textContent = (index + 1);
|
188 |
+
item.className = item.className.replace(/rank-bg-\d+/g, '').trim();
|
189 |
+
item.classList.add(`rank-bg-${index + 1}`);
|
190 |
+
const docId = parseInt(item.getAttribute('data-doc-id'));
|
191 |
+
order.push(docId);
|
192 |
+
});
|
193 |
+
|
194 |
+
const newOrderValue = JSON.stringify(order);
|
195 |
+
if (orderInput.value !== newOrderValue) {
|
196 |
+
orderInput.value = newOrderValue;
|
197 |
+
const event = new Event('input', { bubbles: true });
|
198 |
+
orderInput.dispatchEvent(event);
|
199 |
+
}
|
200 |
}
|
201 |
|
202 |
+
// Initialize immediately and also set up a mutation observer
|
203 |
+
initializeSortable();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
204 |
|
205 |
+
const targetNode = document.getElementById('sortable-list-container');
|
206 |
+
if (targetNode) {
|
207 |
+
const config = { childList: true, subtree: true };
|
208 |
+
const observer = new MutationObserver(function(mutationsList) {
|
209 |
+
for(const mutation of mutationsList) {
|
210 |
+
if (mutation.type === 'childList') {
|
211 |
+
if (document.getElementById('sortable-container')) {
|
212 |
+
initializeSortable();
|
213 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
214 |
}
|
215 |
}
|
216 |
+
});
|
217 |
+
observer.observe(targetNode, config);
|
218 |
+
}
|
219 |
+
});
|
|
|
|
|
|
|
|
|
220 |
</script>
|
221 |
<style>
|
222 |
+
.sortable-container {
|
223 |
+
display: flex;
|
224 |
+
flex-direction: column;
|
225 |
+
gap: 8px;
|
226 |
+
min-height: 200px;
|
227 |
+
padding: 10px;
|
228 |
+
background-color: #f8f9fa;
|
229 |
+
border-radius: 8px;
|
230 |
+
}
|
231 |
.sortable-item {
|
232 |
+
padding: 12px 15px;
|
233 |
+
background-color: #fff;
|
234 |
+
border: 1px solid #e0e0e0;
|
235 |
+
border-radius: 6px;
|
236 |
+
cursor: grab;
|
237 |
+
display: flex;
|
238 |
+
align-items: center;
|
239 |
+
transition: all 0.2s ease;
|
240 |
+
user-select: none;
|
241 |
+
}
|
242 |
+
.sortable-item:hover {
|
243 |
+
background-color: #f8f9fa;
|
244 |
+
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
245 |
+
}
|
246 |
+
.sortable-ghost {
|
247 |
+
background-color: #e3f2fd !important;
|
248 |
+
border-style: dashed !important;
|
249 |
+
opacity: 0.8;
|
250 |
+
}
|
251 |
+
.sortable-chosen {
|
252 |
+
cursor: grabbing;
|
253 |
+
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
|
254 |
}
|
|
|
|
|
|
|
255 |
.rank-badge {
|
256 |
+
display: flex;
|
257 |
+
align-items: center;
|
258 |
+
justify-content: center;
|
259 |
+
width: 28px;
|
260 |
+
height: 28px;
|
261 |
+
border-radius: 50%;
|
262 |
+
background-color: #6c757d;
|
263 |
+
color: white;
|
264 |
+
font-weight: bold;
|
265 |
+
margin-right: 15px;
|
266 |
flex-shrink: 0;
|
267 |
}
|
268 |
+
.doc-content {
|
269 |
+
flex: 1;
|
270 |
+
line-height: 1.4;
|
271 |
+
word-break: break-word;
|
272 |
+
}
|
273 |
.rank-bg-1 .rank-badge { background-color: #198754; }
|
274 |
.rank-bg-2 .rank-badge { background-color: #20c997; }
|
275 |
.rank-bg-3 .rank-badge { background-color: #ffc107; color: #333; }
|