YouTube μμμ μλμΌλ‘ μ μ¬νκ³ μμ½νλ CLI λꡬμ λλ€.
- π μμ λ¬΄λ£ μ μ¬: λ‘컬 Whisper λͺ¨λΈ μ¬μ© (API λΉμ© μμ)
- π GPU κ°μ: faster-whisperλ‘ 5-10λ°° λΉ λ₯Έ μ²λ¦¬
- β‘ κ·Ήν μ΅μ ν: ffmpeg μ²νΉμΌλ‘ λ©λͺ¨λ¦¬ 90% μ κ°, Prompt CachingμΌλ‘ API λΉμ© 90% μ κ°
- π€ μ΅μ Claude Sonnet 4.6: κ³ νμ§ μμ½
- π λ€κ΅μ΄ μ§μ: νκ΅μ΄, μμ΄, μ€κ΅μ΄ μμ½ μ§μ
- π» CLI μΈν°νμ΄μ€: λͺ λ Ήμ€μμ κ°λ¨νκ² μ¬μ©
- π― μμ½ μ μ© λͺ¨λ: μ΄λ―Έ μ μ¬λ νμΌμμ μμ½λ§ λΉ λ₯΄κ² μμ±
# Tap μΆκ°
brew tap SaraHan774/ytt
# μ€μΉ (ffmpeg μλ μ€μΉλ¨)
brew install ytt
# λνν μ€μ μ€ν
ytt-init# macOS
brew install ffmpeg
# Ubuntu/Debian
sudo apt-get install ffmpeg
# Windows (Chocolatey)
choco install ffmpeg# μ μ₯μ ν΄λ‘
git clone <repository-url>
cd ytt
# ν¨ν€μ§ μ€μΉ
pip install -r requirements.txt
pip install -e .μ€μΉ ν μ²μ yttλ₯Ό μ€ννλ©΄ μλμΌλ‘ λνν μ€μ λ§λ²μ¬κ° μ€νλ©λλ€:
# 첫 μ€ν μ μλμΌλ‘ μ€μ μ§ν
ytt
# λλ μλμΌλ‘ μ€μ μ€ν
ytt-init
# μ€μ μ΄κΈ°ν λ° μ¬μ€μ
ytt-init --resetλνν μ€μ μμ ꡬμ±νλ νλͺ©:
- β μμ€ν νκ²½ νμΈ (ffmpeg, GPU λ±)
- π Anthropic API ν€ μ€μ
- π κΈ°λ³Έ μΈμ΄ μ ν (νκ΅μ΄/μμ΄/μ€κ΅μ΄)
- π€ κΈ°λ³Έ Whisper λͺ¨λΈ ν¬κΈ°
- βοΈ μλ μμ½ νμ±ν μ¬λΆ
# νκ²½ λ³μλ‘ μ€μ
export ANTHROPIC_API_KEY="your-api-key"
# λλ CLI λͺ
λ Ήμ΄λ‘ μ€μ
ytt-config set-api-key "your-api-key"
# μ€μ νμΈ
ytt-config show-config
# λλ .env νμΌ μμ±
echo "ANTHROPIC_API_KEY=your-api-key" > .env# μ μ¬λ§ μμ± (μμ μ 보 + μ μ¬ ν
μ€νΈ)
ytt "https://youtube.com/watch?v=xxx" ./output
# μ μ¬ + μμ½ (transcript.json μλ μμ±)
ytt "https://youtube.com/watch?v=xxx" ./output --summarize
# νμμ€ν¬ν νμΌλ ν¨κ» μ μ₯
ytt "https://youtube.com/watch?v=xxx" ./output --timestamps
# JSON + λ©νλ°μ΄ν° νμΌλ ν¨κ» μ μ₯
ytt "https://youtube.com/watch?v=xxx" ./output --json --metadata
# μΈμ΄ μλ μ§μ + μμ½
ytt "https://youtube.com/watch?v=xxx" ./output -l ko --summarize
# μμ΄ μμ + μμ΄ μμ½
ytt "https://youtube.com/watch?v=xxx" ./output -l en --summarizeμ΄λ―Έ μ μ¬κ° μλ£λ λλ ν 리μμ μμ½λ§ μμ±:
# λ¨Όμ μ μ¬ + JSON μ μ₯ (--summarize-only μ¬μ¬μ©μ μν΄ --json νμ)
ytt "URL" ./output -m tiny --json
# λλ --summarizeλ‘ μ²μ μ€ννλ©΄ transcript.json μλ μμ±λ¨
ytt "URL" ./output --summarize
# λμ€μ μμ½λ§ μΆκ°
ytt ./output --summarize-only -l koytt --helpμ£Όμ μ΅μ :
--summarize, -s: μμ½λ ν¨κ» μμ± (transcript.json μλ μ μ₯)--summarize-only: κΈ°μ‘΄ transcript.jsonμΌλ‘ μμ½λ§ μμ±--timestamps: νμμ€ν¬ν ν¬ν¨ μ μ¬ νμΌλ μ μ₯ (transcript_with_timestamps.txt)--json: ꡬ쑰νλ JSON νμΌλ μ μ₯ (transcript.json)--metadata: μμ λ©νλ°μ΄ν° νμΌλ μ μ₯ (metadata.json)--model-size, -m: Whisper λͺ¨λΈ ν¬κΈ° (κΈ°λ³Έκ°: base)--language, -l: μΈμ΄ μ§μ (κΈ°λ³Έκ°: auto - μλ κ°μ§)--no-cleanup: μμ νμΌ μμ νμ§ μμ--no-cache: ν둬ννΈ μΊμ± λΉνμ±ν (μμ½ μ)--vad-aggressive: Aggressive VAD μ¬μ© (λΉ λ₯Έ μ μ¬, μ§§μ 무μ ν¬ν¨ κ°λ₯)--force-librosa: librosa μ²νΉ κ°μ μ¬μ© (ffmpeg λΉνμ±ν)--verbose, -v: μμΈ λ‘κ·Έ μΆλ ₯
κΈ°λ³Έ μ€ν μ transcript.txt νλλ§ μμ±λ©λλ€. λλ¨Έμ§λ μ΅μ
μΌλ‘ μ νμ μΌλ‘ μμ±λ©λλ€.
output/
βββ transcript.txt # μμ μ 보 + μ μ¬ ν
μ€νΈ (νμ μμ±)
βββ transcript_with_timestamps.txt # νμμ€ν¬ν ν¬ν¨ μ μ¬ (--timestamps)
βββ transcript.json # JSON νμ λ°μ΄ν° (--json λλ --summarize)
βββ metadata.json # μμ λ©νλ°μ΄ν° (--metadata)
βββ summary.txt # AI μμ½ (--summarize)
transcript.txtμλ μμ μ λͺ©, URL, μ
λ‘λ, μ¬μ μκ°μ΄ ν€λλ‘ ν¬ν¨λ©λλ€.
ytt "https://youtube.com/watch?v=lecture123" ./lectures/ai-basics \
--summarize \
--model-size medium \
--language koytt "https://youtube.com/watch?v=podcast456" ./podcasts/ep01 \
-m tiny \
-l en \
--timestamps --json --metadata#!/bin/bash
# process-videos.sh
while IFS= read -r url; do
timestamp=$(date +%Y%m%d_%H%M%S)
ytt "$url" "./batch/$timestamp" --summarize -v
echo "β Processed: $url"
done < urls.txt# μ 체 ν
μ€νΈ
pytest
# 컀λ²λ¦¬μ§ ν¬ν¨
pytest --cov=ytt
# λ¨μ ν
μ€νΈλ§
pytest -m "not integration"
# ν΅ν© ν
μ€νΈλ§
pytest -m integration- μμ± μ μ¬: λ¬΄λ£ (λ‘컬 μ²λ¦¬)
- μμ½: Claude API μ¬μ©λμ λ°λ¦ (μ½ 0.5-2 tokens per character)
- tiny λͺ¨λΈ: μ½ μ€μκ°μ 1/10 μλ
- base λͺ¨λΈ: μ½ μ€μκ°μ 1/5 μλ (κΆμ₯)
- medium λͺ¨λΈ: μ½ μ€μκ°μ 1/3 μλ
- large λͺ¨λΈ: μ½ μ€μκ°κ³Ό λΉμ·
μμ: 16λΆ μμ β μ½ 3-4λΆ (base λͺ¨λΈ, GPU μ¬μ© μ)
yttλ λμ©λ μμ μ²λ¦¬λ₯Ό μν λ€μν μ΅μ νλ₯Ό μ 곡ν©λλ€:
ν¨κ³Ό: λ©λͺ¨λ¦¬ μ¬μ©λ 80-90% κ°μ, μ²νΉ μλ 60λ°° ν₯μ
μλ λ°©μ:
- ffmpegκ° μ€μΉλμ΄ μμΌλ©΄ μλμΌλ‘ μ¬μ©
- μ¬μΈμ½λ© μμ΄ λ³΅μ¬λ§ μν (zero-copy)
- librosa λλΉ λ©λͺ¨λ¦¬ ν¨μ¨ κ·Ήλν
μ€μΉ νμΈ:
# ffmpeg μ€μΉ μ¬λΆ νμΈ
ffmpeg -version
# macOSμμ μ€μΉ
brew install ffmpeg
# Ubuntu/Debian
sudo apt-get install ffmpegμλ λΉνμ±ν (νμμ):
# librosa μ²νΉ κ°μ μ¬μ©
ytt "URL" ./output --force-librosaν¨κ³Ό: API λΉμ© 90% μ κ° (Claude API μ¬μ© μ)
μλ λ°©μ:
- μμ€ν ν둬ννΈκ° 5λΆκ° μΊμλ¨
- 2λ²μ§Έ μ²ν¬λΆν° μΊμ μ¬μ¬μ© (ν ν° λΉμ© μ κ°)
- νμ§ μ ν μμ
μλ λΉνμ±ν (νμμ):
# ν둬ννΈ μΊμ± λΉνμ±ν
ytt "URL" ./output --summarize --no-cacheν¨κ³Ό: μ μ¬ μλ 20-30% ν₯μ
μλ λ°©μ:
- λ μ§§μ 무μ ꡬκ°μμ μ€ν΅ (500ms β 300ms)
- λΉ λ₯Έ μ μ¬, νμ§ μ ν μ΅μν
μ¬μ© λ°©λ²:
# Aggressive VAD νμ±ν
ytt "URL" ./output --vad-aggressive30λΆ μμ μ²λ¦¬ (base λͺ¨λΈ, GPU)
| μ΅μ ν | μ²λ¦¬ μκ° | λ©λͺ¨λ¦¬ | API λΉμ© |
|---|---|---|---|
| v1.0.x (μ΅μ ν μ ) | 13.9λΆ | 800MB | $0.80 |
| v1.1.0 (μ΅μ ν ν) | 8.3λΆ | 150MB | $0.08 |
| κ°μ μ¨ | 1.7λ°° | 81%β | 90%β |
60λΆ μμ μ²λ¦¬
| μ΅μ ν | μ²λ¦¬ μκ° | λ©λͺ¨λ¦¬ | API λΉμ© |
|---|---|---|---|
| v1.0.x | 27.8λΆ | 1600MB | $1.60 |
| v1.1.0 | 15.9λΆ | 180MB | $0.16 |
| κ°μ μ¨ | 1.7λ°° | 89%β | 90%β |
# μ΅λ μ±λ₯μΌλ‘ κΈ΄ μμ μ²λ¦¬
ytt "https://youtube.com/watch?v=xxx" ./output \
--summarize \
--vad-aggressive \
--model-size base
# λ©λͺ¨λ¦¬ μ ν νκ²½ (ffmpeg μλ μ¬μ©)
ytt "https://youtube.com/watch?v=xxx" ./output
# λΉμ© μ μ½ (μΊμ± μλ νμ±ν)
ytt "https://youtube.com/watch?v=xxx" ./output --summarize# CUDA νμΈ
python -c "import torch; print('CUDA:', torch.cuda.is_available())"
# CPU κ°μ μ€ν
CUDA_VISIBLE_DEVICES="" ytt "URL" ./output# API ν€ νμΈ
echo $ANTHROPIC_API_KEY
# ν
μ€νΈ
python -c "import os; print(os.getenv('ANTHROPIC_API_KEY'))"# λ μμ λͺ¨λΈ μ¬μ©
ytt "URL" ./output -m tiny- CLI μ¬μ© κ°μ΄λ - μμΈν μ¬μ©λ²κ³Ό μμ
- CLI λμμΈ - μν€ν μ² λ° μ€κ³ λ¬Έμ
Apache License 2.0
μ΄μμ PRμ μΈμ λ νμν©λλ€!