<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Viet Tran</title>
    <description>The latest articles on DEV Community by Viet Tran (@corodomo).</description>
    <link>https://dev.to/corodomo</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1021412%2F26b5eb28-7ce9-47e8-b094-4ad5808b27f4.jpeg</url>
      <title>DEV Community: Viet Tran</title>
      <link>https://dev.to/corodomo</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/corodomo"/>
    <language>en</language>
    <item>
      <title>How We Built AI-Powered Japanese Shadowing Practice</title>
      <dc:creator>Viet Tran</dc:creator>
      <pubDate>Sat, 24 Oct 2026 14:45:19 +0000</pubDate>
      <link>https://dev.to/corodomo/how-we-built-ai-powered-japanese-shadowing-practice-5ef0</link>
      <guid>https://dev.to/corodomo/how-we-built-ai-powered-japanese-shadowing-practice-5ef0</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://medium.com/@corodomo/how-we-built-ai-powered-japanese-shadowing-practice-24dd7d3cd2e5" rel="noopener noreferrer"&gt;Medium&lt;/a&gt;. Cross-posted here for the dev community.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The problem, from a developer's point of view
&lt;/h2&gt;

&lt;p&gt;Here's the spec a language learner would give you:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Take any video. Let me loop one sentence at a time, repeat it out loud, and tell me which sounds I got wrong."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Sounds like a weekend project: grab captions, add a loop button, call a speech API. In practice, each of those three steps breaks in its own way for Japanese — no spaces between words, sentences that run for fifteen seconds, captions timed for reading rather than audio, and two writing systems for the same word.&lt;/p&gt;

&lt;p&gt;We're the team behind &lt;a href="https://corodomo.com/en" rel="noopener noreferrer"&gt;Corodomo&lt;/a&gt;, a web and mobile app that turns videos into Japanese, English, Chinese and Korean lessons. This post walks through the approach we took for &lt;strong&gt;segmentation, timestamp sync, pronunciation scoring and dictation checking&lt;/strong&gt; — not our full internals, but the decisions and the lessons, which should be useful to anyone working with speech, subtitles or learner feedback.&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Problem&lt;/th&gt;
&lt;th&gt;Naive approach&lt;/th&gt;
&lt;th&gt;What worked better&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Split video into practice units&lt;/td&gt;
&lt;td&gt;Use caption blocks&lt;/td&gt;
&lt;td&gt;Combine linguistic boundaries (text) with pauses (audio), cap length&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Loop timing&lt;/td&gt;
&lt;td&gt;Caption start/end times&lt;/td&gt;
&lt;td&gt;Word-level timing, snap to silence, small padding, user-editable subtitles&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pronunciation feedback&lt;/td&gt;
&lt;td&gt;One overall score&lt;/td&gt;
&lt;td&gt;Align attempt to reference, score per syllable, show both&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dictation checking&lt;/td&gt;
&lt;td&gt;String diff&lt;/td&gt;
&lt;td&gt;Normalise kana/kanji and punctuation first, then diff&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  1. Segmentation: the unit of practice is a sentence
&lt;/h2&gt;

&lt;p&gt;Learners don't shadow a video; they shadow a line until it feels natural. So the product depends on cutting audio into pieces someone can hold in short-term memory and repeat in one breath.&lt;/p&gt;

&lt;p&gt;We generate our own transcript with speech recognition, because many videos have no subtitles and auto-captions are split by time, not meaning. We keep word-level timing, because every later step depends on it.&lt;/p&gt;

&lt;p&gt;Then:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No whitespace&lt;/strong&gt; → you need a word segmenter anyway (we reuse it for the clickable dictionary).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Long chained clauses&lt;/strong&gt; (〜て, 〜けど, 〜から) → allow splits at clause boundaries when a sentence is too long.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Speech ≠ punctuation&lt;/strong&gt; → people pause mid-clause and add ね/よ after a breath.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Text-only splitting ignores where the speaker breathes. Pause-only splitting cuts every hesitation. Using both signals produced noticeably more natural loops in our testing.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Timestamp sync: loops must start and end on speech
&lt;/h2&gt;

&lt;p&gt;Off by 300 ms and the learner loses the first mora, or hears the start of the next line. What helped:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Work from &lt;strong&gt;word-level timestamps&lt;/strong&gt;, not caption blocks.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Nudge boundaries toward the nearest pause.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Add &lt;strong&gt;small padding&lt;/strong&gt; so the first consonant isn't clipped.&lt;/li&gt;
&lt;li&gt;Ship &lt;strong&gt;subtitle editing&lt;/strong&gt; so learners can fix bad lines themselves.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Point 4 was the best return on effort. Users forgive a wrong boundary they can fix in two taps.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Pronunciation scoring: a number isn't feedback
&lt;/h2&gt;

&lt;p&gt;"72/100" tells a learner nothing. For Japanese the natural unit is the syllable/mora, so each attempt shows per-syllable scores plus an overall score.&lt;/p&gt;

&lt;p&gt;The high-level pipeline:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;record attempt ──► align to reference text ──► assess each unit ──► aggregate
                     (per syllable)            (sounds + pitch)    (sentence score)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Lessons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Score against the target&lt;/strong&gt;, not against a transcript of what the learner said — otherwise you're grading the recogniser's guesses.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Show the reference&lt;/strong&gt; (with optional furigana) next to the score.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Design for repetition&lt;/strong&gt;: an encouraging message and a next target keep people practising.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Score pitch accent too.&lt;/strong&gt; Each syllable's score includes whether its pitch (high/low) matches the reference, so はし with the wrong accent is flagged even when every sound is right.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;State the limits.&lt;/strong&gt; A score is a guide, not a verdict; point learners to what to listen to again.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  4. Dictation: don't diff raw strings
&lt;/h2&gt;

&lt;p&gt;すこし vs 少し is not a listening error. しょう vs しよう is. So we normalise both strings (script, punctuation) before diffing, while keeping distinctions like small kana and long vowels that reflect what was actually heard. Answers in kana or kanji are both accepted. Then we highlight the difference side by side.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Takeaways for devs building learning tools
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Model the user's &lt;strong&gt;unit of work&lt;/strong&gt; and build every pipeline stage around it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fuse signals&lt;/strong&gt; (text + audio) for boundaries.&lt;/li&gt;
&lt;li&gt;Make feedback &lt;strong&gt;granular and actionable&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Give users an edit button&lt;/strong&gt; for anything ML produces.&lt;/li&gt;
&lt;li&gt;Be explicit about &lt;strong&gt;what the model can't judge&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Try it / roast it
&lt;/h2&gt;

&lt;p&gt;Corodomo runs on web, iPhone, iPad, Mac and Android. You can start learning without signing up; importing your own videos, pronunciation checks and AI speaking practice need a free account, and the free plan includes one hour of AI usage per month.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🔗 &lt;a href="https://corodomo.com/en" rel="noopener noreferrer"&gt;https://corodomo.com/en&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;🎬 Demo: &lt;a href="https://youtu.be/XT-i86GCBtU" rel="noopener noreferrer"&gt;https://youtu.be/XT-i86GCBtU&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We're a two-person core team in Da Nang, Vietnam (plus a few part-time collaborators). If you've built anything with forced alignment, Japanese tokenisation or pronunciation assessment, I'd love to hear how you handled the edge cases — comments are open.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;— Viet, founder of Corodomo&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>ai</category>
      <category>languagelearning</category>
      <category>showdev</category>
    </item>
  </channel>
</rss>
