ไฟล์ข้อมูลระดับคำ — result.words.json

result.words.json เป็นไฟล์ผลลัพธ์เสริมที่ worker สร้างให้ทุกงานที่เปิด ForceAligner (forcealigner_level ไม่ใช่ none) และ GET /status คืนลิงก์เป็น words_url (presigned URL อายุจำกัด เหมือนไฟล์อื่น) ไฟล์นี้มีไว้สำหรับ วิเคราะห์จังหวะการพูดและฝึกโมเดลตัด cue — ไม่ใช่ไฟล์ซับไตเติลสำหรับเล่น ขนาดประมาณ 0.8 MB ต่อชั่วโมงเสียง (≈1.5 MB เมื่อใช้ llmsplitting)

ไฟล์เป็น JSON หนึ่งออบเจ็กต์ (UTF-8 ไม่ escape ภาษาไทย, ตัวเลขเวลาเป็นวินาทีจากต้นไฟล์ ปัด 3 ตำแหน่ง) ช่วงดัชนีทุกช่วงเป็นแบบครึ่งเปิด [a, b)

โครงสร้าง

{
  "format": "loma-fastsrt-words", "version": 1,
  "job_id": "…", "language": "th", "forcealigner_level": "default | llmsplitting",
  "config": { "...job config snapshot ที่ worker ใช้จริง..." },
  "audio": { "duration_seconds": 600.0 },
  "tokenizer": { "name": "nlpo3", "version": "1.4.0", "dict": "loma_worker_words_th", "dict_sha256": "…" },
  "chunks": [
    { "i": 0, "start": 0.0, "end": 23.42, "avg_vad": 0.87, "tokens": [0, 61],
      "asr_text": "…", "asr_segments": [ { "s": 0.0, "e": 5.2, "text": "…" } ],
      "llm": "ok | fallback | none", "llm_error": "" }
  ],
  "tokens": [ { "i": 0, "t": "ขณะเดียวกัน", "s": 10.192, "e": 11.952, "sp": true } ],
  "cue_tokens": [ { "i": 0, "t": "…", "s": 10.208, "e": 11.936, "k": "p2 | p1 | line", "ref": 412, "line": 12 } ],
  "llm": {
    "model": "@preset/fast", "prompt_sha256": "…",
    "attempted": 40, "succeeded": 39, "fallback": 1, "fallback_chunks": [17],
    "lines": [ { "i": 0, "c": 0, "n": 0, "text": "ขณะเดียวกัน ถ้าเทียบกับเงินเฟ้อน่ะครับ",
                 "tokens": [412, 419], "tokens_match": "exact | resync | null", "cue_tokens": [412, 419] } ]
  },
  "cues": [
    { "index": 1, "start": 10.192, "end": 14.752, "tokens": [412, 419],
      "text": "ขณะเดียวกัน ถ้าเทียบกับเงินเฟ้อนะครับ", "raw_text": "…",
      "merged_from": [6], "speakers": ["A"], "speaker": "A" }
  ],
  "cues_index": "tokens | cue_tokens",
  "revised": false, "tokens_reordered": 0,
  "vad": { "sample_rate": 16000, "frame_size": 512, "frame_seconds": 0.032,
           "vad_threshold": 0.4, "effective_vad_threshold": 0.4, "used_vad_fallback": false,
           "digits": "0000135899…",
           "speech_coverage_ratio": 0.9995, "uncovered_speech_seconds": 0.35,
           "gated_speech_seconds": 0.35, "gated_candidates": 11 }
}

ความหมายของฟิลด์

ฟิลด์ ความหมาย
tokens token จาก ForceAligner รอบแรก (คำจาก NLPo3 / คำละติน) เรียงตามลำดับที่ตัวตัด cue อ่าน (เรียงตาม chunk แล้วตามเวลา) s/e คือเวลาเริ่ม-จบของคำ ช่องว่างระหว่าง e ของคำหนึ่งกับ s ของคำถัดไปคือช่วงเงียบที่ aligner เห็น (quantum 80 ms)
tokens[].sp true เมื่อข้อความจาก Whisper มีช่องว่างหลัง token นี้ (ไม่มีคีย์เมื่อไม่มีช่องว่าง) ตัวตัด cue ใช้ช่องว่างนี้เป็นสัญญาณจบวลีเฉพาะรอยต่อไทย-ไทย ไฟล์ที่สร้างก่อน ก.ย. 2569 ไม่มีคีย์นี้ ให้ดูจาก chunks[].asr_text แทน
chunks[].tokens ช่วงดัชนีของ tokens ที่อยู่ใน chunk นั้น asr_segments คือ segment จาก ASR (เวลาเป็นวินาทีจากต้นไฟล์) llm บอกว่า chunk นี้ผ่าน LLM สำเร็จ ใช้โค้ด fallback หรือไม่ได้ส่ง
cues cue สุดท้ายตรงกับ result.srt ทุกบรรทัด (index, start, end, text เท่ากัน) tokens คือช่วงดัชนีของ token ที่ประกอบเป็น cue นี้ ใน array ที่ระบุโดย cues_index ช่วงของ cue ทั้งหมดต่อกันพอดีและครอบคลุม array นั้นทั้งหมด raw_text คือข้อความก่อนใส่ป้ายผู้พูด/ขัดเกลา merged_from คือดัชนี cue ก่อนขั้น final merge speakers/speaker คือป้ายผู้พูดจาก diarization (null เมื่อปิด)
cues_index tokens เมื่อ cue สร้างจาก token รอบแรกโดยตรง (โหมด default) หรือ cue_tokens เมื่อ cue สร้างจาก token ที่จัดเวลาใหม่ (โหมด llmsplitting ซึ่งจัดตำแหน่งรอบสอง)
cue_tokens มีเฉพาะเมื่อ cues_index = cue_tokens — token ที่ cue ประกอบขึ้นจริง k = p2 (token จากการจัดตำแหน่งรอบสอง, line คือดัชนีบรรทัด LLM), p1 (token รอบแรกที่ถูกใช้ต่อเพราะ chunk นั้น fallback, ref ชี้ไป tokens), line (บรรทัดที่ไม่มีเวลาระดับคำ)
llm มีเฉพาะโหมด llmsplitting: บรรทัดดิบที่ LLM ตอบกลับ ก่อน ขั้น merge ใด ๆ lines[].tokens คือช่วงของ tokens (รอบแรก) ที่บรรทัดนี้ครอบคลุม (tokens_match = exact ตรงทุกตัวอักษร, resync จับคู่แบบยืดหยุ่นเพราะ LLM แก้คำ, null จับคู่ไม่ได้) และ cue_tokens คือช่วงใน cue_tokens
vad.digits ค่าความน่าจะเป็นเสียงพูดจาก Silero VAD ทั้งไฟล์ หนึ่งหลัก (0–9) ต่อเฟรม 32 ms (round(prob*9)) เฟรมที่ i ครอบคลุมเวลา [i*frame_seconds, (i+1)*frame_seconds)
tokens_reordered จำนวน token ที่ลำดับตามเวลาไม่ตรงกับลำดับที่ aligner คืนมา (ปกติ 0)
revised true เมื่อข้อความ cue ผ่านขั้น revise_srt สำเร็จ (text อาจต่างจาก raw_text)

ข้อควรรู้

  • ขอบเขตเวลาของ cue ไม่จำเป็นต้องเท่ากับช่วงเวลาของ token ในนั้น (cue แรกของ chunk เริ่มที่ต้น chunk, การยืดเวลาสิ้นสุดไปถึง cue ถัดไป (end-fill) และให้ครบ min_srt_duration_ms, การตัดขอบที่เงียบ, การบังคับให้เวลาไม่ถอยหลัง)
  • ไฟล์นี้เป็นผลลัพธ์เสริม: ถ้าสร้างไม่สำเร็จ งานยังเสร็จตามปกติและ GET /status จะไม่มี words_url
  • vad.digits คือค่า VAD ทั้งไฟล์ ส่วนค่า VAD เฉพาะช่วงของแต่ละ cue (หลักเดียวกัน) อยู่ในบล็อก NOTE loma-fastsrt-vad ของ result.debug.vtt
  • สำหรับการฝึกโมเดลตัด cue ให้ใช้ tokens เป็นอินพุต (เทียบเท่าสิ่งที่ worker เห็นตอนทำงานจริง) และใช้ llm.lines[].tokens / cues[].tokens เป็นป้ายกำกับ

results matching ""

    No results matching ""