diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/MessageInputDto.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/MessageInputDto.cs
index 8c01b62c..2ce6c8fb 100644
--- a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/MessageInputDto.cs
+++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/MessageInputDto.cs
@@ -5,7 +5,7 @@ namespace Yi.Framework.AiHub.Application.Contracts.Dtos;
public class MessageInputDto
{
- public string Content { get; set; }
+ public string? Content { get; set; }
public string Role { get; set; }
public string ModelId { get; set; }
public string? Remark { get; set; }
diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/OpenAi/ChatCompletionsInput.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/OpenAi/ChatCompletionsInput.cs
index 6a2073d2..c75e604f 100644
--- a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/OpenAi/ChatCompletionsInput.cs
+++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/OpenAi/ChatCompletionsInput.cs
@@ -9,9 +9,9 @@ public class ChatCompletionsInput
public string? Prompt { get; set; }
public string Model { get; set; }
- public decimal Temperature { get; set; }
+ public decimal? Temperature { get; set; }
- public int max_tokens { get; set; }
+ public int? max_tokens { get; set; }
}
public class OpenAiMessage
diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/SendMessageOutputDto.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/SendMessageOutputDto.cs
index 542e7f55..7b73c9ee 100644
--- a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/SendMessageOutputDto.cs
+++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/SendMessageOutputDto.cs
@@ -56,7 +56,7 @@ public class Choice
///
/// 结束原因,可能为空
///
- public string FinishReason { get; set; }
+ public string? FinishReason { get; set; }
///
/// 内容过滤结果
diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application/Services/AiChatService.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application/Services/AiChatService.cs
index 278a4997..5508d6de 100644
--- a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application/Services/AiChatService.cs
+++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application/Services/AiChatService.cs
@@ -126,7 +126,7 @@ public class AiChatService : ApplicationService
}
//ai网关代理httpcontext
- await _aiGateWayManager.CompleteChatForHttpContextAsync(_httpContextAccessor.HttpContext, input.Model, history,
+ await _aiGateWayManager.CompleteChatStreamForStatisticsAsync(_httpContextAccessor.HttpContext, input.Model, history,
CurrentUser.Id, input.SessionId, cancellationToken);
}
}
\ No newline at end of file
diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application/Services/OpenApiService.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application/Services/OpenApiService.cs
index 9c6c687c..3f0c443f 100644
--- a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application/Services/OpenApiService.cs
+++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application/Services/OpenApiService.cs
@@ -55,9 +55,18 @@ public class OpenApiService : ApplicationService
}
}
- //ai网关代理httpcontext
- await _aiGateWayManager.CompleteChatForHttpContextAsync(_httpContextAccessor.HttpContext, input.Model, history,
- userId, null, cancellationToken);
+ if (input.Stream)
+ {
+ //ai网关代理httpcontext
+ await _aiGateWayManager.CompleteChatStreamForStatisticsAsync(_httpContextAccessor.HttpContext, input.Model,
+ history,
+ userId, null, cancellationToken);
+ }
+ else
+ {
+ await _aiGateWayManager.CompleteChatForStatisticsAsync(_httpContextAccessor.HttpContext,input.Model, history, userId, null,
+ cancellationToken);
+ }
}
///
@@ -76,7 +85,7 @@ public class OpenApiService : ApplicationService
Owned_by = "organization-owner",
Permission = new List()
}).ToListAsync();
-
+
return new ModelGetOutput()
{
Data = data
diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/AiChat/IChatService.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/AiChat/IChatService.cs
index 6bd0b422..fa023149 100644
--- a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/AiChat/IChatService.cs
+++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/AiChat/IChatService.cs
@@ -5,6 +5,23 @@ namespace Yi.Framework.AiHub.Domain.AiChat;
public interface IChatService
{
- public IAsyncEnumerable CompleteChatAsync(AiModelDescribe aiModelDescribe, List messages,
+ ///
+ /// 聊天完成-流式
+ ///
+ ///
+ ///
+ ///
+ ///
+ public IAsyncEnumerable CompleteChatStreamAsync(AiModelDescribe aiModelDescribe, List messages,
+ CancellationToken cancellationToken);
+
+ ///
+ /// 聊天完成-非流式
+ ///
+ ///
+ ///
+ ///
+ ///
+ public Task CompleteChatAsync(AiModelDescribe aiModelDescribe, List messages,
CancellationToken cancellationToken);
}
\ No newline at end of file
diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/AiChat/Impl/AzureChatService.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/AiChat/Impl/AzureChatService.cs
index efa7b790..a4853c68 100644
--- a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/AiChat/Impl/AzureChatService.cs
+++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/AiChat/Impl/AzureChatService.cs
@@ -12,7 +12,7 @@ public class AzureChatService : IChatService
{
}
- public async IAsyncEnumerable CompleteChatAsync(AiModelDescribe aiModelDescribe,
+ public async IAsyncEnumerable CompleteChatStreamAsync(AiModelDescribe aiModelDescribe,
List messages,
[EnumeratorCancellation] CancellationToken cancellationToken)
{
@@ -62,4 +62,41 @@ public class AzureChatService : IChatService
}
}
}
+
+ public async Task CompleteChatAsync(AiModelDescribe aiModelDescribe,
+ List messages, CancellationToken cancellationToken)
+ {
+ var endpoint = new Uri(aiModelDescribe.Endpoint);
+
+ var deploymentName = aiModelDescribe.ModelId;
+ var apiKey = aiModelDescribe.ApiKey;
+
+ AzureOpenAIClient azureClient = new(
+ endpoint,
+ new AzureKeyCredential(apiKey), new AzureOpenAIClientOptions()
+ {
+ NetworkTimeout = TimeSpan.FromSeconds(600),
+ });
+
+ ChatClient chatClient = azureClient.GetChatClient(deploymentName);
+
+ var response = await chatClient.CompleteChatAsync(messages, new ChatCompletionOptions()
+ {
+ // MaxOutputTokenCount = 2048
+ }, cancellationToken: cancellationToken);
+
+ var output = new CompleteChatResponse
+ {
+ TokenUsage = new TokenUsage()
+ {
+ OutputTokenCount = response?.Value.Usage?.OutputTokenCount ?? 0,
+ InputTokenCount = response?.Value.Usage?.InputTokenCount ?? 0,
+ TotalTokenCount = response?.Value.Usage?.TotalTokenCount ?? 0
+ },
+ IsFinish = true,
+ Content = response?.Value.Content.FirstOrDefault()?.Text
+ };
+
+ return output;
+ }
}
\ No newline at end of file
diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/AiChat/Impl/AzureRestChatService.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/AiChat/Impl/AzureRestChatService.cs
index 3bf78c77..efe13e75 100644
--- a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/AiChat/Impl/AzureRestChatService.cs
+++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/AiChat/Impl/AzureRestChatService.cs
@@ -14,7 +14,7 @@ public class AzureRestChatService : IChatService
{
}
- public async IAsyncEnumerable CompleteChatAsync(AiModelDescribe aiModelDescribe,
+ public async IAsyncEnumerable CompleteChatStreamAsync(AiModelDescribe aiModelDescribe,
List messages,
[EnumeratorCancellation] CancellationToken cancellationToken)
{
@@ -98,6 +98,11 @@ public class AzureRestChatService : IChatService
}
}
+ public Task CompleteChatAsync(AiModelDescribe aiModelDescribe, List messages, CancellationToken cancellationToken)
+ {
+ throw new NotImplementedException("暂未实现");
+ }
+
private JObject? MapToJObject(string line)
{
if (line == "data: [DONE]"||string.IsNullOrWhiteSpace(line) )
diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Managers/AiGateWayManager.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Managers/AiGateWayManager.cs
index 7692af44..b3f9041b 100644
--- a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Managers/AiGateWayManager.cs
+++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Managers/AiGateWayManager.cs
@@ -66,23 +66,78 @@ public class AiGateWayManager : DomainService
///
- /// 聊天完成
+ /// 聊天完成-流式
///
///
///
///
///
- public async IAsyncEnumerable CompleteChatAsync(string modelId, List messages,
+ public async IAsyncEnumerable CompleteChatStreamAsync(string modelId,
+ List messages,
[EnumeratorCancellation] CancellationToken cancellationToken)
{
var modelDescribe = await GetModelAsync(modelId);
var chatService = LazyServiceProvider.GetRequiredKeyedService(modelDescribe.HandlerName);
- await foreach (var result in chatService.CompleteChatAsync(modelDescribe, messages, cancellationToken))
+ await foreach (var result in chatService.CompleteChatStreamAsync(modelDescribe, messages, cancellationToken))
{
yield return result;
}
}
+
+ ///
+ /// 聊天完成-非流式
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public async Task CompleteChatForStatisticsAsync(HttpContext httpContext, string modelId,
+ List messages,
+ Guid? userId = null,
+ Guid? sessionId = null,
+ CancellationToken cancellationToken = default)
+ {
+ var response = httpContext.Response;
+ // 设置响应头,声明是 json
+ response.ContentType = "application/json; charset=UTF-8";
+ await using var writer = new StreamWriter(response.Body, Encoding.UTF8, leaveOpen: true);
+ var modelDescribe = await GetModelAsync(modelId);
+ var chatService = LazyServiceProvider.GetRequiredKeyedService(modelDescribe.HandlerName);
+ var output = await chatService.CompleteChatAsync(modelDescribe, messages, cancellationToken);
+ if (userId is not null)
+ {
+ await _aiMessageManager.CreateUserMessageAsync(userId.Value, sessionId,
+ new MessageInputDto
+ {
+ Content = messages.LastOrDefault().Content.FirstOrDefault()?.Text ?? string.Empty,
+ ModelId = modelId,
+ TokenUsage = output.TokenUsage,
+ });
+
+ await _aiMessageManager.CreateSystemMessageAsync(userId.Value, sessionId,
+ new MessageInputDto
+ {
+ Content = output.Content,
+ ModelId = modelId,
+ TokenUsage = output.TokenUsage
+ });
+
+ await _usageStatisticsManager.SetUsageAsync(userId.Value, modelId, output.TokenUsage.InputTokenCount,
+ output.TokenUsage.OutputTokenCount);
+ }
+
+ var body = JsonConvert.SerializeObject(output, new JsonSerializerSettings
+ {
+ ContractResolver = new CamelCasePropertyNamesContractResolver()
+ });
+ await writer.WriteLineAsync(body);
+ await writer.FlushAsync(cancellationToken);
+ }
+
///
/// 聊天完成-缓存处理
///
@@ -93,7 +148,7 @@ public class AiGateWayManager : DomainService
///
///
///
- public async Task CompleteChatForHttpContextAsync(
+ public async Task CompleteChatStreamForStatisticsAsync(
HttpContext httpContext,
string modelId,
List messages,
@@ -109,7 +164,7 @@ public class AiGateWayManager : DomainService
var gateWay = LazyServiceProvider.GetRequiredService();
- var completeChatResponse = gateWay.CompleteChatAsync(modelId, messages, cancellationToken);
+ var completeChatResponse = gateWay.CompleteChatStreamAsync(modelId, messages, cancellationToken);
var tokenUsage = new TokenUsage();
await using var writer = new StreamWriter(response.Body, Encoding.UTF8, leaveOpen: true);