OSS · Python CLI + Streamlit
speech-habit-lens
原稿は書き直すのに、声の癖は放置している。
1分スピーチを3層で解析します。ESAS 20パラメータの時系列、認識テキスト、両者を突合して声と言葉のズレを名指しするクロス層。全主張に時刻+パラメータ+引用の3点根拠を強制します。
GitHubで見る サンプルレポート(Stallman 60秒) →
- 1分で癖が見える 3層解析を1コマンドで
- 認識ノイズに強い ESASは言語非依存 — 音響層は文字が荒れても切り込める
- 声と言葉のズレを暴く クロス層が「結論手前で声量が落ちる」を名指す
- ハルシネーション抑制 全主張に時刻+パラメータ+引用を強制
- オープンソース · MIT
- CLI + Streamlit UI
- ESAS 20パラメータ全件実測確認済み
- 作者: Ken Imoto
2コマンドで回る
-
shl analyze speech.wav --out report.md音声認識 → ESAS抽出 → Claude三層 → Markdownレポート。エンドツーエンドで3-4分 -
shl serveStreamlit UIをlocalhost:8501で起動。ブラウザマイク録音、Plotly時系列、クロス層カード付き -
--model claude-opus-4-7解析モデルを1発ごとに切替。Sonnet 4.6(既定)、難しいクロスパターンにはOpus 4.7、コスト削減はHaiku 4.5
誰のためのツールか
- 登壇者・創業者 これから話すピッチを事前に監査。本番の前に癖を捕まえる
- プロダクトマネージャー アップデートの説明で聴衆が降りる文を特定して、そこだけ直す
- コーチ・教育者 「なんとなく平板」ではなく、時刻+パラメータ+引用でフィードバックを根拠付ける
- 好奇心のあるエンジニア 自分のスピーチの癖を、1分の音源で楽器のように見る
どんな時に使うか
- ピッチ・トークの練習中: 開幕の癖を本番前に聞く
- ウケなかったデモの後: 声が言葉から遅れた瞬間を特定する
- スピーカーをコーチするとき: 印象論の代わりに、時刻+パラメータの根拠付きレポートを渡す
- 自分の話し方を月次で棚卸しするとき: 気づいていなかった癖を1分の録音から読む
インストール
git clone https://github.com/kenimo49/speech-habit-lens
cd speech-habit-lens
pip install -e .
cp .env.example .env # AMIVOICE_API_KEY + ANTHROPIC_API_KEY AmiVoice APIキー(月60分まで無料)と Anthropic APIキーが必要です。1解析あたりClaude Sonnet使用量は約¥18、月60本回して¥1,080ほどが目安です。
三層解析
- 音響層: ESAS 20パラメータの時系列。テンション推移、抑揚の偏り、出だしのエネルギー、終端の失速
- テキスト層: 認識テキストからフィラー、結論位置、繰り返し語、論理展開
- クロス層: 「結論手前で声量が落ちる」のような身体×言語の連動パターン
- Grounding Rule: 全主張に時刻+パラメータ+引用の3点引用を強制。ハルシネーションを抑制
- ESASは言語非依存: テキスト認識が荒れても音響的な癖は鋭く出る
- ESAS 20パラメータの実フィールド名を全件live APIで実測確認済み(公式docsの記載は5例のみ)
- Streamlit UI: ブラウザマイク録音、PlotlyのインタラクティブESAS時系列、クロス層カード、Markdownレポート DL
4本ピッチの実測
| 指標 | Jobs(締め) | 孫正義(開幕) | 西野(開幕) | 落合(開幕) |
|---|---|---|---|---|
| energy peak | 21 | 44 | 32 | 39 |
| concentration peak | 100 | 100 | 90 | 100 |
| anticipation peak | 68 | 100 | 35 | 91 |
| emo_cog peak | 207 | 136 | 276 | 244 |
| passionate peak | 6 | 4 | 11 | 8 |
| 結論位置 | back | front | middle | back |
| フィラー | 「ね」×1 | 「ね」×1 | 「ちょっと」×5 | 「あの」×1 |
| 認識confidence | 0.74–0.89 | 0.99–1.00 | 0.93–1.00 | 0.70–0.82 |
単一の指標では良し悪しは決まりません。Jobsのenergyピークは21、孫正義は44、両者とも聴衆に届いています。ツールが見せるのは、各話者の癖がどこに宿るか — 西野は「ちょっと」を5回、孫正義は結論を頭で言い切る型、落合は音響が濃いまま認識confidenceが0.70まで落ちる型。数字で決めるのではなく、タイムライン上に癖を名指しできることが目的です。
印象論では見えない2つの動き
ツールが日常的に暴くのはこの2つです。印象論ではそのまま抜け落ちる箇所。
開幕のズレ
anticipation 65 × energy 2
Stallmanの開幕。先取り感は最大、声のエネルギーは最小。頭は踏み出したが声は地面から離れていません。印象論では「緊張していた」で片付く場面を、ツールは秒単位で名指しします。
passionateは伸びない
4本すべてでpassionateピーク ≤ 11
Jobs・孫正義・西野・落合の4本すべてで、ESAS passionateは11を超えません。届く話し方は「熱量」では現れず、anticipation・concentration・抑揚の振れに現れます。クロス層が見に行くのはそこです。
使い方
# 解析: recognize → ESAS → Claude×3層 → Markdownレポート
shl analyze examples/sample.wav --out report.md
# Claudeモデルを1発ごとに指定
shl analyze examples/sample.wav --model claude-opus-4-7 --out report.md
# localhost:8501でマイク録音付きブラウザUI
shl serve Web UI
shl serveでStreamlit UIがlocalhost:8501に立ち上がります。ブラウザのマイク録音か.wavのドラッグ&ドロップで解析し、ESAS時系列をPlotlyでインタラクティブに眺めて、クロス層カードを開き、Markdownレポートをダウンロード。APIキーは.envからサーバー側で読み込まれ、ブラウザには露出しません。
実際に返ってくる判定
ツールが実際のスピーチから拾ってきた3パターン。すべて時刻+パラメータ+引用付き。
- Stallman開幕(0.0s, anticipation=65, energy=2, confidence=15): 先取り感は最大、声のエネルギーは最小。「なんか噛み合ってなかった」と印象で語られる、その具体的な1秒
- intensive_thinking=62 × energy=3: 最も激しく考えている瞬間に声の出力が最低になる逆相関。ツールを回した長尺トークではほぼ全部で観測
- passionate=0 多発 × フィラーゼロ: 言葉は止まらないが情動信号は0。よく練習されたピッチが陥る「流暢だが熱量無し」の型。クロス層でしか見えない
ツールは鏡であって、コーチではありません。タイムラインに癖を名指しするところまでがツールの仕事で、その先はあなたのものです。
v0.2、Zennfes Spring 2026提出版。推奨クリップ長は30-90秒(AmiVoiceの月60分無料枠を保護)。解析はエンドツーエンドで約3-4分かかります。ESASパラメータの意味づけは実測+公式パラメータ一覧からの逆算で、クロス層の所見は臨床測定ではなくコーチングのヒントとして扱ってください。
なぜ作ったか
登壇のフィードバックは印象で語られがちです。「緊張していた」「終わりが弱かった」「途中で聴衆が降りた」。印象が言葉になったときには、その瞬間を作った具体的な1秒はもう手元にありません。ここでの3層は、その1秒を離さないためのものです。音響層は言葉を認識できたかどうかに関係なく1秒を測り、テキスト層は実際に何が話されたかを記録し、クロス層が両者を同じタイムラインに揃えて、癖を印象ではなく引用に変えます。原稿と同じように、話し方もデバッグできるはずです。
Whisper・pyAudioAnalysisとの位置関係
役割が違います。Whisperは書き起こし、pyAudioAnalysisは音響フレームの分類。speech-habit-lensはその上の層で、感情パラメータの時系列と書き起こしを同じタイムラインに並べて、厳格な引用ルールでLLMに癖を名指させます。
| speech-habit-lens | Whisper | pyAudioAnalysis | |
|---|---|---|---|
| 答える問い | 自分の話し方の癖は、秒単位でどこにある? | 話者は何を言った? | このフレームはどの音響クラス? |
| 感情パラメータの時系列 | ✓ ESAS 20パラメータを秒に揃える | — | 手作り音響特徴量 |
| 声×言葉のクロス層 | ✓ 根拠付き引用でLLM解析 | — | — |
| ハルシネーション対策 | ✓ Grounding Rule(時刻+パラ+引用) | 該当なし(書き起こしのみ) | 該当なし(分類器のみ) |
| Web UI | ✓ Streamlit + ブラウザマイク | — | — |
| ライセンス | MIT | MIT | Apache-2.0 |
「—」はそのツールが標準で提供しない面を示します。speech-habit-lensは書き起こしエンジンと音響信号の上に載る層(現在はAmiVoice ESAS)で、上流を差し替えてもクロス層解析は同じ形で動きます。
よくある質問
APIキーは何が必要ですか?
認識とESAS取得にAmiVoice APIキー(月60分まで無料)、3層LLM解析にAnthropic APIキーが必要です。1解析あたりClaude Sonnet 4.6で約¥18、月60本回して¥1,080程度が目安です。
クリップの長さはどれくらい?
30-90秒が本命です。120秒超は拒否、60秒超は警告を出します(AmiVoice月60分無料枠を保護)。ツールはピッチ長の観察窓のために作ってあり、長尺トーク全編を通すためのものではありません。
対応言語は?
テキスト層の書き起こしはAmiVoiceのエンジン依存(既定は日本語)なので、テキスト層の解析は日本語が最強です。ESASは言語非依存で、音響層とクロス層は言語に関係なく動きます。書き起こしがノイズまみれでもクロス層は鈍りません。
ESAS 20パラメータは実在しますか? どう検証しましたか?
AmiVoice公式docsの記載は5例のみです。20フィールド名は2026年5月にlive APIで実測し、6月にパラメータ一覧エンドポイントで再検証しました。値域は全部プロンプトテンプレに明記してあるので、LLMが範囲外の値を出せない設計です。
Grounding Ruleはハルシネーションをどう止めますか?
各層のプロンプトが、全主張に時刻+パラメータ+引用の3点根拠を要求します。3点セットは構造化JSONで下流に渡り、クロス層も同じルールを継承します。引用なし=主張なし。根拠のない発見はパーサーが落とします。
Claudeモデルはどれを選べばいい?
Sonnet 4.6が既定で、ケーススタディはこれで着地します。難しいクロスパターンにはOpus 4.7を試す価値あり(コスト約3倍)。素早いトリアージだけならHaiku 4.5でコスト削減。1発ごとに--modelで切替できます。
ローカルモデル・オンデバイス認識は?
v0.2はクラウド前提です(AmiVoice + Anthropic)。音響信号をローカルのESAS相当に、テキスト層をローカルWhisperに差し替えるのは同梱していませんが、クロス層はモデル非依存なので自然な拡張ポイントです。
臨床測定ですか?
いいえ。クロス層の所見はコーチングのヒントとして扱ってください。パラメータの意味づけは実測+ベンダーのパラメータ一覧からの逆算で、どの癖を直すべきかの判断はあなたに残ります。ツールの仕事は、癖を名指しして秒を引用するところまでです。
作者について
作者はKen Imoto。Zenn・Qiita・Dev.to・当サイトで技術記事300本以上、4言語で書籍40冊以上、Zenn・Qiitaで累計40万PV超、Zenodoで研究論文4本を公開し、LLMO Frameworkを設計しています。
関連する開発ツール
- rhythm-lens 日本語・英語・ポルトガル語Markdownのリズム (文長の揺れ・段落構造・burstiness) を、2本の論文の実測分布とパーセンタイル照合するCLI。AI検出器ではなく、執筆フィードバックの計測器。
- claude-shift 複数のClaude Codeアカウントを管理するツール。activeアカウントをCLIから切り替えつつ、Claude Codeが実際に読んでいる2ファイル認証(~/.claude/.credentials.json + ~/.claude.json)を両方同期。5時間枠と週次の使用率をアカウント横断でChrome拡張から見られる。
- opencut-mcp OpenCut classic を任意の MCP クライアントから操作する MCP サーバー。Playwright がエディタセッションを保持し、12 個のツールでタイムライン・メディアアセット・エクスポートパイプラインを公開。OpenCut classic の fork 向け。
- mcp-scorecard MCPサーバー用のプリフライトチェックCLI。ツールを1つも呼ばずに消費される受動トークン量、ユースケースの絞り込み、セキュリティ、命名衝突の4層でスコアカードを返します。