fix(aws): 打通 AWS Bedrock 转发链路

- model_provider_constants_extend.go: 新增 AWS 凭证配置 key 常量
  (ConfigKeyAWSAccessKeyID/SecretAccessKey/SessionToken/Region)
- GetDifyProviderCredentials: 解析 Dify bedrock provider 的 AWS 凭证字段
- GetAvailableModelsFromDify: AWS/Anthropic 在 credentials 之前提前返回,
  避免因 APIKey 为空触发误报
- ProxyRequest: 在获取凭证后新增 AWS 分支,直接调用 proxyBedrockRequest
  完成 SigV4 签名直连 Bedrock 原生 API(bedrock_extend.go 中已实现,此前未被调用)
This commit is contained in:
npc0-hue
2026-04-23 15:41:53 +08:00
parent 3a02769e4a
commit 5618c89721
2 changed files with 35 additions and 5 deletions
@@ -22,6 +22,12 @@ const (
ConfigKeyOpenaiAPIVersion = "openai_api_version"
ConfigKeyDashScopeAPIKey = "dashscope_api_key"
ConfigKeyAPIKey = "api_key"
// AWS Bedrock 凭证字段(Dify bedrock provider 的 encrypted_config 中使用)
ConfigKeyAWSAccessKeyID = "aws_access_key_id"
ConfigKeyAWSSecretAccessKey = "aws_secret_access_key"
ConfigKeyAWSSessionToken = "aws_session_token"
ConfigKeyAWSRegion = "aws_region"
)
// SupportedProviders 列表展示的提供商顺序
+29 -5
View File
@@ -418,6 +418,10 @@ func (s *ModelProviderService) GetAvailableModelsFromDify(providerName string) (
if providerName == gaia.ProviderAzure {
return s.getAvailableModelsFromProviderModelCredentials(providerName)
}
// AWS Bedrock 没有统一的 /v1/models 接口,模型由前端手输;直接返回空列表
if providerName == gaia.ProviderAWS || providerName == gaia.ProviderAnthropic {
return nil, nil
}
creds, err := s.GetDifyProviderCredentials(providerName)
if err != nil || creds.APIKey == "" {
@@ -441,11 +445,6 @@ func (s *ModelProviderService) GetAvailableModelsFromDify(providerName string) (
base = gaia.DefaultAPIBase[gaia.ProviderGoogle]
}
return s.fetchGeminiModels(client, base, creds.APIKey)
case gaia.ProviderAnthropic:
return nil, nil
case gaia.ProviderAWS:
// AWS Bedrock 没有统一的 OpenAI 兼容 /v1/models 接口,模型由前端 allow-create 手输
return nil, nil
default:
if creds.Endpoint != "" {
return s.fetchOpenAICompatibleModels(client, creds.Endpoint, creds.APIKey)
@@ -689,6 +688,26 @@ func (s *ModelProviderService) GetDifyProviderCredentials(providerName string) (
creds.APIKey, err = s.decryptConfig(config.(string), row.TenantID)
} else if config, ok = configMap[gaia.ConfigKeyAPIKey]; ok {
creds.APIKey, err = s.decryptConfig(config.(string), row.TenantID)
} else if _, hasAWSKey := configMap[gaia.ConfigKeyAWSAccessKeyID]; hasAWSKey {
// AWS Bedrock 凭证:解析 aws_access_key_id / aws_secret_access_key / aws_region
if v, ok2 := configMap[gaia.ConfigKeyAWSAccessKeyID].(string); ok2 && v != "" {
if creds.AWSAccessKeyID, err = s.decryptConfig(v, row.TenantID); err != nil {
return nil, fmt.Errorf("解密 aws_access_key_id 失败: %w", err)
}
}
if v, ok2 := configMap[gaia.ConfigKeyAWSSecretAccessKey].(string); ok2 && v != "" {
if creds.AWSSecretAccessKey, err = s.decryptConfig(v, row.TenantID); err != nil {
return nil, fmt.Errorf("解密 aws_secret_access_key 失败: %w", err)
}
}
if v, ok2 := configMap[gaia.ConfigKeyAWSSessionToken].(string); ok2 && v != "" {
if creds.AWSSessionToken, err = s.decryptConfig(v, row.TenantID); err != nil {
return nil, fmt.Errorf("解密 aws_session_token 失败: %w", err)
}
}
if v, ok2 := configMap[gaia.ConfigKeyAWSRegion].(string); ok2 && v != "" {
creds.AWSRegion = strings.TrimSpace(v)
}
} else {
// 尝试从备选字段中查找
for _, key := range gaia.CredentialKeyFallback {
@@ -1167,6 +1186,11 @@ func (s *ModelProviderService) ProxyRequest(
return err
}
// AWS Bedrock 直连:不走通用 HTTP 转发,改用 SigV4 签名的 Bedrock 原生 API
if providerName == gaia.ProviderAWS {
return s.proxyBedrockRequest(userID, path, method, reqHeader, body, writer, creds)
}
if base = s.getUpstreamBase(providerName, creds); base == "" {
return fmt.Errorf("提供商 %s 无可用上游地址", providerName)
}