Browse Source

feat: Add Chat interface implementation

pull/1421/head
colin 1 week ago
parent
commit
01e61c29a6
  1. 14
      aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Application.Contracts/LINGYUN/Abp/AIManagement/Chats/Dtos/ChatMessageDto.cs
  2. 19
      aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Application.Contracts/LINGYUN/Abp/AIManagement/Chats/Dtos/SendTextChatMessageDto.cs
  3. 8
      aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Application.Contracts/LINGYUN/Abp/AIManagement/Chats/Dtos/TextChatMessageDto.cs
  4. 9
      aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Application.Contracts/LINGYUN/Abp/AIManagement/Chats/IChatAppService.cs
  5. 28
      aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Application/LINGYUN/Abp/AIManagement/Chats/ChatAppService.cs
  6. 30
      aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain/FodyWeavers.xsd
  7. 2
      aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain/LINGYUN.Abp.AIManagement.Domain.csproj
  8. 14
      aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain/LINGYUN/Abp/AIManagement/AbpAIManagementDomainModule.cs
  9. 41
      aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.HttpApi/LINGYUN/Abp/AIManagement/AbpAIManagementHttpApiModule.cs
  10. 30
      aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.HttpApi/LINGYUN/Abp/AIManagement/Chats/ChatController.cs
  11. 42
      aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.HttpApi/Microsoft/AspNetCore/Mvc/SseAsyncEnumerableResult.cs
  12. 18
      aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.HttpApi/Microsoft/AspNetCore/Mvc/SseAsyncEnumerableResultFilter.cs

14
aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Application.Contracts/LINGYUN/Abp/AIManagement/Chats/Dtos/ChatMessageDto.cs

@ -0,0 +1,14 @@
using System;
using Volo.Abp.Application.Dtos;
namespace LINGYUN.Abp.AIManagement.Chats.Dtos;
public abstract class ChatMessageDto : ExtensibleAuditedEntityDto<Guid>
{
public string Workspace { get; set; }
public DateTime CreatedAt { get; set; }
public Guid? UserId { get; set; }
public Guid? ConversationId { get; set; }
}

19
aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Application.Contracts/LINGYUN/Abp/AIManagement/Chats/Dtos/SendTextChatMessageDto.cs

@ -0,0 +1,19 @@
using LINGYUN.Abp.AIManagement.Workspaces;
using System;
using System.ComponentModel.DataAnnotations;
using Volo.Abp.Validation;
namespace LINGYUN.Abp.AIManagement.Chats.Dtos;
public class SendTextChatMessageDto
{
[Required]
[DynamicStringLength(typeof(WorkspaceDefinitionRecordConsts), nameof(WorkspaceDefinitionRecordConsts.MaxNameLength))]
public string Workspace { get; set; }
[Required]
public Guid ConversationId { get; set; }
[Required]
[DynamicStringLength(typeof(TextChatMessageRecordConsts), nameof(TextChatMessageRecordConsts.MaxContentLength))]
public string Content { get; set; }
}

8
aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Application.Contracts/LINGYUN/Abp/AIManagement/Chats/Dtos/TextChatMessageDto.cs

@ -0,0 +1,8 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace LINGYUN.Abp.AIManagement.Chats.Dtos;
public class TextChatMessageDto
{
}

9
aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Application.Contracts/LINGYUN/Abp/AIManagement/Chats/IChatAppService.cs

@ -0,0 +1,9 @@
using LINGYUN.Abp.AIManagement.Chats.Dtos;
using System.Collections.Generic;
using Volo.Abp.Application.Services;
namespace LINGYUN.Abp.AIManagement.Chats;
public interface IChatAppService : IApplicationService
{
IAsyncEnumerable<string> SendMessageAsync(SendTextChatMessageDto input);
}

28
aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Application/LINGYUN/Abp/AIManagement/Chats/ChatAppService.cs

@ -0,0 +1,28 @@
using LINGYUN.Abp.AI.Agent;
using LINGYUN.Abp.AI.Models;
using LINGYUN.Abp.AIManagement.Chats.Dtos;
using Microsoft.Extensions.AI;
using System.Collections.Generic;
namespace LINGYUN.Abp.AIManagement.Chats;
public class ChatAppService : AIManagementApplicationServiceBase, IChatAppService
{
private readonly IAgentService _agentService;
public ChatAppService(IAgentService agentService)
{
_agentService = agentService;
}
public IAsyncEnumerable<string> SendMessageAsync(SendTextChatMessageDto input)
{
var chatMessage = new TextChatMessage(
input.Workspace,
input.Content,
ChatRole.User,
Clock.Now);
chatMessage.WithConversationId(input.ConversationId);
return _agentService.SendMessageAsync(chatMessage);
}
}

30
aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain/FodyWeavers.xsd

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. -->
<xs:element name="Weavers">
<xs:complexType>
<xs:all>
<xs:element name="ConfigureAwait" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:attribute name="ContinueOnCapturedContext" type="xs:boolean" />
</xs:complexType>
</xs:element>
</xs:all>
<xs:attribute name="VerifyAssembly" type="xs:boolean">
<xs:annotation>
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="VerifyIgnoreCodes" type="xs:string">
<xs:annotation>
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="GenerateXsd" type="xs:boolean">
<xs:annotation>
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:schema>

2
aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain/LINGYUN.Abp.AIManagement.Domain.csproj

@ -23,7 +23,7 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\LINGYUN.Abp.AI.Core\LINGYUN.Abp.AI.Core.csproj" />
<ProjectReference Include="..\LINGYUN.Abp.AI.Agent\LINGYUN.Abp.AI.Agent.csproj" />
<ProjectReference Include="..\LINGYUN.Abp.AIManagement.Domain.Shared\LINGYUN.Abp.AIManagement.Domain.Shared.csproj" />
</ItemGroup>

14
aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain/LINGYUN/Abp/AIManagement/AbpAIManagementDomainModule.cs

@ -1,4 +1,6 @@
using LINGYUN.Abp.AI;
using LINGYUN.Abp.AI.Agent;
using LINGYUN.Abp.AI.Localization;
using LINGYUN.Abp.AIManagement.Localization;
using LINGYUN.Abp.AIManagement.Workspaces;
using Microsoft.Extensions.DependencyInjection;
using System.Threading;
@ -8,6 +10,7 @@ using Volo.Abp.Caching;
using Volo.Abp.Data;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Domain;
using Volo.Abp.Localization;
using Volo.Abp.Mapperly;
using Volo.Abp.Modularity;
using Volo.Abp.Threading;
@ -16,7 +19,7 @@ namespace LINGYUN.Abp.AIManagement;
[DependsOn(
typeof(AbpAIManagementDomainSharedModule),
typeof(AbpAICoreModule),
typeof(AbpAIAgentModule),
typeof(AbpCachingModule),
typeof(AbpMapperlyModule),
typeof(AbpDddDomainModule))]
@ -37,6 +40,13 @@ public class AbpAIManagementDomainModule : AbpModule
options.IsDynamicWorkspaceStoreEnabled = false;
});
}
Configure<AbpLocalizationOptions>(options =>
{
options.Resources
.Get<AIManagementResource>()
.AddBaseTypes(typeof(AbpAIResource));
});
}
public override void OnApplicationInitialization(ApplicationInitializationContext context)

41
aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.HttpApi/LINGYUN/Abp/AIManagement/AbpAIManagementHttpApiModule.cs

@ -0,0 +1,41 @@
using LINGYUN.Abp.AIManagement.Localization;
using Localization.Resources.AbpUi;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.AspNetCore.Mvc;
using Volo.Abp.AspNetCore.Mvc.Localization;
using Volo.Abp.Localization;
using Volo.Abp.Modularity;
namespace LINGYUN.Abp.AIManagement;
[DependsOn(
typeof(AbpAIManagementApplicationContractsModule),
typeof(AbpAspNetCoreMvcModule))]
public class AbpAIManagementHttpApiModule : AbpModule
{
public override void PreConfigureServices(ServiceConfigurationContext context)
{
PreConfigure<AbpMvcDataAnnotationsLocalizationOptions>(options =>
{
options.AddAssemblyResource(typeof(AIManagementResource), typeof(AbpAIManagementApplicationContractsModule).Assembly);
});
PreConfigure<IMvcBuilder>(mvcBuilder =>
{
mvcBuilder.AddApplicationPartIfNotExists(typeof(AbpAIManagementHttpApiModule).Assembly);
});
}
public override void ConfigureServices(ServiceConfigurationContext context)
{
Configure<AbpLocalizationOptions>(options =>
{
options.Resources
.Get<AIManagementResource>()
.AddBaseTypes(typeof(AbpUiResource));
});
context.Services.AddTransient<SseAsyncEnumerableResultFilter>();
}
}

30
aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.HttpApi/LINGYUN/Abp/AIManagement/Chats/ChatController.cs

@ -0,0 +1,30 @@
using LINGYUN.Abp.AIManagement.Chats.Dtos;
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
using Volo.Abp;
using Volo.Abp.AspNetCore.Mvc;
namespace LINGYUN.Abp.AIManagement.Chats;
[Controller]
[RemoteService(Name = AIManagementRemoteServiceConsts.RemoteServiceName)]
[Area(AIManagementRemoteServiceConsts.ModuleName)]
[Route($"api/{AIManagementRemoteServiceConsts.ModuleName}/chats")]
public class ChatController : AbpControllerBase, IChatAppService
{
private readonly IChatAppService _service;
public ChatController(IChatAppService service)
{
_service = service;
}
[HttpPost]
[ServiceFilter<SseAsyncEnumerableResultFilter>]
public async virtual IAsyncEnumerable<string> SendMessageAsync(SendTextChatMessageDto input)
{
await foreach (var content in _service.SendMessageAsync(input))
{
yield return content;
}
}
}

42
aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.HttpApi/Microsoft/AspNetCore/Mvc/SseAsyncEnumerableResult.cs

@ -0,0 +1,42 @@
using Microsoft.AspNetCore.Http;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace Microsoft.AspNetCore.Mvc;
public class SseAsyncEnumerableResult : IActionResult
{
private readonly IAsyncEnumerable<string> _asyncEnumerable;
public SseAsyncEnumerableResult(IAsyncEnumerable<string> asyncEnumerable)
{
_asyncEnumerable = asyncEnumerable;
}
public async Task ExecuteResultAsync(ActionContext context)
{
var response = context.HttpContext.Response;
response.Headers.Append("Content-Type", "text/event-stream");
response.Headers.Append("Cache-Control", "no-cache");
response.Headers.Append("Connection", "keep-alive");
response.Headers.Append("X-Accel-Buffering", "no");
try
{
await foreach (var content in _asyncEnumerable)
{
if (!string.IsNullOrEmpty(content))
{
await response.WriteAsync($"data: {content}\n\n");
await response.Body.FlushAsync();
}
}
await response.WriteAsync("data: [DONE]\n\n");
await response.Body.FlushAsync();
}
catch (OperationCanceledException)
{
// ignore
}
}
}

18
aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.HttpApi/Microsoft/AspNetCore/Mvc/SseAsyncEnumerableResultFilter.cs

@ -0,0 +1,18 @@
using Microsoft.AspNetCore.Mvc.Filters;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace Microsoft.AspNetCore.Mvc;
public class SseAsyncEnumerableResultFilter : IAsyncActionFilter
{
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
var executedContext = await next();
if (executedContext.Result is ObjectResult objectResult &&
objectResult.Value is IAsyncEnumerable<string> asyncEnumerable)
{
executedContext.Result = new SseAsyncEnumerableResult(asyncEnumerable);
}
}
}
Loading…
Cancel
Save