diff --git a/OllamaStudy.UseExtensionsAI/OllamaStudy.UseExtensionsAI.csproj b/OllamaStudy.UseExtensionsAI/OllamaStudy.UseExtensionsAI.csproj
index c61e9f8..f39eaab 100644
--- a/OllamaStudy.UseExtensionsAI/OllamaStudy.UseExtensionsAI.csproj
+++ b/OllamaStudy.UseExtensionsAI/OllamaStudy.UseExtensionsAI.csproj
@@ -16,8 +16,9 @@
all
runtime; build; native; contentfiles; analyzers; buildtransitive
-
-
+
+
+
diff --git a/OllamaStudy.UseExtensionsAI/OpenAIAPITest.cs b/OllamaStudy.UseExtensionsAI/OpenAIAPITest.cs
index 523bf6f..811ae5e 100644
--- a/OllamaStudy.UseExtensionsAI/OpenAIAPITest.cs
+++ b/OllamaStudy.UseExtensionsAI/OpenAIAPITest.cs
@@ -12,17 +12,32 @@ namespace OllamaStudy.UseExtensionsAI
///
public class OpenAIAPITest
{
- private ITestOutputHelper _output;
- private IOptionsMonitor _ollamaOptionsMonitor;
- private OpenAIClient _defaultOpenAIClient;
- private ChatClient _chatClient;
-
- public OpenAIAPITest(ITestOutputHelper outputHelper, OpenAIClient defaultOpenAIClient, IOptionsMonitor ollamaOptionsMonitor)
+ private readonly ITestOutputHelper _output;
+ private readonly IOptionsMonitor _ollamaOptionsMonitor;
+ private readonly IHttpClientFactory _httpClientFactory;
+ private readonly HttpClient _defaultHttpClient;
+ private readonly HttpClient _ollamaHttpClient;
+ private readonly HttpClient _uiUiAPIHttpClient;
+ private readonly HttpClient _bailianHttpClient;
+ private readonly HttpClient _zipuHttpClient;
+
+ public OpenAIAPITest
+ (
+ ITestOutputHelper outputHelper,
+ OpenAIClient defaultOpenAIClient,
+ IOptionsMonitor ollamaOptionsMonitor,
+ IHttpClientFactory httpClientFactory
+ )
{
_output = outputHelper;
- _defaultOpenAIClient = defaultOpenAIClient;
_ollamaOptionsMonitor = ollamaOptionsMonitor;
- _chatClient = _defaultOpenAIClient.GetChatClient(_ollamaOptionsMonitor.CurrentValue.Model);
+ _httpClientFactory = httpClientFactory;
+
+ _defaultHttpClient = _httpClientFactory.CreateClient("OpenAIHttpClient");
+ _ollamaHttpClient = _httpClientFactory.CreateClient("OllamaHttpClient");
+ _uiUiAPIHttpClient = _httpClientFactory.CreateClient("UiUiAPIHttpClient");
+ _bailianHttpClient = _httpClientFactory.CreateClient("BailianHttpClient");
+ _zipuHttpClient = _httpClientFactory.CreateClient("ZiPuHttpClient");
}
#region 各种业务Client
@@ -32,74 +47,52 @@ namespace OllamaStudy.UseExtensionsAI
[Fact]
public void GetClients_Test()
{
- #pragma warning disable OPENAI001
- Assert.NotNull(_defaultOpenAIClient);
-
- //音频客户端
- var audioClient = _defaultOpenAIClient.GetAudioClient(_ollamaOptionsMonitor.CurrentValue.Model);
- Assert.NotNull(audioClient);
-
- //聊天客户端
- var chatClient = _defaultOpenAIClient.GetChatClient(_ollamaOptionsMonitor.CurrentValue.Model);
- Assert.NotNull(chatClient);
-
- //嵌入客户端
- var embeddingClient = _defaultOpenAIClient.GetEmbeddingClient(_ollamaOptionsMonitor.CurrentValue.Model);
- Assert.NotNull(embeddingClient);
-
- //图像客户端
- var imageClient = _defaultOpenAIClient.GetImageClient(_ollamaOptionsMonitor.CurrentValue.Model);
- Assert.NotNull(imageClient);
-
- //微调客户端
- var moderationClient = _defaultOpenAIClient.GetModerationClient(_ollamaOptionsMonitor.CurrentValue.Model);
- Assert.NotNull(moderationClient);
-
- //文件客户端
- var openAIFileClient = _defaultOpenAIClient.GetOpenAIFileClient();
- Assert.NotNull(openAIFileClient);
+ Assert.NotNull(_defaultHttpClient);
+ Assert.NotNull(_ollamaHttpClient);
+ Assert.NotNull(_uiUiAPIHttpClient);
+ Assert.NotNull(_bailianHttpClient);
+ Assert.NotNull(_zipuHttpClient);
+ }
+ #endregion
- //模型客户端
- var modelClient = _defaultOpenAIClient.GetOpenAIModelClient();
- Assert.NotNull(modelClient);
+ #region 音频
+ [Fact]
+ public async Task Audio_Test()
+ {
+ var requetData = new
+ {
+ //语音模型
+ model = "gpt-4o-mini-tts",
- //助手客户端(仅评估)
- var assistantClient = _defaultOpenAIClient.GetAssistantClient();
- Assert.NotNull(assistantClient);
+ //要生成音频的文本。最大长度为4096个字符。
+ input = "你好,上海今天的天气非常好,很适合户外游玩!",
- //批量客户端(仅评估)
- var batchClient = _defaultOpenAIClient.GetBatchClient();
- Assert.NotNull(batchClient);
+ //生成音频时使用的语音。支持的语音有:alloy、echo、fable、onyx、nova 和 shimmer。
+ voice = "alloy",
- //评估客户端(仅评估)
- var evaluationClient = _defaultOpenAIClient.GetEvaluationClient();
- Assert.NotNull(evaluationClient);
+ //默认为 mp3 音频的格式。支持的格式有:mp3、opus、aac 和 flac。
+ response_format = "mp3",
- //微调客户端(仅评估)
- var FineTuningClient = _defaultOpenAIClient.GetFineTuningClient();
- Assert.NotNull(FineTuningClient);
+ //默认为 1 生成的音频速度。选择0.25到4.0之间的值。1.0是默认值。
+ speed = 1.0f,
+ };
- //响应客户端(仅评估)
- var openAIResponseClient = _defaultOpenAIClient.GetOpenAIResponseClient(_ollamaOptionsMonitor.CurrentValue.Model);
- Assert.NotNull(openAIResponseClient);
+ using var requestMessage = new HttpRequestMessage(HttpMethod.Post, "https://sg.uiuiapi.com/v1/audio/speech")
+ {
+ Content = JsonContent.Create(requetData)
+ };
- //实时客户端(仅评估)
-#pragma warning disable OPENAI002
- var realtimeClient = _defaultOpenAIClient.GetRealtimeClient();
- Assert.NotNull(realtimeClient);
-#pragma warning restore OPENAI002
+ var responseMessage = await _uiUiAPIHttpClient.SendAsync(requestMessage);
+ responseMessage.EnsureSuccessStatusCode();
- //向量存储客户端(仅评估)
- var vectorStoreClient = _defaultOpenAIClient.GetVectorStoreClient();
- Assert.NotNull(vectorStoreClient);
+ //处理响应
+ var responseObject = await responseMessage.Content.ReadAsByteArrayAsync();
-#pragma warning restore OPENAI001
+ using FileStream stream = File.OpenWrite($"{Guid.NewGuid()}.mp3");
+ stream.Write(responseObject);
}
#endregion
- #region 音频
- #endregion
-
#region 聊天
#endregion
@@ -126,11 +119,7 @@ namespace OllamaStudy.UseExtensionsAI
[Fact]
public void List_Models_Test()
{
- var modelClient = _defaultOpenAIClient.GetOpenAIModelClient();
-
- OpenAI.Models.OpenAIModelCollection openAIModelCollection = modelClient.GetModels().Value;
- _output.WriteLine($"Ollama服务中,共有{openAIModelCollection.Count()}个模型,包括[{string.Join(",", openAIModelCollection)}]");
}
#endregion
diff --git a/OllamaStudy.UseExtensionsAI/OpenAISdkTest.cs b/OllamaStudy.UseExtensionsAI/OpenAISdkTest.cs
index cbadcd2..a0f32bc 100644
--- a/OllamaStudy.UseExtensionsAI/OpenAISdkTest.cs
+++ b/OllamaStudy.UseExtensionsAI/OpenAISdkTest.cs
@@ -573,7 +573,7 @@ public class OpenAISdkTest
They can serve as accents, adding contrast and texture.
""";
- ImageGenerationOptions options = new()
+ OpenAI.Images.ImageGenerationOptions options = new()
{
Quality = GeneratedImageQuality.High,
Size = GeneratedImageSize.W1792xH1024,
diff --git a/OllamaStudy.UseExtensionsAI/Startup.cs b/OllamaStudy.UseExtensionsAI/Startup.cs
index fe5bc70..191b5ae 100644
--- a/OllamaStudy.UseExtensionsAI/Startup.cs
+++ b/OllamaStudy.UseExtensionsAI/Startup.cs
@@ -21,7 +21,7 @@ namespace OllamaStudy.UseExtensionsAI
#endregion
#region Startup 风格
-
+
///
/// (可选) 创建IHostBuilder
///
@@ -31,9 +31,9 @@ namespace OllamaStudy.UseExtensionsAI
return Host.CreateDefaultBuilder();
}
- public void ConfigureHost(IHostBuilder hostBuilder)
+ public void ConfigureHost(IHostBuilder hostBuilder)
{
- hostBuilder.ConfigureAppConfiguration((hostBuilder,configBuilder) =>
+ hostBuilder.ConfigureAppConfiguration((hostBuilder, configBuilder) =>
{
configBuilder
.SetBasePath(Directory.GetCurrentDirectory())
@@ -63,12 +63,12 @@ namespace OllamaStudy.UseExtensionsAI
.Configure(context.Configuration.GetRequiredSection("OllamaServer"));
services
- .AddScoped(provider =>
+ .AddScoped(provider =>
{
var options = provider.GetRequiredService>().CurrentValue;
- return new OllamaApiClient(options.OllamaServerUrl,options.Model);
-
+ return new OllamaApiClient(options.OllamaServerUrl, options.Model);
+
})
.AddScoped(provider =>
{
@@ -76,10 +76,10 @@ namespace OllamaStudy.UseExtensionsAI
var openAIClientOptions = new OpenAIClientOptions()
{
- Endpoint = new Uri(new Uri(options.OllamaServerUrl),"v1")
+ Endpoint = new Uri(new Uri(options.OllamaServerUrl), "v1")
};
- return new OpenAIClient(new ApiKeyCredential("nokey"),openAIClientOptions);
+ return new OpenAIClient(new ApiKeyCredential("nokey"), openAIClientOptions);
})
.AddScoped(provider =>
{
@@ -87,14 +87,14 @@ namespace OllamaStudy.UseExtensionsAI
var openAIClientOptions = new OpenAIClientOptions()
{
- Endpoint = new Uri(new Uri(options.OllamaServerUrl),"v1")
+ Endpoint = new Uri(new Uri(options.OllamaServerUrl), "v1")
};
- return new ChatClient(options.Model,new ApiKeyCredential("nokey"),openAIClientOptions);
+ return new ChatClient(options.Model, new ApiKeyCredential("nokey"), openAIClientOptions);
})
//OpenAI 客户端是线程安全的,可安全的注册为单例
- .AddKeyedSingleton("OpenAIChatClient",(provider,obj) =>
+ .AddKeyedSingleton("OpenAIChatClient", (provider, obj) =>
{
var options = provider.GetRequiredService>().CurrentValue;
@@ -123,7 +123,7 @@ namespace OllamaStudy.UseExtensionsAI
Endpoint = new Uri("https://dashscope.aliyuncs.com/compatible-mode/v1")
};
- return new OpenAIClient(new ApiKeyCredential(""), openAIClientOptions);
+ return new OpenAIClient(new ApiKeyCredential("sk-0122f39e383546b9a0999f70b9ef99e3"), openAIClientOptions);
})
//智谱 OpenAI兼容API
.AddKeyedSingleton("ZipuAPIClient", (provider, obj) =>
@@ -135,6 +135,72 @@ namespace OllamaStudy.UseExtensionsAI
return new OpenAIClient(new ApiKeyCredential("397a799102a6453282da8abb2a1b2581.8fTMHZGRkPHJya4R"), openAIClientOptions);
});
+
+ //HttpClient 注册
+
+ //Ollama HttpClient
+ services
+ .AddHttpClient("OllamaHttpClient", (provider, client) =>
+ {
+ var options = provider.GetRequiredService>().CurrentValue;
+
+ client.BaseAddress = new Uri(options.OllamaServerUrl);
+ client.DefaultRequestHeaders.Add("Authorization", $"Bearer nokey");
+ client.Timeout = TimeSpan.FromSeconds(60);
+ });
+
+ //OpenAI HttpClient
+ services
+ .AddHttpClient("OpenAIHttpClient", (provider, client) =>
+ {
+ var options = provider.GetRequiredService>().CurrentValue;
+
+ client.BaseAddress = new Uri(options.OllamaServerUrl);
+ client.DefaultRequestHeaders.Add("Authorization", $"Bearer nokey");
+ client.Timeout = TimeSpan.FromSeconds(60);
+ });
+
+ //UiUiAPI HttpClient
+ services
+ .AddHttpClient("UiUiAPIHttpClient", (provider, client) =>
+ {
+ client.BaseAddress = new Uri("https://sg.uiuiapi.com/v1");
+ client.DefaultRequestHeaders.Add("Authorization", $"Bearer sk-4azuOUkbzNGP22pQkND8ad1vZl7ladwBQyqGKlWWZyxYgX1L");
+ //client.DefaultRequestHeaders.Add("Content-Type", "application/json");
+ client.Timeout = TimeSpan.FromSeconds(60);
+ })
+ .UseSocketsHttpHandler((socketHttpHandeler, serviceProvider) =>
+ {
+ //配置请求代理:请求走 Fiddler 代理,便于调试
+ socketHttpHandeler.Proxy = new System.Net.WebProxy("http://127.0.0.1:8888");
+ });
+
+ //阿里百炼 HttpClient
+ services
+ .AddHttpClient("BailianHttpClient", (provider, client) =>
+ {
+ //var options = provider.GetRequiredService>().CurrentValue;
+
+ client.BaseAddress = new Uri("https://dashscope.aliyuncs.com/compatible-mode/v1");
+ client.DefaultRequestHeaders.Add("Authorization", $"Bearer sk-0122f39e383546b9a0999f70b9ef99e3");
+ client.Timeout = TimeSpan.FromSeconds(60);
+ });
+
+ //智谱 HttpClient
+ services
+ .AddHttpClient("ZiPuHttpClient", (provider, client) =>
+ {
+ //var options = provider.GetRequiredService>().CurrentValue;
+
+ client.BaseAddress = new Uri("https://open.bigmodel.cn/api/paas/v4/");
+ client.DefaultRequestHeaders.Add("Authorization", $"Bearer 397a799102a6453282da8abb2a1b2581.8fTMHZGRkPHJya4R");
+ client.Timeout = TimeSpan.FromSeconds(60);
+ })
+ .UseSocketsHttpHandler((socketHttpHandeler, serviceProvider) =>
+ {
+ //配置请求代理:请求走 Fiddler 代理,便于调试
+ socketHttpHandeler.Proxy = new System.Net.WebProxy("http://127.0.0.1:8888");
+ });
}
#endregion
}
diff --git a/OllamaStudy.UseOllamaSharp/OllamaApiTest.cs b/OllamaStudy.UseOllamaSharp/OllamaApiTest.cs
index cbcde3f..b9d4313 100644
--- a/OllamaStudy.UseOllamaSharp/OllamaApiTest.cs
+++ b/OllamaStudy.UseOllamaSharp/OllamaApiTest.cs
@@ -889,45 +889,45 @@ namespace OllamaStudy.UseOllamaSharp
}
///
- /// 结构化输出对话请求(没有直接实现)
+ /// 结构化输出对话请求
///
///
[Fact]
- public void ChatRequest_StructuredOutputs_Test()
+ public async Task ChatRequest_StructuredOutputs_Test()
{
- //var chatRequest = new ChatRequest()
- //{
- // Messages = new[]
- // {
- // new Message()
- // {
- // Role = ChatRole.User,
- // Content = "Ollama is 22 years old and busy saving the world. Return a JSON object with the age and availability.",
- // }
- // },
-
- // Think = false,
-
- // //(可选)禁用流式处理响应
- // Stream = false,
-
- // Format = new
- // {
- // type = "object",
- // properties = new { age = new { type = "integer" }, available = new { type = "boolean" } },
- // required = new string[] { "age", "available" }
- // },
- //};
- //var chatDoneResponse = await _ollamaApiClient.ChatAsync(chatRequest).StreamToEndAsync();
- //_output.WriteLine(chatDoneResponse?.Message.Content);
-
- //var jsonObject = new { age = 0, available = false };
-
- //var responseObject = Newtonsoft.Json.JsonConvert.DeserializeAnonymousType(chatDoneResponse?.Message.Content ?? "{}", jsonObject);
-
- //Assert.NotNull(responseObject);
- //Assert.Equal(22, responseObject.age);
- //Assert.True(responseObject.available);
+ var chatRequest = new ChatRequest()
+ {
+ Messages = new Message[]
+ {
+ new Message()
+ {
+ Role = ChatRole.User,
+ Content = "Ollama is 22 years old and busy saving the world. Return a JSON object with the age and availability.",
+ },
+ },
+
+ Think = false,
+
+ //(可选)禁用流式处理响应
+ Stream = false,
+
+ Format = new
+ {
+ type = "object",
+ properties = new { age = new { type = "integer" }, available = new { type = "boolean" } },
+ required = new string[] { "age", "available" }
+ },
+ };
+ var chatDoneResponse = await _ollamaApiClient.ChatAsync(chatRequest).StreamToEndAsync();
+ _output.WriteLine(chatDoneResponse?.Message.Content);
+
+ var jsonObject = new { age = 0, available = false };
+
+ var responseObject = Newtonsoft.Json.JsonConvert.DeserializeAnonymousType(chatDoneResponse?.Message.Content ?? "{}", jsonObject);
+
+ Assert.NotNull(responseObject);
+ Assert.Equal(22, responseObject.age);
+ Assert.True(responseObject.available);
}
///