hetchyy Claude Opus 4.6 commited on
Commit
48bbc75
·
1 Parent(s): 7f362a6

Add special_type to JSON/API responses and hide animate button for transitions

Browse files

- Pipeline JSON output now includes special_type field for special segments
(Amin, Takbir, Tahmeed, Basmala, etc.) with empty ref_from/ref_to
- Session API forwards special_type to clients
- Animate button hidden for transition segments (no word spans for MFA)
while Basmala/Isti'adha retain it

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

Files changed (3) hide show
  1. src/api/session_api.py +5 -2
  2. src/pipeline.py +6 -2
  3. src/ui/segments.py +5 -2
src/api/session_api.py CHANGED
@@ -171,7 +171,7 @@ def _format_response(audio_id, json_output):
171
  """Convert pipeline json_output to the documented API response schema."""
172
  segments = []
173
  for seg in json_output.get("segments", []):
174
- segments.append({
175
  "segment": seg["segment"],
176
  "time_from": seg["time_from"],
177
  "time_to": seg["time_to"],
@@ -181,7 +181,10 @@ def _format_response(audio_id, json_output):
181
  "confidence": seg["confidence"],
182
  "has_missing_words": seg.get("has_missing_words", False),
183
  "error": seg["error"],
184
- })
 
 
 
185
  resp = {"audio_id": audio_id, "segments": segments}
186
  warning = _gpu_fallback_warning()
187
  if warning:
 
171
  """Convert pipeline json_output to the documented API response schema."""
172
  segments = []
173
  for seg in json_output.get("segments", []):
174
+ entry = {
175
  "segment": seg["segment"],
176
  "time_from": seg["time_from"],
177
  "time_to": seg["time_to"],
 
181
  "confidence": seg["confidence"],
182
  "has_missing_words": seg.get("has_missing_words", False),
183
  "error": seg["error"],
184
+ }
185
+ if seg.get("special_type"):
186
+ entry["special_type"] = seg["special_type"]
187
+ segments.append(entry)
188
  resp = {"audio_id": audio_id, "segments": segments}
189
  warning = _gpu_fallback_warning()
190
  if warning:
src/pipeline.py CHANGED
@@ -482,18 +482,22 @@ def _run_post_vad_pipeline(
482
  return parts[0], parts[1] if len(parts) > 1 else parts[0]
483
  return matched_ref, matched_ref
484
 
 
 
485
  segments_list = []
486
  for i, seg in enumerate(segments):
 
487
  segment_data = {
488
  "segment": i + 1,
489
  "time_from": round(seg.start_time, 3),
490
  "time_to": round(seg.end_time, 3),
491
- "ref_from": parse_ref(seg.matched_ref)[0],
492
- "ref_to": parse_ref(seg.matched_ref)[1],
493
  "matched_text": seg.matched_text or "",
494
  "confidence": round(seg.match_score, 3),
495
  "has_missing_words": seg.has_missing_words,
496
  "potentially_undersegmented": seg.potentially_undersegmented,
 
497
  "error": seg.error
498
  }
499
  segments_list.append(segment_data)
 
482
  return parts[0], parts[1] if len(parts) > 1 else parts[0]
483
  return matched_ref, matched_ref
484
 
485
+ from src.alignment.special_segments import ALL_SPECIAL_REFS
486
+
487
  segments_list = []
488
  for i, seg in enumerate(segments):
489
+ is_special = seg.matched_ref in ALL_SPECIAL_REFS
490
  segment_data = {
491
  "segment": i + 1,
492
  "time_from": round(seg.start_time, 3),
493
  "time_to": round(seg.end_time, 3),
494
+ "ref_from": "" if is_special else parse_ref(seg.matched_ref)[0],
495
+ "ref_to": "" if is_special else parse_ref(seg.matched_ref)[1],
496
  "matched_text": seg.matched_text or "",
497
  "confidence": round(seg.match_score, 3),
498
  "has_missing_words": seg.has_missing_words,
499
  "potentially_undersegmented": seg.potentially_undersegmented,
500
+ "special_type": seg.matched_ref if is_special else None,
501
  "error": seg.error
502
  }
503
  segments_list.append(segment_data)
src/ui/segments.py CHANGED
@@ -276,9 +276,12 @@ def render_segment_card(seg: SegmentInfo, idx: int, audio_int16: np.ndarray = No
276
  audio_html = ""
277
  if audio_int16 is not None and sample_rate > 0 and segment_dir is not None:
278
  audio_src = encode_segment_audio(audio_int16, sample_rate, seg.start_time, seg.end_time, segment_dir, idx, inline=audio_inline)
279
- # Add animate button only if segment has matched_ref (Quran text with word spans)
 
 
280
  animate_btn = ""
281
- if seg.matched_ref:
 
282
  animate_btn = f'<button class="animate-btn" data-segment="{idx}" disabled>Animate</button>'
283
  audio_html = f'''
284
  <div class="segment-audio">
 
276
  audio_html = ""
277
  if audio_int16 is not None and sample_rate > 0 and segment_dir is not None:
278
  audio_src = encode_segment_audio(audio_int16, sample_rate, seg.start_time, seg.end_time, segment_dir, idx, inline=audio_inline)
279
+ # Add animate button only if segment has a Quran verse ref (word spans for animation).
280
+ # Basmala/Isti'adha get animate because they have indexed word spans for MFA.
281
+ # Transition segments (Amin, Takbir, Tahmeed) don't.
282
  animate_btn = ""
283
+ _ANIMATABLE_SPECIALS = {"Basmala", "Isti'adha", "Isti'adha+Basmala"}
284
+ if seg.matched_ref and (seg.matched_ref not in ALL_SPECIAL_REFS or seg.matched_ref in _ANIMATABLE_SPECIALS):
285
  animate_btn = f'<button class="animate-btn" data-segment="{idx}" disabled>Animate</button>'
286
  audio_html = f'''
287
  <div class="segment-audio">