diff --git a/src/BE/Chats.BE.csproj b/src/BE/Chats.BE.csproj index 22774063..97cb4b4f 100644 --- a/src/BE/Chats.BE.csproj +++ b/src/BE/Chats.BE.csproj @@ -9,7 +9,7 @@ - + @@ -26,12 +26,12 @@ - + - - + + diff --git a/src/BE/DB/Enums/DBModelProvider.cs b/src/BE/DB/Enums/DBModelProvider.cs index c5f47d14..2c2f90bc 100644 --- a/src/BE/DB/Enums/DBModelProvider.cs +++ b/src/BE/DB/Enums/DBModelProvider.cs @@ -13,4 +13,6 @@ public enum DBModelProvider Sparkdesk = 8, ZhiPuAI = 9, DeepSeek = 10, + xAI = 11, + GithubModels = 12, } diff --git a/src/BE/DB/Init/BasicData.cs b/src/BE/DB/Init/BasicData.cs index 34f1388a..57fdb52d 100644 --- a/src/BE/DB/Init/BasicData.cs +++ b/src/BE/DB/Init/BasicData.cs @@ -247,22 +247,22 @@ private static void InsertModelReferences(ChatsDB db) private static void InsertModelProviders(ChatsDB db) { - // Generated from data, hash: 918110f3f52c51c8fdebe00ca4e2e9dac5d2f2e7f892ed5c7197be6a7fbcfbdf + // Generated from data, hash: 615290985867eb3467e7889a31c4edf5dcdbd113930d67df8e19b6cd27c955ca db.ModelProviders.AddRange( [ - new(){ Id=0, Name="Test", InitialHost=null, InitialSecret=null, }, - new(){ Id=1, Name="Azure OpenAI", InitialHost="https://.openai.azure.com/", InitialSecret="", }, - new(){ Id=2, Name="Tencent Hunyuan", InitialHost="hunyuan.tencentcloudapi.com", InitialSecret="""{"secretId":"", "secretKey":""}""", }, - new(){ Id=3, Name="01.ai", InitialHost=null, InitialSecret="", }, - new(){ Id=4, Name="Moonshot", InitialHost=null, InitialSecret="", }, - new(){ Id=5, Name="OpenAI", InitialHost="https://api.openai.com/v1", InitialSecret="", }, - new(){ Id=6, Name="Wenxin Qianfan", InitialHost=null, InitialSecret="""{"apiKey":"", "secret":""}""", }, - new(){ Id=7, Name="DashScope", InitialHost=null, InitialSecret="", }, - new(){ Id=8, Name="Xunfei SparkDesk", InitialHost=null, InitialSecret="""{"appId": "", "apiKey":"", "secret":""}""", }, - new(){ Id=9, Name="Zhipu AI", InitialHost=null, InitialSecret="", }, - new(){ Id=10, Name="DeepSeek", InitialHost=null, InitialSecret="", }, - new(){ Id=11, Name="x.ai", InitialHost=null, InitialSecret="xai-yourkey", }, - new(){ Id=12, Name="Github Models", InitialHost=null, InitialSecret="ghp_yourkey", } + new(){ Id=0, Name="Test", InitialHost=null, InitialSecret=null, }, + new(){ Id=1, Name="Azure OpenAI", InitialHost="https://.openai.azure.com/", InitialSecret="", }, + new(){ Id=2, Name="Tencent Hunyuan", InitialHost="hunyuan.tencentcloudapi.com", InitialSecret="""{"secretId":"", "secretKey":""}""", }, + new(){ Id=3, Name="01.ai", InitialHost=null, InitialSecret="", }, + new(){ Id=4, Name="Moonshot", InitialHost=null, InitialSecret="", }, + new(){ Id=5, Name="OpenAI", InitialHost="https://api.openai.com/v1", InitialSecret="", }, + new(){ Id=6, Name="Wenxin Qianfan", InitialHost=null, InitialSecret="""{"apiKey":"", "secret":""}""", }, + new(){ Id=7, Name="DashScope", InitialHost=null, InitialSecret="", }, + new(){ Id=8, Name="Xunfei SparkDesk", InitialHost=null, InitialSecret="", }, + new(){ Id=9, Name="Zhipu AI", InitialHost=null, InitialSecret="", }, + new(){ Id=10, Name="DeepSeek", InitialHost=null, InitialSecret="", }, + new(){ Id=11, Name="x.ai", InitialHost=null, InitialSecret="xai-yourkey", }, + new(){ Id=12, Name="Github Models", InitialHost=null, InitialSecret="ghp_yourkey", } ]); } }; \ No newline at end of file diff --git a/src/BE/Services/ChatServices/ChatFactory.cs b/src/BE/Services/ChatServices/ChatFactory.cs index 611642f1..a08ab5e7 100644 --- a/src/BE/Services/ChatServices/ChatFactory.cs +++ b/src/BE/Services/ChatServices/ChatFactory.cs @@ -1,12 +1,7 @@ using Chats.BE.DB; using Chats.BE.DB.Enums; -using Chats.BE.Services.ChatServices.Implementations.Azure; using Chats.BE.Services.ChatServices.Implementations.DashScope; -using Chats.BE.Services.ChatServices.Implementations.DeepSeek; -using Chats.BE.Services.ChatServices.Implementations.GLM; using Chats.BE.Services.ChatServices.Implementations.Hunyuan; -using Chats.BE.Services.ChatServices.Implementations.Kimi; -using Chats.BE.Services.ChatServices.Implementations.LingYi; using Chats.BE.Services.ChatServices.Implementations.OpenAI; using Chats.BE.Services.ChatServices.Implementations.QianFan; using Chats.BE.Services.ChatServices.Implementations.Test; @@ -29,9 +24,11 @@ public ChatService CreateConversationService(Model model) DBModelProvider.ZhiPuAI => new GLMChatService(model), DBModelProvider.Moonshot => new KimiChatService(model), DBModelProvider.HunYuan => new HunyuanChatService(model), - DBModelProvider.Sparkdesk => throw new NotImplementedException("Spark model is not implemented"), + DBModelProvider.Sparkdesk => new SparkDeskChatService(model), DBModelProvider.LingYi => new LingYiChatService(model), DBModelProvider.DeepSeek => new DeepSeekChatService(model), + DBModelProvider.xAI => new XAIChatService(model), + DBModelProvider.GithubModels => new GithubModelsChatService(model), _ => throw new NotSupportedException($"Unknown model provider: {modelProvider}") }; return cs; diff --git a/src/BE/Services/ChatServices/ChatServiceExtensions.cs b/src/BE/Services/ChatServices/ChatServiceExtensions.cs index dc61f33f..5dcc9c11 100644 --- a/src/BE/Services/ChatServices/ChatServiceExtensions.cs +++ b/src/BE/Services/ChatServices/ChatServiceExtensions.cs @@ -9,7 +9,7 @@ public abstract partial class ChatService { public async IAsyncEnumerable ChatStreamedFEProcessed(IReadOnlyList messages, ChatCompletionOptions options, [EnumeratorCancellation] CancellationToken cancellationToken) { - ChatMessage[] filteredMessage = FEProcessMessages(messages, options); + ChatMessage[] filteredMessage = FEPreprocess(messages, options); await foreach (InternalChatSegment seg in ChatStreamedSimulated(suggestedStreaming: true, filteredMessage, options, cancellationToken)) { @@ -48,7 +48,7 @@ public async IAsyncEnumerable ChatStreamedSimulated(bool su } } - private ChatMessage[] FEProcessMessages(IReadOnlyList messages, ChatCompletionOptions options) + protected virtual ChatMessage[] FEPreprocess(IReadOnlyList messages, ChatCompletionOptions options) { if (!Model.ModelReference.AllowSystemPrompt) { @@ -66,10 +66,6 @@ private ChatMessage[] FEProcessMessages(IReadOnlyList messages, Cha } ChatMessage[] filteredMessage = messages.Select(m => FilterVision(Model.ModelReference.AllowVision, m)).ToArray(); - if (Model.ModelReference.AllowVision) - { - options.MaxOutputTokenCount ??= Model.ModelReference.MaxResponseTokens; - } if (!Model.ModelReference.AllowSearch) { options.RemoveAllowSearch(); diff --git a/src/BE/Services/ChatServices/Implementations/Azure/JsonAzureConfig.cs b/src/BE/Services/ChatServices/Implementations/Azure/JsonAzureConfig.cs deleted file mode 100644 index f3d80fb5..00000000 --- a/src/BE/Services/ChatServices/Implementations/Azure/JsonAzureConfig.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System.Text.Json; -using System.Text.Json.Serialization; - -namespace Chats.BE.Services.ChatServices.Implementations.Azure; - -public record JsonAzureApiConfig -{ - [JsonPropertyName("host")] - public required string Host { get; init; } - - [JsonPropertyName("apiKey")] - public required string ApiKey { get; init; } - - public static JsonAzureApiConfig Parse(string json) - { - return JsonSerializer.Deserialize(json)!; - } -} \ No newline at end of file diff --git a/src/BE/Services/ChatServices/Implementations/Azure/JsonAzureModelConfig.cs b/src/BE/Services/ChatServices/Implementations/Azure/JsonAzureModelConfig.cs deleted file mode 100644 index 15f77097..00000000 --- a/src/BE/Services/ChatServices/Implementations/Azure/JsonAzureModelConfig.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System.Text.Json.Serialization; - -namespace Chats.BE.Services.ChatServices.Implementations.Azure; - -public record JsonAzureModelConfig -{ - [JsonPropertyName("prompt")] - public required string Prompt { get; init; } - - [JsonPropertyName("temperature")] - public float? Temperature { get; init; } - - [JsonPropertyName("version")] - public string? Version { get; init; } - - [JsonPropertyName("deploymentName")] - public required string DeploymentName { get; init; } -} \ No newline at end of file diff --git a/src/BE/Services/ChatServices/Implementations/GLM/JsonGLMModelConfig.cs b/src/BE/Services/ChatServices/Implementations/GLM/JsonGLMModelConfig.cs deleted file mode 100644 index 818a9498..00000000 --- a/src/BE/Services/ChatServices/Implementations/GLM/JsonGLMModelConfig.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System.Text.Json.Serialization; - -namespace Chats.BE.Services.ChatServices.Implementations.GLM; - -public record JsonGLMModelConfig -{ - [JsonPropertyName("prompt")] - public required string Prompt { get; init; } - - [JsonPropertyName("temperature")] - public required double Temperature { get; init; } - - [JsonPropertyName("model")] - public required string Model { get; init; } -} diff --git a/src/BE/Services/ChatServices/Implementations/Hunyuan/JsonHunyuanModelConfig.cs b/src/BE/Services/ChatServices/Implementations/Hunyuan/JsonHunyuanModelConfig.cs deleted file mode 100644 index bb9853e5..00000000 --- a/src/BE/Services/ChatServices/Implementations/Hunyuan/JsonHunyuanModelConfig.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System.Text.Json.Serialization; - -namespace Chats.BE.Services.ChatServices.Implementations.Hunyuan; - -public record JsonHunyuanModelConfig -{ - [JsonPropertyName("prompt")] - public required string Prompt { get; init; } - - [JsonPropertyName("temperature")] - public required float? Temperature { get; init; } - - [JsonPropertyName("model")] - public required string Model { get; init; } -} \ No newline at end of file diff --git a/src/BE/Services/ChatServices/Implementations/Kimi/JsonKimiModelConfig.cs b/src/BE/Services/ChatServices/Implementations/Kimi/JsonKimiModelConfig.cs deleted file mode 100644 index 9e3e13df..00000000 --- a/src/BE/Services/ChatServices/Implementations/Kimi/JsonKimiModelConfig.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System.Text.Json.Serialization; - -namespace Chats.BE.Services.ChatServices.Implementations.Kimi; - -public record JsonKimiModelConfig -{ - [JsonPropertyName("prompt")] - public required string Prompt { get; init; } - - [JsonPropertyName("temperature")] - public required float Temperature { get; init; } -} diff --git a/src/BE/Services/ChatServices/Implementations/Azure/AzureChatService.cs b/src/BE/Services/ChatServices/Implementations/OpenAI/AzureChatService.cs similarity index 83% rename from src/BE/Services/ChatServices/Implementations/Azure/AzureChatService.cs rename to src/BE/Services/ChatServices/Implementations/OpenAI/AzureChatService.cs index 027532f6..d9c911d9 100644 --- a/src/BE/Services/ChatServices/Implementations/Azure/AzureChatService.cs +++ b/src/BE/Services/ChatServices/Implementations/OpenAI/AzureChatService.cs @@ -1,11 +1,10 @@ using Azure.AI.OpenAI; using Chats.BE.DB; -using Chats.BE.Services.ChatServices.Implementations.OpenAI; using OpenAI; using OpenAI.Chat; using System.ClientModel; -namespace Chats.BE.Services.ChatServices.Implementations.Azure; +namespace Chats.BE.Services.ChatServices.Implementations.OpenAI; public class AzureChatService(Model model) : OpenAIChatService(model, CreateChatClient(model)) { diff --git a/src/BE/Services/ChatServices/Implementations/DeepSeek/DeepSeekChatService.cs b/src/BE/Services/ChatServices/Implementations/OpenAI/DeepSeekChatService.cs similarity index 51% rename from src/BE/Services/ChatServices/Implementations/DeepSeek/DeepSeekChatService.cs rename to src/BE/Services/ChatServices/Implementations/OpenAI/DeepSeekChatService.cs index e178ebda..893faa92 100644 --- a/src/BE/Services/ChatServices/Implementations/DeepSeek/DeepSeekChatService.cs +++ b/src/BE/Services/ChatServices/Implementations/OpenAI/DeepSeekChatService.cs @@ -1,6 +1,5 @@ using Chats.BE.DB; -using Chats.BE.Services.ChatServices.Implementations.OpenAI; -namespace Chats.BE.Services.ChatServices.Implementations.DeepSeek; +namespace Chats.BE.Services.ChatServices.Implementations.OpenAI; public class DeepSeekChatService(Model model) : OpenAIChatService(model, new Uri("https://api.deepseek.com/v1")); \ No newline at end of file diff --git a/src/BE/Services/ChatServices/Implementations/GLM/GLMChatService.cs b/src/BE/Services/ChatServices/Implementations/OpenAI/GLMChatService.cs similarity index 54% rename from src/BE/Services/ChatServices/Implementations/GLM/GLMChatService.cs rename to src/BE/Services/ChatServices/Implementations/OpenAI/GLMChatService.cs index 088451e0..0e62e4dc 100644 --- a/src/BE/Services/ChatServices/Implementations/GLM/GLMChatService.cs +++ b/src/BE/Services/ChatServices/Implementations/OpenAI/GLMChatService.cs @@ -1,7 +1,6 @@ using Chats.BE.DB; -using Chats.BE.Services.ChatServices.Implementations.OpenAI; -namespace Chats.BE.Services.ChatServices.Implementations.GLM; +namespace Chats.BE.Services.ChatServices.Implementations.OpenAI; public class GLMChatService(Model model) : OpenAIChatService(model, new Uri("https://open.bigmodel.cn/api/paas/v4/")) { diff --git a/src/BE/Services/ChatServices/Implementations/OpenAI/GithubModelsChatService.cs b/src/BE/Services/ChatServices/Implementations/OpenAI/GithubModelsChatService.cs new file mode 100644 index 00000000..6a948c36 --- /dev/null +++ b/src/BE/Services/ChatServices/Implementations/OpenAI/GithubModelsChatService.cs @@ -0,0 +1,5 @@ +using Chats.BE.DB; + +namespace Chats.BE.Services.ChatServices.Implementations.OpenAI; + +public class GithubModelsChatService(Model model) : OpenAIChatService(model, new Uri("https://models.inference.ai.azure.com")); \ No newline at end of file diff --git a/src/BE/Services/ChatServices/Implementations/OpenAI/JsonOpenAIModelConfig.cs b/src/BE/Services/ChatServices/Implementations/OpenAI/JsonOpenAIModelConfig.cs deleted file mode 100644 index 44e4d4a1..00000000 --- a/src/BE/Services/ChatServices/Implementations/OpenAI/JsonOpenAIModelConfig.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System.Text.Json.Serialization; - -namespace Chats.BE.Services.ChatServices.Implementations.OpenAI; - -public record JsonOpenAIModelConfig -{ - [JsonPropertyName("prompt")] - public required string Prompt { get; init; } - - [JsonPropertyName("temperature")] - public float? Temperature { get; init; } - - [JsonPropertyName("model")] - public required string DeploymentName { get; init; } -} \ No newline at end of file diff --git a/src/BE/Services/ChatServices/Implementations/Kimi/KimiChatService.cs b/src/BE/Services/ChatServices/Implementations/OpenAI/KimiChatService.cs similarity index 51% rename from src/BE/Services/ChatServices/Implementations/Kimi/KimiChatService.cs rename to src/BE/Services/ChatServices/Implementations/OpenAI/KimiChatService.cs index c0a6c907..b909ee68 100644 --- a/src/BE/Services/ChatServices/Implementations/Kimi/KimiChatService.cs +++ b/src/BE/Services/ChatServices/Implementations/OpenAI/KimiChatService.cs @@ -1,6 +1,5 @@ using Chats.BE.DB; -using Chats.BE.Services.ChatServices.Implementations.OpenAI; -namespace Chats.BE.Services.ChatServices.Implementations.Kimi; +namespace Chats.BE.Services.ChatServices.Implementations.OpenAI; public class KimiChatService(Model model) : OpenAIChatService(model, new Uri("https://api.moonshot.cn/v1")); \ No newline at end of file diff --git a/src/BE/Services/ChatServices/Implementations/LingYi/LingYiChatService.cs b/src/BE/Services/ChatServices/Implementations/OpenAI/LingYiChatService.cs similarity index 52% rename from src/BE/Services/ChatServices/Implementations/LingYi/LingYiChatService.cs rename to src/BE/Services/ChatServices/Implementations/OpenAI/LingYiChatService.cs index d777fd27..7380a7fd 100644 --- a/src/BE/Services/ChatServices/Implementations/LingYi/LingYiChatService.cs +++ b/src/BE/Services/ChatServices/Implementations/OpenAI/LingYiChatService.cs @@ -1,6 +1,5 @@ using Chats.BE.DB; -using Chats.BE.Services.ChatServices.Implementations.OpenAI; -namespace Chats.BE.Services.ChatServices.Implementations.LingYi; +namespace Chats.BE.Services.ChatServices.Implementations.OpenAI; public class LingYiChatService(Model model) : OpenAIChatService(model, new Uri("https://api.lingyiwanwu.com/v1")); diff --git a/src/BE/Services/ChatServices/Implementations/OpenAI/SparkDeskChatService.cs b/src/BE/Services/ChatServices/Implementations/OpenAI/SparkDeskChatService.cs new file mode 100644 index 00000000..99167ed5 --- /dev/null +++ b/src/BE/Services/ChatServices/Implementations/OpenAI/SparkDeskChatService.cs @@ -0,0 +1,18 @@ +using Chats.BE.DB; +using OpenAI.Chat; + +namespace Chats.BE.Services.ChatServices.Implementations.OpenAI; + +public class SparkDeskChatService(Model model) : OpenAIChatService(model, new Uri("https://spark-api-open.xf-yun.com/v1")) +{ + protected override ChatMessage[] FEPreprocess(IReadOnlyList messages, ChatCompletionOptions options) + { + ChatMessage[] toReturn = base.FEPreprocess(messages, options); + // spark desk enable search is set via tool https://www.xfyun.cn/doc/spark/HTTP%E8%B0%83%E7%94%A8%E6%96%87%E6%A1%A3.html#_3-%E8%AF%B7%E6%B1%82%E8%AF%B4%E6%98%8E + // however unfortunately the tool is not available in OpenAI SDK + // otherwise, the code should be: + // bool enableSearch = options.IsSearchEnabled(); + // options.Tools.Add(MakeSparkDeskSearchTool(enableSearch)); + return toReturn; + } +} \ No newline at end of file diff --git a/src/BE/Services/ChatServices/Implementations/OpenAI/XAIChatService.cs b/src/BE/Services/ChatServices/Implementations/OpenAI/XAIChatService.cs new file mode 100644 index 00000000..338018ab --- /dev/null +++ b/src/BE/Services/ChatServices/Implementations/OpenAI/XAIChatService.cs @@ -0,0 +1,5 @@ +using Chats.BE.DB; + +namespace Chats.BE.Services.ChatServices.Implementations.OpenAI; + +public class XAIChatService(Model model) : OpenAIChatService(model, new Uri("https://api.x.ai/v1")); \ No newline at end of file diff --git a/src/scripts/db-migration/2024/20241211-xai-githubmodels.sql b/src/scripts/db-migration/2024/20241211-xai-githubmodels.sql index b40fc861..f9e00fb9 100644 --- a/src/scripts/db-migration/2024/20241211-xai-githubmodels.sql +++ b/src/scripts/db-migration/2024/20241211-xai-githubmodels.sql @@ -1,5 +1,6 @@ insert into ModelProvider values(11, 'x.ai', NULL, 'xai-yourkey'); insert into ModelProvider values(12, 'Github Models', NULL, 'ghp_yourkey'); +update ModelProvider set InitialSecret = '' where id = 8; insert into ModelReference values (1100, 11, 'grok-beta', 'grok', 0, 0, 2, 0, 0, 1, 1, 131072, 4096, NULL, 5, 15, 'USD'),