first commit
This commit is contained in:
122
core/providers/azure/files.go
Normal file
122
core/providers/azure/files.go
Normal file
@@ -0,0 +1,122 @@
|
||||
package azure
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
|
||||
"github.com/maximhq/bifrost/core/providers/openai"
|
||||
providerUtils "github.com/maximhq/bifrost/core/providers/utils"
|
||||
"github.com/maximhq/bifrost/core/schemas"
|
||||
"github.com/valyala/fasthttp"
|
||||
)
|
||||
|
||||
// setAzureAuth sets the Azure authentication header on the request for OpenAI models.
|
||||
// It handles authentication in order of priority:
|
||||
// 1. Service Principal (client ID/secret/tenant ID) - uses Bearer token
|
||||
// 2. Context token - uses Bearer token
|
||||
// 3. API key - uses api-key header
|
||||
// 4. DefaultAzureCredential auto-detection (managed identity, workload identity, env vars, CLI)
|
||||
func (provider *AzureProvider) setAzureAuth(ctx context.Context, req *fasthttp.Request, key schemas.Key) *schemas.BifrostError {
|
||||
// Service Principal authentication
|
||||
if key.AzureKeyConfig != nil && key.AzureKeyConfig.ClientID != nil &&
|
||||
key.AzureKeyConfig.ClientSecret != nil && key.AzureKeyConfig.TenantID != nil && key.AzureKeyConfig.ClientID.GetValue() != "" && key.AzureKeyConfig.ClientSecret.GetValue() != "" && key.AzureKeyConfig.TenantID.GetValue() != "" {
|
||||
cred, err := provider.getOrCreateAuth(key.AzureKeyConfig.TenantID.GetValue(), key.AzureKeyConfig.ClientID.GetValue(), key.AzureKeyConfig.ClientSecret.GetValue())
|
||||
if err != nil {
|
||||
return providerUtils.NewBifrostOperationError("failed to get or create Azure authentication", err)
|
||||
}
|
||||
|
||||
scopes := getAzureScopes(key.AzureKeyConfig.Scopes)
|
||||
|
||||
token, err := cred.GetToken(ctx, policy.TokenRequestOptions{
|
||||
Scopes: scopes,
|
||||
})
|
||||
if err != nil {
|
||||
return providerUtils.NewBifrostOperationError("failed to get Azure access token", err)
|
||||
}
|
||||
|
||||
if token.Token == "" {
|
||||
return providerUtils.NewBifrostOperationError("azure access token is empty", fmt.Errorf("token is empty"))
|
||||
}
|
||||
|
||||
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token.Token))
|
||||
req.Header.Del("api-key")
|
||||
return nil
|
||||
}
|
||||
|
||||
// Context token authentication
|
||||
if authToken, ok := ctx.Value(AzureAuthorizationTokenKey).(string); ok && authToken != "" {
|
||||
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", authToken))
|
||||
req.Header.Del("api-key")
|
||||
return nil
|
||||
}
|
||||
|
||||
// API key authentication
|
||||
value := key.Value.GetValue()
|
||||
if value != "" {
|
||||
req.Header.Del("Authorization")
|
||||
req.Header.Set("api-key", value)
|
||||
return nil
|
||||
}
|
||||
|
||||
// No explicit credentials - attempt DefaultAzureCredential auto-detection.
|
||||
scopes := getAzureScopes(nil)
|
||||
if key.AzureKeyConfig != nil {
|
||||
scopes = getAzureScopes(key.AzureKeyConfig.Scopes)
|
||||
}
|
||||
|
||||
cred, err := provider.getOrCreateDefaultAzureCredential()
|
||||
if err != nil {
|
||||
return providerUtils.NewBifrostOperationError("no credentials provided and DefaultAzureCredential unavailable", err)
|
||||
}
|
||||
|
||||
token, err := cred.GetToken(ctx, policy.TokenRequestOptions{Scopes: scopes})
|
||||
if err != nil {
|
||||
return providerUtils.NewBifrostOperationError("no credentials provided and DefaultAzureCredential failed to get token", err)
|
||||
}
|
||||
|
||||
if token.Token == "" {
|
||||
return providerUtils.NewBifrostOperationError("no credentials provided and DefaultAzureCredential returned empty token", fmt.Errorf("token is empty"))
|
||||
}
|
||||
|
||||
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token.Token))
|
||||
req.Header.Del("api-key")
|
||||
return nil
|
||||
}
|
||||
|
||||
// AzureFileResponse represents an Azure file response (same as OpenAI).
|
||||
type AzureFileResponse struct {
|
||||
ID string `json:"id"`
|
||||
Object string `json:"object"`
|
||||
Bytes int64 `json:"bytes"`
|
||||
CreatedAt int64 `json:"created_at"`
|
||||
Filename string `json:"filename"`
|
||||
Purpose schemas.FilePurpose `json:"purpose"`
|
||||
Status string `json:"status,omitempty"`
|
||||
StatusDetails *string `json:"status_details,omitempty"`
|
||||
}
|
||||
|
||||
// ToBifrostFileUploadResponse converts Azure file response to Bifrost response.
|
||||
func (r *AzureFileResponse) ToBifrostFileUploadResponse(providerName schemas.ModelProvider, latency time.Duration, sendBackRawResponse bool, rawResponse interface{}) *schemas.BifrostFileUploadResponse {
|
||||
resp := &schemas.BifrostFileUploadResponse{
|
||||
ID: r.ID,
|
||||
Object: r.Object,
|
||||
Bytes: r.Bytes,
|
||||
CreatedAt: r.CreatedAt,
|
||||
Filename: r.Filename,
|
||||
Purpose: r.Purpose,
|
||||
Status: openai.ToBifrostFileStatus(r.Status),
|
||||
StatusDetails: r.StatusDetails,
|
||||
StorageBackend: schemas.FileStorageAPI,
|
||||
ExtraFields: schemas.BifrostResponseExtraFields{
|
||||
Latency: latency.Milliseconds(),
|
||||
},
|
||||
}
|
||||
|
||||
if sendBackRawResponse {
|
||||
resp.ExtraFields.RawResponse = rawResponse
|
||||
}
|
||||
|
||||
return resp
|
||||
}
|
||||
Reference in New Issue
Block a user