Repository navigation
Feature/987 mistral audio transcription support - #1016
Pratham-Mishra04 merged 4 commits into
Conversation
📝 WalkthroughSummary by CodeRabbit
✏️ Tip: You can customize this high-level summary in your review settings. WalkthroughAdds full Mistral transcription support: new types, converters, multipart builders for regular and streaming transcription, provider wiring for HTTP and SSE, enhanced error handling, extensive tests, and docs update marking STT/STT(stream) support. Changes
Sequence Diagram(s)sequenceDiagram
participant Client
participant Bifrost as Bifrost (mistral.go)
participant Converter as Converter (transcription.go)
participant MistralAPI as Mistral API (/v1/audio/transcriptions)
participant Parser as Parser (sonic -> ToBifrost)
Client->>Bifrost: Transcription request (regular or stream)
Bifrost->>Converter: ToMistralTranscriptionRequest(req)
Converter-->>Bifrost: MistralTranscriptionRequest
Bifrost->>Converter: create multipart body (regular / stream)
Converter-->>Bifrost: body + content-type
Bifrost->>MistralAPI: POST multipart (HTTP) or POST (SSE)
alt regular response
MistralAPI-->>Bifrost: JSON response
Bifrost->>Parser: unmarshal -> MistralTranscriptionResponse
Parser-->>Bifrost: ToBifrostTranscriptionResponse()
Bifrost-->>Client: BifrostTranscriptionResponse (with latency & metadata)
else streaming (SSE)
MistralAPI-->>Bifrost: SSE events
Bifrost->>Converter: processStreamEvent(event)
Converter-->>Bifrost: BifrostTranscriptionStreamResponse chunks (delta, language, segment, done)
Bifrost-->>Client: stream chunks (with per-chunk timing & metadata)
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Areas to focus on:
Poem
Pre-merge checks and finishing touches✅ Passed checks (5 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro 📒 Files selected for processing (4)
🧰 Additional context used📓 Path-based instructions (1)**⚙️ CodeRabbit configuration file
Files:
🧠 Learnings (2)📚 Learning: 2025-12-09T17:07:42.007ZApplied to files:
📚 Learning: 2025-12-15T10:16:21.909ZApplied to files:
🧬 Code graph analysis (1)core/internal/testutil/account.go (2)
🔇 Additional comments (5)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (4)
core/providers/mistral/mistral.go (1)
311-317: Consider reusing the already-parsed response for raw response.The raw response is unmarshaled a second time into
interface{}whenShouldSendBackRawResponseis true. You could store theresponseBodydirectly or marshalmistralResponseback, avoiding the redundant parse. This is a minor optimization.// Set raw response if enabled if providerUtils.ShouldSendBackRawResponse(ctx, provider.sendBackRawResponse) { - var rawResponse interface{} - if err := sonic.Unmarshal(responseBody, &rawResponse); err == nil { - response.ExtraFields.RawResponse = rawResponse - } + response.ExtraFields.RawResponse = sonic.Get(responseBody).Raw() }Alternatively, unmarshal once into
interface{}and type-assert or use a more direct approach based on how other providers handle this.core/providers/mistral/types.go (1)
61-73: Consider using pointer type for optionalSeekfield.The
Seekfield at Line 64 isintwithomitempty, which will omit when value is0. If0is a valid seek position that should be serialized, consider changing to*intfor consistency with other optional fields in the struct.type MistralTranscriptionSegment struct { ID int `json:"id"` - Seek int `json:"seek,omitempty"` + Seek *int `json:"seek,omitempty"` Start float64 `json:"start"`core/providers/mistral/transcription.go (2)
131-134: Consider moving writer.Close() to the calling function.The multipart writer is created in
createMistralTranscriptionMultipartBodybut closed here. Idiomatic Go typically has the function that creates a resource also close it. Consider moving thewriter.Close()call to line 144-146 in the calling function.Example refactor in
createMistralTranscriptionMultipartBody:func createMistralTranscriptionMultipartBody(req *MistralTranscriptionRequest, providerName schemas.ModelProvider) (*bytes.Buffer, string, *schemas.BifrostError) { var body bytes.Buffer writer := multipart.NewWriter(&body) if err := parseMistralTranscriptionFormData(writer, req, providerName); err != nil { return nil, "", err } + + if err := writer.Close(); err != nil { + return nil, "", providerUtils.NewBifrostOperationError("failed to close multipart writer", err, providerName) + } return &body, writer.FormDataContentType(), nil }And remove the close from
parseMistralTranscriptionFormData.
93-93: Consider using the actual audio file extension instead of hardcoding "audio.mp3".Mistral's transcription API doesn't strictly require filename extensions for content-type detection, so the current approach works. However, if the actual audio file format is available in the request, using the correct extension (e.g., "audio.wav", "audio.ogg") would be more semantically accurate and could aid debugging. If the format is unknown, "audio.mp3" is an acceptable default.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
core/providers/mistral/mistral.go(2 hunks)core/providers/mistral/mistral_test.go(2 hunks)core/providers/mistral/transcription.go(1 hunks)core/providers/mistral/transcription_test.go(1 hunks)core/providers/mistral/types.go(1 hunks)docs/features/unified-interface.mdx(1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**
⚙️ CodeRabbit configuration file
always check the stack if there is one for the current PR. do not give localized reviews for the PR, always see all changes in the light of the whole stack of PRs (if there is a stack, if there is no stack you can continue to make localized suggestions/reviews)
Files:
core/providers/mistral/mistral_test.gocore/providers/mistral/transcription_test.gocore/providers/mistral/mistral.gocore/providers/mistral/types.godocs/features/unified-interface.mdxcore/providers/mistral/transcription.go
🧬 Code graph analysis (2)
core/providers/mistral/transcription_test.go (4)
core/schemas/transcriptions.go (2)
BifrostTranscriptionRequest(3-10)TranscriptionParameters(32-45)core/providers/mistral/types.go (4)
MistralTranscriptionRequest(42-50)MistralTranscriptionResponse(53-59)MistralTranscriptionSegment(62-73)MistralTranscriptionWord(76-80)core/providers/mistral/transcription.go (1)
ToMistralTranscriptionRequest(14-41)core/providers/mistral/mistral.go (1)
NewMistralProvider(29-60)
core/providers/mistral/mistral.go (5)
core/schemas/bifrost.go (3)
BifrostError(353-362)TranscriptionRequest(96-96)RequestType(83-83)core/providers/mistral/transcription.go (1)
ToMistralTranscriptionRequest(14-41)core/providers/utils/utils.go (2)
NewBifrostOperationError(449-460)ShouldSendBackRawResponse(482-487)core/providers/openai/openai.go (1)
ParseOpenAIError(2080-2108)core/providers/mistral/types.go (1)
MistralTranscriptionResponse(53-59)
🔇 Additional comments (20)
docs/features/unified-interface.mdx (1)
98-98: Documentation update is accurate and consistent with implementation.The Mistral row correctly reflects the new STT capability (non-streaming) as implemented in this PR, with STT (stream) appropriately marked as unsupported.
core/providers/mistral/mistral_test.go (2)
30-32: Test configuration correctly adds transcription model.The
TranscriptionModelis set to"voxtral-mini-latest"which aligns with Mistral's audio transcription model as per the PR objectives.
48-49: Test scenarios correctly configured for transcription support.Enabling
Transcription: trueand disablingTranscriptionStream: falseaccurately reflects the implementation where streaming transcription returns an unsupported operation error.core/providers/mistral/mistral.go (4)
242-258: Well-structured transcription request setup.The request conversion and multipart body creation follow appropriate patterns. Error handling correctly returns early with proper Bifrost error types when conversion fails.
260-282: HTTP request handling follows established patterns.The fasthttp request lifecycle with acquire/release is properly managed with deferred releases. Headers are set correctly including the Bearer authorization.
322-325: Streaming transcription correctly returns unsupported operation.This aligns with the documentation and test configuration showing STT (stream) as not supported.
284-303: Response handling and conversion is correct.The error path reuses
openai.ParseOpenAIErrorfor OpenAI-compatible error responses. The nil check on lines 301-303 afterToBifrostTranscriptionResponse()is defensive—verify if this can ever occur givenMistralTranscriptionResponsewas successfully unmarshaled by examining the method implementation to determine if all code paths return a non-nil value.core/providers/mistral/transcription_test.go (7)
22-57: WAV file generator is well-documented and correct.The minimal WAV file creation properly follows the PCM format specification with correct header fields and silent audio data (128 for 8-bit). This is a good approach for testing transcription without external audio files.
72-199: Request conversion tests are comprehensive.The test cases cover nil inputs, empty files, basic requests, and all optional parameters including
ExtraParamsfor temperature and timestamp_granularities. Good use of table-driven tests with parallel execution.
346-436: Multipart body tests validate form structure correctly.The test properly parses the generated multipart form to verify field presence and file content. Good validation of both required and optional fields.
448-589: Mock server tests provide good coverage of HTTP interactions.Tests verify request method, path, headers, and handle various response scenarios including success with segments/words and error cases. The test server correctly validates Authorization header presence.
591-637: Nil input tests verify proper error handling.Tests confirm that missing input or empty file returns the expected error message "transcription input is not provided".
697-754: Integration test is well-structured with appropriate guards.The test properly skips when
MISTRAL_API_KEYis not set, uses a reasonable timeout, and handles both success and error cases gracefully. The comment noting that minimal audio may be rejected is helpful.
305-312: Verify nil-receiver handling inToBifrostTranscriptionResponsemethod.The review comment raises a valid Go concern. When
tt.inputis nil in the "nil response" test case (line 308), callingtt.input.ToBifrostTranscriptionResponse()requires the method to explicitly handle the nil receiver case. Confirm thatToBifrostTranscriptionResponseincludes a nil-check guard early in its implementation (e.g.,if r == nil { ... }) or document that a non-nil receiver is required. If the method does not handle nil, the test will panic.core/providers/mistral/types.go (2)
40-50: Request type definition is well-structured.The
MistralTranscriptionRequeststruct correctly models the Mistral API with appropriate optional field handling using pointers. JSON tags follow API conventions.
75-80: Word type definition is correct.The
MistralTranscriptionWordstruct properly captures word-level timing information with appropriate field types.core/providers/mistral/transcription.go (4)
14-41: LGTM!The conversion logic is correct with proper nil guards and safe extraction of extra parameters.
44-88: LGTM!The response conversion correctly maps all Mistral transcription fields to Bifrost format, including segments and words.
140-149: LGTM!The function correctly creates the multipart form body and returns the necessary components for the HTTP request.
152-154: LGTM!The float formatting approach is appropriate for multipart form fields.
|
Thanks for the PR @Vivek1898 ❤️ This LGTM. @Pratham-Mishra04 can you have a look once |
|
Yes, @Vivek1898 it looks good but can you also add support for streaming? |
…ovider, enabling users to transcribe audio files through Bifrost's unified interface using Mistral's audio transcription API (`voxtral-mini-latest` model). **This includes both synchronous and streaming transcription support
|
Thanks for the review! |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (2)
core/providers/mistral/transcription.go (1)
34-36: Consider more robust type handling fortimestamp_granularities.The type assertion
bifrostReq.Params.ExtraParams["timestamp_granularities"].([]string)will silently fail if the value is provided as[]interface{}(common when JSON-decoded). Consider handling this case:- if granularities, ok := bifrostReq.Params.ExtraParams["timestamp_granularities"].([]string); ok { - req.TimestampGranularities = granularities - } + if granularities, ok := bifrostReq.Params.ExtraParams["timestamp_granularities"].([]string); ok { + req.TimestampGranularities = granularities + } else if granularitiesIface, ok := bifrostReq.Params.ExtraParams["timestamp_granularities"].([]interface{}); ok { + granularities := make([]string, 0, len(granularitiesIface)) + for _, g := range granularitiesIface { + if s, ok := g.(string); ok { + granularities = append(granularities, s) + } + } + if len(granularities) > 0 { + req.TimestampGranularities = granularities + } + }core/providers/mistral/transcription_test.go (1)
1362-1405: Consolidate duplicate test functions.
TestFormatFloat64EdgeCasesandTestFormatFloat64test the sameformatFloat64function with overlapping test cases (both test0.0,0.5,1.0,1.23456,-0.5). Consider consolidating into a single test function to eliminate duplication.-// TestFormatFloat64EdgeCases tests edge cases for float formatting. -func TestFormatFloat64EdgeCases(t *testing.T) { - t.Parallel() - - tests := []struct { - input float64 - expected string - }{ - {0.0, "0"}, - {0.5, "0.5"}, - {1.0, "1"}, - {1.23456, "1.23456"}, - {-0.5, "-0.5"}, - {0.123456789, "0.123456789"}, - {100.0, "100"}, - {0.001, "0.001"}, - } - - for _, tt := range tests { - result := formatFloat64(tt.input) - assert.Equal(t, tt.expected, result, "formatFloat64(%f)", tt.input) - } -} - // TestFormatFloat64 tests the float64 formatting function. func TestFormatFloat64(t *testing.T) { t.Parallel() tests := []struct { input float64 expected string }{ {0.0, "0"}, {0.5, "0.5"}, {1.0, "1"}, {1.23456, "1.23456"}, {-0.5, "-0.5"}, + {0.123456789, "0.123456789"}, + {100.0, "100"}, + {0.001, "0.001"}, } for _, tt := range tests { result := formatFloat64(tt.input) assert.Equal(t, tt.expected, result, "formatFloat64(%f)", tt.input) } }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (7)
core/internal/testutil/account.go(2 hunks)core/providers/mistral/mistral.go(2 hunks)core/providers/mistral/mistral_test.go(2 hunks)core/providers/mistral/transcription.go(1 hunks)core/providers/mistral/transcription_test.go(1 hunks)core/providers/mistral/types.go(1 hunks)docs/features/unified-interface.mdx(1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**
⚙️ CodeRabbit configuration file
always check the stack if there is one for the current PR. do not give localized reviews for the PR, always see all changes in the light of the whole stack of PRs (if there is a stack, if there is no stack you can continue to make localized suggestions/reviews)
Files:
core/internal/testutil/account.gocore/providers/mistral/mistral.gocore/providers/mistral/mistral_test.gocore/providers/mistral/transcription.godocs/features/unified-interface.mdxcore/providers/mistral/transcription_test.gocore/providers/mistral/types.go
🧬 Code graph analysis (3)
core/internal/testutil/account.go (2)
core/schemas/provider.go (1)
Provider(280-307)core/schemas/bifrost.go (1)
Mistral(41-41)
core/providers/mistral/mistral.go (6)
core/schemas/bifrost.go (5)
BifrostError(353-362)TranscriptionRequest(96-96)RequestType(83-83)ModelProvider(32-32)BifrostResponseExtraFields(284-293)core/providers/mistral/transcription.go (1)
ToMistralTranscriptionRequest(14-41)core/providers/utils/utils.go (4)
SetExtraHeaders(178-208)GetPathFromContext(211-216)ShouldSendBackRawResponse(482-487)GetBifrostResponseForStreamResponse(777-805)core/providers/openai/openai.go (1)
ParseOpenAIError(2080-2108)core/providers/mistral/types.go (5)
MistralTranscriptionResponse(53-59)MistralTranscriptionStreamData(107-120)MistralTranscriptionStreamEvent(101-104)MistralTranscriptionStreamEventType(87-87)MistralTranscriptionStreamEventDone(97-97)core/utils.go (1)
Ptr(51-53)
core/providers/mistral/transcription.go (2)
core/schemas/utils.go (1)
SafeExtractFloat64Pointer(497-505)core/providers/utils/utils.go (1)
NewBifrostOperationError(449-460)
🔇 Additional comments (26)
docs/features/unified-interface.mdx (1)
98-98: LGTM!The provider support matrix correctly reflects the new STT and STT (stream) capabilities added for Mistral in this PR.
core/internal/testutil/account.go (1)
685-711: LGTM! Test configuration properly enables transcription support.The Mistral test configuration correctly adds the
TranscriptionModeland enables bothTranscriptionandTranscriptionStreamscenarios, aligning with the new implementation.core/providers/mistral/mistral_test.go (1)
30-49: LGTM!The test configuration properly adds transcription model and enables both standard and streaming transcription test scenarios for Mistral.
core/providers/mistral/mistral.go (3)
244-322: LGTM!The
Transcriptionmethod is well-implemented:
- Proper nil validation for input
- Correct multipart form construction
- Resource management with deferred releases
- Response body copied before releasing fasthttp response
- Comprehensive error handling with provider-specific error wrapping
324-464: LGTM! Streaming implementation is well-structured.Good implementation of SSE streaming:
- Proper streaming response setup with
resp.StreamBody = true- Correct SSE headers for event-stream
- Appropriate buffer sizing (64KB initial, 1MB max) for audio transcription chunks
- Context cancellation check in the processing loop
- Proper resource cleanup in both error and success paths
466-539: LGTM!The
processStreamEventhelper correctly:
- Handles error detection with appropriate null/empty checks
- Converts stream events to Bifrost format
- Tracks per-chunk latency with
lastChunkTimeand total latency for done events- Sets the stream end indicator context for the done event
core/providers/mistral/transcription.go (2)
43-88: LGTM!The response conversion properly maps all fields from Mistral format to Bifrost format, including segments and words arrays with correct field mappings.
216-261: LGTM!The stream event conversion handles all event types correctly:
- Delta events properly set both
DeltaandTextfields- Language events correctly return empty text (metadata-only event)
- Done events properly convert usage statistics
core/providers/mistral/transcription_test.go (15)
20-57: LGTM!The WAV file creation helper is well-implemented with correct RIFF header structure, proper PCM format chunk, and appropriate silence value (128 for unsigned 8-bit audio). Good documentation explaining the purpose.
71-199: LGTM!Comprehensive table-driven tests covering nil handling, basic conversion, and all optional parameters including
ExtraParamsfor temperature and timestamp granularities. Good use of parallel execution.
201-344: LGTM!Good coverage of response conversion including segments and words mapping. Proper verification of the hardcoded
Task: "transcribe"field.
346-436: LGTM!Good verification of multipart form body creation including parsing and validating individual fields. The
extractBoundaryhelper is a nice utility for test verification.
448-589: LGTM!Excellent mock server test coverage including success paths with various response structures (basic, segments, words) and error paths (server error, unauthorized). Good verification of request structure and response parsing.
591-637: LGTM!Properly tests input validation for nil input field and empty file scenarios, ensuring appropriate error handling.
639-794: LGTM!Comprehensive streaming test coverage with proper SSE event handling, verification of streaming-specific headers (
Accept: text/event-stream), and validation of delta events, segments, and done events.
796-847: LGTM!Consistent nil/empty input validation for the streaming endpoint, matching the non-streaming counterpart.
849-965: LGTM!Thorough testing of streaming event conversion covering all event types (text delta, language, segment, done) with proper verification of the Bifrost response structure including usage information.
967-1006: LGTM!Correctly verifies that the streaming multipart body includes
stream=truealong with other expected fields.
1008-1214: LGTM!Excellent edge case coverage including empty text deltas, missing usage data, multiple consecutive deltas, language-only events, and HTTP error responses. Good defensive testing approach.
1216-1275: LGTM!Well-designed context cancellation test that properly verifies the streaming operation respects context timeouts.
1277-1360: LGTM!Good coverage of
ExtraParamsedge cases including type coercion for temperature (int to float) and handling of invalid types.
1407-1416: LGTM!Minimal logger implementation is appropriate for test purposes, implementing all required interface methods as no-ops.
1418-1566: LGTM!Integration tests are well-structured with proper environment variable gating (
MISTRAL_API_KEY), reasonable timeouts, and graceful handling of both success and error scenarios. Good use of informative logging for manual test runs.core/providers/mistral/types.go (3)
40-59: LGTM!Request and response types are well-structured with appropriate use of pointers for optional fields and correct JSON tags. The documentation comment referencing Mistral's audio transcription docs is helpful.
61-80: LGTM!Segment and word types correctly model the verbose_json output format with appropriate optional fields for detailed transcription metadata.
82-136: LGTM!Streaming types are well-designed with clear event type constants and a flexible data structure that can accommodate different event payloads. The usage type appropriately captures both audio duration and token metrics.
…treaming transcription form
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (3)
core/providers/mistral/transcription.go (2)
24-38: Maketimestamp_granularitiesextraction fromExtraParamsmore tolerant.Right now you only accept
[]stringfor"timestamp_granularities"; any other common shapes (e.g., JSON‑decoded[]anyor a single string) are silently ignored. IfExtraParamscan come from generic maps, consider normalizing[]any/ string cases into[]stringso callers don’t have to match this exact Go type.
209-214: Double‑checktimestamp_granularities[]field name against Mistral’s API spec.Mistral’s docs and OpenAPI define the multipart field as
timestamp_granularities(array of strings) for both sync and streaming transcription; examples use--form 'timestamp_granularities="segment"'without[]. (platform-docs-public.pages.dev)Here you send
timestamp_granularities[], which may be treated as an unknown form field and silently ignored by the API. It would be safer to:
- Use
timestamp_granularitiesas the field name in both sync and streaming builders, writing it once per value, and- Update tests to expect that name.
Please confirm against the live endpoint before changing this, as server‑side parsing details can evolve.
core/providers/mistral/transcription_test.go (1)
1420-1462: Consolidate duplicatedformatFloat64tests.
TestFormatFloat64EdgeCasesandTestFormatFloat64cover very similar cases; you can merge them into a single table‑driven test to reduce duplication without losing coverage.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
core/providers/mistral/transcription.go(1 hunks)core/providers/mistral/transcription_test.go(1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**
⚙️ CodeRabbit configuration file
always check the stack if there is one for the current PR. do not give localized reviews for the PR, always see all changes in the light of the whole stack of PRs (if there is a stack, if there is no stack you can continue to make localized suggestions/reviews)
Files:
core/providers/mistral/transcription.gocore/providers/mistral/transcription_test.go
🔇 Additional comments (2)
core/providers/mistral/transcription_test.go (1)
1-18: Good breadth of tests across conversions, HTTP paths, streaming, and integrations.Nice job covering both sync and streaming flows (including edge cases and context cancellation) plus real‑API integration; this gives solid confidence in the new provider behavior.
core/providers/mistral/transcription.go (1)
90-137: Add serialization ofTimestampGranularitiesto sync multipart form.The sync transcription form builder omits the
TimestampGranularitiesfield, preventing callers from requesting segment/word timestamps in non-streaming mode even though Mistral's/v1/audio/transcriptionsendpoint supports thetimestamp_granularitiesparameter. Mirror the streaming path by serializing each granularity value into the form.
|
Hey @Vivek1898 the PR looks good now, just 2 small comments - and can you also pls update core and transports changelogs |
Merge activity
|
* Added audio transcription (STT) support for the Mistral provider * added audio transcription (Speech-to-Text) support for the Mistral provider, enabling users to transcribe audio files through Bifrost's unified interface using Mistral's audio transcription API (`voxtral-mini-latest` model). **This includes both synchronous and streaming transcription support * Added missing response_format and timestamp_granularities fields to streaming transcription form --------- Co-authored-by: Pratham Mishra <[email protected]>
Summary
This PR adds audio transcription (Speech-to-Text) support for the Mistral provider, enabling users to transcribe audio files through Bifrost's unified interface using Mistral's audio transcription API (
voxtral-mini-latestmodel). This includes both synchronous and streaming transcription support.Closes #987
Changes
Transcription Types (
core/providers/mistral/types.go)MistralTranscriptionRequest- Request struct with model, file, language, prompt, response_format, temperature, and timestamp_granularities fieldsMistralTranscriptionResponse- Response struct with text, duration, language, segments, and wordsMistralTranscriptionSegment- For segment-level timestamps (verbose_json format)MistralTranscriptionWord- For word-level timestampsStreaming Types (
core/providers/mistral/types.go)MistralTranscriptionStreamEventType- Event type constants (transcription.language,transcription.segment,transcription.text.delta,transcription.done)MistralTranscriptionStreamEvent- SSE event wrapperMistralTranscriptionStreamData- Event data payloadMistralTranscriptionStreamSegment- Segment data in streaming responseMistralTranscriptionUsage- Usage information in done eventTranscription Converters (
core/providers/mistral/transcription.go)ToMistralTranscriptionRequest()- Converts Bifrost request to Mistral formatToBifrostTranscriptionResponse()- Converts Mistral response to unified Bifrost formatparseMistralTranscriptionFormData()- Creates multipart form data for audio file uploadcreateMistralTranscriptionMultipartBody()- Builds the multipart request bodycreateMistralTranscriptionStreamMultipartBody()- Builds the streaming multipart request body withstream=trueToBifrostTranscriptionStreamResponse()- Converts Mistral streaming events to Bifrost stream formatProvider Implementation (
core/providers/mistral/mistral.go)Transcription()- Multipart form request to/v1/audio/transcriptionsendpoint with proper Bearer token authentication and error handlingTranscriptionStream()- SSE streaming implementation with support for:transcription.languageevents (language detection)transcription.segmentevents (segment-level transcription)transcription.text.deltaevents (incremental text updates)transcription.doneevents (completion with usage info)Tests (
core/providers/mistral/transcription_test.go)MISTRAL_API_KEY)Documentation & Configuration
docs/features/unified-interface.mdx- Mistral STT and STT Stream columns now show ✅core/internal/testutil/account.go- Enabled Transcription and TranscriptionStream scenarios for Mistralcore/providers/mistral/mistral_test.go- Set TranscriptionStream to trueType of change
Affected areas
How to test
Run all Mistral provider tests
cd core
go test -v ./providers/mistral/...
Run only transcription tests
go test -v ./providers/mistral/... -run Transcription
Run streaming tests specifically
go test -v ./providers/mistral/... -run TranscriptionStream
Run integration test (requires API key)
MISTRAL_API_KEY=your_key go test -v ./providers/mistral/... -run TestMistralTranscriptionIntegration
Run streaming integration test (requires API key)
MISTRAL_API_KEY=your_key go test -v ./providers/mistral/... -run TestMistralTranscriptionStreamIntegration### Manual Testing via Gateway
Start the gateway
make run
Test non-streaming transcription endpoint
curl -X POST http://localhost:8080/v1/audio/transcriptions
-H "Authorization: Bearer $MISTRAL_API_KEY"
-F "model=mistral/voxtral-mini-latest"
-F "file=@/path/to/audio.mp3"
-F "language=en"
Test streaming transcription endpoint
curl -X POST http://localhost:8080/v1/audio/transcriptions
-H "Authorization: Bearer $MISTRAL_API_KEY"
-H "Accept: text/event-stream"
-F "model=mistral/voxtral-mini-latest"
-F "file=@/path/to/audio.mp3"
-F "stream=true"
-F "language=en"## Screenshots/Recordings
N/A - Backend feature
Breaking changes
Related issues
Closes #987
Security considerations
Checklist
docs/contributing/README.mdand followed the guidelines