refactor: 移除自定义 HttpClientFactory,改用依赖注入的 IHttpClientFactory

This commit is contained in:
ccnetcore
2025-09-04 22:26:06 +08:00
parent 6e2dd39246
commit ece89ebad0
7 changed files with 22 additions and 14 deletions

View File

@@ -39,6 +39,12 @@ public static class HttpClientFactory
private static readonly ConcurrentDictionary<string, Lazy<List<HttpClient>>> HttpClientPool = new(); private static readonly ConcurrentDictionary<string, Lazy<List<HttpClient>>> HttpClientPool = new();
/// <summary>
/// 高并发下有问题
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
[Obsolete]
public static HttpClient GetHttpClient(string key) public static HttpClient GetHttpClient(string key)
{ {
return HttpClientPool.GetOrAdd(key, k => new Lazy<List<HttpClient>>(() => return HttpClientPool.GetOrAdd(key, k => new Lazy<List<HttpClient>>(() =>

View File

@@ -10,7 +10,7 @@ using Yi.Framework.AiHub.Domain.Shared.Dtos.OpenAi;
namespace Yi.Framework.AiHub.Domain.AiGateWay.Impl.ThorAzureDatabricks.Chats; namespace Yi.Framework.AiHub.Domain.AiGateWay.Impl.ThorAzureDatabricks.Chats;
public class AzureDatabricksChatCompletionsService(ILogger<AzureDatabricksChatCompletionsService> logger) public class AzureDatabricksChatCompletionsService(ILogger<AzureDatabricksChatCompletionsService> logger,IHttpClientFactory httpClientFactory)
: IChatCompletionService : IChatCompletionService
{ {
private string GetAddress(AiModelDescribe? options, string model) private string GetAddress(AiModelDescribe? options, string model)
@@ -31,7 +31,7 @@ public class AzureDatabricksChatCompletionsService(ILogger<AzureDatabricksChatCo
chatCompletionCreate.StreamOptions = null; chatCompletionCreate.StreamOptions = null;
var response = await HttpClientFactory.GetHttpClient(address).HttpRequestRaw( var response = await httpClientFactory.CreateClient().HttpRequestRaw(
address, address,
chatCompletionCreate, options.ApiKey); chatCompletionCreate, options.ApiKey);
@@ -149,7 +149,7 @@ public class AzureDatabricksChatCompletionsService(ILogger<AzureDatabricksChatCo
using var openai = using var openai =
Activity.Current?.Source.StartActivity("OpenAI 对话补全"); Activity.Current?.Source.StartActivity("OpenAI 对话补全");
var response = await HttpClientFactory.GetHttpClient(address).PostJsonAsync( var response = await httpClientFactory.CreateClient().PostJsonAsync(
address, address,
chatCompletionCreate, options.ApiKey).ConfigureAwait(false); chatCompletionCreate, options.ApiKey).ConfigureAwait(false);

View File

@@ -10,7 +10,7 @@ using Yi.Framework.AiHub.Domain.Shared.Dtos.OpenAi;
namespace Yi.Framework.AiHub.Domain.AiGateWay.Impl.ThorAzureOpenAI.Chats; namespace Yi.Framework.AiHub.Domain.AiGateWay.Impl.ThorAzureOpenAI.Chats;
public class AzureOpenAiChatCompletionCompletionsService(ILogger<AzureOpenAiChatCompletionCompletionsService> logger) public class AzureOpenAiChatCompletionCompletionsService(ILogger<AzureOpenAiChatCompletionCompletionsService> logger,IHttpClientFactory httpClientFactory)
: IChatCompletionService : IChatCompletionService
{ {
public async IAsyncEnumerable<ThorChatCompletionsResponse> CompleteChatStreamAsync(AiModelDescribe options, public async IAsyncEnumerable<ThorChatCompletionsResponse> CompleteChatStreamAsync(AiModelDescribe options,
@@ -21,7 +21,7 @@ public class AzureOpenAiChatCompletionCompletionsService(ILogger<AzureOpenAiChat
Activity.Current?.Source.StartActivity("Azure OpenAI 对话流式补全"); Activity.Current?.Source.StartActivity("Azure OpenAI 对话流式补全");
var url = AzureOpenAIFactory.GetAddress(options, chatCompletionCreate.Model); var url = AzureOpenAIFactory.GetAddress(options, chatCompletionCreate.Model);
var response = await HttpClientFactory.GetHttpClient(options.Endpoint).HttpRequestRaw(url, var response = await httpClientFactory.CreateClient().HttpRequestRaw(url,
chatCompletionCreate, options.ApiKey, "Api-Key"); chatCompletionCreate, options.ApiKey, "Api-Key");
openai?.SetTag("Model", chatCompletionCreate.Model); openai?.SetTag("Model", chatCompletionCreate.Model);
@@ -86,7 +86,7 @@ public class AzureOpenAiChatCompletionCompletionsService(ILogger<AzureOpenAiChat
var url = AzureOpenAIFactory.GetAddress(options, chatCompletionCreate.Model); var url = AzureOpenAIFactory.GetAddress(options, chatCompletionCreate.Model);
var response = var response =
await HttpClientFactory.GetHttpClient(options.Endpoint) await httpClientFactory.CreateClient()
.PostJsonAsync(url, chatCompletionCreate, options.ApiKey, "Api-Key"); .PostJsonAsync(url, chatCompletionCreate, options.ApiKey, "Api-Key");
openai?.SetTag("Model", chatCompletionCreate.Model); openai?.SetTag("Model", chatCompletionCreate.Model);

View File

@@ -5,7 +5,7 @@ using Yi.Framework.AiHub.Domain.Shared.Dtos.OpenAi.Images;
namespace Yi.Framework.AiHub.Domain.AiGateWay.Impl.ThorAzureOpenAI.Images; namespace Yi.Framework.AiHub.Domain.AiGateWay.Impl.ThorAzureOpenAI.Images;
public class AzureOpenAIServiceImageService : IImageService public class AzureOpenAIServiceImageService(IHttpClientFactory httpClientFactory) : IImageService
{ {
public async Task<ImageCreateResponse> CreateImage(ImageCreateRequest imageCreate, AiModelDescribe? options = null, public async Task<ImageCreateResponse> CreateImage(ImageCreateRequest imageCreate, AiModelDescribe? options = null,
CancellationToken cancellationToken = default(CancellationToken)) CancellationToken cancellationToken = default(CancellationToken))
@@ -98,7 +98,7 @@ public class AzureOpenAIServiceImageService : IImageService
multipartContent.Add(new ByteArrayContent(imageEditCreateRequest.Image), "image", multipartContent.Add(new ByteArrayContent(imageEditCreateRequest.Image), "image",
imageEditCreateRequest.ImageName); imageEditCreateRequest.ImageName);
return await HttpClientFactory.GetHttpClient(url).PostFileAndReadAsAsync<ImageCreateResponse>( return await httpClientFactory.CreateClient().PostFileAndReadAsAsync<ImageCreateResponse>(
url, url,
multipartContent, cancellationToken); multipartContent, cancellationToken);
} }

View File

@@ -9,7 +9,7 @@ using Yi.Framework.AiHub.Domain.Shared.Dtos.OpenAi;
namespace Yi.Framework.AiHub.Domain.AiGateWay.Impl.ThorDeepSeek.Chats; namespace Yi.Framework.AiHub.Domain.AiGateWay.Impl.ThorDeepSeek.Chats;
public sealed class DeepSeekChatCompletionsService(ILogger<DeepSeekChatCompletionsService> logger) public sealed class DeepSeekChatCompletionsService(ILogger<DeepSeekChatCompletionsService> logger,IHttpClientFactory httpClientFactory)
: IChatCompletionService : IChatCompletionService
{ {
public async IAsyncEnumerable<ThorChatCompletionsResponse> CompleteChatStreamAsync(AiModelDescribe options, public async IAsyncEnumerable<ThorChatCompletionsResponse> CompleteChatStreamAsync(AiModelDescribe options,
@@ -24,7 +24,7 @@ public sealed class DeepSeekChatCompletionsService(ILogger<DeepSeekChatCompletio
using var openai = using var openai =
Activity.Current?.Source.StartActivity("OpenAI 对话流式补全"); Activity.Current?.Source.StartActivity("OpenAI 对话流式补全");
var response = await HttpClientFactory.GetHttpClient(options.Endpoint).HttpRequestRaw( var response = await httpClientFactory.CreateClient().HttpRequestRaw(
options?.Endpoint.TrimEnd('/') + "/chat/completions", options?.Endpoint.TrimEnd('/') + "/chat/completions",
chatCompletionCreate, options.ApiKey); chatCompletionCreate, options.ApiKey);
@@ -142,7 +142,7 @@ public sealed class DeepSeekChatCompletionsService(ILogger<DeepSeekChatCompletio
options.Endpoint = "https://api.deepseek.com/v1"; options.Endpoint = "https://api.deepseek.com/v1";
} }
var response = await HttpClientFactory.GetHttpClient(options.Endpoint).PostJsonAsync( var response = await httpClientFactory.CreateClient().PostJsonAsync(
options?.Endpoint.TrimEnd('/') + "/chat/completions", options?.Endpoint.TrimEnd('/') + "/chat/completions",
chatCompletionCreate, options.ApiKey).ConfigureAwait(false); chatCompletionCreate, options.ApiKey).ConfigureAwait(false);

View File

@@ -4,7 +4,7 @@ using Yi.Framework.AiHub.Domain.Shared.Dtos.OpenAi.Embeddings;
namespace Yi.Framework.AiHub.Domain.AiGateWay.Impl.ThorSiliconFlow.Embeddings; namespace Yi.Framework.AiHub.Domain.AiGateWay.Impl.ThorSiliconFlow.Embeddings;
public sealed class SiliconFlowTextEmbeddingService public sealed class SiliconFlowTextEmbeddingService(IHttpClientFactory httpClientFactory)
: ITextEmbeddingService : ITextEmbeddingService
{ {
public async Task<EmbeddingCreateResponse> EmbeddingAsync( public async Task<EmbeddingCreateResponse> EmbeddingAsync(
@@ -12,7 +12,7 @@ public sealed class SiliconFlowTextEmbeddingService
AiModelDescribe? options = null, AiModelDescribe? options = null,
CancellationToken cancellationToken = default) CancellationToken cancellationToken = default)
{ {
var response = await HttpClientFactory.GetHttpClient(options.Endpoint).PostJsonAsync( var response = await httpClientFactory.CreateClient().PostJsonAsync(
options?.Endpoint.TrimEnd('/') + "/v1/embeddings", options?.Endpoint.TrimEnd('/') + "/v1/embeddings",
createEmbeddingModel, options!.ApiKey); createEmbeddingModel, options!.ApiKey);

View File

@@ -83,6 +83,8 @@ namespace Yi.Framework.AiHub.Domain
//配置服务号 //配置服务号
Configure<FuwuhaoOptions>(configuration.GetSection("Fuwuhao")); Configure<FuwuhaoOptions>(configuration.GetSection("Fuwuhao"));
services.AddHttpClient();
} }
public override async Task OnApplicationInitializationAsync(ApplicationInitializationContext context) public override async Task OnApplicationInitializationAsync(ApplicationInitializationContext context)