<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Next.js on かつおぶしのブログ</title><link>https://blog.k-bushi.com/tags/next.js/</link><description>Recent content in Next.js on かつおぶしのブログ</description><generator>Hugo -- gohugo.io</generator><language>ja-JP</language><copyright>kbushi</copyright><lastBuildDate>Thu, 05 Mar 2026 12:08:04 +0000</lastBuildDate><atom:link href="https://blog.k-bushi.com/tags/next.js/index.xml" rel="self" type="application/rss+xml"/><item><title>ローカルLLMでずんだもん面接アプリを作ってみた</title><link>https://blog.k-bushi.com/post/tech/ai/ai-vocevox-interview/</link><pubDate>Thu, 05 Mar 2026 11:26:22 +0000</pubDate><guid>https://blog.k-bushi.com/post/tech/ai/ai-vocevox-interview/</guid><description>&lt;h2 id="はじめに"&gt;はじめに
&lt;/h2&gt;&lt;p&gt;今回は &lt;code&gt;Ollama + Next.js + VOICEVOX&lt;/code&gt; を組み合わせて、ローカル環境で完結する面接練習アプリを作ってみた。&lt;/p&gt;
&lt;p&gt;成果物はこちら。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://github.com/katsuobushiFPGA/ai-voicevox-interview" target="_blank" rel="noopener"
&gt;https://github.com/katsuobushiFPGA/ai-voicevox-interview&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="環境"&gt;環境
&lt;/h2&gt;&lt;div&gt;
&lt;div class="code-block-content"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-txt" data-lang="txt"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;- Node.js 20+
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;- Next.js 16 (App Router)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;- TypeScript 5
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;- VOICEVOX Engine
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;- Ollama (`gemma3:4b`)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;- Chrome or Edge (Web Speech APIの利用)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id="作ろうと思った背景"&gt;作ろうと思った背景
&lt;/h2&gt;&lt;p&gt;就職活動をしている中で、面接の受け答えを声に出して練習する時間を増やしたいと考えていた。&lt;/p&gt;
&lt;p&gt;ただ、自分は話すのがあまり得意ではなく、いきなり人との模擬面接だと心理的なハードルが高い。
そのため、まずはAIを相手に壁打ちできる環境を用意することにした。&lt;/p&gt;
&lt;p&gt;最初はテキストだけの構成も考えたが、どうしても味気なく続かなかった。
そこで、ずんだもんの音声と立ち絵を組み合わせて、会話らしさを持たせる方針とした。&lt;/p&gt;
&lt;h2 id="作ったもの"&gt;作ったもの
&lt;/h2&gt;&lt;p&gt;アプリは「質問を受ける -&amp;gt; 音声で答える -&amp;gt; 最後に評価を受ける」という流れである。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;面接質問数を選ぶ&lt;/li&gt;
&lt;li&gt;ずんだもんが質問を読み上げる&lt;/li&gt;
&lt;li&gt;マイク入力で回答する&lt;/li&gt;
&lt;li&gt;全質問終了後にOllamaが評価とコメントを返す&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;ローカルで完結するため、外部APIキーなしで試しやすいのも良かった点である。&lt;/p&gt;
&lt;p&gt;画面は以下のような感じ。&lt;/p&gt;
&lt;a href="https://blog.k-bushi.com/image/tech/ai/ai-voicevox-interview/interview-01.png" data-lightbox="capture"&gt;
&lt;img src="https://blog.k-bushi.com/image/tech/ai/ai-voicevox-interview/interview-01.png" alt="interview-01" loading="lazy" style="max-width:100%;height:auto;" width="280"&gt;
&lt;/a&gt;
&lt;a href="https://blog.k-bushi.com/image/tech/ai/ai-voicevox-interview/interview-02.png" data-lightbox="capture"&gt;
&lt;img src="https://blog.k-bushi.com/image/tech/ai/ai-voicevox-interview/interview-02.png" alt="interview-02" loading="lazy" style="max-width:100%;height:auto;" width="280"&gt;
&lt;/a&gt;
&lt;h2 id="ローカル実行手順"&gt;ローカル実行手順
&lt;/h2&gt;&lt;p&gt;READMEに沿って、&lt;code&gt;git clone&lt;/code&gt; から実行する手順を記載する。&lt;/p&gt;
&lt;p&gt;まず、前提条件は以下。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Git がインストールされていること&lt;/li&gt;
&lt;li&gt;Docker / Docker Compose がインストールされていること&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;リポジトリを取得し、作業ディレクトリへ移動する。&lt;/p&gt;
&lt;div&gt;
&lt;div class="code-block-content"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git clone https://github.com/katsuobushiFPGA/ai-voicevox-interview.git
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; ai-voicevox-interview&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;その後、Docker Composeでまとめて起動する。&lt;/p&gt;
&lt;div&gt;
&lt;div class="code-block-content"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker compose up -d&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;初回はOllamaモデルのダウンロードが入るため、少し時間がかかる。
起動後に &lt;code&gt;http://localhost:3000&lt;/code&gt; へアクセスして動作確認できる。&lt;/p&gt;
&lt;p&gt;ローカル開発モードで試す場合は、VOICEVOX Engine と Ollama を別途起動した上で次を実行する。&lt;/p&gt;
&lt;div&gt;
&lt;div class="code-block-content"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;npm install
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;npm run dev&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;環境変数の例は以下の通り。&lt;/p&gt;
&lt;div&gt;
&lt;div class="code-block-content"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;VOICEVOX_BASE_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;http://localhost:50021
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;OLLAMA_BASE_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;http://localhost:11434
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;OLLAMA_MODEL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;gemma3:4b&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id="アプリの構成"&gt;アプリの構成
&lt;/h2&gt;&lt;p&gt;全体構成は以下の通り。&lt;/p&gt;
&lt;div class="mermaid"&gt;
flowchart LR
U[User]
B[Browser\nNext.js Frontend]
STT[Web Speech API\n音声認識]
API[Next.js API Routes]
Q[questions API\n質問生成/取得]
TTS[tts API\nVOICEVOX Proxy]
EVA[evaluate API\nOllama評価]
V[VOICEVOX Engine\n:50021]
O[Ollama\n:11434]
U --&gt;|音声回答| B
B --&gt;|録音・文字起こし| STT
STT --&gt;|テキスト| B
B --&gt; API
API --&gt; Q
API --&gt; TTS
API --&gt; EVA
Q --&gt;|質問データ| B
TTS --&gt;|音声合成リクエスト| V
V --&gt;|音声データ| B
EVA --&gt;|評価リクエスト| O
O --&gt;|スコア/フィードバック| B
&lt;/div&gt;
&lt;p&gt;フロントエンドはブラウザで完結しつつ、音声合成と評価処理をそれぞれ &lt;code&gt;VOICEVOX&lt;/code&gt; と &lt;code&gt;Ollama&lt;/code&gt; に分離する構成にしている。&lt;/p&gt;
&lt;p&gt;面接1セッションの処理フローは以下の通り。&lt;/p&gt;
&lt;div class="mermaid"&gt;
sequenceDiagram
autonumber
participant User as User
participant Browser as Browser (Next.js UI)
participant API as Next.js API Routes
participant Voicevox as VOICEVOX Engine
participant Ollama as Ollama
User-&gt;&gt;Browser: 面接開始（質問数を選択）
Browser-&gt;&gt;API: 質問取得リクエスト
API--&gt;&gt;Browser: 質問リスト
loop 各質問
Browser-&gt;&gt;API: ttsリクエスト（質問文）
API-&gt;&gt;Voicevox: 音声合成
Voicevox--&gt;&gt;API: 音声データ
API--&gt;&gt;Browser: 音声データ
Browser--&gt;&gt;User: 質問を読み上げ
User-&gt;&gt;Browser: 音声で回答
Browser-&gt;&gt;Browser: Web Speech APIで文字起こし
end
Browser-&gt;&gt;API: evaluateリクエスト（回答一覧）
API-&gt;&gt;Ollama: 評価生成
Ollama--&gt;&gt;API: スコア/フィードバック
API--&gt;&gt;Browser: 評価結果
Browser--&gt;&gt;User: 結果画面を表示
&lt;/div&gt;
&lt;h2 id="作ってみた感想"&gt;作ってみた感想
&lt;/h2&gt;&lt;p&gt;正直、今回は「ここが本当にきつかった」という場面はほぼなかった。
Claude Opus 4.6 を使って実装を進めたことで、細かい詰まりを短時間で解消できたのが大きい。&lt;/p&gt;
&lt;p&gt;改善したいところとして、評価計算の部分にかなり時間がかかっているところがある。&lt;br&gt;
これはモデルの性能なのか、プロンプト設計の問題なのかはまだ分析できていない。&lt;/p&gt;
&lt;p&gt;学びになったのは、技術の難しさもそうだが体験設計の比重であった。
面接練習アプリの場合、精度も大事ではあるが「続けたくなる雰囲気」を作ることが重要だと感じた。&lt;br&gt;
※テキストだけだと味気ないので、ずんだもんの音声と立ち絵を組み合わせたところ楽しさ的なものができたので、VRMモデルを組み合わせるのも面白そうだと感じた。&lt;/p&gt;
&lt;p&gt;基本は、自分が喋れているかを確認するためのアプリで作ったのだけど、興が乗ればずんだもんと会話するような体験にしても面白いかもしれないなぁと思った。&lt;/p&gt;
&lt;h2 id="参考"&gt;参考
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Next.js Documentation&lt;br&gt;
&lt;a class="link" href="https://nextjs.org/docs" target="_blank" rel="noopener"
&gt;https://nextjs.org/docs&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;VOICEVOX&lt;br&gt;
&lt;a class="link" href="https://voicevox.hiroshiba.jp/" target="_blank" rel="noopener"
&gt;https://voicevox.hiroshiba.jp/&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Ollama&lt;br&gt;
&lt;a class="link" href="https://ollama.com/" target="_blank" rel="noopener"
&gt;https://ollama.com/&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Web Speech API&lt;br&gt;
&lt;a class="link" href="https://developer.mozilla.org/en-US/docs/Web/API/Web_Speech_API" target="_blank" rel="noopener"
&gt;https://developer.mozilla.org/en-US/docs/Web/API/Web_Speech_API&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="おわりに"&gt;おわりに
&lt;/h2&gt;&lt;p&gt;就活向けの面接練習をテーマに、ローカルLLMと音声合成を組み合わせたアプリを作ってみた。
同じように「まずはひとりで壁打ちしたい」人には、ローカル完結の構成は相性が良いと感じる。&lt;/p&gt;</description></item></channel></rss>