사용자가 제공한 「Voice Clone Lecture Pipeline · Field Manual」을 이번 취창업역량강화 강의와 실제 경력 포트폴리오 설명 영상에 적용한 기록입니다. 완성 영상은 교수님의 녹음을 참조해 만든 합성 내레이션입니다. 어미 수정판에서는 기존 150개 문단을 전부 재합성했습니다.
| 영상 | 화면 수 | 길이 | 음성 문단 | ASR 정규화 문자 오류율 | 화자 코사인 평균 | 강조 장면 |
|---|---|---|---|---|---|---|
| 강의 | 36 | 21분 28초 | 115 | 1.42% | 0.832 | 131 |
| 포트폴리오 | 8 | 6분 02초 | 35 | 1.41% | 0.832 | 39 |
출력은 1920×1080, 30fps, H.264 영상과 AAC 오디오입니다. 두 영상 합계 150개 음성 문단, 44개 화면, 170개 강조 장면입니다. 각 화면의 시작 장면을 포함한 검수 이미지 214개를 만들고 직접 시각 검수했습니다.
| 노하우 | 이번에 적용한 내용 | 확인할 파일 |
|---|---|---|
| 실제 목소리의 출처 확인 | 사용자가 지정한 바탕화면 녹음 (9).m4a만 사용. 약 66초 원본에서 약 16초 참조 선택. 원본 파일 보존 |
voice/registration.json, checks/user-recording |
| 원문 보존 | PPT 노트와 포트폴리오 설명 원문을 보존. 읽지 않는 출처 문구 16개는 음성에서만 제외 | notes_orig, checks/notes-source-check.json |
| 발음 원고 정규화 | 숫자·영어·코드·단위를 한국어 발음으로 바꾸고 미치환 문자 0건 검사. 원문 자막은 유지 | manifest.json, verify_manual_assets.py |
| 한국어 ICL 합성 | Qwen3-TTS Base에 본인 참조 음성과 전사를 전달. BF16·SDPA·배치 4개로 합성 | presentation_tts.py, config.json |
| 끊긴 작업 재개 | 원고·목소리·모델 설정의 해시로 완료 조각 재사용. 불안정한 한 문단만 다시 합성 | segments/*.json, redo_segment.py, audio_old |
| 끝음절 보호 | 본문 뒤에 ‘감사합니다’를 추가 생성하고, 실제로 확인한 지속 무음에서만 분리. 무음이 불명확하면 다시 생성. 본문 소리에 페이드 적용하지 않음 | protected_endings.py, generation_attempts, checks/raw-preservation.json |
| 어미·대본 검사 | 전체 ASR와 마지막 5초 ASR을 별도로 검사. 재합성 후 확인 대상 0개 | ending-check.json, alignment |
| ASR 시간과 음성 편집 분리 | ASR은 후속 어절을 찾는 참고와 화면 동기화에 사용. 실제 절단은 지속 무음 내부에서 수행하며 ASR 끝 시각에서 자르지 않음 | protected_endings.py, align_and_check.py |
| 문장별 강조 | 문장마다 관련 도형·표·화면 영역을 선택. 소개·전환·화면 근거가 없는 문장에는 강조하지 않음 | highlights/designs, highlight/slide_NN/windows.json |
| 강조 여백 | PPT는 12px. 세로 PDF는 조밀한 줄 간격에 맞춰 가로 12px·세로 4px로 조정 | highlight_render.py |
| 독립 화면 검수 | 3개 작업자가 범위를 나눠 실제 MP4 추출 프레임을 전부 검수. 좌표 수정 후 다시 확인 | checks/visual-review-*.json |
| 원본 PPT 줄바꿈 | PowerPoint 네이티브 출력에서 보인 9·10·15·30장의 단어 분리를 수정. 다른 OOXML 부분은 그대로 보존 | 최종 PPTX, checks/native-v5 |
| 페이지별 보존·부분 렌더 | 페이지별 음성·영상·자막·강조 시간·해시 보존. 수정한 페이지만 재렌더 | output/TRACK/highlight/slide_NN |
| 깨진 영상 방지 | 각 클립 전체 디코딩과 프레임 수를 검사한 뒤 연결. 최종 MP4도 전체 디코딩 | render-check.json |
| 재인코딩 최소화 | 비디오 클립은 stream copy로 연결. 오디오는 연속 WAV에서 AAC로 한 번만 인코딩하여 조각별 지연 방지 | highlight_render.py |
| 소리 크기 정리 | 연속 내레이션을 목표 -18 LUFS, true peak -1.5 dBTP로 두 번 측정해 조정. 샘플 수 유지 | loudness.json, narration.raw.wav |
| 화자 비교 | 공식 CAM++ 모델로 본인 참조, 원본의 다른 구간, 다른 예제 음성, 모든 합성 문단을 비교 | speaker-check.json, checks/campplus-model.json |
| Windows·용량 운영 | UTF-8 실행, M4A는 FFmpeg 변환, 여유 공간 검사, 원자적 임시 파일 교체, 고정 모델 버전 | .cmd, models.lock.json, download_models.py |
원본 음성의 다른 구간과 참조의 코사인 유사도는 0.853~0.883, 다른 공식 예제 음성은 약 0.169였습니다. 이번 합성값은 이 비교 안에서 해석합니다. 다른 녹음에서 관찰한 0.60·0.66 같은 수치를 보편적인 합격선으로 사용하지 않았습니다. 화자 비교는 신원 증명이나 실제 청취 인상의 보장이 아닙니다. ASR 오류율에도 인식기의 표기 오류가 포함됩니다.
첫 버전은 후속 어절 생성 없이 무음만 덧붙였고, ASR이 정상 문장으로 인식한다는 이유로 끝음절 문제를 놓쳤습니다. 사용자가 ‘정리하겠습니ㄷ’처럼 끝난다고 확인했습니다. 이 방식은 폐기하고 전체 문단을 재합성했습니다. 이번 버전은 본문 다음에 후속 어절까지 생성해 본문 끝을 파일 경계에서 벗어나게 하고, 적어도 75ms 이상 지속되는 실제 무음 안에서만 후속 어절을 분리합니다. 무음이 불명확한 조각은 임의로 자르지 않고 다른 합성 결과를 생성합니다. 본문 발화는 페이드하거나 타임스탬프에 맞춰 잘라내지 않습니다. 후속 어절을 포함한 전체 생성 원본과 절단 정보를 모두 보관합니다.
Whisper가 마지막 음절을 문맥상 복원할 수 있으므로 ASR 문장 일치만으로 어미가 온전하다고 판정하지 않습니다. 다른 한국어 CTC 모델도 문제 있는 기존 샘플을 정상 어미로 인식했으므로, 이 점수 역시 끝음절 합격 기준에서 제외했습니다. 실제 무음 경계를 확인하고 수정 전·후 음성 비교를 제공했습니다. 사용자는 비교 음성의 뒤쪽, 새 방식으로 만든 ‘정리하겠습니다’에 대해 ‘뒤쪽은 어미가 온전함’으로 확인했습니다. 같은 생성·분리 방식을 전체 150개 문단에 적용했습니다. 음성 인식과 화자 점수는 진단 자료이며, 모든 문단을 사용자가 직접 청취했다는 뜻은 아닙니다.
무음 경계가 125ms 이하인 21개 문단은 제거된 뒷부분도 별도로 진단했습니다. CTC 전사 21개 모두 보호용 어절의 ‘감사’로 시작했고, 그보다 앞선 본문 음절은 전사되지 않았습니다. 8개는 제거 대상 어절의 끝을 ‘감사니’ 등으로 다르게 인식했습니다. 이 어절은 영상 내레이션에 포함되지 않습니다. 이 결과 역시 본문의 마지막 음절을 직접 들은 것과 같은 증거로 사용하지 않았습니다. 세부 전사는 checks/short-marker-gap-audit.json, 전체 교체·원본 보존과 사용자 비교 확인 기록은 checks/ending-repair-summary.json에 있습니다.
매뉴얼의 Python 3.10·CPU·특정 에이전트 모델 이름은 당시 환경 기록입니다. 이 PC에서 실제 합성과 검사를 통과한 Python 3.11·RTX 5090 환경과 현재 사용 가능한 3개 검수 작업자를 사용했습니다. FlashAttention을 무리하게 설치하거나 동작하는 환경을 낮추지 않았습니다. Windows 파일 관리는 PowerShell·Python의 명시적 경로로 처리했습니다.
외국어 발표는 이번 원고에 없습니다. 향후 필요하면 Qwen3-TTS의 언어 설정과 x-vector-only/ICL을 같은 문장으로 비교해 선택하며, 한국어 어미 검사 규칙을 그대로 적용하지 않습니다. 노래 변환·보컬 분리·Seed-VC 학습·고음 데이터셋·믹싱은 강의 TTS와 별개 작업이므로 실행하지 않았습니다. 미세학습이나 외국어·노래 결과물이 만들어졌다고 표시하지 않습니다.
모델 리비전은 models.lock.json, CAM++ 코드 리비전·모델 SHA-256은 checks/campplus-model.json에 고정했습니다. vendored CAM++ 코드에는 원본 Apache 2.0 라이선스를 보존했습니다.