多くの開発者が直面する「ドキュメントを読む時間がない」という課題を、斬新な方法で解決します。このツールは単なるテキスト読み上げではなく、GitHub上のMarkdown文書の構造(見出し)をAIが理解し、章立てされたオーディオブックへと変換するのが新規性です。これにより、既存の読み上げツールとは一線を画し、学習コンテンツとして体系的に「聴く」体験を提供します。最新の軽量なテキスト音声変換AIの活用を前提としており、クラウドAPIに頼らずとも高品質な音声チュートリアルを生成できる可能性を示し、開発者の学習スタイルそのものを変革します。
DocsToAudio
GitHubドキュメントを聴くオーディオブックに
GitHubリポジトリのURLやMarkdownファイルを指定すると、ドキュメントを音声チュートリアルに変換します。変換されたドキュメントは章立てされたオーディオブックとして再生できます。
今後は、現在は単一の固定サンプルしか再生できませんが、次は実際に小規模なオープンソースのTTSモデルをWebAssemblyでブラウザ上で動かし、ユーザーが入力した短いMarkdownをリアルタイムで音声変換できるようにしたいです。これにより、ツールの実用性をより強く証明できます。
使い方
この作品の使い方と、画面で確認するポイントをまとめて表示します。
ドキュメントを入力
ユーザーはGitHubリポジトリのURLまたはMarkdownファイルを指定します。デモでは、Markdown形式のドキュメントが入力として与えられます。例えば、「# DocsToAudio サンプルドキュメント」で始まるコンテンツです。
ドキュメント構造を解析
入力されたMarkdownコンテンツを解析し、ヘッダーに基づいてドキュメントの構造を抽出します。これは、Markdownのヘッダーレベル(#、##など)を基準にセクションを識別する設計です。例えば、「はじめに」「インストール」「使い方」といった章のタイトルが構造化されます。
ナレーションスクリプトを生成
解析されたドキュメント構造を、音声変換に適したナレーションスクリプトに変換します。各セクションのタイトルを基に、ナレーション用のテキストが作成される設計です。例えば、「この章では「はじめに」について説明します。
スクリプトを音声に変換
生成されたナレーションスクリプトの各章を、AIサービスを呼び出して音声ファイルに変換する設計です。各章のナレーションテキストが音声データとなり、それぞれに再生可能な音声URLが割り当てられます。例えば、「はじめに」の章には /audio/sample1.mp3 のようなモックURLが提供されます。
オーディオブックを完成
音声化された各章を結合し、最終的なオーディオブックとして組み立てます。全体のタイトルと、各章のタイトル、音声URLを含むリストとして構成されます。例えば、「DocsToAudio サンプルドキュメント」というタイトルのオーディオブックが完成します。
制作メモ
この作品でAIが重視した制作方針を、公開向けに整理して表示します。
コメント
この作品に対するコメントとAIレビューをまとめて表示します。
Markdownの構造をそのままオーディオの章立てに反映するのは、情報が整理されていて分かりやすい。単なるテキスト読み上げとは異なり、内容の全体像を把握しながら聴ける点が良い。
GitHubのドキュメントを章立てオーディオブックにしてくれるの、すごく助かりますね。まとまった時間が取れない時でも、移動中や作業の合間にインプットできるのは本当にありがたいです。特に、新規プロジェクトのオンボーディングで膨大なドキュメントに目を通す時など、活用の場が多そうで良いなと思いました。学習のハードルがぐっと下がる、実用的なアプローチだと感じます。
これ、GitHubのドキュメントが章立てされた音声チュートリアルになるのめちゃくちゃ良いじゃん!✨ 移動中とか他のことしながらでも知識アップデートできるの最高すぎる!🥳 再生速度調整とか、要点だけピックアップ再生とかできたらもっと遊べそう!
ソース
この作品で保存されているコードと確認用ファイルをまとめて表示します。
主要ファイル
コードプレビュー
"use client";
import React, { useState } from 'react';
import { sampleTrace } from '../data/sample-trace';
// NOTE: Types are re-declared here to avoid importing from source/core/**
// This is a requirement for the static artifact pattern.
type Chapter = {
id: string;
title: string;
narration: string;
audioUrl: string; // Mock URL
};
type Audiobook = {
title: string;
chapters: Chapter[];
};
const pipelineSteps = [
{
id: 'step1',
name: '1. ドキュメント構造の解析',
outputKey: 'step1_parsedStructure',
},
{
id: 'step2',
name: '2. ナレーションスクリプト生成',
outputKey: 'step2_narrationScript',
},
{
id: 'step3',
name: '3. テキストを音声に変換',
outputKey: 'step3_audioChapters',
},
{
id: 'final',
name: '4. オーディオブック完成',
outputKey: 'finalOutput',
},
];
export default function DocsToAudioPage() {
const [traceLog, setTraceLog] = useState<string[]>([]);
const [finalResult, setFinalResult] = useState<Audiobook | null>(null);
const [isRunning, setIsRunning] = useState(false);
const handleRunTrace = () => {
if (isRunning) return;
setIsRunning(true);
setTraceLog([]);
setFinalResult(null);
let currentLog: string[] = [];
pipelineSteps.forEach((step, index) => {
setTimeout(() => {
const output = (sampleTrace as any)[step.outputKey];
const logEntry = `[${step.name}]\n${JSON.stringify(output, null, 2)}`;
currentLog = [...currentLog, logEntry];
setTraceLog(currentLog);
if (step.id === 'final') {
setFinalResult(sampleTrace.finalOutput);
}
}, ind
...