Skip to main content
Glama

get_voice_stats

Retrieve dictation quality metrics including words per minute, average Whisper confidence, and correction rate for a specified lookback window. Use to analyze voice performance trends over time.

Instructions

Return dictation quality stats (WPM, confidence average, correction rate) over a window.

Returns aggregate metrics: words-per-minute, average Whisper confidence, correction rate (per get_correction_history), session count.

USE WHEN: the user asks "how is my dictation going" or you're analyzing voice quality trends. NOT FOR: per-segment data — use get_recent_voice or search_voice.

BEHAVIOR: pure read. Returns zero-valued metrics if no voice activity in the window.

PARAMETERS: hours: lookback window. Range 1-720 (30d). Default 24.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
hoursNo

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault
resultYes

Implementation Reference

  • Primary implementation of the get_voice_stats tool. Decorated with @mcp_app.tool(), it queries the activity database for voice transcription events within the given hours window and returns dictation count, total audio duration, average duration, correction rate, and LLM cleanup count.
    @mcp_app.tool()
    def get_voice_stats(hours: float = 8.0) -> str:
        """Get voice dictation statistics over the last N hours.
    
        Returns dictation count, total duration, average length, and accuracy info.
    
        Args:
            hours: How many hours back to analyze (default 8).
        """
        hours = max(0.1, min(hours, 168.0))  # cap at 1 week
    
        conn = _get_db()
        if not conn:
            return "No activity database found."
    
        try:
            cutoff = time.time() - (hours * 3600)
            rows = conn.execute(
                "SELECT payload FROM events "
                "WHERE modality = 'voice' AND event_type = 'transcription' "
                "AND timestamp > ?",
                (cutoff,),
            ).fetchall()
            conn.close()
    
            if not rows:
                return f"No dictations in the last {hours:.0f} hours."
    
            total = len(rows)
            total_duration = 0.0
            corrections = 0
            llm_cleanups = 0
    
            for row in rows:
                payload = json.loads(row["payload"])
                total_duration += payload.get("duration_seconds", 0)
                if payload.get("raw_transcript") != payload.get("transcript"):
                    corrections += 1
                if payload.get("cleanup_applied"):
                    llm_cleanups += 1
    
            avg_duration = total_duration / total if total else 0
            correction_rate = corrections / total * 100 if total else 0
    
            lines = [
                f"=== Voice Stats (last {hours:.0f} hours) ===\n",
                f"Total dictations: {total}",
                f"Total audio: {total_duration:.1f}s ({total_duration / 60:.1f} min)",
                f"Average duration: {avg_duration:.1f}s per dictation",
                f"Corrections applied: {corrections}/{total} ({correction_rate:.0f}%)",
                f"LLM cleanups: {llm_cleanups}",
            ]
            return "\n".join(lines)
        except Exception as e:
            return f"Error calculating stats: {e}"
  • Registration via @mcp_app.tool() decorator. The mcp_app is a FastMCP instance created at line 18 of this same file.
    @mcp_app.tool()
    def get_voice_stats(hours: float = 8.0) -> str:
        """Get voice dictation statistics over the last N hours.
    
        Returns dictation count, total duration, average length, and accuracy info.
  • Health check registration that imports and invokes get_voice_stats with a minimal hours parameter (0.01) for testing.
    ("voice", "get_voice_stats",            voice.get_voice_stats,            {"hours": 0.01}),
  • The _get_db() helper used by get_voice_stats to open the shared activity SQLite database.
    def _get_db() -> sqlite3.Connection | None:
        """Open the activity database (shared with Sight/EventBus)."""
        if not _DB_PATH.exists():
            return None
        conn = sqlite3.connect(str(_DB_PATH), timeout=5)
        conn.row_factory = sqlite3.Row
        return conn
  • Glama registry stub — provides the tool definition/schema for the Glama.ai registry but returns a 'local only' message since this tool is only functional on the user's local machine.
    @mcp_app.tool()
    def get_voice_stats(hours: int = 24) -> str:
        """Return dictation quality stats (WPM, confidence average, correction rate) over a window.
    
        Returns aggregate metrics: words-per-minute, average Whisper confidence,
        correction rate (per get_correction_history), session count.
    
        USE WHEN: the user asks "how is my dictation going" or you're analyzing
        voice quality trends.
        NOT FOR: per-segment data — use get_recent_voice or search_voice.
    
        BEHAVIOR: pure read. Returns zero-valued metrics if no voice activity in
        the window.
    
        PARAMETERS:
          hours: lookback window. Range 1-720 (30d). Default 24.
        """
        return _LOCAL_ONLY_MSG
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Without annotations, description fully covers behavioral traits: pure read operation, returns zero-valued metrics if no activity, and no side effects.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Structured with clear sections, bullet points, and front-loaded summary; every sentence adds value.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given output schema exists, description covers return metrics, behavior, and usage completely for a stats tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Adds significant meaning beyond schema: specifies lookback window, range (1-720), and default (24) for the 'hours' parameter.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Clearly states it returns dictation quality stats (WPM, confidence average, correction rate) over a window, and distinguishes itself from siblings like get_recent_voice and search_voice.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Provides explicit 'USE WHEN' and 'NOT FOR' conditions, naming alternative tools for per-segment data.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/ContextPulse/contextpulse'

If you have feedback or need assistance with the MCP directory API, please join our Discord server