fix(stage-ui): make streaming transcription requests half-duplex (#2283)
This commit is contained in:
@@ -3,6 +3,38 @@ import { describe, expect, it } from 'vitest'
|
|||||||
import { streamTranscription } from './index'
|
import { streamTranscription } from './index'
|
||||||
|
|
||||||
describe('streamTranscription', () => {
|
describe('streamTranscription', () => {
|
||||||
|
it('sets half-duplex transport for the browser audio upload', async () => {
|
||||||
|
// ROOT CAUSE:
|
||||||
|
//
|
||||||
|
// Browser fetch requires `duplex: 'half'` when the request body is a
|
||||||
|
// ReadableStream. The official provider set this in its fetch wrapper,
|
||||||
|
// but that wrapper does not own this adapter's stream transport.
|
||||||
|
//
|
||||||
|
// Report: T-3, Official provider transcription does not work reliably.
|
||||||
|
let requestInit: RequestInit | undefined
|
||||||
|
const audioStream = new ReadableStream<ArrayBuffer>({
|
||||||
|
start(controller) {
|
||||||
|
controller.close()
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const result = streamTranscription({
|
||||||
|
baseURL: 'https://example.invalid/transcription',
|
||||||
|
fetch: async (_input: RequestInfo | URL, init?: RequestInit) => {
|
||||||
|
requestInit = init
|
||||||
|
return new Response(new ReadableStream<Uint8Array>({
|
||||||
|
start(controller) {
|
||||||
|
controller.close()
|
||||||
|
},
|
||||||
|
}))
|
||||||
|
},
|
||||||
|
inputAudioStream: audioStream,
|
||||||
|
})
|
||||||
|
|
||||||
|
await expect(result.text).resolves.toBe('')
|
||||||
|
expect((requestInit as RequestInit & { duplex?: string }).duplex).toBe('half')
|
||||||
|
})
|
||||||
|
|
||||||
it('parses split SSE chunks and joins transcription deltas', async () => {
|
it('parses split SSE chunks and joins transcription deltas', async () => {
|
||||||
const encoder = new TextEncoder()
|
const encoder = new TextEncoder()
|
||||||
const responseBody = new ReadableStream<Uint8Array>({
|
const responseBody = new ReadableStream<Uint8Array>({
|
||||||
|
|||||||
@@ -123,10 +123,14 @@ export function streamTranscription(options: StreamTranscriptionOptions): AIRISt
|
|||||||
: new URL(typeof options.baseURL === 'string' ? options.baseURL : 'http://localhost')
|
: new URL(typeof options.baseURL === 'string' ? options.baseURL : 'http://localhost')
|
||||||
const response = await fetcher(requestTarget, {
|
const response = await fetcher(requestTarget, {
|
||||||
body: audioStream,
|
body: audioStream,
|
||||||
|
// Browser fetch requires half-duplex mode for a ReadableStream body.
|
||||||
|
// Keep this at the transport boundary so every SSE transcription
|
||||||
|
// provider receives the required request option.
|
||||||
|
duplex: 'half',
|
||||||
headers: options.headers,
|
headers: options.headers,
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
signal: options.abortSignal,
|
signal: options.abortSignal,
|
||||||
})
|
} as RequestInit & { duplex: 'half' })
|
||||||
|
|
||||||
if (!response.ok)
|
if (!response.ok)
|
||||||
throw new Error(`Streaming transcription request failed with status ${response.status}`)
|
throw new Error(`Streaming transcription request failed with status ${response.status}`)
|
||||||
|
|||||||
Reference in New Issue
Block a user