Skip to content

Feature/987 mistral audio transcription support - #1016

Merged
Pratham-Mishra04 merged 4 commits into
maximhq:mainfrom
Vivek1898:feature/987-mistral-audio-transcription-provider
Dec 16, 2025
Merged

Pratham-Mishra04 merged 4 commits into
maximhq:mainfrom
Vivek1898:feature/987-mistral-audio-transcription-provider

Conversation

@Vivek1898

@Vivek1898 Vivek1898 commented Dec 7, 2025 •

Copy link
Copy Markdown
Contributor

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-latest model). 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 fields
  • MistralTranscriptionResponse - Response struct with text, duration, language, segments, and words
  • MistralTranscriptionSegment - For segment-level timestamps (verbose_json format)
  • MistralTranscriptionWord - For word-level timestamps

Streaming Types (core/providers/mistral/types.go)

  • MistralTranscriptionStreamEventType - Event type constants (transcription.language, transcription.segment, transcription.text.delta, transcription.done)
  • MistralTranscriptionStreamEvent - SSE event wrapper
  • MistralTranscriptionStreamData - Event data payload
  • MistralTranscriptionStreamSegment - Segment data in streaming response
  • MistralTranscriptionUsage - Usage information in done event

Transcription Converters (core/providers/mistral/transcription.go)

  • ToMistralTranscriptionRequest() - Converts Bifrost request to Mistral format
  • ToBifrostTranscriptionResponse() - Converts Mistral response to unified Bifrost format
  • parseMistralTranscriptionFormData() - Creates multipart form data for audio file upload
  • createMistralTranscriptionMultipartBody() - Builds the multipart request body
  • createMistralTranscriptionStreamMultipartBody() - Builds the streaming multipart request body with stream=true
  • ToBifrostTranscriptionStreamResponse() - Converts Mistral streaming events to Bifrost stream format

Provider Implementation (core/providers/mistral/mistral.go)

  • Transcription() - Multipart form request to /v1/audio/transcriptions endpoint with proper Bearer token authentication and error handling
  • TranscriptionStream() - SSE streaming implementation with support for:
    • transcription.language events (language detection)
    • transcription.segment events (segment-level transcription)
    • transcription.text.delta events (incremental text updates)
    • transcription.done events (completion with usage info)

Tests (core/providers/mistral/transcription_test.go)

  • Unit tests for request/response conversions
  • Unit tests for streaming event conversions
  • Multipart body creation tests (both sync and streaming)
  • Mock server tests for success and error scenarios
  • Mock server tests for streaming with various event types
  • Optional integration tests (requires MISTRAL_API_KEY)

Documentation & Configuration

  • Updated docs/features/unified-interface.mdx - Mistral STT and STT Stream columns now show ✅
  • Updated core/internal/testutil/account.go - Enabled Transcription and TranscriptionStream scenarios for Mistral
  • Updated core/providers/mistral/mistral_test.go - Set TranscriptionStream to true

Type of change

  • Bug fix
  • Feature
  • Refactor
  • Documentation
  • Chore/CI

Affected areas

  • Core (Go)
  • Transports (HTTP)
  • Providers/Integrations
  • Plugins
  • UI (Next.js)
  • Docs

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

  • No

Related issues

Closes #987

Security considerations

  • API key handling follows existing patterns (Bearer token in Authorization header)
  • No new secrets or environment variables introduced
  • Audio file data is handled in memory and not persisted

Checklist

  • I read docs/contributing/README.md and followed the guidelines
  • I added/updated tests where appropriate
  • I updated documentation where needed
  • I verified builds succeed (Go and UI)
  • I verified the CI pipeline passes locally if applicable

@coderabbitai

coderabbitai Bot commented Dec 7, 2025 •

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Added audio transcription for Mistral with both standard and real-time streaming STT, including incremental streaming results and enriched timing/metadata.
  • Documentation

    • Updated provider support matrix to mark Mistral as supporting Speech-to-Text and streaming STT.
  • Tests

    • Added comprehensive unit and integration tests and test utilities to validate transcription and streaming behavior.

✏️ Tip: You can customize this high-level summary in your review settings.

Walkthrough

Adds 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

Cohort / File(s) Summary
Type Definitions
core/providers/mistral/types.go
Adds transcription types: MistralTranscriptionRequest, MistralTranscriptionResponse, segment/word structs, streaming event types/constants, stream event/data/segment/usage structs.
Transcription Logic
core/providers/mistral/transcription.go
New converters and helpers: ToMistralTranscriptionRequest, ToBifrostTranscriptionResponse, stream-event mapping, multipart builders for regular and streaming transcription, formatFloat64, and provider-wrapped error returns.
Provider Integration
core/providers/mistral/mistral.go
Implements Transcription and TranscriptionStream: builds multipart requests, issues POST to /v1/audio/transcriptions (HTTP and SSE via fasthttp), parses JSON/SSE responses, processes stream events, and enriches responses with latency/provider/model metadata.
Unit & Integration Tests
core/providers/mistral/transcription_test.go, core/providers/mistral/mistral_test.go
Adds converter/unit tests, multipart body tests, extensive mock-server tests for regular and streaming flows (edge cases, context cancellation), and optional integration tests gated by MISTRAL_API_KEY.
Test Config / Harness
core/internal/testutil/account.go, core/providers/mistral/mistral_test.go
Enables transcription testing: sets TranscriptionModel: "voxtral-mini-latest" and toggles Transcription / TranscriptionStream flags to true; adds test config fields.
Docs
docs/features/unified-interface.mdx
Updates provider support matrix: Mistral now marked as supporting STT and STT (stream).
Misc / Imports & Wiring
go.mod, various files
Adds imports and wiring for streaming and parsing (e.g., bufio, errors, fmt, sonic, fasthttp, multipart, bytes) and provider network/header propagation; maintains unsupported speech methods.

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
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Areas to focus on:

  • core/providers/mistral/mistral.go: multipart assembly, SSE streaming with fasthttp, headers/auth propagation, non-200 error mapping.
  • core/providers/mistral/transcription.go: multipart writer lifecycles, nil-safety in converters, extraction/typing of ExtraParams, float formatting.
  • core/providers/mistral/transcription_test.go: mock-server streaming behavior, generated WAV payload, cancellation and edge-case assertions.
  • core/providers/mistral/types.go: type shapes and pointer/value semantics versus API expectations.

Poem

🐇 I hopped through bytes and multipart seams,
Carried tiny echoes and stitched them into streams,
Deltas, segments, timestamps in a row,
Mistral now listens and helps voices grow —
Sniff, scribble, hop — transcripts in tow!

Pre-merge checks and finishing touches

✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The PR title 'Feature/987 mistral audio transcription support' clearly and concisely describes the main change: adding audio transcription support for the Mistral provider.
Description check ✅ Passed The PR description comprehensively covers all required template sections: summary, detailed changes, type of change, affected areas, testing instructions, breaking changes, related issues, security considerations, and checklist.
Linked Issues check ✅ Passed The PR fully implements all coding requirements from issue #987: transcription types (types.go), converters (transcription.go), provider implementation (Transcription and TranscriptionStream methods), and documentation updates (unified-interface.mdx).
Out of Scope Changes check ✅ Passed All code changes are within scope of issue #987: Mistral provider transcription support, with no unrelated modifications or extraneous changes introduced.
Docstring Coverage ✅ Passed Docstring coverage is 88.89% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 42390d0 and a322ab5.

📒 Files selected for processing (4)
  • core/internal/testutil/account.go (2 hunks)
  • core/providers/mistral/mistral.go (2 hunks)
  • core/providers/mistral/mistral_test.go (2 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.go
  • core/providers/mistral/mistral.go
  • core/providers/mistral/mistral_test.go
  • docs/features/unified-interface.mdx
🧠 Learnings (2)
📚 Learning: 2025-12-09T17:07:42.007Z
Learnt from: qwerty-dvorak
Repo: maximhq/bifrost PR: 1006
File: core/schemas/account.go:9-18
Timestamp: 2025-12-09T17:07:42.007Z
Learning: In core/schemas/account.go, the HuggingFaceKeyConfig field within the Key struct is currently unused and reserved for future Hugging Face inference endpoint deployments. Do not flag this field as missing from OpenAPI documentation or require its presence in the API spec until the feature is actively implemented and used. When the feature is added, update the OpenAPI docs accordingly; otherwise, treat this field as non-breaking and not part of the current API surface.

Applied to files:

  • core/internal/testutil/account.go
  • core/providers/mistral/mistral.go
  • core/providers/mistral/mistral_test.go
📚 Learning: 2025-12-15T10:16:21.909Z
Learnt from: qwerty-dvorak
Repo: maximhq/bifrost PR: 1006
File: core/providers/huggingface/huggingface_test.go:12-63
Timestamp: 2025-12-15T10:16:21.909Z
Learning: In provider tests under core/providers/<provider>/*_test.go, do not require or flag the use of defer for Shutdown(); instead call client.Shutdown() at the end of each test function. This pattern appears consistent across all provider tests. Apply this rule only within this path; for other tests or resources, defer may still be appropriate.

Applied to files:

  • core/providers/mistral/mistral_test.go
🧬 Code graph analysis (1)
core/internal/testutil/account.go (2)
core/schemas/provider.go (1)
  • Provider (312-359)
core/schemas/bifrost.go (1)
  • Mistral (41-41)
🔇 Additional comments (5)
docs/features/unified-interface.mdx (1)

98-98: LGTM! Documentation accurately reflects new transcription support.

The updated support matrix correctly indicates that Mistral now supports both synchronous and streaming speech-to-text transcription.

core/internal/testutil/account.go (1)

757-783: LGTM! Test configuration properly enables transcription support.

The addition of TranscriptionModel with "voxtral-mini-latest" and enabling both Transcription and TranscriptionStream scenarios correctly configures the test utilities to support the new Mistral transcription feature.

core/providers/mistral/mistral_test.go (1)

31-50: LGTM! Provider test configuration matches test utilities.

The test configuration correctly enables transcription and streaming transcription scenarios with the appropriate model. The setup is consistent with the changes in core/internal/testutil/account.go.

core/providers/mistral/mistral.go (2)

254-332: LGTM! Solid synchronous transcription implementation.

The implementation follows best practices:

  • Proper request/response lifecycle management with acquire/release
  • Comprehensive error handling at each step
  • Correct multipart form construction for audio files
  • Appropriate use of OpenAI-compatible error parsing
  • Latency tracking and metadata enrichment

334-474: LGTM! Robust streaming transcription implementation.

Excellent streaming implementation with:

  • Proper SSE event parsing with event/data accumulation
  • Context-aware processing with cancellation checks
  • Generous buffer sizes (64KB initial, 1MB max) appropriate for audio transcription
  • Comprehensive error handling for various failure modes
  • Correct resource cleanup with deferred releases
  • Proper goroutine lifecycle management

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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{} when ShouldSendBackRawResponse is true. You could store the responseBody directly or marshal mistralResponse back, 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 optional Seek field.

The Seek field at Line 64 is int with omitempty, which will omit when value is 0. If 0 is a valid seek position that should be serialized, consider changing to *int for 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 createMistralTranscriptionMultipartBody but closed here. Idiomatic Go typically has the function that creates a resource also close it. Consider moving the writer.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

📥 Commits

Reviewing files that changed from the base of the PR and between ffd9580 and 0cf650f.

📒 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.go
  • core/providers/mistral/transcription_test.go
  • core/providers/mistral/mistral.go
  • core/providers/mistral/types.go
  • docs/features/unified-interface.mdx
  • core/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 TranscriptionModel is 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: true and disabling TranscriptionStream: false accurately 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.ParseOpenAIError for OpenAI-compatible error responses. The nil check on lines 301-303 after ToBifrostTranscriptionResponse() is defensive—verify if this can ever occur given MistralTranscriptionResponse was 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 ExtraParams for 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_KEY is 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 in ToBifrostTranscriptionResponse method.

The review comment raises a valid Go concern. When tt.input is nil in the "nil response" test case (line 308), calling tt.input.ToBifrostTranscriptionResponse() requires the method to explicitly handle the nil receiver case. Confirm that ToBifrostTranscriptionResponse includes 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 MistralTranscriptionRequest struct 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 MistralTranscriptionWord struct 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.

@Vivek1898 Vivek1898 changed the title Added audio transcription (STT) support for the Mistral provider Feature/987 mistral audio transcription support Dec 7, 2025
@akshaydeo

Copy link
Copy Markdown
Contributor

Thanks for the PR @Vivek1898 ❤️

This LGTM. @Pratham-Mishra04 can you have a look once

@Pratham-Mishra04

Copy link
Copy Markdown
Collaborator

…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
@Vivek1898

Copy link
Copy Markdown
Contributor Author

@akshaydeo @Pratham-Mishra04

Thanks for the review!
I’ve added the streaming support as requested. Please take a look and let me know if any further changes are needed.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
core/providers/mistral/transcription.go (1)

34-36: Consider more robust type handling for timestamp_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.

TestFormatFloat64EdgeCases and TestFormatFloat64 test the same formatFloat64 function with overlapping test cases (both test 0.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

📥 Commits

Reviewing files that changed from the base of the PR and between 0cf650f and 7f09a6e.

📒 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.go
  • core/providers/mistral/mistral.go
  • core/providers/mistral/mistral_test.go
  • core/providers/mistral/transcription.go
  • docs/features/unified-interface.mdx
  • core/providers/mistral/transcription_test.go
  • core/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 TranscriptionModel and enables both Transcription and TranscriptionStream scenarios, 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 Transcription method 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 processStreamEvent helper correctly:

  • Handles error detection with appropriate null/empty checks
  • Converts stream events to Bifrost format
  • Tracks per-chunk latency with lastChunkTime and 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 Delta and Text fields
  • 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 ExtraParams for 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 extractBoundary helper 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=true along 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 ExtraParams edge 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.

Comment thread core/providers/mistral/transcription.go Resolved

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (3)
core/providers/mistral/transcription.go (2)

24-38: Make timestamp_granularities extraction from ExtraParams more tolerant.

Right now you only accept []string for "timestamp_granularities"; any other common shapes (e.g., JSON‑decoded []any or a single string) are silently ignored. If ExtraParams can come from generic maps, consider normalizing []any / string cases into []string so callers don’t have to match this exact Go type.


209-214: Double‑check timestamp_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_granularities as 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 duplicated formatFloat64 tests.

TestFormatFloat64EdgeCases and TestFormatFloat64 cover 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

📥 Commits

Reviewing files that changed from the base of the PR and between 7f09a6e and 42390d0.

📒 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.go
  • core/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 of TimestampGranularities to sync multipart form.

The sync transcription form builder omits the TimestampGranularities field, preventing callers from requesting segment/word timestamps in non-streaming mode even though Mistral's /v1/audio/transcriptions endpoint supports the timestamp_granularities parameter. Mirror the streaming path by serializing each granularity value into the form.

Comment thread core/providers/mistral/mistral.go Resolved

Copy link
Copy Markdown
Collaborator

Hey @Vivek1898 the PR looks good now, just 2 small comments - and can you also pls update core and transports changelogs

Comment thread core/providers/mistral/mistral.go Resolved

Pratham-Mishra04 commented Dec 16, 2025 •

Copy link
Copy Markdown
Collaborator

Merge activity

  • Dec 16, 12:05 PM UTC: A user started a stack merge that includes this pull request via Graphite.
  • Dec 16, 12:06 PM UTC: Graphite couldn't merge this PR because it failed for an unknown reason (Fast-forward merges are not supported for forked repositories. Please create a branch in the target repository in order to merge).
  • Dec 16, 12:06 PM UTC: A user started a stack merge that includes this pull request via Graphite.
  • Dec 16, 12:06 PM UTC: Graphite couldn't merge this PR because it failed for an unknown reason (Fast-forward merges are not supported for forked repositories. Please create a branch in the target repository in order to merge).

@Pratham-Mishra04
Pratham-Mishra04 merged commit 363dd44 into maximhq:main Dec 16, 2025
2 checks passed
@coderabbitai coderabbitai Bot mentioned this pull request Dec 22, 2025
occcat pushed a commit to occcat/bifrost that referenced this pull request Sep 2, 2026
* 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]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature]: Support for audio transcriptions in mistral provider

3 participants