본문 바로가기
C.W.K.
Lesson 09 of 10 · published

목소리는 건네받은 걸로 짐작해

~15 min · tts, misreads, one-door, evolution

Level 0불 꺼진 작업장
0 XP0/58 lessons0/12 achievements
0/100 XP to next level100 XP to go0% complete

규칙 하나, 측정 둘

이 트랙 네 번째 강의는 한 언어 구간 안의 외국어 용어를 그 구간의 문자로 옮겨 적으라고 가르쳤어. 짐작으로 정한 규칙이 아니야. 그때 목소리들은 한국어 문장 속 라틴 문자 단어를 만나면 억양이 도박이 됐거든. 주인은 2026-07-26 에 산문 낭독을 두고 이걸 앞으로의 규칙으로 못 박았어.

이게 품질 통과되면 앞으로 한글 영상 한글 목소리는 영어 스펠링을 안 쓰고 음차쪽으로 가면 되는 거고 — 아빠

테이크 파이프라인은 지금도 이걸 지켜. 라틴 문자가 섞인 한국어 구간은 검사에서 떨어져.

그런데 2026-10-21, 같은 주인이 여행 파이프라인에선 반대로 판정했어. 그리고 두 번 다 맞았어. 프리힐리아나 편집본의 바탕이 된 대화에서 주인은 "one of us"라고 말했어. 대본은 그걸 원 오브 어스로 적었고, 목소리는 "one of earth"라고 읽었지. 목소리한테 한글은 소리를 중립적으로 적은 표기가 아냐. 뒤에 그럴듯한 단어가 여럿 숨은 소리야. 어스는 earth 를 한글로 적을 때도 쓰거든. 편집본을 보고 주인이 원리를 짚었어.

오히려 한글 그대로 줘서 보이스 모형이 추정하는 걸 거야 — 아빠

같은 편집본에 같은 종류 실패가 둘 더 있었어. 받아쓰기가 주인의 "kludgy"를 클럼지로 바꿔놨고, 목소리는 그걸 "clumsy"로 읽었어. 피파는 모델 가중치를 무게라고 썼는데, 저울에 다는 무게가 아니라 웨이트였어야 했지. 단어는 소리만이 아니라 뜻으로도 골라.

그래서 모바일 절차 baseline 1.6(869c46c)이 여행 파이프라인과 대화 파이프라인에서 규칙을 뒤집었어. 주인이 영어로 한 말이나, 한국어 표기가 안 정해진 용어는 한국어 say 안에 영어로 적어. 인용한 구절, 게임 고유명사, kludgy 같은 엔지니어링 형용사 같은 것들. 자막도 영어로 나가. 슈퍼 인텔리전스처럼 이미 자리 잡은 외래어는 그대로 두고. 어느 쪽도 취향이 아니야. 둘 다 어떤 목소리가 어떤 글을 어떻게 읽었는지 잰 결과고, 이제 파이프라인을 나눠 나란히 살아.

맞게 적어도 빗나가

영어로 다시 합성해도 끝나지 않았어. 그냥 쓴 "one of us"는 또 "one of Earth"로 돌아왔고, 따옴표를 친 'One of Us'만 제대로 읽혔거든. 그래서 규칙은 철자에서 안 멈춰. 합성이 끝나면 한국어 대사 속 영어 용어를 실은 말 조각은 전부 받아쓰기에 넘겨서 다시 읽고 audio/term-readback.json 에 남겨. out/WATCH.md 는 그 구간들을 표시된 것부터 늘어놓고, 주인은 시청할 때 그 대목을 귀로 확인해. 받아쓰기가 안 깔린 맥에서도 이 단계는 그냥 끝나. 그땐 구간마다 들은 게 없고 표시도 없는 채로 남고, 시청 시트는 그걸 인식 못 한 구간으로 세. 목록은 여전히 구간을 전부 짚지만, 확인했다고 우기진 않아. 받아쓰기는 영어 단어를 어느 문자로도 적을 수 있어서, 깨끗한 전사 자체로는 아무것도 증명 못 해. 이 목록이 하는 일은 그걸 판단할 수 있는 유일한 도구 앞에 위험한 대목을 전부 갖다 놓는 거야.

실패는 반대 방향으로도 나. 한국어 대사 속 영어 철자를 목소리가 잘못 읽으면, 그건 의도한 한글로 적어. "resume"은 프랑스어 résumé 인 레주메로 돌아왔어. 그래서 대본엔 리쥼이나 한국어 표현을 써. 그리고 2026-10-26, 한국어 조사에 붙은 질문 하나가 콩글리시로 돌아왔어. "What took you so long?" 바로 뒤에 조사 '에'가 붙은 문장이었지.

what took you so long 을 완전한 문장으로 독립해야 할 거야 … 한글에 섞이면 v4모형도 아직 이상하게 콩글리시로 읽는 경우가 있어 — 아빠

영어 문장엔 한국어 조사를 절대 안 붙여. 영어는 영어 문장 하나로 세우고, 한국어는 새 문장으로 시작해. What took you so long? 이 질문에 … 이렇게(b8a5d9a). 네 번째 강의의 '끼워 넣지 마'가 모양만 바꾼 거야. 전환은 여전히 목소리가 알아듣는 경계에서 일어나. 다만 그 경계가 이제 호출이 아니라 문장이야.

돈 쓰기 전에 거절하는 표

2026-10-22 까진 이 줄들이 절차 문서 안의 표였고, 리뷰 5 는 파이프라인 어디서도 그 표를 검사하지 않는다는 걸 찾아냈어. 지금은 beacon/misreads.py 에 두 종류 줄로 살아. MISREADS 는 잘못 읽힌다고 알려진 철자야. 줄마다 목소리가 그걸 뭐로 만들었는지, 대신 뭘 적을지, 그리고 출처로 주인의 말이 붙어 있어. cut 은 주인이 읽는 대본 시트에 판정을 적고, beacon mobile approve 와 revoice 는 공급자한테 돈이 나가기 전에 그런 철자가 남은 줄을 거절해. WRONG_HEARINGS 와 LISTEN_WORDS 는 듣기 줄이야. 단어는 맞고, 읽기만 틀릴 수 있는 경우지. "entity"는 주인의 단어라 그대로 두고, 다시 읽기에서 콩글리시 엔티티가 들리면 표시해. "sassy"도 그대로 둬. 세게 읽으면 "sexy"로 들린다고 주인이 일러줬으니까 가볍게 읽히게 하고(a215157). 듣기 줄은 아무것도 거절 못 해. 사람한테 정확히 어디를 들으라고 짚어줄 뿐이야. 그리고 절차는 캐시 키로는 실을 수 없는 지시 하나를 더 얹어. 목소리가 전에 잘못 읽은 구절을 실은 테이크는 새로 합성해. 캐시에서도, 앞선 대화의 오디오에서도 다시 쓰지 않아.

문에서 정해지는 것

읽기 중엔 대본 하나에 관한 게 아닌 것도 있어. 어느 파이프라인의 어느 호출에나 해당되는 거야. 그래서 모든 호출이 지나는 단 한 곳에서 정해. 작업장이 음성 엔진으로 가는 문, beacon/audio.py 의 _korean_safe 야.

첫째는 가족 앱 이름이야. 2026-10-17, 올라간 영상 하나가 Tidings 를 티딩스라고 읽었어.

피파가 아빠랑 같이 만든 앱을 엉터리로 읽는 건 공개 영상에서 민망해 — 아빠

beacon/family_names.py 가 표 하나를 쥐어. READINGS 엔 주인의 판정이나 주인이 받아쓰게 한 메시지에 쓰인 표기만 들어가(Tidings 는 타이딩즈). 주인이 아직 안 정한 이름은 근거와 함께 UNSETTLED 에 있고, 목소리한텐 적힌 그대로 가. 틀렸다고 알려진 표기는 WRONG 에 있고, 대본 관문에서 돈 쓰기 전에 거절돼. 화면엔 영어 이름을 그대로 둬. 그날 주인이 "Tidings 라고 원어로 써 자막은"이라고 했거든. 화면에 한글 앱 이름이 뜨면 표시돼.

둘째는 한자야. 2026-10-27, 피파가 소리 내 말한 走肖爲王 이 주초위왕이 아니라 주소위왕으로 돌아왔어. 주인은 그날 바로 판정했어.

한자는 떼어내서 쓰게 만들고 한자 쓰지 마. 화면 자막에만 보여주고 … 중국어로 읽을 위험도 있으니까 — 아빠

대본엔 한글 읽기를 적고, 한자는 그 바로 뒤에 화면용 풀이로만 붙여. 주초위왕(走肖爲王)처럼. misreads.spoken 은 목소리가 받을 글에서 그 풀이를 떼어내고, 한국어 대사에 남은 다른 한자는 대본 관문에서 그 글자를 짚어 거절해. 그리고 문이 모든 파이프라인에 대해 한 번 더 거절해(760c26a, baseline 1.11). 중국어와 일본어 더빙은 안 건드려. 거기선 그 글자가 자기 문자니까.

두 규칙 다 글 하나를 두 독자 몫으로 갈라. 화면은 적힌 모양을 받고, 목소리는 읽는 법을 받아. 어느 쪽도 다른 쪽으로 새면 안 돼. 이 트랙 첫 강의가 말하는 것과 보여주는 것 사이에 그은 선이, 여기선 목소리 쪽에서 보이는 거야.

두 번째 문

그 한자는 Beacon 영상에서 나온 게 아니야. 두뇌의 음성 모드가 실시간으로 한 대답에서 나왔어. 음성 모드는 자기 문으로 음성 엔진에 닿고, 작업장의 검사는 거기까지 못 닿아. 절차 문서도 이력에 그렇게 적었어. 피파의 음성 모드 길은 별개의 문이라 치프한테 보고했고, 작업장에서 고치진 않았다고. 작업장 검사가 들어가고 24분 뒤, cwkPippa 도 자기 검사를 달았어(431279f8, backend/services/spoken_hanja.py). 정책은 달라. 이유도 있어. 대본은 목소리를 입히기 전에 고칠 수 있지만, 실시간 답은 기다려줄 수가 없거든. 그래서 실시간 답은 절대 거절하지 않고, 풀이 없는 한자는 떼어내고 개수와 표본을 기록으로 남겨. 가나에 붙은 한자는 남겨. 한국어 속에 인용한 일본어 단어니까. 그런데 뭘 한자로 칠지 정하는 문자 범위는 작업장 걸 베낀 사본이고, 둘을 맞춰 두는 건 주석 한 줄이야.

트랙 3 두 번째 강의가 경고한 쪼개기를 눈앞에서 본 거야. 규칙은 하나인데 소유자가 둘이고, 벌써 다르게 굴어. 그 차이는 오늘은 정당해. 그런데 내일 같은 부분이 어긋나지 않게 붙드는 건 주석 하나뿐이야. 그 강의에 붙은 노트가 그 비용을 따져.

목소리는 네 뜻이 아니라 네가 건넨 걸 읽어. 철자 하나하나가, 자기 식대로 풀어버릴 모형한테 주는 지시야. 읽는 법은 모든 호출이 지나는 자리에서 정하고, 화면의 철자와 목소리의 철자는 따로 둬. 틀린 줄 아는 읽기는 돈 내기 전에 거절하고, 맞다고 증명할 수 없는 자리는 사람한테 짚어줘.

Code

음성 엔진으로 가는 단 하나의 문 (beacon/audio.py 원문 그대로, 2026-10-27 기준)·python
# Every call below sends ``family_names.spoken(text)``: a family app name in a
# Korean sentence goes to the voice as Dad reads it (Tidings -> 타이딩즈, todo
# #489), and nothing a viewer reads changes. Applying it here, at the one door
# to Bellows, is what makes it every pipeline's; it is idempotent, so a caller
# that already recorded the reading (talk-episode's tts_text) sends the same.
#
# The same door refuses hanja to a Korean voice (Dad, 2026-10-27, Coop 686:
# 走肖爲王 came back 주소위왕). A screen-only gloss, 주초위왕(走肖爲王), is taken
# out first; any Han character left stops the call and names its sentence.


def _korean_safe(text: str, language: str | None = None) -> str:
    text = misreads.spoken(family_names.spoken(text, language), language)
    misreads.require_no_hanja(text, language)
    return text
스케치: 읽는 법마다 정해지는 자리, 2026-10-27 기준·text
what                           settled in                       how it bites
-----------------------------  -------------------------------  ------------------------------
English term, take pipelines   the script: transliterated       check fails a mixed run
English phrase, travel/talk    the script: English in `say`     ASR readback -> WATCH.md
known misread spelling         misreads.MISREADS                cut sheet; approve, revoice refuse
right word, risky reading      WRONG_HEARINGS, LISTEN_WORDS     flagged on WATCH.md for the ear
family app name                family_names.READINGS            the door, every call
wrong Hangul app name          family_names.WRONG               refused before spend
hanja in a Korean line         misreads.hanja_errors + door     refused; gloss -> screen only
the screen                     the written form                 Hangul app name flagged

# one string, two readers: the subtitle keeps Tidings and 주초위왕(走肖爲王),
# the voice receives 타이딩즈 and 주초위왕.

External links

Exercise

네 시스템이 글을 넘겨주고 그쪽이 그걸 해석하는 자리를 하나 찾아봐. 음성 엔진이든, 번역기든, 검색 색인이든, 언어 모형이든, 파서든. 거기서 중요한 읽기를 적어봐. 이름, 용어, 숫자, 다른 문자에서 온 글자. 그리고 각각이 지금 어디서 정해지는지 적어. 호출하는 쪽 글 안인지, 공용 표인지, 엔진 안인지, 아니면 아무 데서도 안 정해지는지. 아무 데서도 안 정해지는 걸 하나 골라서 두 쪽을 다 설계해봐. 돈 쓰기 전에 틀린 줄 아는 모양을 거절하는 검사 하나, 그리고 어떤 검사로도 맞다고 증명 못 하는 자리를 사람한테 보여주는 다시 읽기 하나.
Hint
눈여겨볼 신호는 호출하는 쪽 글 하나 안에만 있는 수정이야. 어떤 대본이 우연히 철자를 잘 적어서 읽기가 맞았던 거라면, 다음 호출은 틀리게 적어. 모든 호출이 지나는 문 하나를 찾아서 거기서 정해.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인 — 댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.