From cdb5f80604b1c8c5a63b6c333e818ccfcb81cf0a Mon Sep 17 00:00:00 2001
From: zhengxs <674934275@qq.com>
Date: Tue, 10 Sep 2024 18:00:07 +0800
Subject: [PATCH 1/4] =?UTF-8?q?=E5=AE=9A=E4=BD=8D?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../Senaprc.AI.Samples.Agents.csproj | 4 -
.../appsettings.json | 29 +++++-
.../Senparc.AI.Samples.Consoles.csproj | 13 ---
.../appsettings.json | 24 ++++-
src/Senparc.AI.Kernel/Extensions.cs | 39 ++++++++
.../Helpers/SemanticKernelHelper.Config.cs | 17 ++++
.../Senparc.AI.Kernel.csproj | 4 +-
.../SparkAI/SparkAIChatService.cs | 96 +++++++++++++++++++
src/Senparc.AI/Entities/Keys/SparkAIKeys.cs | 30 ++++++
.../Entities/SenparcAiSettingBase.cs | 26 +++++
src/Senparc.AI/Enums.cs | 1 +
.../Interfaces/ISenparcAiSetting.cs | 23 ++++-
12 files changed, 278 insertions(+), 28 deletions(-)
create mode 100644 src/Senparc.AI.Kernel/SparkAI/SparkAIChatService.cs
create mode 100644 src/Senparc.AI/Entities/Keys/SparkAIKeys.cs
diff --git a/Samples/Senaprc.AI.Samples.Agents/Senaprc.AI.Samples.Agents.csproj b/Samples/Senaprc.AI.Samples.Agents/Senaprc.AI.Samples.Agents.csproj
index 2bb7d2a..82017fc 100644
--- a/Samples/Senaprc.AI.Samples.Agents/Senaprc.AI.Samples.Agents.csproj
+++ b/Samples/Senaprc.AI.Samples.Agents/Senaprc.AI.Samples.Agents.csproj
@@ -21,10 +21,6 @@
-
- PreserveNewest
-
-
PreserveNewest
diff --git a/Samples/Senaprc.AI.Samples.Agents/appsettings.json b/Samples/Senaprc.AI.Samples.Agents/appsettings.json
index ee6c3a5..84d6f86 100644
--- a/Samples/Senaprc.AI.Samples.Agents/appsettings.json
+++ b/Samples/Senaprc.AI.Samples.Agents/appsettings.json
@@ -17,12 +17,12 @@
//Senparc.AI 设置
"SenparcAiSetting": {
"IsDebug": true,
- "AiPlatform": "AzureOpenAI", //注意修改为自己平台对应的枚举值
+ "AiPlatform": "SparkAI", //注意修改为自己平台对应的枚举值
"NeuCharAIKeys": {
- "ApiKey": "", //在 https://www.neuchar.com/Developer/AiApp 申请
- "NeuCharEndpoint": "https://www.neuchar.com/", //查看 ApiKey 时可看到 DeveloperId
+ "ApiKey": "5b0b30df3fd44811bdbfed8fe07be3eb", //在 https://www.neuchar.com/Developer/AiApp 申请
+ "NeuCharEndpoint": "https://www.neuchar.com/18673", //查看 ApiKey 时可看到 DeveloperId
"ModelName": {
- "Chat": "gpt-35-turbo"
+ "Chat": "gpt-4-32k"
}
},
"AzureOpenAIKeys": {
@@ -46,6 +46,15 @@
"TextCompletion": "chatglm2"
}
},
+ "SparkAIKeys": {
+ "ApiKey": "40a519641152f3c7caecbcc416065ae1", //TODO:加密
+ "AppId": "a891b281",
+ "ApiSecret": "ODdhYjEzZTY3OGE4OWJkYTI0M2ZlNGIz",
+ "SparkAiEndpoint": "",
+ "ModelName": {
+ "Chat": "gpt-35-turbo"
+ }
+ },
"Items": {
"AzureDalle3": {
"AiPlatform": "AzureOpenAI",
@@ -68,6 +77,18 @@
}
}
},
+ "SparkAIKeys": {
+ "AiPlatform": "SparkAI",
+ "SparkAIKeys": {
+ "ApiKey": "40a519641152f3c7caecbcc416065ae1", //TODO:加密
+ "AppId": "a891b281",
+ "ApiSecret": "ODdhYjEzZTY3OGE4OWJkYTI0M2ZlNGIz",
+ "SparkAiEndpoint": "https://www.neuchar.com//",
+ "ModelName": {
+ "Chat": "gpt-35-turbo"
+ }
+ }
+ },
"OtherModels": {
"AiPlatform": ""
//任意数量的 *Keys 配置
diff --git a/Samples/Senparc.AI.Samples.Consoles/Senparc.AI.Samples.Consoles.csproj b/Samples/Senparc.AI.Samples.Consoles/Senparc.AI.Samples.Consoles.csproj
index c53d65c..394fa45 100644
--- a/Samples/Senparc.AI.Samples.Consoles/Senparc.AI.Samples.Consoles.csproj
+++ b/Samples/Senparc.AI.Samples.Consoles/Senparc.AI.Samples.Consoles.csproj
@@ -9,19 +9,6 @@
-
-
-
-
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
-
diff --git a/Samples/Senparc.AI.Samples.Consoles/appsettings.json b/Samples/Senparc.AI.Samples.Consoles/appsettings.json
index 84a351f..3ac36bc 100644
--- a/Samples/Senparc.AI.Samples.Consoles/appsettings.json
+++ b/Samples/Senparc.AI.Samples.Consoles/appsettings.json
@@ -13,7 +13,7 @@
//Senparc.AI 设置
"SenparcAiSetting": {
"IsDebug": true,
- "AiPlatform": "NeuCharAI", //注意修改为自己平台对应的枚举值
+ "AiPlatform": "SparkAI", //注意修改为自己平台对应的枚举值
"NeuCharAIKeys": {
"ApiKey": "xxxxxxx", //在 https://www.neuchar.com/Developer/AiApp 申请
"NeuCharEndpoint": "https://www.neuchar.com/", //查看 ApiKey 时可看到 DeveloperId,替换掉
@@ -54,6 +54,15 @@
"TextCompletion": "qwen:7b"
}
},
+ "SparkAIKeys": {
+ "ApiKey": "", //TODO:加密
+ "AppId": "",
+ "ApiSecret": "",
+ "SparkAiEndpoint": "",
+ "ModelName": {
+ "Chat": "gpt-35-turbo"
+ }
+ },
"Items": {
"AzureDalle3": {
"AiPlatform": "AzureOpenAI",
@@ -76,6 +85,19 @@
}
}
},
+ "SparkAIKeys": {
+ "AiPlatform": "SparkAI",
+ "SparkAIKeys": {
+ "ApiKey": "40a519641152f3c7caecbcc416065ae1", //TODO:加密
+ "AppId": "a891b281",
+ "ApiSecret": "ODdhYjEzZTY3OGE4OWJkYTI0M2ZlNGIz",
+ "SparkAiEndpoint": "https://www.neuchar.com//",
+ "ModelName": {
+ "Chat": "gpt-35-turbo"
+ }
+ }
+ },
+
"OtherModels": {
"AiPlatform": ""
//任意数量的 *Keys 配置
diff --git a/src/Senparc.AI.Kernel/Extensions.cs b/src/Senparc.AI.Kernel/Extensions.cs
index 6b2d169..d136c38 100644
--- a/src/Senparc.AI.Kernel/Extensions.cs
+++ b/src/Senparc.AI.Kernel/Extensions.cs
@@ -8,6 +8,9 @@
using Microsoft.SemanticKernel.Connectors.OpenAI;
using Microsoft.SemanticKernel.TextGeneration;
using Microsoft.SemanticKernel;
+using Sdcb.SparkDesk;
+using Senparc.AI.Kernel.SparkAI;
+using System.Net;
namespace Senparc.AI.Kernel
{
@@ -36,7 +39,21 @@ public static IKernelBuilder AddFastAPIChatCompletion(this IKernelBuilder builde
builder.Services.AddKeyedSingleton((object?)serviceId, (Func)implementationFactory);
return builder;
}
+ //public static IKernelBuilder AddFOllamaChatCompletion(this IKernelBuilder builder, string modelId, string endpoint, string serviceId = null)
+ //{
+ // string modelId2 = modelId;
+
+ // Func implementationFactory =
+ // (IServiceProvider serviceProvider, object? _) =>
+ // new OpenAIChatCompletionService(modelId, new OpenAIClient(new Uri(endpoint), new Azure.AzureKeyCredential(apiKey)), serviceProvider.GetService());
+
+ // OllamaApiClientExtensions.
+
+ // builder.Services.AddKeyedSingleton((object?)serviceId, (Func)implementationFactory);
+ // builder.Services.AddKeyedSingleton((object?)serviceId, (Func)implementationFactory);
+ // return builder;
+ //}
#region Ollama
public static IKernelBuilder AddFOllamaChatCompletion(this IKernelBuilder builder, string modelId, string endpoint, string serviceId = null)
@@ -65,5 +82,27 @@ public static IKernelBuilder AddFOllamaTextCompletion(this IKernelBuilder builde
}
#endregion
+
+
+ ///
+ /// 添加 SparkAI 聊天服务
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static IKernelBuilder AddSparkAIChatCompletion(this IKernelBuilder builder, string appId, string apiKey, string apiSecret)
+ {
+
+ string apiKey2 = apiKey;
+ string appId2 = appId;
+ string apiSecret2 = apiSecret;
+ // Register SparkAIService as a singleton in the dependency injection container
+ builder.Services.AddSingleton(new SparkAIChatService(appId, apiKey, apiSecret));
+ return builder;
+ }
}
}
diff --git a/src/Senparc.AI.Kernel/Helpers/SemanticKernelHelper.Config.cs b/src/Senparc.AI.Kernel/Helpers/SemanticKernelHelper.Config.cs
index 4bf7f78..ba4bf1c 100644
--- a/src/Senparc.AI.Kernel/Helpers/SemanticKernelHelper.Config.cs
+++ b/src/Senparc.AI.Kernel/Helpers/SemanticKernelHelper.Config.cs
@@ -93,6 +93,11 @@ public IKernelBuilder ConfigChat(string userId, string modelName = null, ISenpar
endpoint: senparcAiSetting.OllamaEndpoint,
serviceId: null
),
+ AiPlatform.SparkAI => kernelBuilder.AddSparkAIChatCompletion(
+ apiKey: senparcAiSetting.ApiKey,
+ appId: senparcAiSetting.SparkAIKeys.AppId,
+ apiSecret: senparcAiSetting.SparkAIKeys.ApiSecret
+ ),
_ => throw new SenparcAiException($"没有处理当前 {nameof(AiPlatform)} 类型:{aiPlatForm}")
};
@@ -163,6 +168,18 @@ public IKernelBuilder ConfigTextCompletion(string userId, string modelName = nul
endpoint: senparcAiSetting.OllamaEndpoint,
serviceId: null
),
+ AiPlatform.SparkAI => kernelBuilder.AddSparkAIChatCompletion(
+ appId:senparcAiSetting.SparkAIKeys.AppId,
+ apiKey:senparcAiSetting.SparkAIKeys.ApiKey,
+ apiSecret:senparcAiSetting.SparkAIKeys.ApiSecret
+ ),
+ //AiPlatform.Ollama => kernelBuilder.AddOpenAIChatCompletion(
+ // modelId: modelName,
+ // apiKey: senparcAiSetting.ApiKey,
+ // orgId: senparcAiSetting.OrganizationId,
+ // endpoint: senparcAiSetting.FastAPIEndpoint,
+ // serviceId: null
+ // ),
_ => throw new SenparcAiException($"没有处理当前 {nameof(AiPlatform)} 类型:{aiPlatForm}")
};
diff --git a/src/Senparc.AI.Kernel/Senparc.AI.Kernel.csproj b/src/Senparc.AI.Kernel/Senparc.AI.Kernel.csproj
index 9478449..3d4ac9a 100644
--- a/src/Senparc.AI.Kernel/Senparc.AI.Kernel.csproj
+++ b/src/Senparc.AI.Kernel/Senparc.AI.Kernel.csproj
@@ -2,7 +2,7 @@
netstandard2.1
- 0.18.0
+ 0.19.0
enable
10.0
Senparc.AI.Kernel
@@ -67,10 +67,12 @@
+
+
diff --git a/src/Senparc.AI.Kernel/SparkAI/SparkAIChatService.cs b/src/Senparc.AI.Kernel/SparkAI/SparkAIChatService.cs
new file mode 100644
index 0000000..eb86c0c
--- /dev/null
+++ b/src/Senparc.AI.Kernel/SparkAI/SparkAIChatService.cs
@@ -0,0 +1,96 @@
+using Microsoft.SemanticKernel;
+using Microsoft.SemanticKernel.TextGeneration;
+using Sdcb.SparkDesk;
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using static Humanizer.On;
+
+
+namespace Senparc.AI.Kernel.SparkAI
+{
+ ///
+ /// 讯飞星火api
+ ///
+ public class SparkAIChatService : ITextGenerationService
+ {
+ private readonly SparkDeskClient _client;
+ private readonly string _appId;
+ private readonly string _apiKey;
+ private readonly string _apiSecret;
+
+ public SparkAIChatService(string appId, string apiKey, string apiSecret)
+ {
+ _appId = appId;
+ _apiKey = apiKey;
+ _apiSecret = apiSecret;
+ _client = new SparkDeskClient(appId, apiKey, apiSecret);
+ }
+
+ public IReadOnlyDictionary Attributes => throw new NotImplementedException();
+
+ public async Task ChatAsync(string[] userMessages)
+ {
+ StringBuilder sb = new StringBuilder();
+ List messages = new List();
+
+ foreach (var message in userMessages)
+ {
+ messages.Add(ChatMessage.FromUser(message));
+ }
+
+ // 假设这里的 ModelVersion.V2_0 是一个有效的版本指示。
+ TokensUsage usage = await _client.ChatAsStreamAsync(ModelVersion.Max, messages.ToArray(), s => sb.Append(s), uid: "zhoujie");
+
+ return sb.ToString();
+ }
+
+ public async IAsyncEnumerable GetStreamingTextContentsAsync(string prompt, PromptExecutionSettings? executionSettings = null, Microsoft.SemanticKernel.Kernel? kernel = null, CancellationToken cancellationToken = default)
+ {
+
+
+ // 构建消息数组,这里使用 prompt 来构建 ChatMessage
+ var messages = new List
+ {
+ ChatMessage.FromUser(prompt)
+ };
+
+ // 用于接收来自 API 的文本数据的 StringBuilder
+ StringBuilder sb = new StringBuilder();
+
+ // 调用 ChatAsStreamAsync 方法,该方法异步接收聊天消息
+ //TokensUsage usage = await _client.ChatAsStreamAsync(ModelVersion.V3, messages.ToArray(), s => sb.Append(s), uid: "zhoujie", cancellationToken: cancellationToken);
+
+ //// 解析流式数据并生成 StreamingTextContent 实例
+ //// 假设每次调用返回全部文本,我们可以直接生成一个 StreamingTextContent 对象
+ //yield return new StreamingTextContent(sb.ToString(), encoding: Encoding.UTF8);
+ // Ensure ChatAsStreamAsync is an async streaming method
+ await foreach (var response in _client.ChatAsStreamAsync(ModelVersion.Max, messages.ToArray()))
+ {
+ yield return new StreamingTextContent(response.Text, encoding: Encoding.UTF8);
+ }
+ }
+
+ public async Task> GetTextContentsAsync(string prompt, PromptExecutionSettings? executionSettings = null, Microsoft.SemanticKernel.Kernel? kernel = null, CancellationToken cancellationToken = default)
+ {
+
+
+ // 调用 ChatAsync 方法并获取响应
+ ChatResponse response = await _client.ChatAsync(ModelVersion.Max, new ChatMessage[]
+ {
+ ChatMessage.FromUser(prompt)
+ });
+
+ // 创建并返回 TextContent 列表
+ return new List
+ {
+ new TextContent { Text=response.Text }
+ };
+ }
+
+
+ }
+
+}
diff --git a/src/Senparc.AI/Entities/Keys/SparkAIKeys.cs b/src/Senparc.AI/Entities/Keys/SparkAIKeys.cs
new file mode 100644
index 0000000..5ed83b7
--- /dev/null
+++ b/src/Senparc.AI/Entities/Keys/SparkAIKeys.cs
@@ -0,0 +1,30 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using Senparc.AI.Entities.Keys;
+
+namespace Senparc.AI
+{
+ ///
+ /// 科大讯飞
+ ///
+ public class SparkAIKeys : BaseKeys
+ {
+ //public string ApiKey { get; set; }
+ //public string OrganizationId { get; set; }
+
+ // 应用APPID(必须为webapi类型应用,并开通星火认知大模型授权)
+ public string AppId { get; set; }
+
+ // 接口密钥(webapi类型应用开通星火认知大模型后,控制台--我的应用---星火认知大模型---相应服务的apikey)
+ public string ApiSecret { get; set; }
+ // 接口密钥(webapi类型应用开通星火认知大模型后,控制台--我的应用---星火认知大模型---相应服务的apisecret)
+ public string ApiKey { get; set; }
+
+ public string SparkAIEndpoint { get; set; }
+
+
+
+
+ }
+}
diff --git a/src/Senparc.AI/Entities/SenparcAiSettingBase.cs b/src/Senparc.AI/Entities/SenparcAiSettingBase.cs
index e18afbf..027b0f4 100644
--- a/src/Senparc.AI/Entities/SenparcAiSettingBase.cs
+++ b/src/Senparc.AI/Entities/SenparcAiSettingBase.cs
@@ -71,6 +71,7 @@ public class SenparcAiSettingBase : ISenparcAiSetting
/// 是否使用 Ollama
///
public virtual bool Ollama => AiPlatform == AiPlatform.Ollama;
+ public virtual bool UseSparkAI => AiPlatform == AiPlatform.SparkAI;
///
/// AI 平台类型
@@ -87,6 +88,10 @@ public class SenparcAiSettingBase : ISenparcAiSetting
public virtual FastAPIKeys FastAPIKeys { get; set; }
public virtual OllamaKeys OllamaKeys { get; set; }
+ ///
+ /// 科大讯飞api
+ ///
+ public virtual SparkAIKeys SparkAIKeys { get; set; }
///
/// Azure OpenAI 或 OpenAI API Key
///
@@ -98,6 +103,7 @@ public class SenparcAiSettingBase : ISenparcAiSetting
AiPlatform.HuggingFace => "",
AiPlatform.FastAPI => FastAPIKeys.ApiKey,
AiPlatform.Ollama => "",
+ AiPlatform.SparkAI => SparkAIKeys.ApiKey,
_ => ""
};
@@ -167,6 +173,12 @@ public class SenparcAiSettingBase : ISenparcAiSetting
#endregion
+ #region SparkAI
+
+ public virtual string SparkAIEndpoint => SparkAIKeys?.SparkAIEndpoint;
+
+ #endregion
+
public virtual bool IsOpenAiKeysSetted => OpenAIKeys != null && !OpenAIKeys.ApiKey.IsNullOrEmpty();
@@ -253,5 +265,19 @@ public ISenparcAiSetting SetOtherPlatform()
}
#endregion
+
+ ///
+ /// 设置 SparkAI
+ ///
+ ///
+ ///
+ public ISenparcAiSetting SetSparkAI(SparkAIKeys sparkAIKeys)
+ {
+ this.AiPlatform = AiPlatform.SparkAI;
+ this.SparkAIKeys = sparkAIKeys;
+ return this;
+ }
+
+
}
}
\ No newline at end of file
diff --git a/src/Senparc.AI/Enums.cs b/src/Senparc.AI/Enums.cs
index 5d4316b..26eaf45 100644
--- a/src/Senparc.AI/Enums.cs
+++ b/src/Senparc.AI/Enums.cs
@@ -21,6 +21,7 @@ public enum AiPlatform
//Oobabooga = 64,//未实现
FastAPI = 128,
Ollama = 256,
+ SparkAI=512
}
///
diff --git a/src/Senparc.AI/Interfaces/ISenparcAiSetting.cs b/src/Senparc.AI/Interfaces/ISenparcAiSetting.cs
index a016962..0f71002 100644
--- a/src/Senparc.AI/Interfaces/ISenparcAiSetting.cs
+++ b/src/Senparc.AI/Interfaces/ISenparcAiSetting.cs
@@ -43,6 +43,7 @@ public interface ISenparcAiSetting
AiPlatform.HuggingFace => HuggingFaceEndpoint,
AiPlatform.FastAPI => FastAPIEndpoint,
AiPlatform.Ollama => OllamaEndpoint,
+ AiPlatform.SparkAI=>SparkAIEndpoint,
_ => throw new SenparcAiException($"未配置 {AiPlatform} 的 Endpoint 输出")
};
@@ -55,6 +56,7 @@ public interface ISenparcAiSetting
/// 是否使用 NeuChar OpenAI
///
bool UseNeuCharAI => AiPlatform == AiPlatform.NeuCharAI;
+ bool UseSparkAI => AiPlatform == AiPlatform.SparkAI;
///
/// AI 平台类型
///
@@ -66,6 +68,8 @@ public interface ISenparcAiSetting
HuggingFaceKeys HuggingFaceKeys { get; set; }
FastAPIKeys FastAPIKeys { get; set; }
OllamaKeys OllamaKeys { get; set; }
+
+ SparkAIKeys SparkAIKeys { get; set; }
///
/// Neuchar OpenAI 或 Azure OpenAI 或 OpenAI API Key
@@ -79,10 +83,7 @@ public interface ISenparcAiSetting
#region OpenAI
- ///
- /// OpenAI Endpoint
- ///
- string OpenAIEndpoint { get; }
+
#endregion
@@ -124,6 +125,14 @@ public interface ISenparcAiSetting
#endregion
+ #region OpenAI
+
+ ///
+ /// OpenAI Endpoint
+ ///
+ string OpenAIEndpoint { get; }
+
+ #endregion
#region FastAPI
string FastAPIEndpoint { get; }
@@ -135,7 +144,9 @@ public interface ISenparcAiSetting
string OllamaEndpoint { get; }
#endregion
-
+ #region SparkAI
+ string SparkAIEndpoint { get; }
+ #endregion
///
/// OpenAIKeys 是否已经设置
///
@@ -150,6 +161,7 @@ public interface ISenparcAiSetting
AiPlatform.HuggingFace => HuggingFaceKeys.ModelName,
AiPlatform.FastAPI => FastAPIKeys.ModelName,
AiPlatform.Ollama => OllamaKeys.ModelName,
+ AiPlatform.SparkAI=>SparkAIKeys.ModelName,
_ => throw new SenparcAiException($"100-未配置 {AiPlatform} 的 Endpoint 输出")
};
@@ -162,6 +174,7 @@ public interface ISenparcAiSetting
AiPlatform.HuggingFace => null,
AiPlatform.FastAPI => null,
AiPlatform.Ollama => null,
+ AiPlatform.SparkAI=>null,
_ => throw new SenparcAiException($"未配置 {AiPlatform} 的 DeploymentName 输出")
};
#pragma warning restore CS8603 // 可能返回 null 引用。
From 8d35290fb5d565e4190291294f3706fd3ef09735 Mon Sep 17 00:00:00 2001
From: zhengxs <674934275@qq.com>
Date: Wed, 11 Sep 2024 17:47:03 +0800
Subject: [PATCH 2/4] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E8=AE=AF=E9=A3=9Eapi?=
=?UTF-8?q?=E5=AF=B9=E6=8E=A5=E3=80=82=20=E4=B8=BA=E4=BA=86=E5=BF=AB?=
=?UTF-8?q?=E9=80=9F=20=E9=87=87=E7=94=A8=E4=BA=86=E7=AC=AC=E4=B8=89?=
=?UTF-8?q?=E6=96=B9=E7=9A=84=E5=BA=93?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/Senparc.AI.Kernel/Extensions.cs | 12 +++-----
.../Helpers/SemanticKernelHelper.Config.cs | 7 +++--
.../Senparc.AI.Kernel.csproj | 23 +++++++++-----
.../SparkAI/SparkAIChatService.cs | 30 +++++++++++++++----
src/Senparc.AI/Entities/Keys/SparkAIKeys.cs | 6 ++--
src/Senparc.AI/Senparc.AI.csproj | 2 +-
6 files changed, 54 insertions(+), 26 deletions(-)
diff --git a/src/Senparc.AI.Kernel/Extensions.cs b/src/Senparc.AI.Kernel/Extensions.cs
index d136c38..50e050c 100644
--- a/src/Senparc.AI.Kernel/Extensions.cs
+++ b/src/Senparc.AI.Kernel/Extensions.cs
@@ -85,7 +85,7 @@ public static IKernelBuilder AddFOllamaTextCompletion(this IKernelBuilder builde
///
- /// 添加 SparkAI 聊天服务
+ /// 添加 SparkAI 聊天服务 现在只有简单聊天
///
///
///
@@ -94,14 +94,10 @@ public static IKernelBuilder AddFOllamaTextCompletion(this IKernelBuilder builde
///
///
///
- public static IKernelBuilder AddSparkAIChatCompletion(this IKernelBuilder builder, string appId, string apiKey, string apiSecret)
- {
-
- string apiKey2 = apiKey;
- string appId2 = appId;
- string apiSecret2 = apiSecret;
+ public static IKernelBuilder AddSparkAIChatCompletion(this IKernelBuilder builder, string appId, string apiKey, string apiSecret,string modelVersion)
+ {
// Register SparkAIService as a singleton in the dependency injection container
- builder.Services.AddSingleton(new SparkAIChatService(appId, apiKey, apiSecret));
+ builder.Services.AddSingleton(new SparkAIChatService(appId, apiKey, apiSecret,modelVersion));
return builder;
}
}
diff --git a/src/Senparc.AI.Kernel/Helpers/SemanticKernelHelper.Config.cs b/src/Senparc.AI.Kernel/Helpers/SemanticKernelHelper.Config.cs
index ba4bf1c..5e00ff3 100644
--- a/src/Senparc.AI.Kernel/Helpers/SemanticKernelHelper.Config.cs
+++ b/src/Senparc.AI.Kernel/Helpers/SemanticKernelHelper.Config.cs
@@ -96,7 +96,9 @@ public IKernelBuilder ConfigChat(string userId, string modelName = null, ISenpar
AiPlatform.SparkAI => kernelBuilder.AddSparkAIChatCompletion(
apiKey: senparcAiSetting.ApiKey,
appId: senparcAiSetting.SparkAIKeys.AppId,
- apiSecret: senparcAiSetting.SparkAIKeys.ApiSecret
+ apiSecret: senparcAiSetting.SparkAIKeys.ApiSecret,
+ modelVersion: senparcAiSetting.SparkAIKeys.ModelVersion
+
),
_ => throw new SenparcAiException($"没有处理当前 {nameof(AiPlatform)} 类型:{aiPlatForm}")
};
@@ -171,7 +173,8 @@ public IKernelBuilder ConfigTextCompletion(string userId, string modelName = nul
AiPlatform.SparkAI => kernelBuilder.AddSparkAIChatCompletion(
appId:senparcAiSetting.SparkAIKeys.AppId,
apiKey:senparcAiSetting.SparkAIKeys.ApiKey,
- apiSecret:senparcAiSetting.SparkAIKeys.ApiSecret
+ apiSecret:senparcAiSetting.SparkAIKeys.ApiSecret,
+ modelVersion:senparcAiSetting.SparkAIKeys.ModelVersion
),
//AiPlatform.Ollama => kernelBuilder.AddOpenAIChatCompletion(
// modelId: modelName,
diff --git a/src/Senparc.AI.Kernel/Senparc.AI.Kernel.csproj b/src/Senparc.AI.Kernel/Senparc.AI.Kernel.csproj
index 3d4ac9a..0e76e09 100644
--- a/src/Senparc.AI.Kernel/Senparc.AI.Kernel.csproj
+++ b/src/Senparc.AI.Kernel/Senparc.AI.Kernel.csproj
@@ -2,7 +2,7 @@
netstandard2.1
- 0.19.0
+ 0.19.3
enable
10.0
Senparc.AI.Kernel
@@ -73,11 +73,18 @@
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Senparc.AI.Kernel/SparkAI/SparkAIChatService.cs b/src/Senparc.AI.Kernel/SparkAI/SparkAIChatService.cs
index eb86c0c..5d4b5a1 100644
--- a/src/Senparc.AI.Kernel/SparkAI/SparkAIChatService.cs
+++ b/src/Senparc.AI.Kernel/SparkAI/SparkAIChatService.cs
@@ -1,6 +1,7 @@
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.TextGeneration;
using Sdcb.SparkDesk;
+using Senparc.AI.Entities.Keys;
using System;
using System.Collections.Generic;
using System.Text;
@@ -20,12 +21,31 @@ public class SparkAIChatService : ITextGenerationService
private readonly string _appId;
private readonly string _apiKey;
private readonly string _apiSecret;
-
- public SparkAIChatService(string appId, string apiKey, string apiSecret)
+ private readonly ModelVersion _modelVersion;
+ public SparkAIChatService(string appId, string apiKey, string apiSecret,string modelVersion= "4_0_ultra")
{
+
_appId = appId;
_apiKey = apiKey;
_apiSecret = apiSecret;
+
+ switch (modelVersion?.ToLower()) {
+ case "lite":
+ _modelVersion = ModelVersion.Lite;
+ break;
+ case "pro":
+ _modelVersion = ModelVersion.Pro;break;
+ case "max":
+ _modelVersion = ModelVersion.Max;
+ break;
+ case "4_0_ultra":
+ _modelVersion = ModelVersion.V4_0_Ultra;
+ break;
+ default:
+ _modelVersion = ModelVersion.V4_0_Ultra; break;
+
+
+ }
_client = new SparkDeskClient(appId, apiKey, apiSecret);
}
@@ -42,7 +62,7 @@ public async Task ChatAsync(string[] userMessages)
}
// 假设这里的 ModelVersion.V2_0 是一个有效的版本指示。
- TokensUsage usage = await _client.ChatAsStreamAsync(ModelVersion.Max, messages.ToArray(), s => sb.Append(s), uid: "zhoujie");
+ TokensUsage usage = await _client.ChatAsStreamAsync(_modelVersion, messages.ToArray(), s => sb.Append(s), uid: "zhoujie");
return sb.ToString();
}
@@ -67,7 +87,7 @@ public async IAsyncEnumerable GetStreamingTextContentsAsyn
//// 假设每次调用返回全部文本,我们可以直接生成一个 StreamingTextContent 对象
//yield return new StreamingTextContent(sb.ToString(), encoding: Encoding.UTF8);
// Ensure ChatAsStreamAsync is an async streaming method
- await foreach (var response in _client.ChatAsStreamAsync(ModelVersion.Max, messages.ToArray()))
+ await foreach (var response in _client.ChatAsStreamAsync(_modelVersion, messages.ToArray()))
{
yield return new StreamingTextContent(response.Text, encoding: Encoding.UTF8);
}
@@ -78,7 +98,7 @@ public async Task> GetTextContentsAsync(string prompt
// 调用 ChatAsync 方法并获取响应
- ChatResponse response = await _client.ChatAsync(ModelVersion.Max, new ChatMessage[]
+ ChatResponse response = await _client.ChatAsync(_modelVersion, new ChatMessage[]
{
ChatMessage.FromUser(prompt)
});
diff --git a/src/Senparc.AI/Entities/Keys/SparkAIKeys.cs b/src/Senparc.AI/Entities/Keys/SparkAIKeys.cs
index 5ed83b7..42b2a4d 100644
--- a/src/Senparc.AI/Entities/Keys/SparkAIKeys.cs
+++ b/src/Senparc.AI/Entities/Keys/SparkAIKeys.cs
@@ -22,8 +22,10 @@ public class SparkAIKeys : BaseKeys
public string ApiKey { get; set; }
public string SparkAIEndpoint { get; set; }
-
-
+ ///
+ /// 版本
+ ///
+ public string ModelVersion { get; set; }
}
diff --git a/src/Senparc.AI/Senparc.AI.csproj b/src/Senparc.AI/Senparc.AI.csproj
index 118134c..25379eb 100644
--- a/src/Senparc.AI/Senparc.AI.csproj
+++ b/src/Senparc.AI/Senparc.AI.csproj
@@ -2,7 +2,7 @@
netstandard2.1
- 0.16.5
+ 0.16.7
enable
10.0
Senparc.AI
From ccd5a48fa3d3cc6b6ebfb83a612b6d5f7efdbd39 Mon Sep 17 00:00:00 2001
From: zhengxs <674934275@qq.com>
Date: Fri, 13 Sep 2024 11:20:04 +0800
Subject: [PATCH 3/4] =?UTF-8?q?=E7=A7=BB=E9=99=A4=E7=AC=AC=E4=B8=89?=
=?UTF-8?q?=E6=96=B9=E4=BE=9D=E8=B5=96=EF=BC=8C=20=E4=BD=BF=E7=94=A8Micros?=
=?UTF-8?q?oft.SemanticKernel=E7=9A=84=20IKernelBuilder=20=E5=AF=B9?=
=?UTF-8?q?=E6=8E=A5=E8=AE=AF=E9=A3=9E=E6=98=9F=E7=81=AB?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.gitignore | 2 +
.../appsettings.json | 107 ------------------
2 files changed, 2 insertions(+), 107 deletions(-)
delete mode 100644 Samples/Senparc.AI.Samples.Consoles/appsettings.json
diff --git a/.gitignore b/.gitignore
index 03c9f61..6934a01 100644
--- a/.gitignore
+++ b/.gitignore
@@ -11,3 +11,5 @@ appsettings.Development.json
/src/.idea/.idea.Senparc.AI/.idea
/Samples/Senparc.AI.Samples.Consoles/Properties/PublishProfiles
/Samples/Senparc.AI.Samples.Consoles/Senparc.AI.Samples.Consoles.csproj.user
+/Samples/Senparc.AI.Samples.Consoles/appsettings.json
+/src/ConsoleApp1/ConsoleApp1.csproj
diff --git a/Samples/Senparc.AI.Samples.Consoles/appsettings.json b/Samples/Senparc.AI.Samples.Consoles/appsettings.json
deleted file mode 100644
index 3ac36bc..0000000
--- a/Samples/Senparc.AI.Samples.Consoles/appsettings.json
+++ /dev/null
@@ -1,107 +0,0 @@
-{
- "Logging": {
- "IncludeScopes": false,
- "LogLevel": {
- "Default": "Warning"
- }
- },
- //CO2NET 设置
- "SenparcSetting": {
- "IsDebug": true,
- "DefaultCacheNamespace": "DefaultCacheTest"
- },
- //Senparc.AI 设置
- "SenparcAiSetting": {
- "IsDebug": true,
- "AiPlatform": "SparkAI", //注意修改为自己平台对应的枚举值
- "NeuCharAIKeys": {
- "ApiKey": "xxxxxxx", //在 https://www.neuchar.com/Developer/AiApp 申请
- "NeuCharEndpoint": "https://www.neuchar.com/", //查看 ApiKey 时可看到 DeveloperId,替换掉
- "NeuCharAIApiVersion": "2022-12-01",
- "ModelName": {
- "Chat": "gpt-35-turbo",
- "Embedding": "text-embedding-ada-002",
- "TextCompletion": "gpt-35-turbo-instruct"
- }
- },
- "AzureOpenAIKeys": {
- "ApiKey": "", //TODO:加密
- "AzureEndpoint": "", //https://xxxx.openai.azure.com/
- "AzureOpenAIApiVersion": "2022-12-01", //调用限制请参考:https://learn.microsoft.com/en-us/azure/cognitive-services/openai/quotas-limits
- "ModelName": {
- "Chat": "gpt-35-turbo"
- }
- },
- "OpenAIKeys": {
- "ApiKey": "", //TODO:加密
- "OrganizationId": "",
- "OpenAIEndpoint": null,
- "ModelName": {
- "Chat": "gpt-35-turbo"
- }
- },
- "HuggingFaceKeys": {
- "Endpoint": "", //HuggingFace 的 Endpoint
- "ModelName": {
- "TextCompletion": "chatglm2"
- }
- },
- "OllamaKeys": {
- "Endpoint": "http://localhost:11434/",
- "ModelName": {
- "Chat": "qwen:7b",
- "Embedding": "qwen:7b",
- "TextCompletion": "qwen:7b"
- }
- },
- "SparkAIKeys": {
- "ApiKey": "", //TODO:加密
- "AppId": "",
- "ApiSecret": "",
- "SparkAiEndpoint": "",
- "ModelName": {
- "Chat": "gpt-35-turbo"
- }
- },
- "Items": {
- "AzureDalle3": {
- "AiPlatform": "AzureOpenAI",
- "AzureOpenAIKeys": {
- "ApiKey": "",
- "AzureEndpoint": "",
- "AzureOpenAIApiVersion": "2022-12-01",
- "ModelName": {
- "TextToImage": "dall-e-3"
- }
- }
- },
- "MyNeuCharAI": {
- "AiPlatform": "NeuCharAI",
- "NeuCharAIKeys": {
- "ApiKey": "MyNeuCharAIKey",
- "NeuCharEndpoint": "https://www.neuchar.com/",
- "ModelName": {
- "Chat": "gpt-35-turbo"
- }
- }
- },
- "SparkAIKeys": {
- "AiPlatform": "SparkAI",
- "SparkAIKeys": {
- "ApiKey": "40a519641152f3c7caecbcc416065ae1", //TODO:加密
- "AppId": "a891b281",
- "ApiSecret": "ODdhYjEzZTY3OGE4OWJkYTI0M2ZlNGIz",
- "SparkAiEndpoint": "https://www.neuchar.com//",
- "ModelName": {
- "Chat": "gpt-35-turbo"
- }
- }
- },
-
- "OtherModels": {
- "AiPlatform": ""
- //任意数量的 *Keys 配置
- }
- }
- }
-}
\ No newline at end of file
From 2033acecd0cb559882c6557c6e0dcf0b6d8dc5f2 Mon Sep 17 00:00:00 2001
From: zhengxs <674934275@qq.com>
Date: Fri, 13 Sep 2024 11:28:50 +0800
Subject: [PATCH 4/4] =?UTF-8?q?=E7=A7=BB=E9=99=A4=E5=A4=9A=E4=BD=99?=
=?UTF-8?q?=E4=BE=9D=E8=B5=96?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../Samples/ChatSample.cs | 30 +--
.../Senparc.AI.Samples.Consoles.csproj | 6 +
src/ConsoleApp1/Program.cs | 10 +
src/Senparc.AI.Kernel/Extensions.cs | 43 +++-
.../Helpers/ExtensionHelper.cs | 33 ++++
.../Helpers/SemanticKernelHelper.Config.cs | 46 +++--
.../Senparc.AI.Kernel.csproj | 7 +-
.../SparkAI/Model/ChatApiRequest.cs | 10 +
.../SparkAI/Model/ChatRequestHeader.cs | 10 +
.../SparkAI/OpenAIHttpClientHandler.cs | 41 ++++
.../SparkAI/SparkAIChatCompletionService.cs | 75 +++++++
.../SparkAI/SparkApiClient.cs | 186 ++++++++++++++++++
src/Senparc.AI.sln | 18 ++
src/Senparc.AI/Entities/Keys/SparkAIKeys.cs | 5 +
.../Interfaces/ISenparcAiSetting.cs | 2 +-
src/Senparc.AI/Senparc.AI.csproj | 2 +-
src/Senparc.AI/appsettings.schema.json | 2 +-
17 files changed, 484 insertions(+), 42 deletions(-)
create mode 100644 src/ConsoleApp1/Program.cs
create mode 100644 src/Senparc.AI.Kernel/SparkAI/Model/ChatApiRequest.cs
create mode 100644 src/Senparc.AI.Kernel/SparkAI/Model/ChatRequestHeader.cs
create mode 100644 src/Senparc.AI.Kernel/SparkAI/OpenAIHttpClientHandler.cs
create mode 100644 src/Senparc.AI.Kernel/SparkAI/SparkAIChatCompletionService.cs
create mode 100644 src/Senparc.AI.Kernel/SparkAI/SparkApiClient.cs
diff --git a/Samples/Senparc.AI.Samples.Consoles/Samples/ChatSample.cs b/Samples/Senparc.AI.Samples.Consoles/Samples/ChatSample.cs
index 50cc9bd..a310a10 100644
--- a/Samples/Senparc.AI.Samples.Consoles/Samples/ChatSample.cs
+++ b/Samples/Senparc.AI.Samples.Consoles/Samples/ChatSample.cs
@@ -95,31 +95,33 @@ 输入 exit 退出。
var useMultiLine = false;
//开始对话
var talkingRounds = 0;
- while (true)
- {
- talkingRounds++;
+ //bool useMultiLine = false; // 确保变量被正确初始化
+ //StringBuilder multiLineContent = new StringBuilder(); // 初始化多行内容存储
+ while (true) {
+ talkingRounds++;
await Console.Out.WriteLineAsync($"[{talkingRounds}] 人类:");
var input = Console.ReadLine() ?? "";
- if (input.ToUpper() == "[ML]")
- {
+ // 修剪输入并转换为大写
+ if (input.Trim().ToUpper() == "[ML]") {
await Console.Out.WriteLineAsync("识别到多行模式,请继续输入");
+ await Console.Out.FlushAsync(); // 强制刷新缓冲区,确保输出顺序一致
useMultiLine = true;
}
- while (useMultiLine)
- {
- if (input.ToUpper() == "[END]")
- {
+ while (useMultiLine) {
+ input = Console.ReadLine();
+
+ // 检查是否结束多行模式
+ if (input.Trim().ToUpper() == "[END]") {
useMultiLine = false;
input = multiLineContent.ToString();
- }
- else
- {
+ multiLineContent.Clear(); // 清空多行内容缓存
+ } else {
await Console.Out.WriteLineAsync("请继续输入,直到输入 [END] 停止...");
- input = Console.ReadLine();
- multiLineContent.Append(input);
+ await Console.Out.FlushAsync(); // 强制刷新缓冲区,确保输出顺序一致
+ multiLineContent.AppendLine(input); // 添加多行内容到 StringBuilder 中
}
}
diff --git a/Samples/Senparc.AI.Samples.Consoles/Senparc.AI.Samples.Consoles.csproj b/Samples/Senparc.AI.Samples.Consoles/Senparc.AI.Samples.Consoles.csproj
index 394fa45..4a71b52 100644
--- a/Samples/Senparc.AI.Samples.Consoles/Senparc.AI.Samples.Consoles.csproj
+++ b/Samples/Senparc.AI.Samples.Consoles/Senparc.AI.Samples.Consoles.csproj
@@ -21,4 +21,10 @@
+
+
+ Always
+
+
+
\ No newline at end of file
diff --git a/src/ConsoleApp1/Program.cs b/src/ConsoleApp1/Program.cs
new file mode 100644
index 0000000..39fa642
--- /dev/null
+++ b/src/ConsoleApp1/Program.cs
@@ -0,0 +1,10 @@
+namespace ConsoleApp1
+{
+ internal class Program
+ {
+ static void Main(string[] args)
+ {
+ Console.WriteLine("Hello, World!");
+ }
+ }
+}
diff --git a/src/Senparc.AI.Kernel/Extensions.cs b/src/Senparc.AI.Kernel/Extensions.cs
index 50e050c..61825e5 100644
--- a/src/Senparc.AI.Kernel/Extensions.cs
+++ b/src/Senparc.AI.Kernel/Extensions.cs
@@ -8,9 +8,13 @@
using Microsoft.SemanticKernel.Connectors.OpenAI;
using Microsoft.SemanticKernel.TextGeneration;
using Microsoft.SemanticKernel;
-using Sdcb.SparkDesk;
using Senparc.AI.Kernel.SparkAI;
using System.Net;
+using System.Net.Http.Headers;
+using System.Net.Http;
+using static Humanizer.On;
+using System.IO;
+using System.Threading;
namespace Senparc.AI.Kernel
{
@@ -82,10 +86,8 @@ public static IKernelBuilder AddFOllamaTextCompletion(this IKernelBuilder builde
}
#endregion
-
-
///
- /// 添加 SparkAI 聊天服务 现在只有简单聊天
+ /// 添加讯飞聊天服务
///
///
///
@@ -94,11 +96,36 @@ public static IKernelBuilder AddFOllamaTextCompletion(this IKernelBuilder builde
///
///
///
- public static IKernelBuilder AddSparkAIChatCompletion(this IKernelBuilder builder, string appId, string apiKey, string apiSecret,string modelVersion)
- {
- // Register SparkAIService as a singleton in the dependency injection container
- builder.Services.AddSingleton(new SparkAIChatService(appId, apiKey, apiSecret,modelVersion));
+ public static IKernelBuilder AddSparkAPIChatCompletion(this IKernelBuilder builder, string modelId, string apiKey, string endpoint, string? orgId = null, string? serviceId = null)
+ {
+ // 创建 HttpClient,用于与讯飞星火 API 交互
+ var httpClient = new HttpClient();
+ httpClient.BaseAddress = new Uri(endpoint);
+ httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", apiKey);
+ Func implementationFactory =
+ (IServiceProvider serviceProvider, object? _) =>
+ new OpenAIChatCompletionService(modelId, new Uri(endpoint), apiKey, null, httpClient);
+ builder.Services.AddKeyedSingleton((object?)serviceId, (Func)implementationFactory);
+ builder.Services.AddKeyedSingleton((object?)serviceId, (Func)implementationFactory);
return builder;
}
+
+ /////
+ ///// 添加 SparkAI 聊天服务 现在只有简单聊天 过时
+ /////
+ /////
+ /////
+ /////
+ /////
+ /////
+ /////
+ /////
+ //public static IKernelBuilder AddSparkAIChatCompletion(this IKernelBuilder builder, string appId, string apiKey, string apiSecret,string modelVersion)
+ //{
+ // // Register SparkAIService as a singleton in the dependency injection container SparkApiClient
+ // // builder.Services.AddSingleton(new SparkAIChatService(appId, apiKey, apiSecret,modelVersion));
+ // builder.Services.AddSingleton(new SparkApiClient(apiKey, modelVersion));
+ // return builder;
+ //}
}
}
diff --git a/src/Senparc.AI.Kernel/Helpers/ExtensionHelper.cs b/src/Senparc.AI.Kernel/Helpers/ExtensionHelper.cs
index 662a8d8..c86e1af 100644
--- a/src/Senparc.AI.Kernel/Helpers/ExtensionHelper.cs
+++ b/src/Senparc.AI.Kernel/Helpers/ExtensionHelper.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Security.Cryptography;
using System.Text;
using Microsoft.SemanticKernel;
@@ -17,5 +18,37 @@ public static void Set(this KernelArguments kernelArguments, string key, object
{
kernelArguments[key] = value;
}
+
+ public static string GenerateApiPassword(string key, string secret)
+ {
+ // 拼接 key 和 secret
+ string combined = $"{key}:{secret}";
+
+ // 将拼接后的字符串进行 Base64 编码
+ byte[] byteArray = Encoding.UTF8.GetBytes(combined);
+ string base64Encoded = Convert.ToBase64String(byteArray);
+
+ return base64Encoded;
+ }
+
+ public static string GetAuthorizationUrl(string apiKey, string apiSecret, string hostUrl)
+ {
+ var url = new Uri(hostUrl);
+
+ string dateString = DateTime.UtcNow.ToString("r");
+
+ byte[] signatureBytes = Encoding.ASCII.GetBytes($"host: {url.Host}\ndate: {dateString}\nGET {url.AbsolutePath} HTTP/1.1");
+
+ using HMACSHA256 hmacsha256 = new(Encoding.ASCII.GetBytes(apiSecret));
+ byte[] computedHash = hmacsha256.ComputeHash(signatureBytes);
+ string signature = Convert.ToBase64String(computedHash);
+
+ string authorizationString = $"api_key=\"{apiKey}\",algorithm=\"hmac-sha256\",headers=\"host date request-line\",signature=\"{signature}\"";
+ string authorization = Convert.ToBase64String(Encoding.ASCII.GetBytes(authorizationString));
+
+ string query = $"authorization={authorization}&date={dateString}&host={url.Host}";
+
+ return new UriBuilder(url) { Scheme = url.Scheme, Query = query }.ToString();
+ }
}
}
diff --git a/src/Senparc.AI.Kernel/Helpers/SemanticKernelHelper.Config.cs b/src/Senparc.AI.Kernel/Helpers/SemanticKernelHelper.Config.cs
index 5e00ff3..029470c 100644
--- a/src/Senparc.AI.Kernel/Helpers/SemanticKernelHelper.Config.cs
+++ b/src/Senparc.AI.Kernel/Helpers/SemanticKernelHelper.Config.cs
@@ -93,13 +93,20 @@ public IKernelBuilder ConfigChat(string userId, string modelName = null, ISenpar
endpoint: senparcAiSetting.OllamaEndpoint,
serviceId: null
),
- AiPlatform.SparkAI => kernelBuilder.AddSparkAIChatCompletion(
- apiKey: senparcAiSetting.ApiKey,
- appId: senparcAiSetting.SparkAIKeys.AppId,
- apiSecret: senparcAiSetting.SparkAIKeys.ApiSecret,
- modelVersion: senparcAiSetting.SparkAIKeys.ModelVersion
-
- ),
+ AiPlatform.SparkAI => kernelBuilder.AddSparkAPIChatCompletion(
+ apiKey: senparcAiSetting.SparkAIKeys.ApiPassword,
+ endpoint: senparcAiSetting.Endpoint,
+ modelId: senparcAiSetting.SparkAIKeys.ModelName.Chat,
+ serviceId: null
+
+ ),
+ // AiPlatform.SparkAI => kernelBuilder.AddSparkAIChatCompletion(
+ // apiKey: senparcAiSetting.ApiKey,
+ // appId: senparcAiSetting.SparkAIKeys.AppId,
+ // apiSecret: senparcAiSetting.SparkAIKeys.ApiSecret,
+ // modelVersion: senparcAiSetting.SparkAIKeys.ModelVersion
+
+ //),
_ => throw new SenparcAiException($"没有处理当前 {nameof(AiPlatform)} 类型:{aiPlatForm}")
};
@@ -170,12 +177,18 @@ public IKernelBuilder ConfigTextCompletion(string userId, string modelName = nul
endpoint: senparcAiSetting.OllamaEndpoint,
serviceId: null
),
- AiPlatform.SparkAI => kernelBuilder.AddSparkAIChatCompletion(
- appId:senparcAiSetting.SparkAIKeys.AppId,
- apiKey:senparcAiSetting.SparkAIKeys.ApiKey,
- apiSecret:senparcAiSetting.SparkAIKeys.ApiSecret,
- modelVersion:senparcAiSetting.SparkAIKeys.ModelVersion
- ),
+ AiPlatform.SparkAI => kernelBuilder.AddSparkAPIChatCompletion(
+ apiKey: senparcAiSetting.SparkAIKeys.ApiPassword,
+ endpoint: senparcAiSetting.Endpoint,
+ modelId: senparcAiSetting.SparkAIKeys.ModelName.Chat,
+ serviceId: null
+ ),
+ //AiPlatform.SparkAI => kernelBuilder.AddSparkAIChatCompletion(
+ // appId: senparcAiSetting.SparkAIKeys.AppId,
+ // apiKey: senparcAiSetting.SparkAIKeys.ApiKey,
+ // apiSecret: senparcAiSetting.SparkAIKeys.ApiSecret,
+ // modelVersion: senparcAiSetting.SparkAIKeys.ModelVersion
+ //),
//AiPlatform.Ollama => kernelBuilder.AddOpenAIChatCompletion(
// modelId: modelName,
// apiKey: senparcAiSetting.ApiKey,
@@ -238,7 +251,12 @@ public IKernelBuilder ConfigTextEmbeddingGeneration(string userId, string modelN
apiKey: senparcAiSetting.ApiKey,
modelId: modelName,
httpClient: _httpClient),
-
+ // AiPlatform.SparkAI => kernelBuilder.AddSparkAPItext(
+ // deploymentName: deploymentName,
+ // endpoint: senparcAiSetting.Endpoint,
+ // apiKey: senparcAiSetting.ApiKey,
+ // modelId: modelName,
+ // httpClient: _httpClient),
AiPlatform.HuggingFace => kernelBuilder.AddHuggingFaceTextEmbeddingGeneration(
model: modelName,
endpoint: new Uri(senparcAiSetting.Endpoint ?? throw new SenparcAiException("HuggingFace 必须提供 Endpoint")),
diff --git a/src/Senparc.AI.Kernel/Senparc.AI.Kernel.csproj b/src/Senparc.AI.Kernel/Senparc.AI.Kernel.csproj
index 0e76e09..dba5699 100644
--- a/src/Senparc.AI.Kernel/Senparc.AI.Kernel.csproj
+++ b/src/Senparc.AI.Kernel/Senparc.AI.Kernel.csproj
@@ -2,7 +2,7 @@
netstandard2.1
- 0.19.3
+ 0.19.4
enable
10.0
Senparc.AI.Kernel
@@ -61,6 +61,8 @@
+
+
@@ -72,14 +74,13 @@
-
-
+
diff --git a/src/Senparc.AI.Kernel/SparkAI/Model/ChatApiRequest.cs b/src/Senparc.AI.Kernel/SparkAI/Model/ChatApiRequest.cs
new file mode 100644
index 0000000..c475aeb
--- /dev/null
+++ b/src/Senparc.AI.Kernel/SparkAI/Model/ChatApiRequest.cs
@@ -0,0 +1,10 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Senparc.AI.Kernel.SparkAI.Model
+{
+ internal class ChatApiRequest
+ {
+ }
+}
diff --git a/src/Senparc.AI.Kernel/SparkAI/Model/ChatRequestHeader.cs b/src/Senparc.AI.Kernel/SparkAI/Model/ChatRequestHeader.cs
new file mode 100644
index 0000000..6f54cb5
--- /dev/null
+++ b/src/Senparc.AI.Kernel/SparkAI/Model/ChatRequestHeader.cs
@@ -0,0 +1,10 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Senparc.AI.Kernel.SparkAI.Model
+{
+ internal class ChatRequestHeader
+ {
+ }
+}
diff --git a/src/Senparc.AI.Kernel/SparkAI/OpenAIHttpClientHandler.cs b/src/Senparc.AI.Kernel/SparkAI/OpenAIHttpClientHandler.cs
new file mode 100644
index 0000000..7734e22
--- /dev/null
+++ b/src/Senparc.AI.Kernel/SparkAI/OpenAIHttpClientHandler.cs
@@ -0,0 +1,41 @@
+using System;
+using System.Collections.Generic;
+using System.Net.Http;
+using System.Text;
+using System.Threading.Tasks;
+using System.Threading;
+
+namespace Senparc.AI.Kernel.SparkAI
+{
+ public class OpenAIHttpClientHandler : HttpClientHandler
+ {
+ protected override async Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
+ {
+ UriBuilder uriBuilder;
+ switch (request.RequestUri?.LocalPath) {
+ case "/v1/chat/completions":
+ uriBuilder = new UriBuilder(request.RequestUri) {
+ // 这里是你要修改的 URL
+ Scheme = "http",
+ Host = "你的ip地址",
+ Port = 3000,
+ Path = "v1/chat/completions",
+ };
+ request.RequestUri = uriBuilder.Uri;
+ break;
+ }
+
+ // 接着,调用基类的 SendAsync 方法将你的修改后的请求发出去
+ HttpResponseMessage response = await base.SendAsync(request, cancellationToken);
+
+ int n = 0;
+ while ((int)response.StatusCode == 500 && n < 10) {
+ response = await base.SendAsync(request, cancellationToken);
+ n++;
+ }
+
+ return response;
+ }
+ }
+
+}
diff --git a/src/Senparc.AI.Kernel/SparkAI/SparkAIChatCompletionService.cs b/src/Senparc.AI.Kernel/SparkAI/SparkAIChatCompletionService.cs
new file mode 100644
index 0000000..d7d2e82
--- /dev/null
+++ b/src/Senparc.AI.Kernel/SparkAI/SparkAIChatCompletionService.cs
@@ -0,0 +1,75 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Net.WebSockets;
+using System.Runtime.CompilerServices;
+using System.Security.Cryptography;
+using System.Text;
+using System.Text.Json.Serialization;
+using System.Text.Json;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.SemanticKernel;
+using Microsoft.SemanticKernel.ChatCompletion;
+using Microsoft.SemanticKernel.Services;
+using Microsoft.SemanticKernel.TextGeneration;
+using Sdcb.SparkDesk;
+
+namespace Senparc.AI.Kernel.SparkAI
+{
+ public class SparkDeskClient
+ {
+
+ private readonly string _appId;
+ private readonly string _apiKey;
+ private readonly string _apiSecret;
+
+ private readonly static JsonSerializerOptions _defaultJsonEncodingOptions = new() {
+ DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
+ };
+
+ ///
+ /// Initializes a new instance of the class with specified parameters.
+ ///
+ /// The app ID.
+ /// The API key.
+ /// The API Secret.
+ public SparkDeskClient(string appId, string apiKey, string apiSecret)
+ {
+ _appId = appId ?? throw new ArgumentNullException(nameof(appId));
+ _apiKey = apiKey ?? throw new ArgumentNullException(nameof(apiKey));
+ _apiSecret = apiSecret ?? throw new ArgumentNullException(nameof(apiSecret));
+ }
+
+
+
+
+
+ ///
+ /// Generates authorization URL for SparkDesk API.
+ ///
+ /// SparkDesk API key.
+ /// SparkDesk API secret.
+ /// Host URL. Optional, default is value from const field.
+ /// Authorization URL.
+ public static string GetAuthorizationUrl(string apiKey, string apiSecret, string hostUrl)
+ {
+ var url = new Uri(hostUrl);
+
+ string dateString = DateTime.UtcNow.ToString("r");
+
+ byte[] signatureBytes = Encoding.ASCII.GetBytes($"host: {url.Host}\ndate: {dateString}\nGET {url.AbsolutePath} HTTP/1.1");
+
+ using HMACSHA256 hmacsha256 = new(Encoding.ASCII.GetBytes(apiSecret));
+ byte[] computedHash = hmacsha256.ComputeHash(signatureBytes);
+ string signature = Convert.ToBase64String(computedHash);
+
+ string authorizationString = $"api_key=\"{apiKey}\",algorithm=\"hmac-sha256\",headers=\"host date request-line\",signature=\"{signature}\"";
+ string authorization = Convert.ToBase64String(Encoding.ASCII.GetBytes(authorizationString));
+
+ string query = $"authorization={authorization}&date={dateString}&host={url.Host}";
+
+ return new UriBuilder(url) { Scheme = url.Scheme, Query = query }.ToString();
+ }
+ }
+}
diff --git a/src/Senparc.AI.Kernel/SparkAI/SparkApiClient.cs b/src/Senparc.AI.Kernel/SparkAI/SparkApiClient.cs
new file mode 100644
index 0000000..d05ec73
--- /dev/null
+++ b/src/Senparc.AI.Kernel/SparkAI/SparkApiClient.cs
@@ -0,0 +1,186 @@
+
+using System;
+using System.Net.Http;
+using System.Net.Http.Headers;
+using System.Threading.Tasks;
+using System.Threading;
+using System.Text;
+using Microsoft.SemanticKernel;
+using System.Collections.Generic;
+using System.Runtime.CompilerServices;
+using System.IO;
+using System.Text.Json;
+using Microsoft.SemanticKernel.TextGeneration;
+namespace Senparc.AI.Kernel
+{
+ public class SparkApiClient : ITextGenerationService
+ {
+ private readonly HttpClient _httpClient;
+ private readonly string _apiKey;
+ private readonly string _baseUrl;
+ private readonly string _modelVersion;
+ public class StreamingTextContent
+ {
+ public string Text { get; }
+ public Encoding Encoding { get; }
+
+ public StreamingTextContent(string text, Encoding encoding)
+ {
+ Text = text;
+ Encoding = encoding;
+ }
+ }
+ public class ChatResponse
+ {
+ public string Text { get; set; }
+ // Add other properties as needed to match the API response
+ }
+ public IReadOnlyDictionary Attributes => throw new NotImplementedException();
+
+ public SparkApiClient(string apiKey, string modelVersion, string baseUrl = "https://spark-api-open.xf-yun.com/v1/chat/completions")
+ {
+ _httpClient = new HttpClient();
+ _apiKey = apiKey ?? throw new ArgumentNullException(nameof(apiKey));
+ _baseUrl = baseUrl ?? throw new ArgumentNullException(nameof(baseUrl));
+ _modelVersion = modelVersion ?? throw new ArgumentNullException(nameof(modelVersion));
+ }
+
+
+ //public async IAsyncEnumerable GetStreamingTextContentsAsync(string prompt, PromptExecutionSettings? executionSettings = null, Microsoft.SemanticKernel.Kernel? kernel = null, CancellationToken cancellationToken = default)
+ //{
+ // var messages = new List