hatimqman commited on
Commit
c8d246c
·
1 Parent(s): 5c6eaf8

طوابع زمنيّة لكلّ كلمة (word_timestamps) لضبط حدود الآيات صوتيًّا

Browse files
Files changed (1) hide show
  1. app.py +15 -4
app.py CHANGED
@@ -87,15 +87,26 @@ async def transcribe(request: Request):
87
  return {"text": (out.get("text") or "").strip(), "model": "quran"}
88
  # VAD + عتبات مضادّة للهلوسة: large-v3 يهلوس على الصمت/المقاطع القصيرة (نصوص يوتيوب دخيلة)،
89
  # فيُنتج نصًّا لا يطابق فيتجمّد الوسم الحيّ. VAD يحذف السكتات قبل التفريغ، والعتبات تُسقط الهلوسة.
 
 
 
 
 
 
90
  segments, _ = _general().transcribe(
91
  audio, language="ar", beam_size=1, temperature=0.0,
92
- without_timestamps=True, condition_on_previous_text=False,
93
  vad_filter=True, vad_parameters=dict(min_silence_duration_ms=300, speech_pad_ms=120),
94
  no_speech_threshold=0.6, compression_ratio_threshold=2.4, log_prob_threshold=-1.0,
95
  )
96
- txt = "".join(s.text for s in segments).strip()
97
- print(f"[DIAG] general {txt!r}", flush=True)
98
- return {"text": txt, "model": "general"}
 
 
 
 
 
99
  except Exception as e:
100
  print(f"[DIAG] EXC {type(e).__name__}: {e}", flush=True)
101
  return JSONResponse({"text": "", "error": str(e), "model": which}, status_code=200)
 
87
  return {"text": (out.get("text") or "").strip(), "model": "quran"}
88
  # VAD + عتبات مضادّة للهلوسة: large-v3 يهلوس على الصمت/المقاطع القصيرة (نصوص يوتيوب دخيلة)،
89
  # فيُنتج نصًّا لا يطابق فيتجمّد الوسم الحيّ. VAD يحذف السكتات قبل التفريغ، والعتبات تُسقط الهلوسة.
90
+ # ★ 2026-08-13: word_timestamps=True — طوابع زمنيّة لكلّ كلمة (محاذاة DTW على أوزان الانتباه
91
+ # داخل faster-whisper نفسه، بلا نموذجٍ إضافيّ ولا تحميلٍ جديد ولا إقلاعٍ باردٍ أطول).
92
+ # السبب: العميل كان **يستنتج** حدود الآيات من التتبّع النصّيّ مع تعويض زمن الاستدلال (تقدير)،
93
+ # فينزاح مقطع الآية المُرسَل لمحرّك QPS فينهار تطابقه رغم صحّة التلاوة (رُصد ١٢٪ و٢٪ حيًّا على
94
+ # سورة الزلزلة). بهذه الطوابع تصير حدود الآيات **صوتيّةً مضبوطة** لا مُقدَّرة.
95
+ # حقل `words` إضافيٌّ فقط — `text` يبقى كما هو تمامًا، فالعملاء القدامى لا يتأثّرون.
96
  segments, _ = _general().transcribe(
97
  audio, language="ar", beam_size=1, temperature=0.0,
98
+ without_timestamps=False, word_timestamps=True, condition_on_previous_text=False,
99
  vad_filter=True, vad_parameters=dict(min_silence_duration_ms=300, speech_pad_ms=120),
100
  no_speech_threshold=0.6, compression_ratio_threshold=2.4, log_prob_threshold=-1.0,
101
  )
102
+ segs = list(segments)
103
+ txt = "".join(s.text for s in segs).strip()
104
+ words = []
105
+ for s in segs:
106
+ for w in (getattr(s, "words", None) or []):
107
+ words.append({"w": w.word.strip(), "s": round(float(w.start), 3), "e": round(float(w.end), 3)})
108
+ print(f"[DIAG] general → {txt!r} ({len(words)} words)", flush=True)
109
+ return {"text": txt, "model": "general", "words": words}
110
  except Exception as e:
111
  print(f"[DIAG] EXC {type(e).__name__}: {e}", flush=True)
112
  return JSONResponse({"text": "", "error": str(e), "model": which}, status_code=200)