diff --git a/CHANGELOG.md b/CHANGELOG.md index 74f79ab..eb449c2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,17 @@ All notable changes to this project are documented here. The format is based on ## [Unreleased] +### Changed + +- **BREAKING: Clip + Voice contracts aligned to the LIVE gateway** (verified by probing + `api.wave.online`). SDK/CLI clients generated from the previous spec will break: + - `ClipCreate` now requires `source` (recording id string) + `in`/`out` relative time strings + (`5s`, `2m`), replacing the rejected `videoId`/`startTime`/`endTime` numeric shape. + - `POST /voice/generate` → `POST /voice` (the live path); `VoiceGenerateRequest` requires only + `text` (`voiceId` optional, also sent as `voice_id` by the SDK). The 200 response now documents + that the primary path returns raw `audio/mpeg` bytes directly. The old `/voice/generate` path + is not kept as a deprecated alias because the live gateway does not serve it. + ### Added - **MoQ join-token mint surface** (`openapi.yaml`) — the Media over QUIC product had no spec at diff --git a/openapi.yaml b/openapi.yaml index dc10210..08c608e 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -390,7 +390,7 @@ paths: items: $ref: '#/components/schemas/Voice' - /voice/generate: + /voice: post: tags: [Voice] summary: Generate speech from text @@ -404,20 +404,22 @@ paths: responses: '200': description: > - Speech generated. The gateway returns one of three shapes depending on - the engine path: an inline JSON payload with base64 audio + character - `alignment` (single round-trip, carries word timestamps), an async job - to poll, or raw audio bytes when timestamps were not requested. + Speech generated. Returns the raw MP3 bytes (`audio/mpeg`) by default (verified + against the live gateway: POST `/voice` with `{ text }` returns the MP3 directly). + The `application/json` shapes are returned only when the request opts out of the + default: requests that ask for character timestamps receive a `VoiceSynthesisInline` + payload (base64 audio + `alignment`), and engines that process asynchronously return + a `VoiceGeneration` job to poll. content: + audio/mpeg: + schema: + type: string + format: binary application/json: schema: oneOf: - $ref: '#/components/schemas/VoiceSynthesisInline' - $ref: '#/components/schemas/VoiceGeneration' - audio/mpeg: - schema: - type: string - format: binary '401': $ref: '#/components/responses/Unauthorized' '403': @@ -2238,14 +2240,17 @@ components: ClipCreate: type: object - required: [videoId, startTime, endTime] + required: [source, in, out] properties: - videoId: + source: type: string - startTime: - type: number - endTime: - type: number + description: Recording id the clip is cut from (e.g. `rec_abc123`). Verified against the live gateway — the older `{ type, id, start_time, end_time }` source object is rejected. + in: + type: string + description: Start offset as a relative time string, e.g. `5s` or `2m`. + out: + type: string + description: End offset as a relative time string, e.g. `10s` or `1m30s`. title: type: string description: @@ -2398,12 +2403,20 @@ components: VoiceGenerateRequest: type: object - required: [voiceId, text] + required: [text] + # `voiceId` and `voice_id` are wire aliases for the same setting; supplying both is invalid. + not: + required: [voiceId, voice_id] properties: + text: + type: string + description: Text to convert to speech. voiceId: type: string - text: + description: Voice id to use. Optional; the gateway picks a default when omitted. Also accepted on the wire as the `voice_id` alias. + voice_id: type: string + description: Snake_case wire alias for `voiceId` (the form the SDK sends). Provide either `voiceId` or `voice_id`, not both. stability: type: number minimum: 0