Skip to content

Commit cf1514b

Browse files
Funbucketclaude
andcommitted
feat(why-ci): 영상 파이프라인 한/영 분리 및 EN 노트북 YouTube 임베드 추가
Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
1 parent 71beeb8 commit cf1514b

34 files changed

Lines changed: 3203 additions & 64 deletions

.claude/skills/manim-video-pipeline/SKILL.md

Lines changed: 31 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -58,30 +58,30 @@ Manim CE 기반 교육 영상 제작 워크플로우.
5858

5959
## 프로젝트 구조
6060

61+
언어별 영상을 지원한다. 기본 언어는 `ko`(한국어)이며, `en`(영어) 등 추가 언어를 병행 제작할 수 있다.
62+
6163
```text
6264
videos/{topic}/
6365
├── src/
64-
│ ├── {topic}.py # Manim Scene 클래스 모음
66+
│ ├── {topic}_ko.py # 한국어 버전 Manim Scene 클래스 모음
67+
│ ├── {topic}_en.py # 영어 버전 Manim Scene 클래스 모음
6568
│ └── scripts/
66-
│ ├── 01_{scene_name}.txt # 씬별 내레이션 스크립트
67-
│ └── ...
68-
├── preview/
69-
│ ├── 01_{scene_name}_mux.mp4
70-
│ └── ...
71-
└── build/
72-
├── manim/ # Manim 내부 캐시/중간 산출물 전용
73-
│ ├── Tex/
74-
│ ├── texts/
75-
│ ├── images/
76-
│ └── videos/
69+
│ ├── ko/ # 한국어 내레이션 스크립트 (커밋됨)
70+
│ │ ├── 01_{scene_name}.txt
71+
│ │ └── ...
72+
│ └── en/ # 영어 내레이션 스크립트 (커밋됨)
73+
│ ├── 01_{scene_name}.txt
74+
│ └── ...
75+
└── build/ # gitignore — 작업자가 자유롭게 관리
76+
├── manim/
7777
├── audio/
78-
│ ├── 01_{scene_name}.mp3 # 씬별 오디오 (TTS 생성)
79-
│ └── ...
8078
└── final/
81-
├── 01_{scene_name}_hq.mp4
82-
└── {topic}_full.mp4
8379
```
8480

81+
- `src/scripts/ko/`, `src/scripts/en/`은 커밋되는 소스 파일이다.
82+
- `build/`는 gitignore이므로 언어별 하위 폴더 구조는 작업자가 자유롭게 결정한다.
83+
- 영어 버전 `.py`가 추가되기 전에는 `src/{topic}.py`(한국어 단일 파일)를 그대로 써도 된다.
84+
8585
## 관련 코드북 노트북
8686

8787
```text
@@ -306,7 +306,8 @@ Scene 구조 기반 내레이션 스크립트 생성 (한국어).
306306

307307
### Scene 렌더
308308
```bash
309-
cd videos/{topic} && manim -pql --media_dir build/manim src/{topic}.py Scene{NN}_{ClassName}
309+
# 언어별 py 파일 사용 (예: _en, _ko suffix)
310+
cd videos/{topic} && manim -pql --media_dir build/manim src/{topic}_{lang}.py Scene{NN}_{ClassName}
310311
```
311312

312313
### 오디오 합성
@@ -317,40 +318,35 @@ cd videos/{topic} && manim -pql --media_dir build/manim src/{topic}.py Scene{NN}
317318
### 최종 합본 + BGM
318319
```bash
319320
cd videos/{topic} && ../../.claude/skills/manim-video-pipeline/scripts/mix_bgm.sh \
320-
build/final/{topic}_full.mp4 \
321+
build/final/{lang}/{topic}_{lang}_full.mp4 \
321322
path/to/bgm.mp3 \
322-
build/final/{topic}_full_bgm.mp4 \
323+
build/final/{lang}/{topic}_{lang}_full_bgm.mp4 \
323324
--bgm-volume 0.10
324325
```
325326

326327
### ElevenLabs 오디오 생성
327-
```bash
328-
cd .claude/skills/manim-video-pipeline && \
329-
npm run elevenlabs-audio -- --topic {topic} --scene 01 --name {scene_name}
330-
```
331-
332-
직접 script 경로를 줄 수도 있다:
328+
`--script`로 언어별 scripts 경로를 명시한다. build 출력 위치는 작업자가 자유롭게 관리한다:
333329
```bash
334330
cd .claude/skills/manim-video-pipeline && \
335331
npm run elevenlabs-audio -- --topic {topic} --scene 01 --name {scene_name} \
336-
--script ../../../videos/{topic}/src/scripts/01_{scene_name}.txt
332+
--script ../../../videos/{topic}/src/scripts/{lang}/01_{scene_name}.txt
337333
```
338334

339335
### 현재 Scene 반복 루프 예시
340336
```bash
341337
# 1) Scene 01 코드 작성 후 debug 렌더
342-
cd videos/{topic} && manim -pql --media_dir build/manim src/{topic}.py Scene01_{ClassName}
338+
cd videos/{topic} && manim -pql --media_dir build/manim src/{topic}_{lang}.py Scene01_{ClassName}
343339

344340
# 2) mp3를 받은 뒤 480p 테스트 mux (build/manim 결과 직접 사용)
345341
../../.claude/skills/manim-video-pipeline/scripts/mux_audio.sh \
346-
build/manim/videos/{topic}/480p15/Scene01_{ClassName}.mp4 \
347-
build/audio/01_{scene_name}.mp3 \
348-
preview/01_{scene_name}_mux.mp4
349-
350-
# 4) 사용자가 만족하면 고화질 저장
351-
manim -pqh --media_dir build/manim src/{topic}.py Scene01_{ClassName}
352-
# 또는 고화질 렌더 결과와 오디오를 mux하여
353-
# build/final/01_{scene_name}_hq.mp4 로 저장
342+
build/manim/videos/{topic}_{lang}/480p15/Scene01_{ClassName}.mp4 \
343+
build/audio/{lang}/01_{scene_name}.mp3 \
344+
preview/{lang}/01_{scene_name}_mux.mp4
345+
346+
# 3) 사용자가 만족하면 고화질 저장
347+
manim -pqh --media_dir build/manim src/{topic}_{lang}.py Scene01_{ClassName}
348+
# 고화질 렌더 결과와 오디오를 mux하여
349+
# build/final/{lang}/01_{scene_name}_hq.mp4 로 저장
354350
```
355351

356352
### 전체 합본

.claude/skills/manim-video-pipeline/scripts/generate_elevenlabs_audio.mjs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,17 @@ const OUTPUT_FORMAT = "mp3_44100_128";
1414

1515
function printUsage() {
1616
console.log(`Usage:
17-
node scripts/generate_elevenlabs_audio.mjs --topic TOPIC --scene 01 --name scene_name [--script PATH]
17+
node scripts/generate_elevenlabs_audio.mjs --topic TOPIC --scene 01 --name scene_name [--lang LANG] [--script PATH]
1818
node scripts/generate_elevenlabs_audio.mjs --topic TOPIC --scene 01 --name scene_name --text "..."
1919
2020
Options:
2121
--topic topic directory under videos/
2222
--scene scene number, e.g. 01
2323
--name scene snake_case name
24-
--script explicit script file path
24+
--lang language code, e.g. ko (default) or en — affects script/audio subfolder
25+
--script explicit script file path (overrides --lang-based default)
2526
--text direct text input instead of a script file
27+
--speed TTS speed multiplier (default: 1.0, range: 0.7–1.2)
2628
--dry-run validate paths and print output target without API call
2729
--help show this message`);
2830
}
@@ -181,6 +183,7 @@ async function main() {
181183
const topic = args.topic;
182184
const scene = args.scene;
183185
const sceneName = args.name;
186+
const speed = args.speed ? Number.parseFloat(args.speed) : 1.0;
184187
const dryRun = Boolean(args["dry-run"]);
185188

186189
if (!topic || !scene || !sceneName) {
@@ -234,6 +237,7 @@ async function main() {
234237
text: chunks[i],
235238
modelId: MODEL_ID,
236239
outputFormat: OUTPUT_FORMAT,
240+
voiceSettings: { speed },
237241
});
238242
const buffer = await streamToBuffer(audioStream);
239243
const chunkPath = path.join(tempDir, `${String(i + 1).padStart(2, "0")}.mp3`);
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
---
2+
name: notebook-references
3+
description: >
4+
Jupyter 노트북의 마지막 셀에 참고 자료를 추가하거나 수정할 때 사용.
5+
"참고 자료 추가해줘", "references 넣어줘", "참고문헌 업데이트" 등을 요청할 때 트리거.
6+
한국어 노트북과 영어 노트북 모두 동일한 인용 형식 컨벤션을 적용.
7+
---
8+
9+
# notebook-references
10+
11+
Causal Studio 노트북의 참고 자료 셀 작성 컨벤션.
12+
13+
## 형식
14+
15+
마지막 셀을 찾아 아래 형식으로 작성한다. NotebookEdit으로 셀을 수정하거나, 없으면 새 셀을 추가한다.
16+
17+
### 영어 노트북 (`_en.ipynb`)
18+
19+
```markdown
20+
## References
21+
22+
This notebook draws on <주요 참고 자료 1–2개>.
23+
24+
- **Author, A., & Author, B. (Year)**. Title of paper or book. *Journal or Publisher*.
25+
[URL](URL)
26+
27+
- **Author, C. (Year)**. *Book Title*. Online book.
28+
[URL](URL)
29+
30+
- **Dataset Name — Description**.
31+
[URL](URL)
32+
```
33+
34+
### 한국어 노트북 (`_ko.ipynb`)
35+
36+
```markdown
37+
## 참고 자료
38+
39+
이 노트북은 <주요 참고 자료 1–2개>를 주요 참고 자료로 작성되었습니다.
40+
41+
- **Author, A., & Author, B. (Year)**. Title of paper or book. *Journal or Publisher*.
42+
[URL](URL)
43+
44+
- **Author, C. (Year)**. *Book Title*. Online book.
45+
[URL](URL)
46+
47+
- **데이터셋 이름 — 설명**.
48+
[URL](URL)
49+
```
50+
51+
## 규칙
52+
53+
- 저자·연도·제목은 **굵게** (볼드)
54+
- 저널명·책 제목은 *이탤릭*
55+
- URL은 별도 줄에 두 칸 들여쓰기 후 `[URL](URL)` 형식
56+
- 논문: `Author (Year). Title. *Journal*.`
57+
- 책: `Author (Year). *Title*. Online book.` 또는 Publisher
58+
- 데이터셋: `**이름 — 설명**.` (저자/연도 없이)
59+
- 한국어 노트북에서도 저자명·제목은 영어 그대로 유지
60+
61+
## 기존 노트북 예시
62+
63+
FDC 노트북 (`frontdoor_criterion_ko.ipynb`) 참고:
64+
```markdown
65+
## 참고 자료
66+
67+
이 노트북은 Matheus Facure의 *Causal Inference for the Brave and True*와 Bellemare & Bloem (2024)을 주요 참고 자료로 작성되었습니다.
68+
69+
- **Bellemare, M. F., & Bloem, J. R. (2024)**. The Paper of How: Estimating Treatment Effects Using the Front-Door Criterion. *Oxford Bulletin of Economics and Statistics*.
70+
[https://...](https://...)
71+
72+
- **Facure, M. (2022)**. *Causal Inference for the Brave and True*. Online book.
73+
[https://matheusfacure.github.io/python-causality-handbook/](https://matheusfacure.github.io/python-causality-handbook/)
74+
75+
- **NYC TLC — 2023 High Volume For-Hire Vehicle Trip Records**.
76+
[https://...](https://...)
77+
```

book/fdc/frontdoor_criterion_en.ipynb

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@
143143
"id": "300ceab1",
144144
"metadata": {},
145145
"source": [
146-
"## Data Construction\n",
146+
"## Data Setup\n",
147147
"\n",
148148
"We apply the methodology of Bellemare & Bloem (2024) to the 2023 New York City HVFHS dataset. We work with a randomly drawn 5M-row sample from the full dataset (230 million rows). On the first run, the sample is downloaded from HuggingFace and cached locally."
149149
]
@@ -1688,8 +1688,6 @@
16881688
"- A conditionally exogenous mediator M exists between X and Y (e.g., an algorithmically determined match), and\n",
16891689
"- Variation in M arises effectively exogenously.\n",
16901690
"\n",
1691-
"Applicable domains include the tech industry (recommendation algorithms, content allocation), labor economics (training program take-up rates), and health economics (medical testing errors).\n",
1692-
"\n",
16931691
"### Methodological Limitations\n",
16941692
"\n",
16951693
"- **FDC Assumption 1** (all X→Y effects pass through M): This cannot be directly tested. We cannot rule out the possibility that merely knowing a ride is shared influences tipping psychology directly.\n",

book/fdc/frontdoor_criterion_ko.ipynb

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1688,8 +1688,6 @@
16881688
"- X와 Y 사이에 조건부 외생적 중재변수 M이 존재하며 (예: 알고리즘이 결정하는 매칭 여부)\n",
16891689
"- M의 변동이 사실상 외생적으로 발생하는 상황\n",
16901690
"\n",
1691-
"테크 업계(추천 알고리즘, 콘텐츠 배분), 노동경제학(직업 훈련 참여율), 보건경제학(의료 검사 오류) 등에 적용 가능합니다.\n",
1692-
"\n",
16931691
"### 방법론적 한계\n",
16941692
"\n",
16951693
"- **FDC 가정 1** (X→Y 효과가 전부 M 경유): 직접 검증 불가. 공유 인지 자체가 팁 심리에 직접 영향을 줄 가능성을 배제할 수 없습니다.\n",
@@ -1714,12 +1712,6 @@
17141712
"- **NYC TLC — 2023 High Volume For-Hire Vehicle Trip Records**. \n",
17151713
" [https://data.cityofnewyork.us/Transportation/2023-High-Volume-FHV-Trip-Data/u253-aew4/about_data](https://data.cityofnewyork.us/Transportation/2023-High-Volume-FHV-Trip-Data/u253-aew4/about_data)"
17161714
]
1717-
},
1718-
{
1719-
"cell_type": "markdown",
1720-
"id": "c0b260e1",
1721-
"metadata": {},
1722-
"source": []
17231715
}
17241716
],
17251717
"metadata": {

book/myst.yml

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,21 @@ project:
1919
- file: intro_en.md
2020
- file: intro_ko.md
2121
hidden: true
22-
- title: Why Causal Inference?
23-
file: why_causal_inference/why_causal_inference_en.ipynb
24-
- file: why_causal_inference/why_causal_inference_ko.ipynb
25-
hidden: true
26-
- title: "When Confounders Hide | Front-Door Criterion"
27-
file: fdc/frontdoor_criterion_en.ipynb
28-
- file: fdc/frontdoor_criterion_ko.ipynb
22+
23+
- title: 📖 Book
24+
children:
25+
- title: Why Causal Inference?
26+
file: why_causal_inference/why_causal_inference_en.ipynb
27+
- file: why_causal_inference/why_causal_inference_ko.ipynb
28+
hidden: true
29+
- title: "When Confounders Hide | Front-Door Criterion"
30+
file: fdc/frontdoor_criterion_en.ipynb
31+
- file: fdc/frontdoor_criterion_ko.ipynb
32+
hidden: true
33+
34+
- title: 🎬 Videos
35+
file: videos_en.md
36+
- file: videos_ko.md
2937
hidden: true
3038

3139
site:

book/videos_en.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Videos
2+
3+
**🌐 Language:** **English** | [한국어 →](/videos-ko)
4+
5+
<div style="display:flex; flex-flow:wrap; justify-content:flex-start;">
6+
7+
<div style="width:45%; margin-bottom:24px; margin-right:24px;">
8+
<h3 style="font-size:1rem; margin-bottom:8px;">Why Should We Care About Causal Inference? <span style="font-weight:normal; color:#888;"></span></h3>
9+
<div style="position:relative; padding-bottom:56.25%; height:0; overflow:hidden;">
10+
<iframe src="https://www.youtube.com/embed/tddr5GIIpFc?si=Q5tYCAevcSRKQH1j"
11+
style="position:absolute; top:0; left:0; width:100%; height:100%; border:0;"
12+
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
13+
allowfullscreen></iframe>
14+
</div>
15+
<p style="margin-top:8px; font-size:0.9rem; color:#555;">Through counterfactuals and potential outcomes, explains why correlation isn't causation — and how RCTs solve it.</p>
16+
</div>
17+
18+
</div>

book/videos_ko.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# 영상 목록
2+
3+
**🌐 언어:** [← English](/videos-en) | **한국어**
4+
5+
<div style="display:flex; flex-flow:wrap; justify-content:flex-start;">
6+
7+
<div style="width:45%; margin-bottom:24px; margin-right:24px;">
8+
<h3 style="font-size:1rem; margin-bottom:8px;">우리가 왜 인과추론에 관심을 가져야 할까요?</h3>
9+
<div style="position:relative; padding-bottom:56.25%; height:0; overflow:hidden;">
10+
<iframe src="https://www.youtube.com/embed/IKurxtuTb3o"
11+
style="position:absolute; top:0; left:0; width:100%; height:100%; border:0;"
12+
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
13+
allowfullscreen></iframe>
14+
</div>
15+
<p style="margin-top:8px; font-size:0.9rem; color:#555;">반사실과 잠재적 결과 개념을 통해, 상관관계가 왜 인과관계가 아닌지 설명하고 무작위 실험(RCT)의 역할을 소개합니다.</p>
16+
</div>
17+
18+
</div>

book/why_causal_inference/why_causal_inference_en.ipynb

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,31 @@
1818
"<small><em>Written by Haechang Cho · <a href=\"https://github.com/Funbucket\">GitHub</a> · <a href=\"https://www.linkedin.com/in/hae-chang-cho/\">LinkedIn</a></em></small>"
1919
]
2020
},
21+
{
22+
"cell_type": "code",
23+
"execution_count": 2,
24+
"id": "01f15a40",
25+
"metadata": {},
26+
"outputs": [
27+
{
28+
"data": {
29+
"text/html": [
30+
"<iframe width=\"560\" height=\"315\" src=\"https://www.youtube.com/embed/tddr5GIIpFc?si=jR277dXZfHRgGMFF\" title=\"YouTube video player\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" referrerpolicy=\"strict-origin-when-cross-origin\" allowfullscreen></iframe>"
31+
],
32+
"text/plain": [
33+
"<IPython.core.display.HTML object>"
34+
]
35+
},
36+
"execution_count": 2,
37+
"metadata": {},
38+
"output_type": "execute_result"
39+
}
40+
],
41+
"source": [
42+
"from IPython.display import HTML\n",
43+
"HTML('''<iframe width=\"560\" height=\"315\" src=\"https://www.youtube.com/embed/tddr5GIIpFc?si=jR277dXZfHRgGMFF\" title=\"YouTube video player\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" referrerpolicy=\"strict-origin-when-cross-origin\" allowfullscreen></iframe>''')"
44+
]
45+
},
2146
{
2247
"cell_type": "markdown",
2348
"id": "643181d0",
@@ -951,11 +976,10 @@
951976
"source": [
952977
"## References\n",
953978
"\n",
954-
"This notebook was written with reference to Matheus Facure's Python Causality Handbook.\n",
979+
"This notebook draws on Matheus Facure's *Causal Inference for the Brave and True*.\n",
955980
"\n",
956-
"- [01 - Introduction To Causality](https://matheusfacure.github.io/python-causality-handbook/01-Introduction-To-Causality.html)\n",
957-
"- [02 - Randomised Experiments](https://matheusfacure.github.io/python-causality-handbook/02-Randomised-Experiments.html)\n",
958-
"- [04 - Graphical Causal Models](https://matheusfacure.github.io/python-causality-handbook/04-Graphical-Causal-Models.html)\n"
981+
"- **Facure, M. (2022)**. *Causal Inference for the Brave and True*. Online book. \n",
982+
" [https://matheusfacure.github.io/python-causality-handbook/](https://matheusfacure.github.io/python-causality-handbook/)"
959983
]
960984
}
961985
],

0 commit comments

Comments
 (0)