OSS · Python CLI + Streamlit

speech-habit-lens

We rehearse the words. We ignore the voice.

A 1-minute speech, three layers of analysis: 20 AmiVoice ESAS parameters over time, the recognized text, and the cross layer that catches where voice and words fall out of sync. Every observation must cite time, parameter and quote.

View on GitHub Sample report (Stallman 60s) →

  • Habits in one minute 3-layer analysis in one command
  • Robust to recognition noise ESAS is language-independent — the acoustic layer still cuts through
  • Voice/word desync surfaced The cross layer names it: "energy drops right before the conclusion"
  • Hallucinations suppressed Every claim must cite time + parameter + quote
  • Open Source · MIT
  • CLI + Streamlit UI
  • 20 ESAS params, all verified
  • Created by Ken Imoto
Terminal demo: shl help output, then a rendered Markdown report from a real 60-second Stallman speech analysis showing acoustic × verbal correlation patterns with time, parameter and quote citations

Two commands

  1. shl analyze speech.wav --out report.md Recognize the audio, extract ESAS, run three Claude layers, and write a grounded Markdown report — about 3–4 minutes end to end.
  2. shl serve Launch the Streamlit UI at localhost:8501 with in-browser mic recording, Plotly time series and cross-layer cards.
  3. --model claude-opus-4-7 Swap the analysis model per run: Sonnet 4.6 (default), Opus 4.7 for the toughest cross patterns, Haiku 4.5 to cut cost.

Who it’s for

  • Speakers & founders audit the pitch you are about to give — before the room is watching
  • Product managers find the sentence where your update stops landing, then fix that one
  • Coaches & educators ground feedback in measured evidence instead of "you sounded a bit flat"
  • Curious engineers see your own speech habits the way an instrument sees them, in one minute of audio

When to reach for it

  • Rehearsing a pitch or a talk: hear the opening habit before it goes live
  • After a demo that fell flat: find the moment the voice left the words behind
  • Coaching a speaker: replace impressions with a time-stamped, parameter-cited report
  • Auditing your own delivery: a monthly reading of the habits you did not know you had

Install

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

Needs an AmiVoice API key (free up to 60 minutes per month) and an Anthropic API key. One analysis costs roughly ¥18 of Claude Sonnet usage — around 60 runs per month for ¥1,080.

The three layers

  • Acoustic layer: ESAS 20 parameters over time — tension curve, intonation bias, opening energy, ending fade
  • Text layer: fillers, conclusion position, repeated words, logic flow from the recognized transcript
  • Cross layer: body–language correlations like "vocal energy drops right before the conclusion"
  • Grounding Rule: every claim must cite time, parameter and quote, which suppresses hallucinated observations
  • ESAS is language-independent: acoustic habits surface sharply even when text recognition is noisy
  • All 20 ESAS field names verified against the live API — the official docs list only 5 examples
  • Streamlit UI: in-browser mic recording, interactive Plotly time series, expandable cross-layer cards, Markdown report download

Measured across 4 pitches

Same tool, four 60-second speech clips from Jobs, Son (SoftBank), Nishino and Ochiai. Numbers below are the peak values printed by the tool.

metricJobs (close)Son (open)Nishino (open)Ochiai (open)
energy peak21443239
concentration peak10010090100
anticipation peak681003591
emo_cog peak207136276244
passionate peak64118
conclusion positionbackfrontmiddleback
fillers"ne" ×1"ne" ×1"chotto" ×5"ano" ×1
recognition confidence0.74–0.890.99–1.000.93–1.000.70–0.82

A single indicator does not tell you who is a great speaker: Jobs’ peak energy is 21, Son’s is 44, and both land. The tool surfaces where each speaker’s habit lives — Nishino’s five "chotto" fillers, Son’s pitch delivered entirely from the front, Ochiai’s recognition confidence dropping to 0.70 while his acoustic pattern stays intense. The point is not the score; it is the specific habit named on the timeline.

The two moves that matter most

These are the two things the tool routinely surfaces that impressions do not.

Opening desync

anticipation 65 × energy 2

The Stallman opener: maximum anticipation, minimum vocal energy. The head has stepped forward; the voice has not left the ground yet. Impressions call this "he seemed nervous" — the tool names the specific second.

passionate stays flat

passionate peak ≤ 11 across all 4 pitches

Across Jobs, Son, Nishino and Ochiai, ESAS passionate never rises above 11. Emotion in delivery does not show up as "passion". It shows up as anticipation, concentration and intonation swings — which is where the cross layer looks.

Usage

# analyze: recognize → ESAS → Claude × 3 layers → Markdown report
shl analyze examples/sample.wav --out report.md

# pick the Claude model per run
shl analyze examples/sample.wav --model claude-opus-4-7 --out report.md

# browser UI with mic recording at localhost:8501
shl serve

Web UI

shl serve starts a Streamlit UI at localhost:8501: record from the browser mic or drop a .wav, read the ESAS time series interactively in Plotly, open the cross-layer cards, and download the Markdown report. API keys are read server-side from .env and never reach the browser.

Streamlit web UI after a real analysis of the 60-second sample speech: interactive ESAS time-series chart with selectable parameters next to the recognized transcript

What real runs return

Three patterns the tool has surfaced on real speeches. Every line ships with time + parameter + quote.

  • Stallman opener (0.0s, anticipation=65, energy=2, confidence=15): maximum anticipation with minimum vocal energy. A run-up that never leaves the ground — the specific second that reads as "he seemed off" in impressions.
  • intensive_thinking=62 × energy=3: the moments of hardest thinking coincide with the lowest vocal output. Present in every long-form talk the tool has been run against so far.
  • passionate=0 while fluent: words flow without pause, ESAS passionate stays at zero. Fluent but flat — a common failure mode of well-rehearsed pitches, only visible on the cross layer.

The tool is a mirror, not a coach. It names the habit on the timeline; what you do with it is yours.

v0.2, built for Zennfes Spring 2026. Recommended clip length 30–90 seconds (60 minutes/month is the free AmiVoice tier). Analysis runs about 3–4 minutes end to end. The ESAS parameter semantics are reverse-engineered from measurements plus the official parameter list — treat the cross-layer findings as coaching hints, not clinical measurements.

Why this tool exists

Most delivery feedback lives at the level of impression: "you seemed nervous", "the closing felt weak", "you lost me in the middle". By the time the impression is put into words, the specific second that produced it is gone. The three layers here exist to hold on to that second: the acoustic layer measures it whether you recognized the words or not, the text layer records what was actually said, and the cross layer aligns them so a habit becomes a citation instead of a vibe. Debug the delivery like you would debug code.

Alongside Whisper and pyAudioAnalysis

Different jobs. Whisper transcribes; pyAudioAnalysis classifies acoustic frames. speech-habit-lens is the layer on top: it aligns a per-parameter emotional time series with the transcript and asks an LLM to name the habits, under a strict citation rule.

speech-habit-lensWhisperpyAudioAnalysis
What it answers What is my delivery habit, second by second? What did the speaker say? Which acoustic class does this frame belong to?
Emotional time series ✓ 20 ESAS parameters aligned to seconds Handcrafted acoustic features
Voice × word cross layer ✓ LLM with grounded citations
Hallucination guard ✓ Grounding Rule (time + param + quote) n/a (transcript only) n/a (classifier only)
Web UI ✓ Streamlit + browser mic
License MIT MIT Apache-2.0

A dash means the tool does not offer that surface out of the box. speech-habit-lens sits on top of a transcript engine and an acoustic signal (AmiVoice ESAS in this build) — swap either upstream layer and the cross-layer analysis still runs.

FAQ

What API keys do I need?

AmiVoice API key (free up to 60 minutes per month) for recognition and ESAS, plus an Anthropic API key for the 3-layer LLM analysis. One analysis costs roughly ¥18 of Claude Sonnet 4.6 usage; expect ~¥1,080 per month if you run about 60 clips.

How long can the clip be?

30 to 90 seconds is the sweet spot. Clips over 120 seconds are rejected outright and clips over 60 trigger a warning, both to protect the free AmiVoice tier. The tool is built for the pitch-length observation window, not full talks.

What language does it work with?

The recognized-text layer defaults to AmiVoice’s Japanese engine, so text-layer analysis is strongest in Japanese. ESAS is language-independent, so the acoustic layer and the cross layer work regardless of the language — noisy recognition does not blunt them.

Are the 20 ESAS parameters real, and how were they verified?

The official AmiVoice docs list only 5 example parameters. All 20 field names were measured against the live API in May and re-verified against the parameter-list endpoint in June 2026. Every value range is documented in the prompt templates so the LLM cannot infer values out of range.

How does Grounding Rule stop hallucinations?

The prompt for each layer requires every claim to cite time, parameter and quote. The three-piece evidence is passed downstream as structured JSON, and the cross layer inherits the same rule — no citation, no claim. Findings without evidence are dropped by the parser.

Which Claude model should I use?

Sonnet 4.6 is the default and lands the case studies. Opus 4.7 is worth trying on the toughest cross patterns at roughly 3× cost. Haiku 4.5 is the cost-cut option when you just want fast triage — pick per run with --model.

What about local models or on-device recognition?

v0.2 is cloud-first (AmiVoice + Anthropic). Swapping the acoustic signal for a local ESAS-equivalent or the text layer for a local Whisper is not shipped but is the natural extension — the cross layer is model-agnostic.

Is this a clinical measurement?

No. Treat the cross-layer findings as coaching hints, not clinical measurements. Parameter semantics were reverse-engineered from measurements plus the vendor’s parameter list, and coaching context (what habit is worth fixing) is your call — the tool names the habit and cites the second.

About the author

Built by Ken Imoto: 300+ technical articles across Zenn, Qiita, Dev.to and this site, 40+ books in 4 languages, 400K+ pageviews on Zenn and Qiita, 4 research papers on Zenodo, and creator of the LLMO Framework.

Related developer tools

All products →

← All products