last ...
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
using AutoMapper;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using xAiApi.AI.Interfaces;
|
||||
using xAiApi.AI.Mppings;
|
||||
using xAiApi.AI.Services;
|
||||
|
||||
namespace xAiApi.AI.DI
|
||||
@@ -16,7 +18,17 @@ namespace xAiApi.AI.DI
|
||||
)
|
||||
{
|
||||
//
|
||||
// Register AutoMapper Using Mapping Profiles ...
|
||||
services.AddAutoMapper(typeof(MappingProfiles).Assembly);
|
||||
|
||||
//
|
||||
// TODO: Remove this ...
|
||||
services.AddSingleton<IXAIService, XAIService>();
|
||||
|
||||
//
|
||||
// Since we Used Repositories in this Service,
|
||||
// we have to Register it Scoped Lifetime ...
|
||||
services.AddScoped<IXAiProvider, XAiProvider>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
@@ -21,7 +20,7 @@ namespace xAiApi.AI.Interfaces
|
||||
/// </summary>
|
||||
/// <value></value>
|
||||
public XAiApiConfiguration Configuration { get; }
|
||||
|
||||
|
||||
//
|
||||
#region Helpers ...
|
||||
/// <summary>
|
||||
@@ -161,6 +160,8 @@ namespace xAiApi.AI.Interfaces
|
||||
);
|
||||
#endregion
|
||||
|
||||
//
|
||||
#region Actions ...
|
||||
/// <summary>
|
||||
/// Ask a Question ...
|
||||
/// </summary>
|
||||
@@ -177,5 +178,23 @@ namespace xAiApi.AI.Interfaces
|
||||
XUserClaimsInfoDto userInfo = null,
|
||||
CancellationToken cancellationToken = default
|
||||
);
|
||||
|
||||
/// <summary>
|
||||
/// Ask a Question in Streaming ...
|
||||
/// </summary>
|
||||
/// <param name="prompt"></param>
|
||||
/// <param name="projectId"></param>
|
||||
/// <param name="conversationId"></param>
|
||||
/// <param name="userInfo"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
IAsyncEnumerable<XAiMessageUpdateDto> AskStream(
|
||||
string prompt,
|
||||
string projectId = null,
|
||||
string conversationId = null,
|
||||
XUserClaimsInfoDto userInfo = null,
|
||||
CancellationToken cancellationToken = default
|
||||
);
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.Extensions.AI;
|
||||
using xAiModels.Models;
|
||||
using xCommons.Extensions;
|
||||
using xModels.Base;
|
||||
|
||||
namespace xAiApi.AI.Models.Dtos
|
||||
{
|
||||
public class XAiRequirementDto : XBaseDto
|
||||
{
|
||||
/// <summary>
|
||||
/// Prepared Ai Project ...
|
||||
/// if Exists one Using Project ID,
|
||||
/// if not Created Default Project ...
|
||||
/// </summary>
|
||||
public XAiProjectDto AiProject { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Prepared Ai Conversation ...
|
||||
/// if Exists one Using Conversation ID,
|
||||
/// if not Created new Conversation ...
|
||||
/// </summary>
|
||||
public XAiConversationDto AiConversation { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Prepared Chat History for Asking ...
|
||||
/// including Asked Prompt ...
|
||||
/// </summary>
|
||||
public IList<ChatMessage> ChatHistory { get; set; } = new List<ChatMessage>();
|
||||
|
||||
/// <summary>
|
||||
/// Check User has Permission on
|
||||
/// Project, Conversation and LLM Usages also ...
|
||||
/// </summary>
|
||||
public bool HasPermission { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Check Ai Project is Default Project of Specified User or not ...
|
||||
/// Default Project is Main Conversations Contains ...
|
||||
/// </summary>
|
||||
public bool IsDefaultProject { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Check Ai Conversations is New Conversation or not ...
|
||||
/// </summary>
|
||||
public bool IsFirstConversation { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Check Model is Validate or not ...
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public bool IsValid()
|
||||
{
|
||||
//
|
||||
var result =
|
||||
HasPermission &&
|
||||
!AiProject.IsNullOrDefault() &&
|
||||
!AiConversation.IsNullOrDefault();
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
using AutoMapper;
|
||||
using xAiApi.AI.Models.Entities;
|
||||
using xAiModels.Models;
|
||||
|
||||
namespace xAiApi.AI.Mppings
|
||||
{
|
||||
public class MappingProfiles : Profile
|
||||
{
|
||||
public MappingProfiles()
|
||||
{
|
||||
//
|
||||
#region Entity to Dto ...
|
||||
//
|
||||
CreateMap<XAiProject, XAiProjectDto>()
|
||||
.ForMember(
|
||||
x => x.Owner,
|
||||
opt => opt.MapFrom<XAiProjectOwnerMappingResolver>()
|
||||
);
|
||||
|
||||
//
|
||||
CreateMap<XAiMessage, XAiMessageDto>()
|
||||
.ForMember(
|
||||
x => x.Owner,
|
||||
opt => opt.MapFrom<XAiMessageOwnerMappingResolver>()
|
||||
);
|
||||
|
||||
//
|
||||
CreateMap<XAiConversation, XAiConversationDto>()
|
||||
.ForMember(
|
||||
x => x.Owner,
|
||||
opt => opt.MapFrom<XAiConversationOwnerMappingResolver>()
|
||||
);
|
||||
#endregion
|
||||
|
||||
//
|
||||
#region Dto to Entity ...
|
||||
CreateMap<XAiProjectDto, XAiProject>();
|
||||
CreateMap<XAiMessageDto, XAiMessage>();
|
||||
CreateMap<XAiConversationDto, XAiConversation>();
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
using xAiApi.AI.Models.Entities;
|
||||
using xAiModels.Models;
|
||||
using xIdentityService.Interfaces;
|
||||
|
||||
namespace xAiApi.AI.Mppings
|
||||
{
|
||||
public class XAiConversationOwnerMappingResolver : XBaseOwnerMappingResolver<XAiConversation, XAiConversationDto>
|
||||
{
|
||||
public XAiConversationOwnerMappingResolver(
|
||||
IXIdentityProvider identityProvider
|
||||
) : base(identityProvider)
|
||||
{ }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
using xAiApi.AI.Models.Entities;
|
||||
using xAiModels.Models;
|
||||
using xIdentityService.Interfaces;
|
||||
|
||||
namespace xAiApi.AI.Mppings
|
||||
{
|
||||
public class XAiMessageOwnerMappingResolver : XBaseOwnerMappingResolver<XAiMessage, XAiMessageDto>
|
||||
{
|
||||
public XAiMessageOwnerMappingResolver(
|
||||
IXIdentityProvider identityProvider
|
||||
) : base(identityProvider)
|
||||
{ }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
using xAiApi.AI.Models.Entities;
|
||||
using xAiModels.Models;
|
||||
using xIdentityService.Interfaces;
|
||||
|
||||
namespace xAiApi.AI.Mppings
|
||||
{
|
||||
public class XAiProjectOwnerMappingResolver : XBaseOwnerMappingResolver<XAiProject, XAiProjectDto>
|
||||
{
|
||||
public XAiProjectOwnerMappingResolver(
|
||||
IXIdentityProvider identityProvider
|
||||
) : base(identityProvider)
|
||||
{ }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
using AutoMapper;
|
||||
using xModels.Dtos;
|
||||
using xCommons.Extensions;
|
||||
using xIdentityService.Interfaces;
|
||||
using xIdentityService.Extensions;
|
||||
|
||||
namespace xAiApi.AI.Mppings
|
||||
{
|
||||
/// <summary>
|
||||
/// an AutoMapper Value Resolver for Mapping TEntity to TDto
|
||||
/// When TEntity Has OwnerId Property and Owner ...
|
||||
/// </summary>
|
||||
/// <typeparam name="TEntity"></typeparam>
|
||||
/// <typeparam name="TDto"></typeparam>
|
||||
public abstract class XBaseOwnerMappingResolver<TEntity, TDto> : IValueResolver<TEntity, TDto, XPersonDto>
|
||||
where TDto : class
|
||||
where TEntity : class
|
||||
{
|
||||
//
|
||||
private string destPropertyName = "Owner";
|
||||
private string srcPropertyName = "OwnerId";
|
||||
private readonly IXIdentityProvider identityProvider;
|
||||
|
||||
public XBaseOwnerMappingResolver(
|
||||
IXIdentityProvider identityProvider
|
||||
)
|
||||
{
|
||||
this.identityProvider = identityProvider;
|
||||
}
|
||||
|
||||
public XPersonDto Resolve(
|
||||
TEntity source,
|
||||
TDto destination,
|
||||
XPersonDto destMember,
|
||||
ResolutionContext context
|
||||
)
|
||||
{
|
||||
//
|
||||
XPersonDto result = null;
|
||||
|
||||
//
|
||||
// Check Source is not Null ...
|
||||
if (source.IsNull())
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
//
|
||||
// Check OwnerId Exists ...
|
||||
var isOwnerExists = source.HasProperty(srcPropertyName);
|
||||
if (!isOwnerExists)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
//
|
||||
// Retrieve OwnerId from Source ...
|
||||
var ownerId = source.GetProperty<TEntity, string>(srcPropertyName);
|
||||
isOwnerExists = !ownerId.IsNullOrEmpty();
|
||||
if (!isOwnerExists)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
//
|
||||
// Retrieve Private Trusted Device ...
|
||||
var device = identityProvider.GetDevice();
|
||||
|
||||
//
|
||||
// Retrieve Specified OwnerId's UserInfo ...
|
||||
var userInfo = identityProvider.GetUserInfo(
|
||||
device: device,
|
||||
userSelectByParam: ownerId
|
||||
).RunTask();
|
||||
|
||||
//
|
||||
// Check UserInfo Exists ...
|
||||
if (!userInfo.IsNullOrDefault())
|
||||
{
|
||||
//
|
||||
// Converts UserInfo to XPersonDto ...
|
||||
result = userInfo.ToXPersonDto();
|
||||
}
|
||||
|
||||
//
|
||||
// Setting Dest Member ...
|
||||
destMember = result;
|
||||
|
||||
//
|
||||
// Setting Destination Property Value ...
|
||||
destination.SetProperty(destPropertyName, result);
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
+444
-301
@@ -1,16 +1,17 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using AutoMapper;
|
||||
using Microsoft.Extensions.AI;
|
||||
using Microsoft.SemanticKernel.ChatCompletion;
|
||||
using OllamaSharp;
|
||||
using xAiApi.AI.Configuration;
|
||||
using xAiApi.AI.Constants;
|
||||
using xAiApi.AI.Extensions;
|
||||
using xAiApi.AI.Interfaces;
|
||||
using xAiApi.AI.Interfaces.Entities;
|
||||
using xAiApi.AI.Models.Dtos;
|
||||
using xAiApi.AI.Models.Entities;
|
||||
using xAiModels.Constants;
|
||||
using xAiModels.Extensions;
|
||||
@@ -30,25 +31,64 @@ namespace xAiApi.AI.Services
|
||||
/// </summary>
|
||||
public class XAiProvider : IXAiProvider
|
||||
{
|
||||
//
|
||||
#region Properties ...
|
||||
/// <summary>
|
||||
/// Configuration ...
|
||||
/// </summary>
|
||||
/// <value></value>
|
||||
public XAiApiConfiguration Configuration { get; }
|
||||
|
||||
//
|
||||
private readonly IChatClient chatClient;
|
||||
private readonly ChatOptions chatOptions;
|
||||
private readonly IXIdentityProvider identityProvider;
|
||||
private readonly IXAiProjectRepository aiProjectRepository;
|
||||
private readonly IXAiMessageRepository aiMessagetRepository;
|
||||
private readonly IXAiConversationRepository aiConversationRepository;
|
||||
/// <summary>
|
||||
/// Mapper Service ...
|
||||
/// </summary>
|
||||
private readonly IMapper mapper;
|
||||
|
||||
/// <summary>
|
||||
/// LLm Chat Client ...
|
||||
/// used for Interacting by LLM ...
|
||||
/// </summary>
|
||||
private readonly IChatClient chatClient;
|
||||
|
||||
/// <summary>
|
||||
/// LLM Configuration Options ...
|
||||
/// usually used for Enable Function Tools and etc ...
|
||||
/// </summary>
|
||||
private readonly ChatOptions chatOptions;
|
||||
|
||||
/// <summary>
|
||||
/// Identity Provider Service ...
|
||||
/// use for Validate User Info ...
|
||||
/// </summary>
|
||||
private readonly IXIdentityProvider identityProvider;
|
||||
|
||||
/// <summary>
|
||||
/// Ai Project Repository Service ...
|
||||
/// <see cref="IXAiProjectRepository"/>
|
||||
/// </summary>
|
||||
private readonly IXAiProjectRepository aiProjectRepository;
|
||||
|
||||
/// <summary>
|
||||
/// Ai Message Repository Service ...
|
||||
/// <see cref="IXAiMessageRepository"/>
|
||||
/// </summary>
|
||||
private readonly IXAiMessageRepository aiMessageRepository;
|
||||
|
||||
/// <summary>
|
||||
/// Ai Conversation Repository Service ...
|
||||
/// <see cref="IXAiConversationRepository"/>
|
||||
/// </summary>
|
||||
private readonly IXAiConversationRepository aiConversationRepository;
|
||||
#endregion
|
||||
|
||||
//
|
||||
#region Constructor ...
|
||||
public XAiProvider(
|
||||
IMapper mapper,
|
||||
XAiApiConfiguration configuration,
|
||||
IXIdentityProvider identityProvider,
|
||||
IXAiProjectRepository aiProjectRepository,
|
||||
IXAiMessageRepository aiMessagetRepository,
|
||||
IXAiMessageRepository aiMessageRepository,
|
||||
IXAiConversationRepository aiConversationRepository
|
||||
)
|
||||
{
|
||||
@@ -56,9 +96,10 @@ namespace xAiApi.AI.Services
|
||||
Configuration = configuration;
|
||||
|
||||
//
|
||||
this.mapper = mapper;
|
||||
this.identityProvider = identityProvider;
|
||||
this.aiProjectRepository = aiProjectRepository;
|
||||
this.aiMessagetRepository = aiMessagetRepository;
|
||||
this.aiMessageRepository = aiMessageRepository;
|
||||
this.aiConversationRepository = aiConversationRepository;
|
||||
|
||||
//
|
||||
@@ -96,6 +137,7 @@ namespace xAiApi.AI.Services
|
||||
// ],
|
||||
};
|
||||
}
|
||||
#endregion
|
||||
|
||||
//
|
||||
#region Helpers ...
|
||||
@@ -112,28 +154,7 @@ namespace xAiApi.AI.Services
|
||||
)
|
||||
{
|
||||
//
|
||||
XAiProjectDto result = null;
|
||||
|
||||
//
|
||||
if (!entity.IsNullOrDefault())
|
||||
{
|
||||
//
|
||||
result = entity.ToDto();
|
||||
if (!entity.OwnerId.IsNullOrEmpty())
|
||||
{
|
||||
//
|
||||
result.Owner = await GetPerson(
|
||||
entity.OwnerId,
|
||||
cancellationToken
|
||||
);
|
||||
}
|
||||
|
||||
//
|
||||
result.Conversations = await ToDtos(
|
||||
entity.Conversations,
|
||||
cancellationToken
|
||||
);
|
||||
}
|
||||
var result = mapper.Map<XAiProjectDto>(entity);
|
||||
|
||||
//
|
||||
return result;
|
||||
@@ -152,28 +173,7 @@ namespace xAiApi.AI.Services
|
||||
)
|
||||
{
|
||||
//
|
||||
XAiMessageDto result = null;
|
||||
|
||||
//
|
||||
if (!entity.IsNullOrDefault())
|
||||
{
|
||||
//
|
||||
result = entity.ToDto();
|
||||
if (!entity.OwnerId.IsNullOrEmpty())
|
||||
{
|
||||
//
|
||||
result.Owner = await GetPerson(
|
||||
entity.OwnerId,
|
||||
cancellationToken
|
||||
);
|
||||
}
|
||||
|
||||
//
|
||||
result.Conversation = await ToDto(
|
||||
entity.Conversation,
|
||||
cancellationToken
|
||||
);
|
||||
}
|
||||
var result = mapper.Map<XAiMessageDto>(entity);
|
||||
|
||||
//
|
||||
return result;
|
||||
@@ -192,34 +192,7 @@ namespace xAiApi.AI.Services
|
||||
)
|
||||
{
|
||||
//
|
||||
XAiConversationDto result = null;
|
||||
|
||||
//
|
||||
if (!entity.IsNullOrDefault())
|
||||
{
|
||||
//
|
||||
result = entity.ToDto();
|
||||
if (!entity.OwnerId.IsNullOrEmpty())
|
||||
{
|
||||
//
|
||||
result.Owner = await GetPerson(
|
||||
entity.OwnerId,
|
||||
cancellationToken
|
||||
);
|
||||
}
|
||||
|
||||
//
|
||||
result.Project = await ToDto(
|
||||
entity.Project,
|
||||
cancellationToken
|
||||
);
|
||||
|
||||
//
|
||||
result.Messages = await ToDtos(
|
||||
entity.Messages,
|
||||
cancellationToken
|
||||
);
|
||||
}
|
||||
var result = mapper.Map<XAiConversationDto>(entity);
|
||||
|
||||
//
|
||||
return result;
|
||||
@@ -238,25 +211,10 @@ namespace xAiApi.AI.Services
|
||||
)
|
||||
{
|
||||
//
|
||||
IList<XAiProjectDto> list = new List<XAiProjectDto>();
|
||||
var result = mapper.Map<IEnumerable<XAiProjectDto>>(entities);
|
||||
|
||||
//
|
||||
var enumerable = entities.ToAsyncEnumerable(cancellationToken);
|
||||
await foreach (var entity in enumerable)
|
||||
{
|
||||
//
|
||||
var dto = await ToDto(
|
||||
entity,
|
||||
cancellationToken
|
||||
);
|
||||
if (!dto.IsNullOrDefault())
|
||||
{
|
||||
list.Add(dto);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
return list.AsEnumerable();
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -272,25 +230,10 @@ namespace xAiApi.AI.Services
|
||||
)
|
||||
{
|
||||
//
|
||||
IList<XAiMessageDto> list = new List<XAiMessageDto>();
|
||||
var result = mapper.Map<IEnumerable<XAiMessageDto>>(entities);
|
||||
|
||||
//
|
||||
var enumerable = entities.ToAsyncEnumerable(cancellationToken);
|
||||
await foreach (var entity in enumerable)
|
||||
{
|
||||
//
|
||||
var dto = await ToDto(
|
||||
entity,
|
||||
cancellationToken
|
||||
);
|
||||
if (!dto.IsNullOrDefault())
|
||||
{
|
||||
list.Add(dto);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
return list.AsEnumerable();
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -306,25 +249,10 @@ namespace xAiApi.AI.Services
|
||||
)
|
||||
{
|
||||
//
|
||||
IList<XAiConversationDto> list = new List<XAiConversationDto>();
|
||||
var result = mapper.Map<IEnumerable<XAiConversationDto>>(entities);
|
||||
|
||||
//
|
||||
var enumerable = entities.ToAsyncEnumerable(cancellationToken);
|
||||
await foreach (var entity in enumerable)
|
||||
{
|
||||
//
|
||||
var dto = await ToDto(
|
||||
entity,
|
||||
cancellationToken
|
||||
);
|
||||
if (!dto.IsNullOrDefault())
|
||||
{
|
||||
list.Add(dto);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
return list.AsEnumerable();
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -340,30 +268,7 @@ namespace xAiApi.AI.Services
|
||||
)
|
||||
{
|
||||
//
|
||||
var result = new XQueryResult<XAiProjectDto>();
|
||||
|
||||
//
|
||||
if (!queryResult.IsNullOrDefault())
|
||||
{
|
||||
//
|
||||
result = result.UpdateData(
|
||||
updateWith: queryResult,
|
||||
propertyBlackList: new List<string>
|
||||
{
|
||||
nameof(XQueryResult<XAiProject>.Items)
|
||||
}
|
||||
);
|
||||
|
||||
//
|
||||
if (queryResult.Items.HasChild())
|
||||
{
|
||||
//
|
||||
result.Items = await ToDtos(
|
||||
queryResult.Items,
|
||||
cancellationToken
|
||||
);
|
||||
}
|
||||
}
|
||||
var result = mapper.Map<XQueryResult<XAiProjectDto>>(queryResult);
|
||||
|
||||
//
|
||||
return result;
|
||||
@@ -382,30 +287,7 @@ namespace xAiApi.AI.Services
|
||||
)
|
||||
{
|
||||
//
|
||||
var result = new XQueryResult<XAiMessageDto>();
|
||||
|
||||
//
|
||||
if (!queryResult.IsNullOrDefault())
|
||||
{
|
||||
//
|
||||
result = result.UpdateData(
|
||||
updateWith: queryResult,
|
||||
propertyBlackList: new List<string>
|
||||
{
|
||||
nameof(XQueryResult<XAiMessage>.Items)
|
||||
}
|
||||
);
|
||||
|
||||
//
|
||||
if (queryResult.Items.HasChild())
|
||||
{
|
||||
//
|
||||
result.Items = await ToDtos(
|
||||
queryResult.Items,
|
||||
cancellationToken
|
||||
);
|
||||
}
|
||||
}
|
||||
var result = mapper.Map<XQueryResult<XAiMessageDto>>(queryResult);
|
||||
|
||||
//
|
||||
return result;
|
||||
@@ -424,30 +306,7 @@ namespace xAiApi.AI.Services
|
||||
)
|
||||
{
|
||||
//
|
||||
var result = new XQueryResult<XAiConversationDto>();
|
||||
|
||||
//
|
||||
if (!queryResult.IsNullOrDefault())
|
||||
{
|
||||
//
|
||||
result = result.UpdateData(
|
||||
updateWith: queryResult,
|
||||
propertyBlackList: new List<string>
|
||||
{
|
||||
nameof(XQueryResult<XAiConversation>.Items)
|
||||
}
|
||||
);
|
||||
|
||||
//
|
||||
if (queryResult.Items.HasChild())
|
||||
{
|
||||
//
|
||||
result.Items = await ToDtos(
|
||||
queryResult.Items,
|
||||
cancellationToken
|
||||
);
|
||||
}
|
||||
}
|
||||
var result = mapper.Map<XQueryResult<XAiConversationDto>>(queryResult);
|
||||
|
||||
//
|
||||
return result;
|
||||
@@ -522,6 +381,8 @@ namespace xAiApi.AI.Services
|
||||
}
|
||||
#endregion
|
||||
|
||||
//
|
||||
#region Actions ...
|
||||
/// <summary>
|
||||
/// Ask a Question ...
|
||||
/// </summary>
|
||||
@@ -540,124 +401,195 @@ namespace xAiApi.AI.Services
|
||||
)
|
||||
{
|
||||
//
|
||||
// Access Project ...
|
||||
var project = await GetProject(
|
||||
userInfo: userInfo,
|
||||
projectId: projectId,
|
||||
cancellationToken: cancellationToken
|
||||
);
|
||||
var isValid = !project.IsNullOrDefault();
|
||||
if (!isValid)
|
||||
{
|
||||
XException.NotFound.Throw();
|
||||
}
|
||||
|
||||
//
|
||||
// Check Project is Default Project or not ...
|
||||
var isDefaultProject = project.Title == XAiProjectEnum.Default.GetStringValue();
|
||||
|
||||
//
|
||||
// Access Conversation ...
|
||||
var conversation = await GetConversation(
|
||||
// Get All Requirements and also
|
||||
// Prepare Ai Project / Conversations and also ChatHistory
|
||||
// which Including Prompt ...
|
||||
var requirements = await GetRequirements(
|
||||
prompt: prompt,
|
||||
userInfo: userInfo,
|
||||
projectId: projectId,
|
||||
conversationId: conversationId,
|
||||
cancellationToken: cancellationToken
|
||||
);
|
||||
isValid = !conversation.IsNullOrDefault();
|
||||
if (!isValid)
|
||||
{
|
||||
XException.NotFound.Throw();
|
||||
}
|
||||
|
||||
//
|
||||
// Check First Question or not ...
|
||||
var isFirstConversation = !conversation.Messages.HasChild();
|
||||
|
||||
//
|
||||
// Check Permissions ...
|
||||
isValid = await HasPermission(
|
||||
userInfo: userInfo,
|
||||
projectId: projectId,
|
||||
cancellationToken: cancellationToken
|
||||
);
|
||||
var isValid =
|
||||
!requirements.IsNullOrDefault() &&
|
||||
requirements.HasPermission;
|
||||
if (!isValid)
|
||||
{
|
||||
XException.NotAllowed.Throw();
|
||||
}
|
||||
|
||||
//
|
||||
// Preparing Chat History ...
|
||||
IList<ChatMessage> chatHistory = null;
|
||||
|
||||
//
|
||||
// Check if First Question ...
|
||||
if (isFirstConversation)
|
||||
{
|
||||
//
|
||||
// Add Introduction Prompt ...
|
||||
chatHistory.Add(
|
||||
new ChatMessage(
|
||||
content: Configuration.Introduction,
|
||||
role: XAiChatRole.System.ToChatRole()
|
||||
)
|
||||
);
|
||||
|
||||
//
|
||||
// Add Project Prompt, if not Default Project ...
|
||||
if (!isDefaultProject)
|
||||
{
|
||||
//
|
||||
chatHistory.Add(
|
||||
new ChatMessage(
|
||||
content: project.Prompt,
|
||||
role: XAiChatRole.System.ToChatRole()
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
// Complete Chat History ...
|
||||
// TODO: Complete this ...
|
||||
}
|
||||
|
||||
//
|
||||
// Prepare Prompt ...
|
||||
prompt = await PreparePrompt(
|
||||
prompt: prompt,
|
||||
userInfo: userInfo,
|
||||
projectId: projectId,
|
||||
cancellationToken: cancellationToken
|
||||
);
|
||||
if (chatHistory.IsNull())
|
||||
{
|
||||
chatHistory = new List<ChatMessage>();
|
||||
}
|
||||
chatHistory.Add(
|
||||
new ChatMessage(
|
||||
content: prompt,
|
||||
role: XAiChatRole.User.ToChatRole()
|
||||
)
|
||||
);
|
||||
|
||||
//
|
||||
// Getting Response Message from LLM ...
|
||||
var chatResult = await chatClient
|
||||
.GetResponseAsync(
|
||||
options: chatOptions,
|
||||
messages: chatHistory,
|
||||
messages: requirements.ChatHistory,
|
||||
cancellationToken: cancellationToken
|
||||
);
|
||||
|
||||
//
|
||||
// TODO: Handle Here ...
|
||||
// Handle Issued Chat Response ...
|
||||
isValid =
|
||||
!chatResult.IsNullOrDefault() &&
|
||||
chatResult.FinishReason == ChatFinishReason.Stop;
|
||||
if (!isValid)
|
||||
{
|
||||
XException.ActionFailed.Throw();
|
||||
}
|
||||
|
||||
//
|
||||
throw new NotImplementedException();
|
||||
// Prepare Response Message ...
|
||||
var responseMessage = new XAiMessage
|
||||
{
|
||||
OwnerId = userInfo.UserId,
|
||||
Content = chatResult.Text,
|
||||
CreatedOn = DateTime.UtcNow,
|
||||
UpdatedAt = DateTime.UtcNow,
|
||||
Role = XAiChatRole.Assistant,
|
||||
ConversationId = requirements.AiConversation.Id
|
||||
};
|
||||
responseMessage = await aiMessageRepository.AddAsync(
|
||||
saveChanges: true,
|
||||
item: responseMessage
|
||||
);
|
||||
isValid = !responseMessage.IsNullOrDefault();
|
||||
if (!isValid)
|
||||
{
|
||||
XException.InvalidData.Throw();
|
||||
}
|
||||
|
||||
//
|
||||
// Converts Entity to Dto ...
|
||||
var result = await ToDto(
|
||||
entity: responseMessage,
|
||||
cancellationToken: cancellationToken
|
||||
);
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ask a Question in Streaming ...
|
||||
/// </summary>
|
||||
/// <param name="prompt"></param>
|
||||
/// <param name="projectId"></param>
|
||||
/// <param name="conversationId"></param>
|
||||
/// <param name="userInfo"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
public async IAsyncEnumerable<XAiMessageUpdateDto> AskStream(
|
||||
string prompt,
|
||||
string projectId = null,
|
||||
string conversationId = null,
|
||||
XUserClaimsInfoDto userInfo = null,
|
||||
[EnumeratorCancellation]
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
//
|
||||
// Get All Requirements and also
|
||||
// Prepare Ai Project / Conversations and also ChatHistory
|
||||
// which Including Prompt ...
|
||||
var requirements = await GetRequirements(
|
||||
prompt: prompt,
|
||||
userInfo: userInfo,
|
||||
projectId: projectId,
|
||||
conversationId: conversationId,
|
||||
cancellationToken: cancellationToken
|
||||
);
|
||||
var isValid =
|
||||
!requirements.IsNullOrDefault() &&
|
||||
requirements.HasPermission;
|
||||
if (!isValid)
|
||||
{
|
||||
XException.NotAllowed.Throw();
|
||||
}
|
||||
|
||||
//
|
||||
// Getting Response Message from LLM ...
|
||||
var chatResponseEnumerable = chatClient
|
||||
.GetStreamingResponseAsync(
|
||||
options: chatOptions,
|
||||
messages: requirements.ChatHistory,
|
||||
cancellationToken: cancellationToken
|
||||
);
|
||||
|
||||
//
|
||||
// Create an Empty Message for ID ...
|
||||
var responseMessage = new XAiMessage
|
||||
{
|
||||
OwnerId = userInfo.UserId,
|
||||
Role = XAiChatRole.Assistant,
|
||||
CreatedOn = DateTime.UtcNow,
|
||||
UpdatedAt = DateTime.UtcNow,
|
||||
Content = "Streaming Content",
|
||||
ConversationId = requirements.AiConversation.Id
|
||||
};
|
||||
responseMessage = await aiMessageRepository.AddAsync(
|
||||
saveChanges: true,
|
||||
item: responseMessage
|
||||
);
|
||||
|
||||
//
|
||||
// Collecting Data through Enumeration ...
|
||||
string content = string.Empty;
|
||||
var sequence = DateTime.UtcNow.ToTimestamp();
|
||||
await foreach (var data in chatResponseEnumerable)
|
||||
{
|
||||
//
|
||||
// Crucially, check the cancellation token before continuing
|
||||
// Throwing OperationCanceledException is the standard way to signal cancellation.
|
||||
if (cancellationToken.CanBeCanceled)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
//
|
||||
// Append recieved data to Content ...
|
||||
content += data;
|
||||
|
||||
//
|
||||
// Crate Message Update Model ...
|
||||
var item = new XAiMessageUpdateDto
|
||||
{
|
||||
Sequense = sequence,
|
||||
Content = data.Text,
|
||||
Id = responseMessage.Id,
|
||||
OwnerId = userInfo.UserId,
|
||||
UpdatedAt = DateTime.UtcNow,
|
||||
Role = XAiChatRole.Assistant,
|
||||
ConversationId = requirements.AiConversation.Id
|
||||
};
|
||||
|
||||
//
|
||||
sequence++;
|
||||
|
||||
//
|
||||
yield return item;
|
||||
}
|
||||
|
||||
//
|
||||
// Update Response Message Entity ...
|
||||
responseMessage.Content = content;
|
||||
responseMessage.UpdatedAt = DateTime.UtcNow;
|
||||
responseMessage = await aiMessageRepository.UpdateAsync(
|
||||
saveChanges: true,
|
||||
item: responseMessage,
|
||||
id: responseMessage.Id
|
||||
);
|
||||
isValid = !responseMessage.IsNullOrDefault();
|
||||
if (!isValid)
|
||||
{
|
||||
XException.ActionFailed.Throw();
|
||||
}
|
||||
|
||||
//
|
||||
yield break;
|
||||
}
|
||||
#endregion
|
||||
|
||||
//
|
||||
#region Private ...
|
||||
/// <summary>
|
||||
@@ -893,6 +825,217 @@ namespace xAiApi.AI.Services
|
||||
//
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Prepare Requirements for Asking a Prompt from Model ...
|
||||
/// </summary>
|
||||
/// <param name="prompt"></param>
|
||||
/// <param name="projectId"></param>
|
||||
/// <param name="conversationId"></param>
|
||||
/// <param name="userInfo"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
private async Task<XAiRequirementDto> GetRequirements(
|
||||
string prompt,
|
||||
string projectId = null,
|
||||
string conversationId = null,
|
||||
XUserClaimsInfoDto userInfo = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
//
|
||||
var result = new XAiRequirementDto();
|
||||
|
||||
//
|
||||
// Access Project ...
|
||||
var project = await GetProject(
|
||||
userInfo: userInfo,
|
||||
projectId: projectId,
|
||||
cancellationToken: cancellationToken
|
||||
);
|
||||
var isValid = !project.IsNullOrDefault();
|
||||
if (!isValid)
|
||||
{
|
||||
XException.NotFound.Throw();
|
||||
}
|
||||
|
||||
//
|
||||
result.AiProject = project;
|
||||
|
||||
//
|
||||
// Check Project is Default Project or not ...
|
||||
var isDefaultProject = project.Title == XAiProjectEnum.Default.GetStringValue();
|
||||
|
||||
//
|
||||
result.IsDefaultProject = isDefaultProject;
|
||||
|
||||
//
|
||||
// Access Conversation ...
|
||||
var conversation = await GetConversation(
|
||||
userInfo: userInfo,
|
||||
projectId: projectId,
|
||||
conversationId: conversationId,
|
||||
cancellationToken: cancellationToken
|
||||
);
|
||||
isValid = !conversation.IsNullOrDefault();
|
||||
if (!isValid)
|
||||
{
|
||||
XException.NotFound.Throw();
|
||||
}
|
||||
|
||||
//
|
||||
// Check First Question or not ...
|
||||
var isFirstConversation = !conversation.Messages.HasChild();
|
||||
|
||||
//
|
||||
result.AiConversation = conversation;
|
||||
result.IsFirstConversation = isFirstConversation;
|
||||
|
||||
//
|
||||
// Check Permissions ...
|
||||
isValid = await HasPermission(
|
||||
userInfo: userInfo,
|
||||
projectId: projectId,
|
||||
cancellationToken: cancellationToken
|
||||
);
|
||||
if (!isValid)
|
||||
{
|
||||
XException.NotAllowed.Throw();
|
||||
}
|
||||
|
||||
//
|
||||
result.HasPermission = isValid;
|
||||
|
||||
//
|
||||
// Check if First Question ...
|
||||
if (isFirstConversation)
|
||||
{
|
||||
//
|
||||
// Add Introduction Prompt ...
|
||||
var aiMessage = new XAiMessage
|
||||
{
|
||||
OwnerId = userInfo.UserId,
|
||||
Role = XAiChatRole.System,
|
||||
CreatedOn = DateTime.UtcNow,
|
||||
UpdatedAt = DateTime.UtcNow,
|
||||
ConversationId = conversation.Id,
|
||||
Content = Configuration.Introduction,
|
||||
};
|
||||
aiMessage = await aiMessageRepository.AddAsync(
|
||||
item: aiMessage,
|
||||
saveChanges: true
|
||||
);
|
||||
isValid = !aiMessage.IsNullOrDefault();
|
||||
if (!isValid)
|
||||
{
|
||||
XException.ActionFailed.Throw();
|
||||
}
|
||||
|
||||
//
|
||||
result.ChatHistory.Add(
|
||||
new ChatMessage(
|
||||
content: Configuration.Introduction,
|
||||
role: XAiChatRole.System.ToChatRole()
|
||||
)
|
||||
);
|
||||
|
||||
//
|
||||
// Add Project Prompt, if not Default Project ...
|
||||
if (!isDefaultProject)
|
||||
{
|
||||
//
|
||||
aiMessage = new XAiMessage
|
||||
{
|
||||
Content = project.Prompt,
|
||||
OwnerId = userInfo.UserId,
|
||||
Role = XAiChatRole.System,
|
||||
CreatedOn = DateTime.UtcNow,
|
||||
UpdatedAt = DateTime.UtcNow,
|
||||
ConversationId = conversation.Id,
|
||||
};
|
||||
aiMessage = await aiMessageRepository.AddAsync(
|
||||
item: aiMessage,
|
||||
saveChanges: true
|
||||
);
|
||||
isValid = !aiMessage.IsNullOrDefault();
|
||||
if (!isValid)
|
||||
{
|
||||
XException.ActionFailed.Throw();
|
||||
}
|
||||
|
||||
//
|
||||
result.ChatHistory.Add(
|
||||
new ChatMessage(
|
||||
content: project.Prompt,
|
||||
role: XAiChatRole.System.ToChatRole()
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
// Complete Chat History ...
|
||||
foreach (var msg in conversation.Messages)
|
||||
{
|
||||
//
|
||||
result.ChatHistory.Add(
|
||||
new ChatMessage(
|
||||
content: msg.Content,
|
||||
role: msg.Role.ToChatRole()
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Prepare Prompt ...
|
||||
prompt = await PreparePrompt(
|
||||
prompt: prompt,
|
||||
userInfo: userInfo,
|
||||
projectId: projectId,
|
||||
cancellationToken: cancellationToken
|
||||
);
|
||||
if (result.ChatHistory.IsNull())
|
||||
{
|
||||
result.ChatHistory = new List<ChatMessage>();
|
||||
}
|
||||
|
||||
//
|
||||
// Prepare Prompt XAiMessage ...
|
||||
var promptAiMessage = new XAiMessage
|
||||
{
|
||||
Content = prompt,
|
||||
OwnerId = userInfo.UserId,
|
||||
Role = XAiChatRole.User,
|
||||
CreatedOn = DateTime.UtcNow,
|
||||
UpdatedAt = DateTime.UtcNow,
|
||||
ConversationId = conversation.Id,
|
||||
};
|
||||
|
||||
//
|
||||
// Add Prompt Message to Database ...
|
||||
promptAiMessage = await aiMessageRepository.AddAsync(
|
||||
saveChanges: true,
|
||||
item: promptAiMessage
|
||||
);
|
||||
isValid = !promptAiMessage.IsNullOrDefault();
|
||||
if (!isValid)
|
||||
{
|
||||
XException.InvalidData.Throw();
|
||||
}
|
||||
|
||||
//
|
||||
result.ChatHistory.Add(
|
||||
new ChatMessage(
|
||||
content: prompt,
|
||||
role: XAiChatRole.User.ToChatRole()
|
||||
)
|
||||
);
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -6,22 +6,34 @@ using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.AI;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using OpenAI.Realtime;
|
||||
using xAiApi.AI.Interfaces;
|
||||
using xAiApi.Base;
|
||||
using xAiModels.Models;
|
||||
using xCommons.Configurations;
|
||||
using xCommons.Extensions;
|
||||
using xCommons.Providers;
|
||||
using xIdentityHelper;
|
||||
using xIdentityService.Constants;
|
||||
using xIdentityService.Interfaces;
|
||||
|
||||
namespace xAiApi.Controllers.V1
|
||||
{
|
||||
/// <summary>
|
||||
/// a Controller Which Provides Actions for
|
||||
/// using Ai Service ...
|
||||
/// </summary>
|
||||
public class AIController : XIBaseV1Controller
|
||||
{
|
||||
private readonly IXAIService aiService;
|
||||
/// <summary>
|
||||
/// Ai Provider ...
|
||||
/// </summary>
|
||||
private readonly IXAiProvider aiService;
|
||||
|
||||
//
|
||||
#region Constructor ...
|
||||
public AIController(
|
||||
IXAIService aiService,
|
||||
IXAiProvider aiService,
|
||||
ILogger<XIBaseV1Controller> logger,
|
||||
XAppConfiguration appConfiguration,
|
||||
IXIdentityProvider identityProvider,
|
||||
@@ -35,13 +47,26 @@ namespace xAiApi.Controllers.V1
|
||||
{
|
||||
this.aiService = aiService;
|
||||
}
|
||||
#endregion
|
||||
|
||||
//
|
||||
#region Actions ...
|
||||
/// <summary>
|
||||
/// As a Message from Ai ...
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// </remarks>
|
||||
/// <param name="prompt">specified prompt</param>
|
||||
/// <param name="projectId">active Project Id</param>
|
||||
/// <param name="conversationId">active Conversation Id</param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns>Ai Model's answer <see cref="XAiMessageDto"/></returns>
|
||||
[HttpGet("AskAI")]
|
||||
[Authorize(Policy = XPolicies.EnabledUser)]
|
||||
public async Task<ActionResult<string>> AskAI(
|
||||
public async Task<ActionResult<XAiMessageDto>> AskAI(
|
||||
[FromQuery] string prompt,
|
||||
[FromQuery] string projectId = null,
|
||||
[FromQuery] string conversationId = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
@@ -50,43 +75,18 @@ namespace xAiApi.Controllers.V1
|
||||
try
|
||||
{
|
||||
//
|
||||
var userInfo = await GetUserInfo();
|
||||
var result = await aiService
|
||||
.GetTextResponseAsync(
|
||||
.Ask(
|
||||
prompt: prompt,
|
||||
userInfo: userInfo,
|
||||
projectId: projectId,
|
||||
conversationId: conversationId,
|
||||
cancellationToken: cancellationToken
|
||||
);
|
||||
|
||||
//
|
||||
return Ok(result);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
//
|
||||
var result = GetExceptionActionResult(ex);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
[HttpGet("AskAIAsChatMessage")]
|
||||
[Authorize(Policy = XPolicies.EnabledUser)]
|
||||
public async Task<ActionResult<ChatMessage>> AskAIAsChatMessage(
|
||||
[FromQuery] string prompt,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
//
|
||||
// Do ...
|
||||
try
|
||||
{
|
||||
//
|
||||
var result = await aiService
|
||||
.GetResponseAsync(
|
||||
prompt: prompt,
|
||||
cancellationToken: cancellationToken
|
||||
);
|
||||
|
||||
//
|
||||
return Ok(result);
|
||||
return Ok(result.ToDynamicObject());
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -100,6 +100,8 @@ namespace xAiApi.Controllers.V1
|
||||
[Authorize(Policy = XPolicies.EnabledUser)]
|
||||
public async Task AskAIStream(
|
||||
[FromQuery] string prompt,
|
||||
[FromQuery] string projectId = null,
|
||||
[FromQuery] string conversationId = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
@@ -113,69 +115,37 @@ namespace xAiApi.Controllers.V1
|
||||
.Append("Content-Type", "text/event-stream");
|
||||
|
||||
//
|
||||
// Retrieving Stream ...
|
||||
var userInfo = await GetUserInfo();
|
||||
var stream = aiService
|
||||
.GetTextReponseStreamAsync(
|
||||
.AskStream(
|
||||
prompt: prompt,
|
||||
userInfo: userInfo,
|
||||
projectId: projectId,
|
||||
conversationId: conversationId,
|
||||
cancellationToken: cancellationToken
|
||||
);
|
||||
|
||||
//
|
||||
await foreach (var message in stream)
|
||||
{
|
||||
//
|
||||
// Do What we Have to Do with Message ...
|
||||
// Converts Model to Json String ...
|
||||
var json = message.ToJSON();
|
||||
|
||||
//
|
||||
var msgBytes = message.ToBytes();
|
||||
// Generates Json byte[] ...
|
||||
var bytes = json.ToBytes();
|
||||
|
||||
//
|
||||
// Write Bytes to Stream ...
|
||||
await Response.Body.WriteAsync(
|
||||
msgBytes,
|
||||
bytes,
|
||||
0,
|
||||
msgBytes.Length
|
||||
bytes.Length,
|
||||
cancellationToken
|
||||
);
|
||||
await Response.Body.FlushAsync();
|
||||
}
|
||||
|
||||
//
|
||||
// Closing Connection ...
|
||||
await Response.Body.FlushAsync();
|
||||
}
|
||||
catch (Exception)
|
||||
{ }
|
||||
}
|
||||
|
||||
[HttpGet("AskAIStreamAsChatMessage")]
|
||||
[Authorize(Policy = XPolicies.EnabledUser)]
|
||||
public async Task AskAIStreamAsChatMessage(
|
||||
[FromQuery] string prompt,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
//
|
||||
// Do ...
|
||||
try
|
||||
{
|
||||
//
|
||||
// Adding Content Type ...
|
||||
Response.Headers
|
||||
.Append("Content-Type", "text/event-stream");
|
||||
|
||||
//
|
||||
// Retrieving Stream ...
|
||||
var stream = aiService
|
||||
.GetReponseStreamAsync(
|
||||
prompt: prompt,
|
||||
cancellationToken: cancellationToken
|
||||
);
|
||||
|
||||
//
|
||||
await foreach (var message in stream)
|
||||
{
|
||||
//
|
||||
await Response.Body.WriteModelToStream(
|
||||
model: message,
|
||||
cancellationToken: cancellationToken
|
||||
);
|
||||
// Flushing Stream ...
|
||||
await Response.Body.FlushAsync(cancellationToken);
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
using System;
|
||||
using Microsoft.AspNetCore.SignalR;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using xAiApi.AI.Interfaces.Entities;
|
||||
using xAiApi.AI.Models.Entities;
|
||||
using xAiApi.Base;
|
||||
using xCommons.Configurations;
|
||||
using xCommons.Providers;
|
||||
using xIdentityService.Interfaces;
|
||||
using xPushService.Base;
|
||||
|
||||
namespace xAiApi.Controllers.V1.Entities
|
||||
{
|
||||
public class AiConversationsController : XIBaseV1EntityHubController<XAiConversation, Guid>
|
||||
{
|
||||
public AiConversationsController(
|
||||
ILogger<AiConversationsController> logger,
|
||||
XAppConfiguration appConfiguration,
|
||||
IXIdentityProvider identityProvider,
|
||||
XValidationProvider validationProvider,
|
||||
IXAiConversationRepository repository,
|
||||
IHubContext<XBaseEntityHub<XAiConversation, Guid>> hub = null
|
||||
) : base(
|
||||
logger,
|
||||
appConfiguration,
|
||||
identityProvider,
|
||||
validationProvider,
|
||||
repository,
|
||||
hub
|
||||
)
|
||||
{ }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
using System;
|
||||
using Microsoft.AspNetCore.SignalR;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using xAiApi.AI.Interfaces.Entities;
|
||||
using xAiApi.AI.Models.Entities;
|
||||
using xAiApi.Base;
|
||||
using xCommons.Configurations;
|
||||
using xCommons.Providers;
|
||||
using xIdentityService.Interfaces;
|
||||
using xPushService.Base;
|
||||
|
||||
namespace xAiApi.Controllers.V1.Entities
|
||||
{
|
||||
public class AiMessagesController : XIBaseV1EntityHubController<XAiMessage, Guid>
|
||||
{
|
||||
public AiMessagesController(
|
||||
ILogger<AiMessagesController> logger,
|
||||
XAppConfiguration appConfiguration,
|
||||
IXIdentityProvider identityProvider,
|
||||
XValidationProvider validationProvider,
|
||||
IXAiMessageRepository repository,
|
||||
IHubContext<XBaseEntityHub<XAiMessage, Guid>> hub = null
|
||||
) : base(
|
||||
logger,
|
||||
appConfiguration,
|
||||
identityProvider,
|
||||
validationProvider,
|
||||
repository,
|
||||
hub
|
||||
)
|
||||
{ }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
using System;
|
||||
using Microsoft.AspNetCore.SignalR;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using xAiApi.AI.Interfaces.Entities;
|
||||
using xAiApi.AI.Models.Entities;
|
||||
using xAiApi.Base;
|
||||
using xCommons.Configurations;
|
||||
using xCommons.Providers;
|
||||
using xIdentityService.Interfaces;
|
||||
using xPushService.Base;
|
||||
|
||||
namespace xAiApi.Controllers.V1.Entities
|
||||
{
|
||||
public class AiProjectsController : XIBaseV1EntityHubController<XAiProject, Guid>
|
||||
{
|
||||
public AiProjectsController(
|
||||
ILogger<AiProjectsController> logger,
|
||||
XAppConfiguration appConfiguration,
|
||||
IXIdentityProvider identityProvider,
|
||||
XValidationProvider validationProvider,
|
||||
IXAiProjectRepository repository,
|
||||
IHubContext<XBaseEntityHub<XAiProject, Guid>> hub = null
|
||||
) : base(
|
||||
logger,
|
||||
appConfiguration,
|
||||
identityProvider,
|
||||
validationProvider,
|
||||
repository,
|
||||
hub
|
||||
)
|
||||
{ }
|
||||
}
|
||||
}
|
||||
@@ -36,7 +36,8 @@ namespace xAiApi.Data.Repositories.Ef
|
||||
{
|
||||
//
|
||||
return dbSet
|
||||
.Include(x => x.Conversations);
|
||||
.Include(x => x.Conversations)
|
||||
.ThenInclude(x => x.Messages);
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
Reference in New Issue
Block a user