
네 필러(Filler)를 세어라. AmiVoice API를 사용하여 일본어 필러를 지우지 않고 세는 CLI를 만들어 보았다
요약
AmiVoice API의 Hybrid 엔진을 활용하여 일본어 음성 파일 내 필러(Filler)의 개수와 타이밍을 추출하는 CLI 도구 제작 사례를 소개합니다. 필러를 삭제하지 않고 토큰 형태로 유지하는 기능을 통해 발표 연습을 위한 객관적 데이터 확보 방법을 다룹니다.
핵심 포인트
- AmiVoice Hybrid 엔진의 keepFillerToken 옵션 활용
- 필러를 %...% 토큰 형식으로 유지하여 시각 및 신뢰도 추출
- E2E 엔진과 Hybrid 엔진의 필러 제어 차이점 분석
- 음성 인식 API를 활용한 개인용 분석 도구 구현
서론
"네 죄를 네가 알렸다" 같은 멋진 대사에 🟢⚫️ 감탄하던 청춘 시절은 이미 오래전에 지나갔고, 저지른 죄를 기억 저편으로 밀어내는 데 전력을 다하고 있는 요즘입니다.
그러던 중, LT(Lightning Talk)나 기타 발표 연습을 하기 위해 자신의 이야기를 녹음해 보면, 어딘가 핵심을 찌르지 못하고 발화가 귀를 스쳐 지나가는 듯한 느낌이 듭니다….
전 직장에서 멘토가 되어 주셨던 분으로부터 "잘 전달하기 위해서는 먼저 자신의 말하기 방식을 객관적으로 아는 것이 중요하다"라는 조언을 들었습니다.
하지만 겁이 많은 저에게 그것은 그야말로 판도라의 상자였으며, 개선할 여지라고 한다면 앞날이 막막한 그 음성 파일을 저는 직시할 수가 없습니다….
그래서 저는 생각했습니다. AmiVoice API를 사용하면, 자신의 녹음 파일만 있어도 필러(Filler)의 개수와 타이밍, 그리고 그 종류를 직시하지 않고도 뽑아낼 수 있지 않을까? …라고 말이죠.
참 좋은 시대가 되었습니다. AI가 있다면 대부분의 개인용 도구는 하루면 완성되니까요.
…현실에서 눈을 돌리지 말고, 애초에 말하는 내용부터 정밀하게 검토하라고요?
네, 물론입니다. 그것도 언젠가는 할 거예요.
필러(Filler)에 관한 연구 등등
잡담은 이쯤 해두고, AmiVoice가 뛰어나다는 점, 즉 필러 삭제 및 일본어의 고정밀 인식을 이용해 반대로 필러를 검출해 보고 + AI와 함께 발표 연습까지 할 수 있다면 행복하지 않을까?
그것이 이번 작업의 시작입니다.
TL;DR
- AmiVoice API를 사용한 필러 카운트(Filler Count) CLI를 만들어 보았습니다.
- AmiVoice API의
keepFillerToken=1을 사용하면, 필러를%...%형식의 토큰(token)으로 유지할 수 있습니다. - 토큰 기반으로 하면 시각(Time)과 신뢰도(Confidence)도 다룰 수 있습니다. - 단, 사람이 필러처럼 느끼는 단어가 전부
%...%가 되는 것은 아닙니다.
AmiVoice API의 사양
먼저 AmiVoice API에 대해 가볍게 복습해 봅시다.
AmiVoice API는 Advanced Media가 제공하는 음성 인식 SaaS입니다.
일본어 도메인 특화 엔진이 풍부하며(의료, 금융, 보험…), 중요한 점은 필러 워드(Filler Word) 자동 삭제 기능을 가지고 있다는 점입니다.
"에— 그러니까(えーっと)"나 "저기—(あのー)"를 인식한 후 텍스트에서 지워줍니다. 훌륭합니다. 이것만 써도 강해진 것 같군요… 우오오.
이번에는 이것을 역으로 이용하겠습니다.
엔진은 2계통이 있다
AmiVoice API의 엔진에는 크게 2계통이 있습니다.
| 계통 | 식별자 예시 | 필러 제어 |
|---|---|---|
| Hybrid 엔진 (기존 방식) | -a-general | keepFillerToken으로 제어 가능 |
| End-to-End 엔진 (E2E) | -a2-ja-general | 항상 자동 삭제, 제어 불가 |
이번의 주인공은 **-a-general (일본어_회화_범용 Hybrid 엔진)**입니다.
E2E 엔진은 정밀도가 높고 숫자나 알파벳에 강하다고 알려져 있지만, 필러 토큰을 항상 삭제해 버리기 때문에 이번 용도로는 사용할 수 없습니다. 필러를 "지우지 않고" 세는 것이 목적이니까요.
흥미롭게도 하이브리드 엔진은 도메인 최적화도 되어 있는 듯하여, 단순한 코퍼스(Corpus) 데이터만은 아닐지도 모르겠습니다 (잘은 모름).
요청 형식
동기 HTTP API의 엔드포인트는 다음 하나입니다.
POST https://acp-api.amivoice.com/v1/recognize
요청은 multipart/form-data로 보냅니다. 필드는 3개입니다.
| 필드 | 필수 | 설명 |
|---|---|---|
u | ○ | API 키 |
d | ○ | 인식 파라미터 (공백으로 구분된 key=value 형식) |
a | ○ | 음성 데이터 (반드시 마지막 파트) |
d 필드에 채워 넣는 파라미터가 이번의 핵심입니다. 최소한 이것만 있으면 작동합니다.
grammarFileNames=-a-general keepFillerToken=1
curl로 재현하면 다음과 같습니다.
curl -X POST https://acp-api.amivoice.com/v1/recognize \
-F "u=YOUR_API_KEY" \
-F "d=grammarFileNames=-a-general keepFillerToken=1" \
...
keepFillerToken=0 と 1의 차이
이 부분이 이번의 핵심입니다.
keepFillerToken=0 (기본값): 필러 워드(Filler word)를 인식한 후, 텍스트에서 삭제합니다.
입력 음성: 「えーっと、会議があるので、えー、資料を作成しておきます」
인식 결과: 「会議があるので資料を作成しておきます」
keepFillerToken=1: 필러 워드를 삭제하지 않고, 앞뒤를 %로 감싼 형식으로 유지합니다.
입력 음성: 「えーっと、会議があるので、えー、資料を作成しておきます」
인식 결과: 「%えっと%会議があるので%えー%資料を作成しておきます」
응답 구조
응답은 JSON 형식으로 반환됩니다. 구조의 개요는 다음과 같습니다.
{
"text": "전체 발화 결합 텍스트",
"results": [
...
필러 토큰은 tokens[].written이 %えー%와 같이 앞뒤를 %로 감싼 형식이 됩니다. spoken에는 %가 없는 실제 발음이 들어갑니다. 일반적인 단어와 명확하게 구분할 수 있다는 점이 포인트입니다.
또한, 시간은 밀리초(ms) 단위로 반환됩니다. starttime: 1510이라면 1.510초부터 시작한다는 의미입니다.
대략적인 처리 과정
전체 처리 플로우는 다음과 같습니다.
음성 전송 방법
multipart/form-data로 음성 바이너리를 던지기만 하면 됩니다.
a 필드는 반드시 마지막 파트에 배치해야 합니다.
지원 포맷은 .wav와 .mp3입니다. 샘플링 레이트(Sampling rate)는 16kHz 모노럴을 권장합니다. 녹음 파일을 직접 변환해야 한다면, 인류 마지막의 비경이자 흑마술인 ffmpeg가 편리합니다.
ffmpeg -i input.m4a -ar 16000 -ac 1 output.wav
필러 검출 로직
AmiVoice로부터 tokens[]가 반환되면, written 필드를 정규 표현식(Regular expression)으로 판정합니다.
// ^%[^%]+%$ 에 매치 → 필러
var fillerPattern = regexp.MustCompile(`^%[^%]+%$`)
%えー%에는 매치됩니다. %(퍼센트 기호 1글자)에는 매치되지 않습니다.
왜 1글자를 제외하느냐 하면, 「ぱーせんと(퍼센트)」라고 발화했을 경우 written: "%"가 반환될 수 있기 때문입니다.
필러 마커인 %えー%와는 구분할 수 있습니다.
매치된 토큰으로부터 다음을 계산합니다.
| 메트릭 (Metrics) | 계산 방법 |
|---|---|
| 총 필러 수 | 매치된 token 수 |
| ... |
음성 길이 추정에 대해 한 가지 주의점이 있습니다.
AmiVoice API의 응답에는 음성의 총 재생 시간이 직접 포함되지 않습니다.
따라서 이 CLI에서는 전체 토큰 중에서 가장 큰 endtime을 음성 길이로 사용하고 있습니다. 끝부분에 무음 구간이 있는 경우 실제보다 짧게 추정됩니다.
출력 형식
--format markdown (기본값) 또는 --format json을 선택할 수 있습니다.
# Markdown으로 표준 출력
filler-cli analyze speech.wav
# JSON으로 파일에 저장
...
Markdown 출력은 다음과 같은 모습으로 만들어 보았습니다.
# Filler Analysis: speech.wav
## Estimated Speech Duration
69.8 s
...
정확도 등
검증을 위해 3종류의 대본을 준비했습니다 (상세 내용은 끝부분에).
| 샘플 | 내용 | 시간 |
|---|---|---|
| sample_a | 대본 읽기 · 필러 적음 | 약 60초 |
| ... |
keepFillerToken의 차이를 한눈에 확인
keepFillerToken=0과 keepFillerToken=1의 결과를 나란히 배치합니다.
| 샘플 | keepFillerToken=0 | keepFillerToken=1 |
|---|---|---|
| sample_a | 0건 | 1건 (あ) |
| ... |
keepFillerToken=0은 모든 샘플에서 0건입니다. 필러가 삭제되었으므로 당연한 결과입니다.
「필러가 0개」가 아니라 「추출할 수 없음」입니다. 일반적인 받아쓰기나 기타 용도라면 이쪽을 사용해야 합니다.
sample_b 필러가 많은 대본의 상세 내용
대본상의 필러 수는 10개(えー×5, あのー×3, えっと×2)였습니다.
API 결과: えー×5, あのー×3, えーっと×1, えっとー×1, そのー×1 (계 11건)
빈도: 9.45건/분
평균 confidence: 0.97
대본의 「えっと」가 「えーっと」와 「えっとー」라는 2가지 변형으로 인식된 점이 흥미롭습니다.
또한 대본에 없는 「そのー」가 1건 추가로 검출되었는데, 이는 대본을 읽는 중이었음에도 무의식중에 입 밖으로 나온 단어입니다. 인간이란 참 귀엽네요 🥰
정확도 측면에서는 거의 기대했던 결과입니다.
sample_c 즉흥 스피치의 상세 내용
API 결과: えー×2, う×1, ま×1, あ×1, うーん×1, え×1, こ×1 (계 8건)
빈도: 2.84건/분
평균 confidence: 0.81
이 부분이 고민되는 포인트입니다.
う, ま, あ, え, こ와 같은 단음절이 5건 포함되어 있습니다.
실제로 녹음 시 입에서 나온 소리인 것은 확실하지만, 이것들을 「필러 (Filler)」라고 부를 것인지는 사람마다 감각이 갈립니다.
말을 하려다 만 소리, 입버릇 같은 확인음, 문장 끊김의 짧은 감탄사 등 즉흥 스피치에는 모호한 소리가 혼재합니다.
confidence를 보면 あ (0.57)와 えー (0.59)는 낮으며, AmiVoice 스스로도 확신이 낮은 판정을 내리고 있습니다.
한계 정리
| 문제 | 설명 |
|---|---|
| 단음절의 혼입 | こ, ま, う 등 짧은 소리도 %...%가 될 수 있음 |
| 필러 정의의 경계 | その, まあ, はい 등 문맥에 따른 필러는 검출되지 않음 |
| 완전 목록 비공개 | AmiVoice가 어떤 단어를 필러로 취급하는지는 비공개이며 변경될 가능성이 있음 |
| 음성 길이의 추정 오차 | 끝부분에 무음이 있으면 durationSec가 과소 추정됨 |
| 동기화 API 상한 | 약 16MB (16kHz 16bit 모노럴 기준 약 4분이 기준) |
요컨대, 「인간이 필러 같다고 느끼는 모든 단어를 카운트하는 도구」는 아닙니다. AmiVoice가 %...%로 반환한 것 = 이 CLI가 검출하는 필러입니다. 정의는 AmiVoice에 달려 있습니다.
사용 예시와 Skills
설치
go install github.com/maro114510/filler-cli@latest
Go 1.26 이상이 필요합니다. 바이너리를 직접 다운로드하고 싶다면 GitHub의 Releases 페이지에서~
API 키 준비
AmiVoice Cloud Console에서 API 키를 취득합니다.
API 키를 전달하는 방법은 3가지가 있습니다.
| 방법 | 비고 |
|---|---|
환경 변수 AMIVOICE_API_KEY | CI나 스크립트용. 매번 사용한다면 .env + direnv가 편함 |
| 대화형 프롬프트 | 최초 실행 시 입력을 요구함. ~/.config/filler-cli/credentials.json에 캐시 (2시간) |
| 서비스 ID + 패스워드 | AMIVOICE_SERVICE_ID와 AMIVOICE_SERVICE_PASSWORD를 환경 변수에 설정하면 자동으로 원타임 키를 발행 |
기본적인 사용법
# Markdown 형식으로 표준 출력 (기본값)
filler-cli analyze speech.wav
# JSON으로 파일에 저장 (나중에 비교하고 싶을 때 유용)
...
어떤 상황에서 쓸 수 있는가
이 도구의 장점은 음성을 다시 들을 용기가 없어도 필러 상황을 알 수 있다는 점입니다.
녹음 파일을 넘겨주면 종류, 빈도, 타임라인까지 알아서 정리해 줍니다.
LT(Lightning Talk) 연습을 복기할 때 사용한다면, 다음과 같은 흐름이 자연스럽습니다.
- 발표를 녹음 (QuickTime이나 iPhone의 음성 메모)
- 필요하다면
ffmpeg로 16kHz 모노럴 WAV로 변환 - 명령어 한 줄로 필러 분석이 완전 자동 — 종류, 빈도, 타임라인 세트가 한꺼번에 나옴
filler-cli analyze --format json --output before.json speech.wav
- 연습·개선 후 재녹음
- 다시
analyze하여
before.json과
비교
빈도와 종류의 내역을 비교하면, 개선된 실감이 숫자로 나타납니다.
첫 등장 시각이 전반부에 집중되어 있다면, 도입부의 긴장이 나타나기 쉬운 신호로 읽을 수 있습니다.
면접 연습에서도 동일하게 사용할 수 있습니다. "에—"보다 "아노—"가 많다거나, 특정 질문에 대한 답변에서 필러 (Filler) 밀도가 높아지는 등, 패턴을 파악하는 것만으로도 의식이 달라지지 않을까요?
presentation-coach 스킬
CLI를 직접 입력할 필요가 없다. 이것이 가장 큰 장점입니다. (으스대며)
filler-cli에는 AI Agent를 위한 presentation-coach 스킬이 동봉되어 있습니다.
평소 사용하는 Claude에게 말을 거는 것만으로, filler-cli analyze 실행부터 슬라이드 분석·코칭 리포트까지 전부 해줍니다.
AmiVoice의 API 키만 설정해 두면, Claude 측의 추가 설정은 필요 없습니다.
셋업 (Setup)
gh CLI 또는 npx로 설치할 수 있습니다.
gh skill install maro114510/filler-cli
npx skills add maro114510/filler-cli
사용법
녹음 파일과 슬라이드를 준비하고, Claude에게 말을 걸기만 하면 됩니다.
"발표 연습 피드백을 주세요"
"슬라이드와 음성을 함께 분석해 줘"
"어느 부분을 연습하면 좋을까?"
"녹음을 봐줬으면 좋겠어"
왠지 해낼 수 있을 것 같은 기분이 들지도 모릅니다.
요약
- AmiVoice API의
keepFillerToken=1을 사용하면, 필러를 삭제하지 않고%...%형식으로 유지할 수 있음 - 토큰 (Token) 기반이므로 타임스탬프 (Timestamp)와 신뢰도 (Confidence)도 함께 가져올 수 있음 - 정밀도의 핵심은 "AmiVoice가 무엇을 필러로 판단하는가"에 달려 있음. 인간의 감각과 반드시 일치하지는 않음
- 동기 (Synchronous) API는 약 16MB(약 4분)가 상한선. 긴 녹음에는 비동기 (Asynchronous)/WebSocket이 필요함
- 소스 코드는 아래에 있습니다! 괜찮다면 스타(Star) 부탁드려요⭐️
AmiVoice API의 매력을 조금이라도 전달할 수 있었다면 행복하겠습니다. 여러분의 발표 생활에 행운이 가득하기를.
…에—, 그, 뭐랄까. 이상입니다.
검증용 대본
sample_a: 대본 읽기·필러 적음 (60초)
안녕하세요. 오늘은 AmiVoice API를 사용한 일본어 필러 분석 CLI에 대해 소개합니다.
이 도구는 음성 파일을 입력하면, 텍스트 변환 결과에 포함된 필러 토큰을 추출하여 횟수와 출현 시각을 리포트합니다.
주요 대상은 LT(Lightning Talk)나 면접 연습 등, 짧은 발화를 개선하고 싶은 상황입니다.
...
sample_b: 대본 읽기·필러 많음 (60초)
에—, 안녕하세요. 오늘은, 아노—, AmiVoice API를 사용한 일본어 필러 분석 CLI에 대해 소개합니다.
에또, 이 도구는 음성 파일을 입력하면, 에—, 텍스트 변환 결과에 포함된 필러 토큰을 추출합니다.
아노—, 주요 대상은 LT나 면접 연습 등, 짧은 발화를 개선하고 싶은 상황입니다.
...
sample_c: 즉흥 설명 (90~180초)
대본 없이 녹음.
테마: "이 CLI에서 AmiVoice API의 keepFillerToken을 사용하여, 필러를 세는 메커니즘을 설명해 주세요"
말할 내용:
- 왜 만들었는가
...
링크
AmiVoice API
참고 문헌
- Laske, M. M. & DiGennaro Reed, F. D. (2024). Um, so, like, do speech disfluencies matter? A parametric evaluation of filler sounds and words. Journal of Applied Behavior Analysis, 57(3), 574–583.
https://pubmed.ncbi.nlm.nih.gov/38819033/ - Kirkland, A., Gustafson, J., & Székely, É. (2023). Pardon my disfluency: The impact of disfluency effects on the perception of speaker competence and confidence. INTERSPEECH 2023.
https://www.speech.kth.se/tts-demos/kirkland23_interspeech.pdf - Nishizaki, H., Sohmiya, M., Kobayashi, K., & Sekiguchi, Y. (2007). The effect of filled pauses in a lecture speech on impressive evaluation of listeners. INTERSPEECH 2007.
https://www.isca-archive.org/interspeech_2007/nishizaki07_interspeech.pdf - Cevasco, J. & van den Broek, P. (2016). The effect of filled pauses on the processing of the surface form and the establishment of causal connections during the comprehension of spoken expository discourse. Cognitive Processing, 17(2), 185–194.
Laske, M. M. & DiGennaro Reed, F. D. (2024). Um, so, like, do speech disfluencies matter? Journal of Applied Behavior Analysis, 57(3), 574–583. https://pubmed.ncbi.nlm.nih.gov/38819033/ ↩︎ - Kirkland, A., Gustafson, J., & Székely, É. (2023). Pardon my disfluency: The impact of disfluency effects on the perception of speaker competence and confidence. INTERSPEECH 2023.
https://www.speech.kth.se/tts-demos/kirkland23_interspeech.pdf ↩︎ - Nishizaki, H., Sohmiya, M., Kobayashi, K., & Sekiguchi, Y. (2007). The effect of filled pauses in a lecture speech on impressive evaluation of listeners. INTERSPEECH 2007.
https://www.isca-archive.org/interspeech_2007/nishizaki07_interspeech.pdf ↩︎ - Cevasco, J. & van den Broek, P. (2016). The effect of filled pauses on the processing of the surface form and the establishment of causal connections. Cognitive Processing, 17(2), 185–194. https://pubmed.ncbi.nlm.nih.gov/26899571/ ↩︎
논의 (Discussion)
AI 자동 생성 콘텐츠
본 콘텐츠는 Zenn AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기