package openai import ( "fmt" "mime/multipart" "github.com/maximhq/bifrost/core/providers/utils" "github.com/maximhq/bifrost/core/schemas" ) // ToBifrostTranscriptionRequest converts an OpenAI transcription request to Bifrost format func (request *OpenAITranscriptionRequest) ToBifrostTranscriptionRequest(ctx *schemas.BifrostContext) *schemas.BifrostTranscriptionRequest { provider, model := schemas.ParseModelString(request.Model, utils.CheckAndSetDefaultProvider(ctx, schemas.OpenAI)) return &schemas.BifrostTranscriptionRequest{ Provider: provider, Model: model, Input: &schemas.TranscriptionInput{ File: request.File, }, Params: &request.TranscriptionParameters, Fallbacks: schemas.ParseFallbacks(request.Fallbacks), } } // ToOpenAITranscriptionRequest converts a Bifrost transcription request to OpenAI format func ToOpenAITranscriptionRequest(bifrostReq *schemas.BifrostTranscriptionRequest) *OpenAITranscriptionRequest { if bifrostReq == nil || bifrostReq.Input.File == nil { return nil } transcriptionInput := bifrostReq.Input params := bifrostReq.Params openaiReq := &OpenAITranscriptionRequest{ Model: bifrostReq.Model, File: transcriptionInput.File, Filename: transcriptionInput.Filename, } if params != nil { openaiReq.TranscriptionParameters = *params } return openaiReq } // ParseTranscriptionFormDataBodyFromRequest parses the transcription request and writes it to the multipart form. func ParseTranscriptionFormDataBodyFromRequest(writer *multipart.Writer, openaiReq *OpenAITranscriptionRequest, providerName schemas.ModelProvider) *schemas.BifrostError { // Add model field before the file so upstreams can route without buffering the audio payload. if err := writer.WriteField("model", openaiReq.Model); err != nil { return utils.NewBifrostOperationError("failed to write model field", err) } // Add optional fields if openaiReq.Language != nil { if err := writer.WriteField("language", *openaiReq.Language); err != nil { return utils.NewBifrostOperationError("failed to write language field", err) } } if openaiReq.Prompt != nil { if err := writer.WriteField("prompt", *openaiReq.Prompt); err != nil { return utils.NewBifrostOperationError("failed to write prompt field", err) } } if openaiReq.ResponseFormat != nil { if err := writer.WriteField("response_format", *openaiReq.ResponseFormat); err != nil { return utils.NewBifrostOperationError("failed to write response_format field", err) } } if openaiReq.Temperature != nil { if err := writer.WriteField("temperature", fmt.Sprintf("%g", *openaiReq.Temperature)); err != nil { return utils.NewBifrostOperationError("failed to write temperature field", err) } } for _, granularity := range openaiReq.TimestampGranularities { if err := writer.WriteField("timestamp_granularities[]", granularity); err != nil { return utils.NewBifrostOperationError("failed to write timestamp_granularities field", err) } } for _, include := range openaiReq.Include { if err := writer.WriteField("include[]", include); err != nil { return utils.NewBifrostOperationError("failed to write include field", err) } } if openaiReq.Stream != nil && *openaiReq.Stream { if err := writer.WriteField("stream", "true"); err != nil { return utils.NewBifrostOperationError("failed to write stream field", err) } } // Add file field last so large multipart uploads don't block model discovery upstream. filename := openaiReq.Filename if filename == "" { filename = utils.AudioFilenameFromBytes(openaiReq.File) } fileWriter, err := writer.CreateFormFile("file", filename) if err != nil { return utils.NewBifrostOperationError("failed to create form file", err) } if _, err := fileWriter.Write(openaiReq.File); err != nil { return utils.NewBifrostOperationError("failed to write file data", err) } // Close the multipart writer if err := writer.Close(); err != nil { return utils.NewBifrostOperationError("failed to close multipart writer", err) } return nil }