Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions core/changelog.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
- feat: add handling for HTML and empty responses from providers
- feat: add audio token pricing support for models
- feat: adds new parameter for each provider key config `use_for_batch_apis`. This helps users to select which APIs or accounts to be used for Batch APIs.
- feat: adds s3 bucket config support for Bedrock provider.
- feat: prompt caching support for anthropic and bedrock(claude and nova models)
Expand Down
11 changes: 11 additions & 0 deletions core/providers/elevenlabs/elevenlabs.go
Original file line number Diff line number Diff line change
Expand Up @@ -522,6 +522,17 @@ func (provider *ElevenlabsProvider) Transcription(ctx context.Context, key schem
return nil, providerUtils.NewBifrostOperationError(schemas.ErrProviderResponseDecode, err, providerName)
}

// Check for empty response
trimmed := strings.TrimSpace(string(responseBody))
if len(trimmed) == 0 {
return nil, &schemas.BifrostError{
IsBifrostError: true,
Error: &schemas.ErrorField{
Message: schemas.ErrProviderResponseEmpty,
},
}
}

chunks, err := parseTranscriptionResponse(responseBody)
if err != nil {
return nil, providerUtils.NewBifrostOperationError(err.Error(), nil, providerName)
Expand Down
40 changes: 32 additions & 8 deletions core/providers/mistral/mistral.go
Original file line number Diff line number Diff line change
Expand Up @@ -299,12 +299,36 @@ func (provider *MistralProvider) Transcription(ctx context.Context, key schemas.
return nil, openai.ParseOpenAIError(resp, schemas.TranscriptionRequest, providerName, request.Model)
}

// Copy response body before releasing
responseBody := append([]byte(nil), resp.Body()...)
responseBody, err := providerUtils.CheckAndDecodeBody(resp)
if err != nil {
return nil, providerUtils.NewBifrostOperationError(schemas.ErrProviderResponseDecode, err, providerName)
}

// Check for empty response
trimmed := strings.TrimSpace(string(responseBody))
if len(trimmed) == 0 {
return nil, &schemas.BifrostError{
IsBifrostError: true,
Error: &schemas.ErrorField{
Message: schemas.ErrProviderResponseEmpty,
},
}
}

copiedResponseBody := append([]byte(nil), responseBody...)

// Parse Mistral's transcription response
var mistralResponse MistralTranscriptionResponse
if err := sonic.Unmarshal(responseBody, &mistralResponse); err != nil {
if err := sonic.Unmarshal(copiedResponseBody, &mistralResponse); err != nil {
if providerUtils.IsHTMLResponse(resp, copiedResponseBody) {
errorMessage := providerUtils.ExtractHTMLErrorMessage(copiedResponseBody)
return nil, &schemas.BifrostError{
IsBifrostError: false,
Error: &schemas.ErrorField{
Message: errorMessage,
},
}
}
return nil, providerUtils.NewBifrostOperationError(schemas.ErrProviderResponseUnmarshal, err, providerName)
}

Expand All @@ -323,7 +347,7 @@ func (provider *MistralProvider) Transcription(ctx context.Context, key schemas.
// Set raw response if enabled
if providerUtils.ShouldSendBackRawResponse(ctx, provider.sendBackRawResponse) {
var rawResponse interface{}
if err := sonic.Unmarshal(responseBody, &rawResponse); err == nil {
if err := sonic.Unmarshal(copiedResponseBody, &rawResponse); err == nil {
response.ExtraFields.RawResponse = rawResponse
}
}
Expand Down Expand Up @@ -441,7 +465,7 @@ func (provider *MistralProvider) TranscriptionStream(ctx context.Context, postHo
// Process accumulated event if we have both event and data
if currentEvent != "" && currentData != "" {
chunkIndex++
provider.processStreamEvent(ctx, postHookRunner, currentEvent, currentData, request.Model, providerName, chunkIndex, startTime, &lastChunkTime, responseChan)
provider.processTranscriptionStreamEvent(ctx, postHookRunner, currentEvent, currentData, request.Model, providerName, chunkIndex, startTime, &lastChunkTime, responseChan)
}
// Reset for next event
currentEvent = ""
Expand All @@ -460,7 +484,7 @@ func (provider *MistralProvider) TranscriptionStream(ctx context.Context, postHo
// Process any remaining event
if currentEvent != "" && currentData != "" {
chunkIndex++
provider.processStreamEvent(ctx, postHookRunner, currentEvent, currentData, request.Model, providerName, chunkIndex, startTime, &lastChunkTime, responseChan)
provider.processTranscriptionStreamEvent(ctx, postHookRunner, currentEvent, currentData, request.Model, providerName, chunkIndex, startTime, &lastChunkTime, responseChan)
}

// Handle scanner errors
Expand All @@ -473,8 +497,8 @@ func (provider *MistralProvider) TranscriptionStream(ctx context.Context, postHo
return responseChan, nil
}

// processStreamEvent processes a single SSE event and sends it to the response channel.
func (provider *MistralProvider) processStreamEvent(
// processTranscriptionStreamEvent processes a single SSE event and sends it to the response channel.
func (provider *MistralProvider) processTranscriptionStreamEvent(
ctx context.Context,
postHookRunner schemas.PostHookRunner,
eventType string,
Expand Down
27 changes: 25 additions & 2 deletions core/providers/openai/openai.go
Original file line number Diff line number Diff line change
Expand Up @@ -1890,17 +1890,40 @@ func (provider *OpenAIProvider) Transcription(ctx context.Context, key schemas.K
return nil, providerUtils.NewBifrostOperationError(schemas.ErrProviderResponseDecode, err, providerName)
}

// Check for empty response
trimmed := strings.TrimSpace(string(responseBody))
if len(trimmed) == 0 {
return nil, &schemas.BifrostError{
IsBifrostError: true,
Error: &schemas.ErrorField{
Message: schemas.ErrProviderResponseEmpty,
},
}
}

copiedResponseBody := append([]byte(nil), responseBody...)

// Parse OpenAI's transcription response directly into BifrostTranscribe
response := &schemas.BifrostTranscriptionResponse{}

if err := sonic.Unmarshal(responseBody, response); err != nil {
if err := sonic.Unmarshal(copiedResponseBody, response); err != nil {
// Check if it's an HTML response
if providerUtils.IsHTMLResponse(resp, copiedResponseBody) {
errorMessage := providerUtils.ExtractHTMLErrorMessage(copiedResponseBody)
return nil, &schemas.BifrostError{
IsBifrostError: false,
Error: &schemas.ErrorField{
Message: errorMessage,
},
}
}
return nil, providerUtils.NewBifrostOperationError(schemas.ErrProviderResponseUnmarshal, err, providerName)
}

// Parse raw response for RawResponse field
var rawResponse interface{}
if providerUtils.ShouldSendBackRawResponse(ctx, provider.sendBackRawResponse) {
if err := sonic.Unmarshal(responseBody, &rawResponse); err != nil {
if err := sonic.Unmarshal(copiedResponseBody, &rawResponse); err != nil {
return nil, providerUtils.NewBifrostOperationError(schemas.ErrProviderRawResponseUnmarshal, err, providerName)
}
}
Expand Down
Loading
Loading