Spaces:
Running
Running
rejection 2 step implementation in phase 2
Browse files
components/review_dashboard_page.py
CHANGED
@@ -121,11 +121,30 @@ class ReviewDashboardPage:
|
|
121 |
return None, None, gr.update(value=None, autoplay=False)
|
122 |
try:
|
123 |
log.info(f"Downloading voice for review: {filename_to_load}")
|
|
|
|
|
|
|
124 |
sr, wav = LOADER.load_audio(filename_to_load)
|
|
|
|
|
|
|
|
|
125 |
return (sr, wav), (sr, wav.copy()), gr.update(value=(sr, wav), autoplay=True)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
126 |
except Exception as e:
|
127 |
log.error(f"Audio download failed for {filename_to_load}: {e}")
|
128 |
-
gr.Error(f"Failed to load audio: {filename_to_load}. Error: {e}")
|
129 |
return None, None, gr.update(value=None, autoplay=False)
|
130 |
|
131 |
def load_review_items_fn(session):
|
@@ -164,11 +183,9 @@ class ReviewDashboardPage:
|
|
164 |
|
165 |
log.info(f"Found target annotator with ID: {target_annotator_obj.id}")
|
166 |
|
167 |
-
# Get all annotations by target annotator
|
168 |
annotations = db.query(Annotation).join(TTSData).filter(
|
169 |
-
Annotation.annotator_id == target_annotator_obj.id
|
170 |
-
Annotation.annotated_sentence.isnot(None),
|
171 |
-
Annotation.annotated_sentence != ""
|
172 |
).options(
|
173 |
orm.joinedload(Annotation.tts_data),
|
174 |
orm.joinedload(Annotation.annotator)
|
@@ -178,6 +195,9 @@ class ReviewDashboardPage:
|
|
178 |
|
179 |
items = []
|
180 |
for annotation in annotations:
|
|
|
|
|
|
|
181 |
# Check if this annotation has been reviewed by current user
|
182 |
existing_validation = db.query(Validation).filter_by(
|
183 |
annotation_id=annotation.id,
|
@@ -198,27 +218,48 @@ class ReviewDashboardPage:
|
|
198 |
rejection_reason_val = existing_validation.description
|
199 |
rejection_visible_val = True
|
200 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
201 |
items.append({
|
202 |
"annotation_id": annotation.id,
|
203 |
"tts_id": annotation.tts_data.id,
|
204 |
"filename": annotation.tts_data.filename,
|
205 |
"sentence": annotation.tts_data.sentence,
|
206 |
-
"annotated_sentence":
|
|
|
207 |
# "annotator_name": annotation.annotator.name, # Anonymized
|
208 |
"annotated_at": annotation.annotated_at.isoformat() if annotation.annotated_at else "",
|
209 |
"validation_status": validation_status
|
210 |
})
|
211 |
|
212 |
-
# Find the first item that is not reviewed
|
213 |
initial_idx = 0
|
214 |
if items:
|
215 |
found_unreviewed = False
|
|
|
216 |
for i, item_data in enumerate(items):
|
217 |
-
if item_data["validation_status"] == "Not Reviewed"
|
|
|
218 |
initial_idx = i
|
219 |
found_unreviewed = True
|
220 |
break
|
221 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
222 |
initial_idx = len(items) - 1 if items else 0
|
223 |
|
224 |
# Set initial display
|
@@ -270,6 +311,10 @@ class ReviewDashboardPage:
|
|
270 |
current_item = items[idx]
|
271 |
rejection_reason = ""
|
272 |
rejection_visible = False
|
|
|
|
|
|
|
|
|
273 |
if current_item["validation_status"].startswith("Rejected"):
|
274 |
# Extract reason from status like "Rejected (reason)" or just use empty if no parenthesis
|
275 |
start_paren = current_item["validation_status"].find("(")
|
|
|
121 |
return None, None, gr.update(value=None, autoplay=False)
|
122 |
try:
|
123 |
log.info(f"Downloading voice for review: {filename_to_load}")
|
124 |
+
# Show progress to user
|
125 |
+
gr.Info(f"Loading audio file: {filename_to_load}")
|
126 |
+
|
127 |
sr, wav = LOADER.load_audio(filename_to_load)
|
128 |
+
|
129 |
+
log.info(f"Successfully loaded audio: {filename_to_load} (SR: {sr}, Length: {len(wav)} samples)")
|
130 |
+
gr.Info(f"β
Audio loaded successfully!")
|
131 |
+
|
132 |
return (sr, wav), (sr, wav.copy()), gr.update(value=(sr, wav), autoplay=True)
|
133 |
+
except TimeoutError as e:
|
134 |
+
log.error(f"Audio download timeout for {filename_to_load}: {e}")
|
135 |
+
gr.Error(f"β±οΈ Timeout loading audio: {filename_to_load}. The server may be slow or unreachable.")
|
136 |
+
return None, None, gr.update(value=None, autoplay=False)
|
137 |
+
except ConnectionError as e:
|
138 |
+
log.error(f"Audio download connection error for {filename_to_load}: {e}")
|
139 |
+
gr.Error(f"π Connection error loading audio: {filename_to_load}. Please check your internet connection.")
|
140 |
+
return None, None, gr.update(value=None, autoplay=False)
|
141 |
+
except FileNotFoundError as e:
|
142 |
+
log.error(f"Audio file not found for {filename_to_load}: {e}")
|
143 |
+
gr.Error(f"π Audio file not found: {filename_to_load}")
|
144 |
+
return None, None, gr.update(value=None, autoplay=False)
|
145 |
except Exception as e:
|
146 |
log.error(f"Audio download failed for {filename_to_load}: {e}")
|
147 |
+
gr.Error(f"β Failed to load audio: {filename_to_load}. Error: {e}")
|
148 |
return None, None, gr.update(value=None, autoplay=False)
|
149 |
|
150 |
def load_review_items_fn(session):
|
|
|
183 |
|
184 |
log.info(f"Found target annotator with ID: {target_annotator_obj.id}")
|
185 |
|
186 |
+
# Get all annotations by target annotator (including deleted ones)
|
187 |
annotations = db.query(Annotation).join(TTSData).filter(
|
188 |
+
Annotation.annotator_id == target_annotator_obj.id
|
|
|
|
|
189 |
).options(
|
190 |
orm.joinedload(Annotation.tts_data),
|
191 |
orm.joinedload(Annotation.annotator)
|
|
|
195 |
|
196 |
items = []
|
197 |
for annotation in annotations:
|
198 |
+
# Check if annotation is deleted (no annotated_sentence or empty)
|
199 |
+
is_deleted = not annotation.annotated_sentence or annotation.annotated_sentence.strip() == ""
|
200 |
+
|
201 |
# Check if this annotation has been reviewed by current user
|
202 |
existing_validation = db.query(Validation).filter_by(
|
203 |
annotation_id=annotation.id,
|
|
|
218 |
rejection_reason_val = existing_validation.description
|
219 |
rejection_visible_val = True
|
220 |
|
221 |
+
# For deleted annotations, show special status
|
222 |
+
if is_deleted:
|
223 |
+
annotated_sentence_display = "[DELETED ANNOTATION]"
|
224 |
+
if validation_status == "Not Reviewed":
|
225 |
+
validation_status = "Not Reviewed (Deleted)"
|
226 |
+
else:
|
227 |
+
annotated_sentence_display = annotation.annotated_sentence
|
228 |
+
|
229 |
items.append({
|
230 |
"annotation_id": annotation.id,
|
231 |
"tts_id": annotation.tts_data.id,
|
232 |
"filename": annotation.tts_data.filename,
|
233 |
"sentence": annotation.tts_data.sentence,
|
234 |
+
"annotated_sentence": annotated_sentence_display,
|
235 |
+
"is_deleted": is_deleted,
|
236 |
# "annotator_name": annotation.annotator.name, # Anonymized
|
237 |
"annotated_at": annotation.annotated_at.isoformat() if annotation.annotated_at else "",
|
238 |
"validation_status": validation_status
|
239 |
})
|
240 |
|
241 |
+
# Find the first item that is not reviewed (prioritize non-deleted annotations)
|
242 |
initial_idx = 0
|
243 |
if items:
|
244 |
found_unreviewed = False
|
245 |
+
# First, try to find unreviewed non-deleted annotations
|
246 |
for i, item_data in enumerate(items):
|
247 |
+
if (item_data["validation_status"] == "Not Reviewed" and
|
248 |
+
not item_data.get("is_deleted", False)):
|
249 |
initial_idx = i
|
250 |
found_unreviewed = True
|
251 |
break
|
252 |
+
|
253 |
+
# If no unreviewed non-deleted items, look for any unreviewed items
|
254 |
+
if not found_unreviewed:
|
255 |
+
for i, item_data in enumerate(items):
|
256 |
+
if item_data["validation_status"].startswith("Not Reviewed"):
|
257 |
+
initial_idx = i
|
258 |
+
found_unreviewed = True
|
259 |
+
break
|
260 |
+
|
261 |
+
# If no unreviewed items at all, use the last item
|
262 |
+
if not found_unreviewed:
|
263 |
initial_idx = len(items) - 1 if items else 0
|
264 |
|
265 |
# Set initial display
|
|
|
311 |
current_item = items[idx]
|
312 |
rejection_reason = ""
|
313 |
rejection_visible = False
|
314 |
+
|
315 |
+
# Check if this is a deleted annotation
|
316 |
+
is_deleted = current_item.get("is_deleted", False)
|
317 |
+
|
318 |
if current_item["validation_status"].startswith("Rejected"):
|
319 |
# Extract reason from status like "Rejected (reason)" or just use empty if no parenthesis
|
320 |
start_paren = current_item["validation_status"].find("(")
|