EFaligner는 HTK(Hidden Markov Model Toolkit) 기반의 영어 강제 정렬(Forced Alignment) 시스템입니다. P2FA(Penn Forced Aligner)를 기반으로 하여 음성 파일과 전사 텍스트를 입력받아 음소(phoneme) 및 단어(word) 단위의 정확한 시간 정렬 정보를 Praat TextGrid 형식으로 출력합니다.
문서 갱신일: 2026-10-25. 현재 웹앱과 GPU 전사 환경은 Python 3.12에서 검증했습니다.
| 항목 | EFaligner 설정 |
|---|---|
| 서비스 주소 | efaligner.tyoon.net |
| Whisper 전사 | 전사 화면 · medium.en, 영어, CUDA 우선 |
| 기존 WAV/TextGrid 검토 | 검토 화면 |
| 정렬 결과 tier | phone, word |
| 운영 서비스 | efaligner.service · Nginx 뒤의 Gunicorn 127.0.0.1:5021 |
| Python 환경 | /var/www/html/efaligner/.venv |
로그인 후 사용합니다. GPU는 Whisper 전사에 사용하며, 강제정렬은 HTK가 수행합니다. 한국어 파일은 KFaligner를 사용하세요.
- 전사가 있는 경우: 메인 화면에서 같은 이름의 WAV + TXT/LAB를 업로드합니다.
- 전사가 없는 경우:
/transcribe에서 WAV를 전사하고 편집한 뒤 Run alignment를 누릅니다. 먼저 저장 버튼을 누를 필요는 없습니다. - 정렬 결과 검토: 파일별 파형과 모든 TextGrid tier를 확인합니다. 기존 WAV + TextGrid는
/review에서 여러 쌍을 업로드할 수 있습니다. - 일부만 수정: 오류 구간을 선택하고 그 구간의 전사를 수정한 뒤 Realign selection을 실행합니다.
- 내려받기: TextGrid를 개별 다운로드하거나, WAV·TXT/LAB·TextGrid가 같은 폴더에 들어가는 ZIP을 받습니다.
- 자동 음소 정렬: 영어 음성과 텍스트를 음소 단위로 정확하게 정렬
- 다중 샘플레이트 지원: 8kHz, 11.025kHz, 16kHz 음성 파일 처리
- 자동 리샘플링: sox를 이용한 자동 변환
- TextGrid 출력: Praat에서 바로 사용 가능한 표준 형식
- 웹 인터페이스: Whisper GPU 전사, 수정 전사 바로 정렬, 파일별 WaveSurfer 검토, 부분 재정렬 제공
- Short Pause (sp) 처리: 단어 사이의 휴지를 별도 구간으로 분리
- P2FA 호환: Penn Forced Aligner와 호환되는 모델 사용
- Python: 3.12 (현재 웹앱·Whisper 환경 검증 버전)
- HTK: 3.4.1 (Hidden Markov Model Toolkit)
- sox: 음성 리샘플링용
- FFmpeg: Whisper 음성 디코딩용
- GPU 전사 사용 시: CUDA 12.6 PyTorch와 호환되는 NVIDIA 드라이버
- OS: Linux (Ubuntu 20.04+ 권장)
requirements.txt에 Flask 확장, g2p-en, praat-parselmouth 등
웹앱·영어 정렬에 필요한 패키지가 들어 있습니다. Whisper GPU 전사는
requirements-whisper.txt를 추가로 설치합니다.
requirements-lock.txt는 Whisper/CUDA를 포함한 현재 환경의 버전을 기록합니다.
cd /var/www/html/efalignerHTK는 라이선스 제약으로 직접 다운로드가 필요합니다:
- HTK 공식 사이트에서 HTK-3.4.1 다운로드
- 압축 해제 및 컴파일:
tar -xvf HTK-3.4.1.tar.gz
cd htk
./configure --prefix=/usr/local
make all
sudo make installsudo apt-get update
sudo apt-get install sox libsox-fmt-all# Python 3.12 환경에서 실행
python3 -m venv .venv
.venv/bin/python -m pip install -r requirements.txt
# 이 서버의 CUDA 기반 Whisper 전사 사용 시 추가 설치
.venv/bin/python -m pip install -r requirements-whisper.txt현재 운영 환경을 같은 버전으로 재생성하려면 다음 명령을 사용합니다.
.venv/bin/python -m pip install -r requirements-lock.txt --extra-index-url https://download.pytorch.org/whl/cu126NLTK 발음 사전·영어 품사 태거 설치와 .env 설정은
배포 문서를 참고하세요. 기존 .env와 사용자 DB는 덮어쓰지 않습니다.
명령행 정렬도 .venv/bin/python을 사용하거나 가상환경을 활성화한 상태에서 실행합니다.
P2FA 모델이 model/ 디렉토리에 있는지 확인:
ls -la model/
# dict, monophones, 8000/, 11025/, 16000/ 폴더가 있어야 함python3 align.py <audio.wav> <transcript.txt> <output.TextGrid>예시:
python3 align.py test/BREY00538.wav test/BREY00538.txt test/BREY00538.TextGrid-r RATE: 샘플레이트 지정 (8000, 11025, 16000 중 하나)-s START: 시작 시간 (초 단위, 기본값 0)-e END: 종료 시간 (초 단위)
예시:
# 16kHz로 강제 변환
python3 align.py -r 16000 audio.wav transcript.txt output.TextGrid
# 특정 구간만 정렬 (5초부터 15초까지)
python3 align.py -s 5.0 -e 15.0 audio.wav transcript.txt output.TextGrid- 형식: WAV (PCM)
- 샘플레이트: 8kHz, 11.025kHz, 16kHz (권장)
- 채널: 모노 (단일 채널)
- 비트 깊이: 16-bit
- 인코딩: UTF-8, UTF-16, Latin-1 지원
- 내용: 순수 텍스트 (영어 대소문자 모두 가능)
- 특수 기호: 자동으로 제거됨 (
,,.,!,?등)
예시:
The quick brown fox jumps over the lazy dog.
This is a test sentence for alignment.
- 형식: Praat TextGrid (short format)
- 티어:
- phone: 음소 단위 정렬
- word: 단어 단위 정렬
efaligner/
├── align.py # 메인 정렬 스크립트
├── run.sh # 테스트 실행 스크립트
├── README.md # 이 파일
├── model/ # P2FA 음향 모델
│ ├── dict # 발음 사전
│ ├── monophones # 음소 목록
│ ├── 8000/ # 8kHz 모델
│ │ ├── config
│ │ ├── hmmdefs
│ │ └── macros
│ ├── 11025/ # 11.025kHz 모델
│ │ ├── config
│ │ ├── hmmdefs
│ │ └── macros
│ └── 16000/ # 16kHz 모델
│ ├── config
│ ├── hmmdefs
│ └── macros
├── test/ # 테스트 파일
│ ├── BREY00538.wav
│ ├── BREY00538.txt
│ └── BREY00538.TextGrid
├── tmp/ # 임시 작업 디렉토리 (자동 생성)
└── webapp/ # Flask 웹 애플리케이션
├── app.py
├── templates/
└── data/
운영 서버: https://efaligner.tyoon.net
이 서버의 설치·운영 절차는 deploy/README.md를 참고하세요.
앱은 127.0.0.1:5021에서 실행되며 Nginx가 HTTPS 요청을 전달합니다.
기존 venv/는 이전 Python 환경이므로 새 .venv/를 사용합니다.
# 최초 서비스 등록 및 HTTPS 인증서 발급
sudo bash /var/www/html/efaligner/deploy/install.sh
# 이후 코드 변경 적용
sudo systemctl reload efaligner로컬 실행은 저장소 루트에서 bash start_webapp.sh를 사용합니다.
일반 WAV/TXT 정렬 경로가 tmp/와 dict.local을 공유하므로 Gunicorn은 sync worker 1개를 사용합니다.
Whisper 화면의 Run alignment와 부분 재정렬은 전용 임시 폴더·사전 복사본을 사용합니다.
실행 중인 서비스와 CLI 정렬 작업을 동시에 실행하지 마세요.
업로드 한도는 .env의 MAX_CONTENT_LENGTH_MB와 deploy/nginx.conf의
client_max_body_size를 함께 조정합니다. 현재 둘 다 64MB입니다.
운영 .env는 WHISPER_MODEL_NAME=medium.en, WHISPER_DEVICE=cuda를 사용합니다.
영어 전용 모델은 .cache/whisper/medium.en.pt에 저장되며, 서비스 재시작 후 첫 전사
요청에서 GPU 메모리에 적재합니다. 이후 요청은 적재한 모델을 재사용합니다.
CUDA를 사용할 수 없거나 모델 적재에 실패하면 앱은 CPU로 재시도합니다.
# 모델을 미리 다운로드·적재하여 확인
.venv/bin/python -c "import whisper; whisper.load_model('medium.en', device='cuda', download_root='.cache/whisper')"FFmpeg는 /home/tyoon/miniconda3/envs/espnet/bin/ffmpeg, HTK는
/home/tyoon/htk_install/bin을 사용하며 서비스가 PATH에 추가합니다.
.env 또는 앱 코드를 변경한 뒤에는 sudo systemctl reload efaligner로 반영합니다.
Whisper 결과의 Manual transcript를 수정한 뒤 Save manual transcript 왼쪽의 Run alignment를 누르면 현재 파일의 WAV와 편집창의 최신 전사를 사용해 정렬합니다. 미리 Save를 누를 필요가 없으며, 정렬 요청 시 수정 전사도 함께 저장합니다.
- 현재 페이지의 파일 한 개만 정렬하고 다른 파일의 전사와 Whisper 자동 전사는 유지합니다.
- 결과는 파형·TextGrid 검토 화면에서 확인하고, Back to manual transcript로 원래 전사 페이지에 돌아갈 수 있습니다.
- Save manual transcript는 전사 저장만 수행합니다.
- 정렬이 실패해도 수정 전사를 유지하므로 내용을 확인하고 다시 실행할 수 있습니다.
- 결과 ZIP에는 해당 WAV, 사용한 수정 전사 TXT, TextGrid가 같은 폴더에 포함됩니다.
- 전사 WAV/TXT ZIP을 다운로드해도 원본을 보관하므로 이후 다시 정렬할 수 있습니다.
- 화면 업데이트 전에 열어 둔 전사 페이지는 새로고침한 뒤 사용하세요.
- 새 WAV + TXT/LAB 정렬이 끝나면
/review/<job_id>에서 파일별 파형과 TextGrid를 표시합니다. - 기존 정렬 파일은 메인 화면의 Open Waveform / TextGrid Review 또는
/review에서 같은 이름의 WAV와 TextGrid를 여러 쌍 업로드합니다. - 업로드한 쌍마다 검토 카드가 하나씩 표시됩니다. WAV 5개와 대응하는 TextGrid 5개를 올리면 카드 5개가 나타납니다. 오류가 있는 파일도 오류 카드로 남고 다른 파일의 검토는 계속할 수 있습니다.
- 모든 interval/point tier를 음성의 시간축에 맞춰 표시합니다. 구간을 클릭하면 라벨·시작·끝 시간을 확인하고 해당 구간을 재생합니다.
- 파일별 재생 속도, 확대, 가로 스크롤을 지원합니다. 다른 파일을 재생하면 이전 파일은 일시 정지됩니다.
- Praat long/short TextGrid와 Unicode·인용부호·여러 줄 라벨을 지원합니다. 음성 밖의 주석은 화면에서만 잘라 표시하며 원본 시간값은 변경하지 않습니다.
- ZIP에는 WAV·TextGrid·전사 파일이 하위 폴더 없이 함께 들어갑니다. ZIP 다운로드 후에도 검토용 원본을 유지하므로 같은 주소로 다시 검토할 수 있습니다.
- 새 검토 작업은 로그인한 업로드 계정에서만 열 수 있습니다. 기존 공유 게스트 계정은 같은 계정 사용자끼리 작업을 공유합니다.
- WaveSurfer 7.12.12와 라이선스는
webapp/static/vendor/wavesurfer/에 포함되어 외부 CDN 없이 동작합니다. TextGrid 파싱에는praat-parselmouth를 사용합니다.
검토 카드에서 Select region을 켜고 파형을 드래그하거나 TextGrid 구간을 클릭합니다. 선택 영역 양 끝을 끌거나 Start/End에 정확한 초를 입력한 뒤, Corrected transcript에 선택 구간에 들리는 영어 전사만 입력하고 Realign selection을 누릅니다. 단어 중간을 자르지 않도록 선택하고 짧은 무음 여유를 포함하면 정렬에 도움이 됩니다.
- 선택 범위는 WAV와 TextGrid 안의 0.1초 이상 구간이어야 합니다.
- 선택 구간의 음성만 16kHz mono 복사본으로 추출해 영어 정렬기에 전달합니다.
- 선택 범위 안의
phone/wordtier만 교체합니다 (phones,phoneme(s),words별칭도 지원). - 선택 범위 밖의 시간값과 라벨은 정확히 보존합니다. 선택 경계를 가로지르는 구간은 해당 경계에서 나뉘며 바깥쪽 라벨은 유지됩니다.
- 다른 주석 tier와 point tier, 다른 파일, 원본 WAV는 변경하지 않습니다. 보존 검사가 실패하면 결과를 저장하지 않습니다.
- 작업별 전용 임시 폴더와
dict.local복사본을 사용합니다. 미등록 단어의 발음을 생성하면 한 번 재시도하며, 전사 단어가 누락된 정렬은 저장하지 않습니다. - 정렬 실패·시간 초과(180초) 시 원본을 유지합니다. 다른 창에서 이미 변경된 파일을 오래된 버전으로 덮어쓰지 않습니다.
- Undo last edit는 직전 변경 한 번을 취소하여 이전 TextGrid의 원본 바이트를 복원합니다.
- Download original TextGrid는 최초 수정 전 파일을 다운로드합니다. 백업은 해당 작업의
.edits/에 보관하고 일반 ZIP에는 포함하지 않습니다. - TextGrid와 ZIP 다운로드에는 최신 TextGrid가 포함됩니다. 업로드한 원본 TXT/LAB와 미리보기는 그대로 보관합니다.
| 위치 | 내용 |
|---|---|
webapp/data/users.db |
사용자 DB |
webapp/data/transcribe_jobs/<job_id>/ |
Whisper 원본 WAV, 자동 전사, 수정 전사와 job.json |
webapp/data/uploads/<job_id>/ |
정렬·검토에 사용한 WAV와 TXT/LAB |
webapp/data/jobs/<job_id>/ |
TextGrid, 검토 manifest와 ZIP |
webapp/data/jobs/<job_id>/.edits/ |
부분 수정 전 원본, 직전 취소용 백업과 수정 정보 |
ZIP은 다운로드할 때 최신 TextGrid로 다시 생성하며 .edits/ 백업과 manifest는 포함하지 않습니다.
기존 WAV/TextGrid만 업로드한 작업에는 원래 TXT/LAB가 없으므로 ZIP에도 들어가지 않습니다.
부분 재정렬은 TextGrid를 갱신하고 원본 TXT/LAB는 별도로 보관합니다.
자료는 ZIP 다운로드 후에도 유지되며 자동 보관 만료는 없습니다. 검토 URL을 저장하면 같은 계정으로 다시 열 수 있습니다.
.env의 MAX_FILES_PER_REQUEST는 파일 수이며 WAV + TXT 또는 WAV + TextGrid 한 쌍은
파일 2개로 계산합니다. 앱 기본값 100개는 최대 50쌍입니다.
TRANSCRIBE_MAX_FILES의 기본값은 WAV 20개, 요청 전체 크기는 앱 기본값 64MB입니다.
실제 한도는 .env와 Nginx 설정을 확인하세요.
sudo systemctl status efaligner
sudo systemctl reload efaligner
sudo systemctl restart efaligner
sudo journalctl -u efaligner -n 80 --no-pager
sudo certbot renew --cert-name efaligner.tyoon.net --dry-run- webapp/app.py: 전사, 저장·정렬 버튼, 다운로드.
- webapp/review.py: 파일별 파형·TextGrid 검토 API.
- webapp/partial_alignment.py: 선택 구간 병합, 보존 검사, 취소.
- webapp/segment_aligner.py: 독립 작업 폴더·사전, 미등록 단어 재시도, 시간 초과 처리.
- webapp/static/js/transcribe-actions.js: 정렬 버튼의 진행 상태 표시.
- tests: 전사→정렬, 다중 파일 검토, 부분 재정렬과 다운로드 회귀 검증.
.venv/bin/python -m unittest discover -s tests -p 'test_*.py' -v위 갱신일 기준 자동 검증 25개와 실제 Whisper 영어 전사→편집→HTK 정렬의 HTTPS 브라우저 검증이 통과했습니다. 현재 파일만 정렬하는 동작, 미저장 수정 내용 반영, ZIP 파일 구성, 모바일 버튼 배치도 확인했습니다. 단위 테스트는 임시 디렉터리를 사용합니다.
- 기반: P2FA (Penn Forced Aligner) v1.003
- 학습 데이터: TIMIT 코퍼스
- 음소 세트: CMU 음소 체계 기반
- HMM 상태: 3-state left-to-right HMM
- 전처리: 텍스트 정규화 및 사전 확인
- 특징 추출: PLP (Perceptual Linear Prediction) 계수
- 정렬: Viterbi 알고리즘 기반 강제 정렬
- 후처리: sp(short pause) 분리 및 TextGrid 생성
- sil (Silence): 발화 전후의 긴 침묵 구간
- sp (Short Pause): 단어 사이의 짧은 휴지 (P2FA 모델에서 사용)
- 처리: 각 단어의 정확한 시작/끝 시간 사용 (v1.1+)
- 효과: 더 정확한 단어 경계 및 침묵 구간 표현
- 수정 전: Word tier에서 각 단어의 끝 시간이 다음 단어의 시작 시간으로 잘못 표시됨
- 수정 후: 각 단어/침묵 구간이 실제 음소 경계 기반의 정확한 시작/끝 시간을 가짐
- 영향: 침묵 구간(sil/sp)의 정확도 향상, 단어 간 간격 정확히 표현
# HTK가 PATH에 있는지 확인
which HCopy
# 없으면 HTK 재설치 또는 PATH 설정
export PATH=/usr/local/bin:$PATH# sox 설치
sudo apt-get install sox libsox-fmt-all- 발음 사전에 없는 단어
dict.local파일에 발음 추가:
NEWWORD N Y UW W ER D
- 음성 파일과 텍스트 불일치
- 음성 품질 확인 (노이즈, 볼륨)
- 전사 텍스트 정확성 확인
- 샘플레이트: 16kHz 사용 권장 (정확도 향상)
- 파일 크기: 한 번에 처리할 파일 크기는 5MB 이하 권장
- 배치 처리: 앱 기본값 100개 파일(최대 50쌍); 실제
.env설정 확인
P2FA 기본 사전(model/dict)에 없는 단어는 SKIPPING WORD 로그로 표시되며 g2p-en이 발음 생성을 시도합니다.
일반 CLI/전체 업로드 경로에서 새 발음을 추가한 뒤 재실행 안내가 나오면 다시 정렬합니다.
Run alignment와 부분 재정렬은 작업용 사전 복사본으로 한 번 재시도하고, 여전히 누락되는 단어가 있으면 결과를 저장하지 않습니다.
필요한 경우 사용자 사전 dict.local을 프로젝트 루트(efaligner/)에 생성하면, 실행 시 자동으로 기본 사전과 병합하여 사용합니다.
- 위치와 파일명
- 경로:
efaligner/dict.local - 인코딩: UTF-8 권장
- 형식
- 한 줄에 하나의 항목:
WORD PHONEME1 PHONEME2 ... - 단어는 대문자 사용 권장(P2FA/CMU 관례)
- 발음은 ARPABET 음소 체계 사용(P2FA 모델과 일관)
예시:
AIYOUNG EY1 Y AH2 NG
GITHUB G IH1 T HH AH2 B
COPILOT K OW1 P AY2 L AH0 T
- 주의사항
sil,sp등 특수 토큰은 재정의하지 마세요(모델/스크립트에서 사용).- 동일 단어가 여러 번 정의되면 예측 불가 동작이 발생할 수 있으므로 한 번만 정의하세요.
- 대소문자 매칭에 유의하세요(사전은 대문자를 기대합니다).
- 점검 방법
- 실행 전 빠르게 포함 여부 확인:
rg -n "^WORD " model/dict dict.local - 실행 중 로그에서
SKIPPING WORD가 사라졌는지 확인
- 백업 권장
- 현재
.gitignore는dict.local을 제외합니다. 사전 변경을 보존하려면 별도 백업 정책을 정하세요. - 대규모 추가 전에는 사본을 만들어 변경 이력을 남기세요.
이 프로젝트는 MIT 라이선스 하에 배포됩니다.
- P2FA (Penn Forced Aligner): 기본 모델 및 코드 제공
- HTK (Hidden Markov Model Toolkit): 음성 인식 엔진
- TIMIT 코퍼스: 음향 모델 학습 데이터
문제가 발생하거나 개선 사항이 있으면 이슈를 등록해주세요.
EFaligner - Precise English Speech Alignment Made Easy