Files

378 lines
22 KiB
Markdown

# voice-pet-pipeline Specification
## Purpose
TBD - created by archiving change add-voice-pet-pipeline. Update Purpose after archive.
## Requirements
### Requirement: Python desktop pet runtime
The system SHALL be specified as a local Python desktop pet application that owns the voice pipeline, desktop pet state, local audio input, and local audio output in the first version.
#### Scenario: App starts in local desktop mode
- **WHEN** the user starts the future application on macOS
- **THEN** the system SHALL initialize as a local desktop pet process rather than a remote service or browser-only tool
#### Scenario: Implementation follows OpenSpec artifacts
- **WHEN** this OpenSpec change is implemented
- **THEN** the repository SHALL contain Python source code, automated tests, validation commands, and project-local pet assets aligned with the planning artifacts
### Requirement: Local microphone and speaker transport
The system SHALL use the local microphone as the first-version input Transport and the local system speaker as the first-version output Transport, and `run-live` SHALL exercise those real local devices by default.
#### Scenario: Microphone input is available
- **WHEN** the configured microphone is available and permitted
- **THEN** the live Transport SHALL provide streaming audio frames to wake detection, VAD, and STT stages
#### Scenario: Speaker output is available
- **WHEN** TTS returns a valid local audio segment or audio file and the configured speaker is available
- **THEN** the live Transport or macOS playback command SHALL play the audio through the local speaker
#### Scenario: Audio device is unavailable
- **WHEN** the microphone or speaker is missing, denied, unsupported, or inaccessible through `sounddevice`
- **THEN** the system SHALL expose a recoverable Transport error with a stable error code and SHALL NOT silently fall back to fixture audio in live mode
### Requirement: Wake word detection
The system SHALL listen locally for the Chinese wake word “小杰小杰” before accepting user speech for a conversation turn.
#### Scenario: Wake word is detected
- **WHEN** the user says “小杰小杰” and the wakeword provider returns confidence above the configured threshold
- **THEN** the pipeline SHALL transition from wake listening to speech detection
#### Scenario: Wake word is not detected
- **WHEN** background speech or noise does not match “小杰小杰”
- **THEN** the pipeline SHALL remain in wake listening and SHALL NOT invoke STT, LLM, or TTS
#### Scenario: Wake model fails
- **WHEN** the wakeword provider cannot load or process audio
- **THEN** the system SHALL report a wakeword error and SHALL NOT crash the desktop pet process
### Requirement: VAD speech endpoint detection
After wakeword detection, the system SHALL use VAD to identify when the user starts and stops speaking.
#### Scenario: User begins speaking
- **WHEN** VAD detects continuous speech above the configured start threshold
- **THEN** the pipeline SHALL begin recording the current utterance
#### Scenario: User stops speaking
- **WHEN** VAD detects continuous silence above the configured end threshold
- **THEN** the pipeline SHALL close the current audio segment and send it to STT
#### Scenario: User says nothing after wakeword
- **WHEN** no speech is detected before the configured no-speech timeout
- **THEN** the pipeline SHALL return to wake listening without invoking STT or LLM
#### Scenario: Recording exceeds maximum duration
- **WHEN** speech continues beyond the configured maximum utterance duration
- **THEN** the pipeline SHALL end the segment, mark the end reason, and continue to STT with the captured audio
### Requirement: Local STT transcription
The system SHALL transcribe captured user utterances through the configured STT provider; cloud mode SHALL use NewAPI-compatible ASR and local mode SHALL use project-local `sherpa-onnx` model assets under `models/`.
#### Scenario: STT succeeds
- **WHEN** configured STT returns non-empty text for a captured live audio segment
- **THEN** the pipeline SHALL add the trimmed text as a user message to the current process conversation context
#### Scenario: STT returns empty text
- **WHEN** STT returns empty text, punctuation-only text, or an invalid transcript
- **THEN** the live runtime SHALL skip LLM invocation and return to standby with a recoverable status
#### Scenario: STT provider fails
- **WHEN** the STT provider raises an error, cloud ASR fails, or local model loading fails
- **THEN** the system SHALL emit an STT or model error code and SHALL recover to a state where future wake attempts are possible if startup can continue safely
### Requirement: Conversation context management
The system SHALL maintain an in-memory conversation context for the active desktop pet session, and live repeated voice runtime SHALL define that session as the current `run-live` process only.
#### Scenario: User transcript is accepted
- **WHEN** a valid STT transcript is produced during a live turn
- **THEN** the system SHALL append it to the current process context as a user message before invoking the LLM
#### Scenario: Assistant reply completes
- **WHEN** the LLM and TTS stages complete a non-empty reply during a live turn
- **THEN** the system SHALL append the assistant text to the current process context
#### Scenario: Context exceeds configured budget
- **WHEN** the context exceeds the configured message or character budget
- **THEN** the system SHALL preserve the system prompt and most recent conversation turns while removing older ordinary messages
#### Scenario: Runtime exits
- **WHEN** the `run-live` process exits
- **THEN** the system SHALL discard the context and SHALL NOT persist it across process restarts
### Requirement: Cloud LLM streaming reply
The system SHALL use a cloud LLM provider for reply generation, with an OpenAI/NewAPI-compatible chat completions endpoint as the first-version runtime target.
#### Scenario: LLM stream begins
- **WHEN** the LLM provider receives valid context messages and configuration
- **THEN** it SHALL stream reply deltas rather than waiting for the full reply before producing output
#### Scenario: LLM model is configured
- **WHEN** the system starts
- **THEN** the LLM base URL, API key, and model name SHALL be read from `.env` or local uncommitted configuration and SHALL NOT be hard-coded in pipeline logic
#### Scenario: LLM request fails
- **WHEN** the LLM provider times out, is rate limited, lacks credentials, or encounters a network error
- **THEN** the pipeline SHALL emit a structured LLM error and transition through error recovery to wake listening
### Requirement: Local TTS synthesis and playback
The system SHALL synthesize assistant replies through the configured TTS provider and SHALL play synthesized speech through the local system output path; cloud mode SHALL use NewAPI-compatible TTS and local mode SHALL use a local playback-capable TTS provider.
#### Scenario: Reply text is ready for speech
- **WHEN** the LLM produces a non-empty reply for a live turn
- **THEN** the TTS provider SHALL synthesize that text into locally playable speech
#### Scenario: Playback starts
- **WHEN** the first synthesized audio output is available
- **THEN** the output Transport or macOS playback command SHALL begin playback through the local speaker
#### Scenario: TTS fails
- **WHEN** TTS returns empty audio, fails to create an audio file, or playback command fails
- **THEN** the live runtime SHALL emit a structured TTS or playback error and SHALL recover without terminating default loop mode
### Requirement: Pipeline state machine
The system SHALL expose deterministic pipeline states for `idle`, `wake_listening`, `speech_detecting`, `recording`, `transcribing`, `thinking`, `speaking`, `interrupted`, and `error_recovering`.
#### Scenario: Normal conversation turn
- **WHEN** wakeword, VAD, STT, LLM, TTS, and playback all succeed
- **THEN** the state sequence SHALL progress through wake listening, speech detection, recording, transcribing, thinking, speaking, and back to wake listening
#### Scenario: Recoverable provider error
- **WHEN** any provider fails during a conversation turn
- **THEN** the state machine SHALL enter error recovery and then return to wake listening after cleanup
#### Scenario: UI subscribes to state
- **WHEN** the pipeline state changes
- **THEN** the desktop pet UI SHALL be able to update its visible state without directly invoking audio or model providers
### Requirement: Desktop pet visual states
The system SHALL define desktop pet visual states for idle, listening, recording, thinking, speaking, and error feedback.
#### Scenario: Wakeword is detected
- **WHEN** the pipeline enters speech detection or recording
- **THEN** the desktop pet SHALL show a listening or recording visual state
#### Scenario: LLM is generating
- **WHEN** the pipeline enters thinking
- **THEN** the desktop pet SHALL show a thinking visual state
#### Scenario: TTS is playing
- **WHEN** the pipeline enters speaking
- **THEN** the desktop pet SHALL show a speaking visual state
#### Scenario: Error occurs
- **WHEN** the pipeline enters error recovery
- **THEN** the desktop pet SHALL show a concise visible error state and then return to idle or wake listening when recovered
### Requirement: Generated pet asset specification
The system SHALL specify that production desktop pet images are generated with the image generation skill when usable, or with a reproducible project-local fallback when image generation output is unavailable or fails validation, and saved inside the project as transparent PNG assets.
#### Scenario: Image generation output is usable
- **WHEN** pet images are generated with `imagegen` and pass role and transparency validation
- **THEN** the images SHALL be processed for transparency, validated, and saved to a project asset directory
#### Scenario: Image generation output is unavailable or invalid
- **WHEN** image generation output is unavailable, inaccessible as a project file, or fails role/transparency validation
- **THEN** the system SHALL use a reproducible project-local fallback to create transparent PNG pet state assets and SHALL validate them before use
#### Scenario: Planning phase is executed
- **WHEN** this OpenSpec change is implemented
- **THEN** generated or generated-derived pet assets SHALL be saved inside the project and SHALL NOT be referenced from a temporary generation directory
### Requirement: Audio feedback suppression
The system SHALL prevent the desktop pet's own TTS playback from being treated as a new user wakeword or speech input.
#### Scenario: TTS playback is active
- **WHEN** the output Transport is playing synthesized assistant speech
- **THEN** wakeword detection and VAD input processing SHALL be suppressed or ignored for that playback window by default
#### Scenario: User speaks during playback
- **WHEN** the user speaks while TTS playback is active in the first version
- **THEN** the system SHALL ignore that speech unless a future interruption feature is explicitly specified
### Requirement: Structured errors and logging
The system SHALL represent stage failures with structured error codes and log state transitions, latency metrics, and provider names.
#### Scenario: Stage transition occurs
- **WHEN** the pipeline changes state
- **THEN** the system SHALL log the turn ID, old state, new state, timestamp, and triggering event
#### Scenario: Provider call completes
- **WHEN** a provider call succeeds or fails
- **THEN** the system SHALL log provider name, stage, duration, and error code if present
#### Scenario: Sensitive data is present
- **WHEN** logs are written
- **THEN** the system SHALL NOT log API keys, authorization headers, or raw credentials
### Requirement: Performance targets
The system SHALL define measurable first-version latency and reliability targets for wakeword response, endpoint detection, LLM first output, and speech playback.
#### Scenario: Wakeword latency is measured
- **WHEN** wakeword detection succeeds in a normal local environment
- **THEN** the system SHALL target visible listening feedback within 800 ms
#### Scenario: User stops speaking
- **WHEN** the user stops speaking after a normal utterance
- **THEN** VAD endpoint detection SHALL target transition to transcription within 900 ms
#### Scenario: LLM begins responding
- **WHEN** a valid transcript has been sent to the LLM provider
- **THEN** the system SHALL target first playable reply text within 3.5 seconds
#### Scenario: Normal reply is spoken
- **WHEN** a normal Chinese question under 10 seconds is processed
- **THEN** the system SHALL target the start of spoken playback within 5 seconds P95 after the user stops speaking
### Requirement: Security and privacy
The system SHALL protect credentials and minimize audio persistence.
#### Scenario: API key is required
- **WHEN** the LLM provider needs an OpenAI API key
- **THEN** the key SHALL be loaded from `.env` or local uncommitted configuration and SHALL NOT be committed
#### Scenario: Audio is processed
- **WHEN** user speech is captured for STT
- **THEN** raw audio SHALL NOT be persisted by default
#### Scenario: Cloud LLM is invoked
- **WHEN** the system sends data to the cloud LLM
- **THEN** it SHALL send transcript text and necessary conversation context, not raw microphone audio
### Requirement: Testability
The system SHALL be designed so each stage can be tested with mock providers, file-based audio fixtures, and fake live runtime components without requiring real devices in automated tests.
#### Scenario: Repeated runtime is unit tested
- **WHEN** fake live providers produce two deterministic turns
- **THEN** tests SHALL verify two STT calls, two LLM calls, two TTS calls, two playback calls, and final return to standby
#### Scenario: Temporary context is unit tested
- **WHEN** fake live providers run two turns in one runtime instance
- **THEN** tests SHALL verify the second LLM request includes the first turn user and assistant messages
#### Scenario: Process-local context is unit tested
- **WHEN** a second runtime instance is created after a first instance has conversation history
- **THEN** tests SHALL verify the second instance starts with no user/assistant history
#### Scenario: OpenSpec planning validation runs
- **WHEN** this change is complete before implementation
- **THEN** `openspec validate complete-live-repeat-voice-runtime --strict` and `openspec validate --all --strict` SHALL pass
### Requirement: Module-level git commit gates
The system implementation process SHALL require an immediate Git commit after each major module or milestone is completed, where a major module means a top-level task group from `tasks.md` or a phase milestone from `proposal.md`.
#### Scenario: Major module is completed
- **WHEN** an implementer completes a top-level task group or milestone phase
- **THEN** the implementer SHALL run the applicable build, tests, lint/type checks, and OpenSpec validation before committing
#### Scenario: Build validation fails before commit
- **WHEN** the applicable build, tests, lint/type checks, or OpenSpec validation fail
- **THEN** the implementer SHALL NOT create the module commit until the failure is fixed and validation passes
#### Scenario: Module commit is created
- **WHEN** validation passes for the completed module
- **THEN** the implementer SHALL immediately create a Git commit using the Chinese message format “[模块名]:完成[具体功能描述],包含[关键变更]”
#### Scenario: Intermediate work remains after module completion
- **WHEN** module-related changes remain unstaged or uncommitted after the module is completed
- **THEN** the implementer SHALL include those changes in the module commit or explicitly separate unrelated external changes before continuing to the next module
### Requirement: Live repeat voice runtime
The system SHALL provide a `run-live` command that performs real repeated voice conversation with local microphone input, configured speech recognition and speech synthesis providers, cloud LLM reply generation, local speaker playback, and automatic return to standby.
#### Scenario: Live runtime starts in standby
- **WHEN** the user runs `PYTHONPATH=src python3.11 -m owner_voice_pet run-live`
- **THEN** the system SHALL load `.env`, validate required live dependencies, initialize local audio/model providers, and enter a standby listening loop
#### Scenario: Live runtime completes two turns
- **WHEN** the user wakes the system with “小杰小杰”, asks a question, hears the reply, then wakes it again and asks another question
- **THEN** the system SHALL complete wake, recording, STT, LLM, TTS, playback for both turns and SHALL return to standby after each turn
#### Scenario: Once mode completes one turn
- **WHEN** the user runs `PYTHONPATH=src python3.11 -m owner_voice_pet run-live --once`
- **THEN** the system SHALL run at most one wake-to-playback turn and exit after the turn completes or fails with a documented live error
### Requirement: Temporary in-process conversation history
The live runtime SHALL maintain conversation history only in memory for the current process and SHALL include retained user/assistant history in later LLM requests during that same process.
#### Scenario: Second turn uses first turn history
- **WHEN** the first live turn appends a user transcript and an assistant reply
- **AND** a second live turn sends an LLM request
- **THEN** the second request SHALL include the first turn user message and assistant message unless configured context limits require truncation
#### Scenario: New runtime starts empty
- **WHEN** a new `run-live` process or new live runtime instance starts
- **THEN** it SHALL NOT load user/assistant history from a previous process or previous runtime instance
#### Scenario: Process exits
- **WHEN** the live runtime exits for any reason
- **THEN** conversation history SHALL be discarded and SHALL NOT be written to disk, database, logs, or model files
### Requirement: Local speech model management
The system SHALL provide project-local speech model preparation and diagnostics for live VAD/STT operation, storing downloaded model artifacts under `models/` without committing them to Git.
#### Scenario: Models are downloaded
- **WHEN** the user runs `python3.11 scripts/download_speech_models.py --dir models`
- **THEN** the script SHALL create or update a project-local model directory with the files required by the configured VAD/STT providers
#### Scenario: Model check succeeds
- **WHEN** required dependencies and model files are available
- **THEN** `PYTHONPATH=src python3.11 -m owner_voice_pet model-check` SHALL exit successfully and report the model directory and checked providers
#### Scenario: Model check fails
- **WHEN** `sherpa-onnx` is unavailable, a model file is missing, or a model cannot be loaded
- **THEN** `model-check` SHALL fail with a structured model error and SHALL NOT start live microphone listening
### Requirement: Configurable speech provider mode
The system SHALL read `OWNER_SPEECH_PROVIDER` from `.env` to choose between cloud speech providers and local speech providers for first-version live runtime.
#### Scenario: Cloud speech provider is selected
- **WHEN** `OWNER_SPEECH_PROVIDER=cloud`
- **THEN** live ASR SHALL use the configured cloud model from `OWNER_ASR_MODEL`, live TTS SHALL use the configured cloud model from `OWNER_TTS_MODEL`, and the implementation SHALL default those models to `mimo-v2.5-asr` and `mimo-v2.5-tts`
#### Scenario: Local speech provider is selected
- **WHEN** `OWNER_SPEECH_PROVIDER=local`
- **THEN** live ASR/VAD SHALL use project-local speech model assets and local TTS SHALL use a local playback-capable provider
#### Scenario: Speech provider is invalid
- **WHEN** `OWNER_SPEECH_PROVIDER` is neither `cloud` nor `local`
- **THEN** startup validation SHALL fail with a structured configuration error
### Requirement: Live audio device readiness
The system SHALL provide live audio device diagnostics and SHALL use `sounddevice` for first-version real microphone and speaker access.
#### Scenario: Device check succeeds
- **WHEN** `sounddevice` can be imported and at least one input and one output device are available
- **THEN** `PYTHONPATH=src python3.11 -m owner_voice_pet device-check` SHALL exit successfully and report usable audio devices
#### Scenario: Device check fails
- **WHEN** `sounddevice` is missing, device query fails, microphone permission is denied, or no usable input/output device exists
- **THEN** `device-check` SHALL fail with a structured audio device error
#### Scenario: Live runtime uses real devices
- **WHEN** `run-live` starts successfully
- **THEN** it SHALL use the local microphone as its default input and the local speaker or macOS playback command as its default output rather than fixture audio
### Requirement: Live terminal state reporting
The live runtime SHALL emit concise Chinese terminal status messages for observable runtime states.
#### Scenario: Normal turn status
- **WHEN** a live turn succeeds
- **THEN** terminal output SHALL include states equivalent to standby, wake hit, recording, transcribing, thinking, speaking, and returning to standby
#### Scenario: Recoverable error status
- **WHEN** a live turn encounters empty STT, LLM failure, TTS failure, or playback failure
- **THEN** terminal output SHALL include the failing stage and a stable error code or recoverable explanation
### Requirement: Live runtime error recovery
The live runtime SHALL recover from turn-level failures and continue listening in default loop mode.
#### Scenario: LLM fails during default loop
- **WHEN** the LLM provider times out, is rate limited, or returns a network error during a live turn
- **THEN** the system SHALL report `LIVE_LLM_FAILED` or an equivalent structured error and SHALL return to standby without terminating the process
#### Scenario: TTS or playback fails during default loop
- **WHEN** local TTS or audio playback fails during a live turn
- **THEN** the system SHALL report the failure and SHALL return to standby without terminating the process
#### Scenario: Startup dependency fails
- **WHEN** `.env`, required models, or audio devices are unavailable at startup
- **THEN** the system SHALL exit with a documented non-zero status instead of entering a fake live loop