Files
spring-ai/audio/README.md
T
asmhatreandClaude Sonnet 5.5 279be7eb9f Add audio module: meeting minutes with Spring AI speech-to-text, structured output and text-to-speech
OpenAiAudioTranscriptionModel -> ChatClient.entity(Minutes.class) -> OpenAiAudioSpeechModel,
WAV chunking at a silence under the 25 MB upload limit, SDK retry behaviour, the 4096-character
speech limit and a cost model. Audio endpoints are a local mock and the chat model a stub; no real
model was called. Spring Boot 4.1.2, Spring AI 2.0.2, Java 25.

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01CifR2BE7PBvRy5hT8TS9oz
2026-10-26 02:00:28 +00:00

2.8 KiB

audio

A meeting-minutes generator on Spring AI 2.0.2: a recording goes through OpenAiAudioTranscriptionModel, the transcript becomes a typed Minutes record with ChatClient.entity(...), and the action items are read back with OpenAiAudioSpeechModel. Files over the upload limit are split in the middle of a silence; a cost model with formulas prices a meeting.

No real model was called. The two audio endpoints (/v1/audio/transcriptions, /v1/audio/speech) are a local mock (src/test/.../support/FakeAudioServer.java) that the real Spring AI classes and the OpenAI Java SDK talk to over HTTP, so the requests in output/ are what those classes really send. The "recording" is 30 synthetic tones, one per scripted sentence, and the mock's "transcription" decodes the pitch back into the sentence. The chat model is a scripted stub. Nothing here measures the accuracy, latency or price of any real model; the cost table applies OpenAI's published prices (read on 2026-10-26) to stated assumptions.

Spring Boot 4.1.2
Spring AI 2.0.2 (spring-ai-openai, spring-ai-client-chat)
Java 25
Run scripts/run-all.sh (about 45 s)

Source

File What it is
MinutesService transcribe (chunked) -> summarise -> readAloud (split at 4096 characters)
SilenceChunker splits a WAV under a byte budget, cutting in the middle of the longest silence it finds; also the blind baseline
Minutes the record the model's reply is parsed into
NamedBytes a ByteArrayResource with a file name (the extension is how the upload is typed)
CostModel the three cost formulas and the prices they were run with
Wav the 60 lines of RIFF/WAVE the chunker needs

Captured output (output/)

File Shows
01-api-shape.txt class names and defaults in the 2.0.2 jars
02-transcribe-small.txt, 02b-filename.txt the multipart request; file name and extension
03-large-file.txt 413 on a 30 MB file; two silence-aligned chunks recover every line
04-blind-split.txt cutting every N bytes lands inside a sentence
05-structured-output.txt, 05b-bad-replies.txt the schema appended to the prompt; three replies that fail to parse
06-speech.txt, 06b-speech-split.txt the speech request; the 4096-character wall; splitting
07-retries.txt SDK retries re-upload the whole file
08-cost.txt cost per meeting length; file size per encoding
09-end-to-end.txt the three steps wired together