Claude Skill · 587 lines · 3+ clips tested

CaptionSkill

word-by-word bilingual captions · ไทย↔en · whisper.cpp + hyperframes

whisper.cpp Metal GPU pythainlp newmm GLM LLM proofread HyperFrames render

00Overview

สร้าง word-by-word bilingual captions ซิงค์กับเสียงแล้ว render ด้วย HyperFrames เป็น MP4

รองรับทั้ง 🇹🇭 ไทย → EN (คำไทย active + EN แปล) และ 🇬🇧 EN → ไทย (EN words active + ไทยแปล)

01Pipeline

🇹🇭 TH → EN Mode

  • ❶ ffmpeg normalize → H.264
  • ❷ ffmpeg extract 16 kHz WAV
  • whisper.cpp -l th Metal GPU
  • openai-whisper medium translate th→en
  • pythainlp newmm รวม fragments → groups
  • LLM proofread ตรวจคำผิด ASR
  • ❼ HyperFrames compose + render

🇬🇧 EN → TH Mode

  • ❶ ffmpeg normalize → H.264
  • ❷ ffmpeg extract 16 kHz WAV
  • whisper.cpp -l en Metal GPU
  • LLM translate en→th
  • ❺ group EN words + distribute TH
  • LLM proofread EN words
  • LLM review_th ตรวจคุณภาพแปลไทย
  • ❽ HyperFrames compose + render

Tools

Toolใช้ทำอะไร
ffmpegconvert video → H.264 + extract 16kHz audio
whisper-clitranscribe with Metal GPU (large-v3-turbo GGML)
openai-whispertranslate th→en (medium model, CPU FP32)
pythainlpตัดคำไทย newmm + กระจาย TH translation ตาม groups
GLM LLMtranslate en→th + proofread ASR + review TH quality
hyperframescompose HTML+GSAP + render MP4

02Setup

Project structure

project/
├── video_fixed.mp4          ← H.264 normalized
├── audio.wav                ← 16kHz mono WAV
├── whisper_cpp_th.json      ← transcribe output
├── translate_en.json        ← EN translation
├── groups.json              ← caption groups
├── index.html               ← HyperFrames composition
├── output.mp4               ← rendered result
└── capture/assets/fonts/    ← Sarabun woff2 (6 files, ~60KB)

Fonts — Sarabun 400/700/800

Copy จาก project เดิมได้เลย (6 ไฟล์ woff2):

cp <old-project>/capture/assets/fonts/* <new-project>/capture/assets/fonts/
# Sarabun-{400,700,800}-{thai,latin}.woff2

03Transcribe

Thai — whisper.cpp (Metal GPU)

ffmpeg -y -i video_fixed.mp4 -ar 16000 -ac 1 -c:a pcm_s16le audio.wav

whisper-cli \
  -m ~/.cache/whisper/ggml-large-v3-turbo.bin \
  -f audio.wav -l th \
  --output-json-full -of whisper_cpp_th \
  -t 8 -np -bo 5 -bs 5 -sow

~2.6s สำหรับ 14s clip (Metal GPU)

English Translate — openai-whisper medium

model_m = whisper.load_model('medium')
result_en = model_m.transcribe('video_fixed.mp4', language='th', task='translate')

~3.6s สำหรับ 14s clip (CPU) → total ~6.7s vs large-v3-turbo CPU ~17.5s

Fastest pipeline: whisper.cpp Metal + openai-whisper medium = 2.6x faster กว่า openai-whisper large-v3-turbo CPU

04⚠ Pitfalls

Thai Word Fragments — ต้องรวมมือ
Whisper แยกไทยเป็นตัวอักษร/สระ ไม่ใช่คำ
ห้าม threshold merging — สระ/วรรณยุกต์ซ้อน timestamp (gap=0) → รวมทุกอย่างเป็นก้อน
วิธีที่ถูก: segment text → แบ่งคำ (newmm) → map fragments ตามลำดับ
Word Timestamps หายหลัง ~60%
Whisper มัก map fragment เดียวครอบช่วงที่เหลือ → ใช้ segment boundaries จาก EN translation และ group กว้างขึ้น
EN segment ยาวครอบหลาย Thai group
ห้ามแปะทั้งประโยคซ้ำทุก group → ล้นจอ + ซ้ำ แก้: แบ่งคำ EN กระจายตามจำนวน groups
whisper.cpp translate ไม่ทำงานกับไทย → ต้องใช้ openai-whisper medium
คำอังกฤษในประโยคไทย (Bitcoin, Pizza, Laszlo) Whisper ถอดเป็นคำเดียวสมบูรณ์ — timestamps สะอาด ไม่ต้องรวม fragment

05คำผิดที่ Whisper ได้ยินผิดบ่อย

Whisper ได้ยินคำจริงสาเหตุ
โกรนมิดโลกพยัญชนะคล้าย
ทั้งสือ / ตั้งสือหนังสือออกเสียงเร็ว
เหตุเห็นต/ต+็น สับสน
เหตุการเหตุการณ์หาย ณ์
อดิต / อดิอดีตสระ ิ/ี สับสน
อาหารอ่านคำที่ตามมาถูกกลืน
เคียนเสียนเขียนเรื่องคำซ้อนกัน
ละลึก / การละลึกรำลึกรำ → ละ เสียงคล้าย
ควรสำคัญความสำคัญความ → ควร สระสับสน

AI proofread (GLM LLM) ตรวจแก้อัตโนมัติ — แต่ต้องตรวจทานมือเพิ่มในบางคำ

06Caption Groups

หลักการ

GROUPS data structure

var GROUPS = [
  {
    id: 0, groupStart: 0.00, groupEnd: 1.78,
    en: "English phrase",       // TH mode: EN translation
    words: [                    // TH mode: Thai words; EN mode: English words
      { wi: 0, wordStart: 0.00 },
      { wi: 1, wordStart: 1.08 }
    ]
  }
];
GROUPS word count = HTML span count — ไม่ตรง = GSAP target null warnings (lint trap #1)

07Template (16:9 / 9:16)

Dimensions

ค่า16:99:16
resolution1920 × 10801080 × 1920
.cg bottom64px280px
.cw font-size72px62px
.cg-en font-size36px32px
.cg-thai wrapwrapwrap + center
.cg-enwhite-space: normal, max-width: 1180pxmax-width: 920px

HTML structure

<div class="cg">
  <div class="cg-inner">
    <div class="cg-thai">         <!-- active word-by-word -->
      <span class="cw">คำแรก</span>
      <span class="cw">คำสอง</span>
    </div>
    <div class="cg-en">English</div>  <!-- translation line -->
  </div>
</div>

EN Audio — swap classes

เปลี่ยน .cg-thai.cg-en-words + .cg-en เก็บคำแปลไทยแทน

08ตัดเสียงเงียบ

ห้ามใช้ -c copy + -ss/-to — ไม่ frame-accurate → เสียงซ้ำ + ภาพกระตุก
ต้องใช้ filter_complex trim เท่านั้น

Parameters

ParameterDefaultปรับเมื่อ
NOISE-35dBตัดน้อยเกิน → -30dB; มากเกิน → -40dB
THRESHOLD0.3sสั้นลง → 0.2s; เก็บ pause → 0.5s
d=0.250.25smin duration ที่ถือว่า silence

09Design

Typography

ElementFontWeight
Active words (TH/EN)Sarabun800
Translation lineSarabun400

Active word colours

Bitcoin #F7931A Crypto #7B61FF News #EF4444 Tech #3B82F6 Nature #22C55E

Key values

ตัวเลือกค่าเหตุผล
Active color#F7931Aส้ม Bitcoin — เปลี่ยนตาม topic
Inactive opacity42%ต่ำพอให้เห็นชัดว่า active คือคำไหน
Translation opacity65%รองจาก active แต่ยังอ่านได้
Pill backgroundrgba(0,0,0,0.68)contrast ทุกสภาพแสง
Animationback.out(1.6) scale-popbouncy เหมาะ social

10Checklist ก่อน Deliver