Skip to content
@peachy-jp

피치

피치와 함께 일본어 스피치
피치

피치

피치와 함께 일본어 스피치

Note

일본어를 배우는 이유는 대개 시험이 아니라 직접 듣고 말하기 위해서다. 그러나 대부분의 학습 도구는 한자와 문법, 자격증 대비에 맞춰져 있고 자격증조차 말하기는 평가하지 않는다. 독학하는 사람에게는 일본어로 말을 붙여볼 상대마저 없으며, 말하기를 연습시켜 주는 AI 대화 앱도 일본어에서 의미를 가르는 피치(인토네이션)가 원어민과 얼마나 다른지는 짚어 주지 못한다.

피치는 이러한 문제를 해결한다. 언제든 부담 없이 나눌 수 있는 AI 음성 회화, 그리고 좋아하는 영상이나 음성을 가져와 문장 단위로 따라 말하는 쉐도잉이다. 어느 쪽이든 사용자의 발화를 원어민의 F0 곡선과 모라 단위로 포개어, 어느 음에서 어떻게 벌어졌는지를 색으로 드러낸다.

그 결과 학습자는 점수가 아니라 실제로 통하는 발음에 집중하게 되고, 말할 상대가 없다는 벽과 내 발음이 맞는지 모른다는 벽을 한꺼번에 허문다. 틀려도 괜찮은 상대와 충분히 연습하고 자기 발음이 어디까지 닿았는지 눈으로 확인하면서, 학습자는 원어민에 가까운 어휘 사용과 억양으로 다가설 수 있다.



Pain Point

목적에 맞는 학습 방법의 부재

  • 일본어 학습자가 꼽는 학습 목적의 상위는 콘텐츠 향유, 여행, 취업처럼 직접 듣고 말하는 상황
  • 그러나 시중의 학습 도구 대부분은 한자, 문법, 자격증 대비에 맞춰져 있음
  • JLPT를 비롯한 자격증은 문법, 어휘, 독해, 청해만 평가할 뿐 말하기는 측정하지 않음
  • 최고 등급인 N1을 따고도 막상 원어민과 대화가 통하지 않는 격차가 반복됨

말하기 연습 상대의 부재

  • 혼자 공부하는 학습자에게는 일본어로 말을 붙여 볼 상대 자체가 없음
  • 원어민이나 교사와 회화를 연습할 기회를 충분히 갖기 어려움
  • 사람과의 대화는 틀릴까 봐 입을 떼지 못하는 말하기 불안을 동반해, 연습량 자체가 줄어듦

발음, 인토네이션 피드백의 부재

  • AI 음성 대화 앱이 늘었지만, 피드백은 문법, 어휘, 유창성 수준에 머묾
  • 일본어에서 의미를 가르는 피치(인토네이션)가 원어민과 어떻게 다른지는 추출해 비교하지 않음
  • 발음 점수 앱도 몇 점인지 결과만 줄 뿐, 어느 모라에서 어떻게 어긋났는지는 보여주지 못함



Solution

실시간 AI 음성 회화

자신의 실력 때문에 실제 사람과 말하기가 불안한 사람도, 언제든 원하는 상황을 골라 연습할 수 있음

  • 시나리오 프리셋이나 직접 설정한 상황으로 롤플레잉
  • 장소, 역할, 목적, 성공기준을 정해 목표가 있는 과제형 대화
  • JLPT 레벨(N5~N1)에 맞춰 에이전트 발화 속도와 난도 자동 조절
  • 보이스와 간사이 사투리 세기 선택, 내 자료(기사 등)를 붙여넣어 그 소재로 대화
  • 대화가 끝나면 항목별 성공, 실패 판정과 교정 문장을 받고, 내 발화를 말풍선에서 다시 들으며 글자 단위로 확인

Tip

병원 접수 상황을 고르면 접수 직원 역할의 AI가 「本日はどうされましたか?」라며 먼저 말을 걸고, 증상 설명부터 접수까지 실제처럼 주고받는다

내 콘텐츠 쉐도잉

정해진 교재 문장이 아니라 내가 좋아하는 바로 그 장면으로 연습

  • 좋아하는 드라마나 인터뷰 영상, 음성을 올리면 문장 단위로 분리되어 분석됨
  • 한 문장씩 후리가나와 원어민 피치 라인을 보며 듣고 따라 말하기
  • 원어민의 인토네이션과 발음은 물론 말투까지 따라 하며 네이티브에 가까워질 수 있음

Tip

좋아하는 일본 드라마 한 장면을 올리면 대사가 문장별로 쪼개지고, 각 문장의 원어민 억양을 보며 그대로 따라 말할 수 있다

원어민 F0 곡선 비교

점수가 아니라 어느 모라에서 어떻게 어긋났는지를 눈으로 보여줌

  • 원어민 F0와 내 F0를 시간축 정렬(DTW)해 겹친 곡선으로 시각화
  • 모라 단위로 피치가 어긋난 지점, 장음(長音), 촉음(促音) 오류를 색으로 짚어줌
  • 단어 사전식 표기가 아니라 accent phrase, downstep이 반영된 문장 속 실제 곡선

Tip

젓가락 はし를 다리 はし의 억양으로 발음하면 해당 모라가 빨갛게 표시되고, 원어민 곡선과 내 곡선이 어디서 벌어졌는지 한눈에 보인다

발화 단어 단어장 추출

대화나 쉐도잉 중 모르는 단어를 그 자리에서 단어장에 담아 Anki로 복습

  • 대화 말풍선이나 학습 문장을 형태소 단위로 골라 단어장에 추가
  • 탭(단어)이나 드래그(구)로 선택하고 한자별 읽기까지 함께 저장
  • 단어를 따로 찾아 옮겨 적을 필요 없이 한 앱에서 학습과 복습이 이어짐

Tip

회화 중 상대가 쓴 予約라는 단어를 몰랐다면, 말풍선에서 그 단어를 탭해 읽기를 확인하고 바로 Anki 덱에 넣을 수 있다



기술 스택

Frontend

  • Tauri 2 (Rust 셸 + WKWebView)
  • React + TypeScript
  • TanStack Router, TanStack Query, Zustand
  • Tailwind CSS, Base UI, lucide-react
  • i18next / react-i18next
  • Vite, Vitest

Backend & AI

  • Rust 코어 (Tauri commands, sqlx + SQLite, specta 타입 바인딩)
  • Python 사이드카 (음성/피치 분석, 형태소 분석, forced alignment)
  • ElevenLabs Agents (멀티턴 음성 회화)
  • DeepL (번역)

Infra & DevOps

  • GitHub Actions (ci.yml, project-status.yml) — CI/CD
  • Gemini (코드 리뷰)
  • GitHub Issues + Projects (태스크 관리, GitHub Flow)
  • SQLite + sqlx 마이그레이션 (로컬 데이터, 클라우드 DB 없음)
  • Anki .apkg export (단어장 내보내기)

아키텍처

플로우차트

쉐도잉과 회화 두 경로는 같은 발음 피드백으로 수렴한 뒤, 단어장과 학습 기록으로 이어진다.

flowchart TD
    Start([피치 시작]) --> Mode{학습 방식}

    Mode -->|쉐도잉| U1[콘텐츠 업로드<br/>영상 또는 음성]
    U1 --> U2[음성 추출, 노이즈 제거]
    U2 --> U3[음성 인식, 화자 분리, 강제정렬]
    U3 --> U4[문장 분리, 모라 분할]
    U4 --> U5[원어민 피치, 에너지 추출]
    U5 --> U6[문장별 듣고 따라 말하기]
    U6 --> U7[내 발화 분석<br/>음성 인식, 피치 추출, 시간축 정렬]

    Mode -->|회화| C1[상황 설정<br/>시나리오, 레벨, 보이스]
    C1 --> C2[AI와 실시간 음성 대화]
    C2 --> C3[대화 종료]
    C3 --> C4[사후 평가, 발화 강제정렬]

    U7 --> FB[발음 피드백<br/>모라별 피치, 장음, 촉음 시각화]
    C4 --> FB
    FB --> W[모르는 단어 단어장 추출]
    FB --> H[학습 기록 저장]
Loading

시퀀스 다이어그램

쉐도잉 — 원어민 발화를 분석해 두고, 사용자가 따라 말할 때마다 비교한다.

sequenceDiagram
    actor U as 사용자
    participant A as 앱
    participant P as 분석 파이프라인

    U->>A: 콘텐츠 업로드
    A->>P: 원어민 발화 분석 요청
    P->>P: 음성 추출, 노이즈 제거
    P->>P: 음성 인식, 화자 분리, 강제정렬
    P->>P: 문장 분리, 모라 분할
    P->>P: 피치, 에너지 추출
    P-->>A: 문장별 원어민 데이터
    A-->>U: 문장 표시 (후리가나, 원어민 피치 라인)

    loop 문장마다
        U->>A: 녹음 (따라 말하기)
        A->>P: 내 발화 분석 요청
        P->>P: 음성 인식, 강제정렬
        P->>P: 피치 추출, 원어민과 시간축 정렬
        P->>P: 모라별 피치, 장음, 촉음 판정
        P-->>A: 비교 결과
        A-->>U: 곡선 비교, 모라별 색 피드백
    end
Loading

회화 — AI와 실시간으로 대화한 뒤, 종료 시점에 평가와 발음 분석을 한 번에 받는다.

sequenceDiagram
    actor U as 사용자
    participant A as 앱
    participant V as 음성 대화 엔진
    participant P as 분석 파이프라인

    U->>A: 상황 설정 (시나리오, 레벨, 보이스)
    A->>V: 대화 세션 시작
    loop 멀티턴 대화
        U->>V: 음성 발화
        V-->>U: 음성 응답
        V-->>A: 발화 기록
    end
    U->>A: 대화 종료
    A->>V: 사후 평가 요청
    V-->>A: 항목별 평가, 교정
    A->>P: 발화 강제정렬 요청
    P-->>A: 모라 정렬, 형태소 토큰
    A-->>U: 평가, 발음 하이라이트, 단어장 추출
Loading

ERD

쉐도잉 데이터(시리즈 → 소스 → 문장 → 모라)와 회화 데이터(세션 → 발화)가 나뉘어 있고, 두 경로에서 뽑은 단어가 단어장 버퍼로 모인다.

erDiagram
    series ||--o{ sources : "포함"
    sources ||--o{ sentences : "문장 분리"
    sentences ||--o{ moras : "모라 분할"
    sentences ||--o| user_attempts : "마지막 시도 1건"
    conversation_sessions ||--o{ conversation_messages : "발화"
    sentences ||..o{ anki_buffer : "단어 추출"

    series {
        int id PK
        string name
    }
    sources {
        int id PK
        int series_id FK
        string title
        bool has_video
        string status
    }
    sentences {
        int id PK
        int source_id FK
        string text
        string text_reading
        int speaker_id
        json f0
        json energy
    }
    moras {
        int id PK
        int sentence_id FK
        string character
        string reading
        string mora_type
        string level
    }
    user_attempts {
        int id PK
        int sentence_id FK
        json f0
        float dtw_distance
        float mora_error_rate
    }
    conversation_sessions {
        int id PK
        string scenario
        string jlpt_level
        json eval_json
        datetime started_at
        datetime ended_at
    }
    conversation_messages {
        int id PK
        int session_id FK
        string role
        int idx
        string text
        json mora_json
        json tokens_json
    }
    anki_buffer {
        int id PK
        string type
        string surface
        string reading
        string status
    }
Loading

Note

회화에서 추출한 단어는 발화 텍스트에서 바로 담기므로 문장, 소스와 연결되지 않고 단어장 버퍼에 단독으로 저장된다.

Popular repositories Loading

  1. .github .github Public

Repositories

Showing 1 of 1 repositories

Top languages

Loading…

Most used topics

Loading…