last ...
This commit is contained in:
@@ -1,6 +1,8 @@
|
|||||||
|
using AutoMapper;
|
||||||
using Microsoft.AspNetCore.Builder;
|
using Microsoft.AspNetCore.Builder;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using xAiApi.AI.Interfaces;
|
using xAiApi.AI.Interfaces;
|
||||||
|
using xAiApi.AI.Mppings;
|
||||||
using xAiApi.AI.Services;
|
using xAiApi.AI.Services;
|
||||||
|
|
||||||
namespace xAiApi.AI.DI
|
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>();
|
services.AddSingleton<IXAIService, XAIService>();
|
||||||
|
|
||||||
|
//
|
||||||
|
// Since we Used Repositories in this Service,
|
||||||
|
// we have to Register it Scoped Lifetime ...
|
||||||
|
services.AddScoped<IXAiProvider, XAiProvider>();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
@@ -161,6 +160,8 @@ namespace xAiApi.AI.Interfaces
|
|||||||
);
|
);
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
//
|
||||||
|
#region Actions ...
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Ask a Question ...
|
/// Ask a Question ...
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -177,5 +178,23 @@ namespace xAiApi.AI.Interfaces
|
|||||||
XUserClaimsInfoDto userInfo = null,
|
XUserClaimsInfoDto userInfo = null,
|
||||||
CancellationToken cancellationToken = default
|
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;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using AutoMapper;
|
||||||
using Microsoft.Extensions.AI;
|
using Microsoft.Extensions.AI;
|
||||||
using Microsoft.SemanticKernel.ChatCompletion;
|
|
||||||
using OllamaSharp;
|
using OllamaSharp;
|
||||||
using xAiApi.AI.Configuration;
|
using xAiApi.AI.Configuration;
|
||||||
using xAiApi.AI.Constants;
|
using xAiApi.AI.Constants;
|
||||||
using xAiApi.AI.Extensions;
|
|
||||||
using xAiApi.AI.Interfaces;
|
using xAiApi.AI.Interfaces;
|
||||||
using xAiApi.AI.Interfaces.Entities;
|
using xAiApi.AI.Interfaces.Entities;
|
||||||
|
using xAiApi.AI.Models.Dtos;
|
||||||
using xAiApi.AI.Models.Entities;
|
using xAiApi.AI.Models.Entities;
|
||||||
using xAiModels.Constants;
|
using xAiModels.Constants;
|
||||||
using xAiModels.Extensions;
|
using xAiModels.Extensions;
|
||||||
@@ -30,25 +31,64 @@ namespace xAiApi.AI.Services
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class XAiProvider : IXAiProvider
|
public class XAiProvider : IXAiProvider
|
||||||
{
|
{
|
||||||
|
//
|
||||||
|
#region Properties ...
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Configuration ...
|
/// Configuration ...
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value></value>
|
/// <value></value>
|
||||||
public XAiApiConfiguration Configuration { get; }
|
public XAiApiConfiguration Configuration { get; }
|
||||||
|
|
||||||
//
|
/// <summary>
|
||||||
private readonly IChatClient chatClient;
|
/// Mapper Service ...
|
||||||
private readonly ChatOptions chatOptions;
|
/// </summary>
|
||||||
private readonly IXIdentityProvider identityProvider;
|
private readonly IMapper mapper;
|
||||||
private readonly IXAiProjectRepository aiProjectRepository;
|
|
||||||
private readonly IXAiMessageRepository aiMessagetRepository;
|
|
||||||
private readonly IXAiConversationRepository aiConversationRepository;
|
|
||||||
|
|
||||||
|
/// <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(
|
public XAiProvider(
|
||||||
|
IMapper mapper,
|
||||||
XAiApiConfiguration configuration,
|
XAiApiConfiguration configuration,
|
||||||
IXIdentityProvider identityProvider,
|
IXIdentityProvider identityProvider,
|
||||||
IXAiProjectRepository aiProjectRepository,
|
IXAiProjectRepository aiProjectRepository,
|
||||||
IXAiMessageRepository aiMessagetRepository,
|
IXAiMessageRepository aiMessageRepository,
|
||||||
IXAiConversationRepository aiConversationRepository
|
IXAiConversationRepository aiConversationRepository
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
@@ -56,9 +96,10 @@ namespace xAiApi.AI.Services
|
|||||||
Configuration = configuration;
|
Configuration = configuration;
|
||||||
|
|
||||||
//
|
//
|
||||||
|
this.mapper = mapper;
|
||||||
this.identityProvider = identityProvider;
|
this.identityProvider = identityProvider;
|
||||||
this.aiProjectRepository = aiProjectRepository;
|
this.aiProjectRepository = aiProjectRepository;
|
||||||
this.aiMessagetRepository = aiMessagetRepository;
|
this.aiMessageRepository = aiMessageRepository;
|
||||||
this.aiConversationRepository = aiConversationRepository;
|
this.aiConversationRepository = aiConversationRepository;
|
||||||
|
|
||||||
//
|
//
|
||||||
@@ -96,6 +137,7 @@ namespace xAiApi.AI.Services
|
|||||||
// ],
|
// ],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
//
|
//
|
||||||
#region Helpers ...
|
#region Helpers ...
|
||||||
@@ -112,28 +154,7 @@ namespace xAiApi.AI.Services
|
|||||||
)
|
)
|
||||||
{
|
{
|
||||||
//
|
//
|
||||||
XAiProjectDto result = null;
|
var result = mapper.Map<XAiProjectDto>(entity);
|
||||||
|
|
||||||
//
|
|
||||||
if (!entity.IsNullOrDefault())
|
|
||||||
{
|
|
||||||
//
|
|
||||||
result = entity.ToDto();
|
|
||||||
if (!entity.OwnerId.IsNullOrEmpty())
|
|
||||||
{
|
|
||||||
//
|
|
||||||
result.Owner = await GetPerson(
|
|
||||||
entity.OwnerId,
|
|
||||||
cancellationToken
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
result.Conversations = await ToDtos(
|
|
||||||
entity.Conversations,
|
|
||||||
cancellationToken
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
//
|
||||||
return result;
|
return result;
|
||||||
@@ -152,28 +173,7 @@ namespace xAiApi.AI.Services
|
|||||||
)
|
)
|
||||||
{
|
{
|
||||||
//
|
//
|
||||||
XAiMessageDto result = null;
|
var result = mapper.Map<XAiMessageDto>(entity);
|
||||||
|
|
||||||
//
|
|
||||||
if (!entity.IsNullOrDefault())
|
|
||||||
{
|
|
||||||
//
|
|
||||||
result = entity.ToDto();
|
|
||||||
if (!entity.OwnerId.IsNullOrEmpty())
|
|
||||||
{
|
|
||||||
//
|
|
||||||
result.Owner = await GetPerson(
|
|
||||||
entity.OwnerId,
|
|
||||||
cancellationToken
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
result.Conversation = await ToDto(
|
|
||||||
entity.Conversation,
|
|
||||||
cancellationToken
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
//
|
||||||
return result;
|
return result;
|
||||||
@@ -192,34 +192,7 @@ namespace xAiApi.AI.Services
|
|||||||
)
|
)
|
||||||
{
|
{
|
||||||
//
|
//
|
||||||
XAiConversationDto result = null;
|
var result = mapper.Map<XAiConversationDto>(entity);
|
||||||
|
|
||||||
//
|
|
||||||
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
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
//
|
||||||
return result;
|
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);
|
return result;
|
||||||
await foreach (var entity in enumerable)
|
|
||||||
{
|
|
||||||
//
|
|
||||||
var dto = await ToDto(
|
|
||||||
entity,
|
|
||||||
cancellationToken
|
|
||||||
);
|
|
||||||
if (!dto.IsNullOrDefault())
|
|
||||||
{
|
|
||||||
list.Add(dto);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
return list.AsEnumerable();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <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);
|
return result;
|
||||||
await foreach (var entity in enumerable)
|
|
||||||
{
|
|
||||||
//
|
|
||||||
var dto = await ToDto(
|
|
||||||
entity,
|
|
||||||
cancellationToken
|
|
||||||
);
|
|
||||||
if (!dto.IsNullOrDefault())
|
|
||||||
{
|
|
||||||
list.Add(dto);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
return list.AsEnumerable();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <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);
|
return result;
|
||||||
await foreach (var entity in enumerable)
|
|
||||||
{
|
|
||||||
//
|
|
||||||
var dto = await ToDto(
|
|
||||||
entity,
|
|
||||||
cancellationToken
|
|
||||||
);
|
|
||||||
if (!dto.IsNullOrDefault())
|
|
||||||
{
|
|
||||||
list.Add(dto);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
return list.AsEnumerable();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -340,30 +268,7 @@ namespace xAiApi.AI.Services
|
|||||||
)
|
)
|
||||||
{
|
{
|
||||||
//
|
//
|
||||||
var result = new XQueryResult<XAiProjectDto>();
|
var result = mapper.Map<XQueryResult<XAiProjectDto>>(queryResult);
|
||||||
|
|
||||||
//
|
|
||||||
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
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
//
|
||||||
return result;
|
return result;
|
||||||
@@ -382,30 +287,7 @@ namespace xAiApi.AI.Services
|
|||||||
)
|
)
|
||||||
{
|
{
|
||||||
//
|
//
|
||||||
var result = new XQueryResult<XAiMessageDto>();
|
var result = mapper.Map<XQueryResult<XAiMessageDto>>(queryResult);
|
||||||
|
|
||||||
//
|
|
||||||
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
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
//
|
||||||
return result;
|
return result;
|
||||||
@@ -424,30 +306,7 @@ namespace xAiApi.AI.Services
|
|||||||
)
|
)
|
||||||
{
|
{
|
||||||
//
|
//
|
||||||
var result = new XQueryResult<XAiConversationDto>();
|
var result = mapper.Map<XQueryResult<XAiConversationDto>>(queryResult);
|
||||||
|
|
||||||
//
|
|
||||||
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
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
//
|
||||||
return result;
|
return result;
|
||||||
@@ -522,6 +381,8 @@ namespace xAiApi.AI.Services
|
|||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
//
|
||||||
|
#region Actions ...
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Ask a Question ...
|
/// Ask a Question ...
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -540,124 +401,195 @@ namespace xAiApi.AI.Services
|
|||||||
)
|
)
|
||||||
{
|
{
|
||||||
//
|
//
|
||||||
// Access Project ...
|
// Get All Requirements and also
|
||||||
var project = await GetProject(
|
// Prepare Ai Project / Conversations and also ChatHistory
|
||||||
userInfo: userInfo,
|
// which Including Prompt ...
|
||||||
projectId: projectId,
|
var requirements = await GetRequirements(
|
||||||
cancellationToken: cancellationToken
|
prompt: prompt,
|
||||||
);
|
|
||||||
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(
|
|
||||||
userInfo: userInfo,
|
userInfo: userInfo,
|
||||||
projectId: projectId,
|
projectId: projectId,
|
||||||
conversationId: conversationId,
|
conversationId: conversationId,
|
||||||
cancellationToken: cancellationToken
|
cancellationToken: cancellationToken
|
||||||
);
|
);
|
||||||
isValid = !conversation.IsNullOrDefault();
|
var isValid =
|
||||||
if (!isValid)
|
!requirements.IsNullOrDefault() &&
|
||||||
{
|
requirements.HasPermission;
|
||||||
XException.NotFound.Throw();
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Check First Question or not ...
|
|
||||||
var isFirstConversation = !conversation.Messages.HasChild();
|
|
||||||
|
|
||||||
//
|
|
||||||
// Check Permissions ...
|
|
||||||
isValid = await HasPermission(
|
|
||||||
userInfo: userInfo,
|
|
||||||
projectId: projectId,
|
|
||||||
cancellationToken: cancellationToken
|
|
||||||
);
|
|
||||||
if (!isValid)
|
if (!isValid)
|
||||||
{
|
{
|
||||||
XException.NotAllowed.Throw();
|
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 ...
|
// Getting Response Message from LLM ...
|
||||||
var chatResult = await chatClient
|
var chatResult = await chatClient
|
||||||
.GetResponseAsync(
|
.GetResponseAsync(
|
||||||
options: chatOptions,
|
options: chatOptions,
|
||||||
messages: chatHistory,
|
messages: requirements.ChatHistory,
|
||||||
cancellationToken: cancellationToken
|
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 ...
|
#region Private ...
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -893,6 +825,217 @@ namespace xAiApi.AI.Services
|
|||||||
//
|
//
|
||||||
return result;
|
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
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -6,22 +6,34 @@ using Microsoft.AspNetCore.Http;
|
|||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.Extensions.AI;
|
using Microsoft.Extensions.AI;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
using OpenAI.Realtime;
|
||||||
using xAiApi.AI.Interfaces;
|
using xAiApi.AI.Interfaces;
|
||||||
using xAiApi.Base;
|
using xAiApi.Base;
|
||||||
|
using xAiModels.Models;
|
||||||
using xCommons.Configurations;
|
using xCommons.Configurations;
|
||||||
using xCommons.Extensions;
|
using xCommons.Extensions;
|
||||||
using xCommons.Providers;
|
using xCommons.Providers;
|
||||||
using xIdentityHelper;
|
using xIdentityHelper;
|
||||||
|
using xIdentityService.Constants;
|
||||||
using xIdentityService.Interfaces;
|
using xIdentityService.Interfaces;
|
||||||
|
|
||||||
namespace xAiApi.Controllers.V1
|
namespace xAiApi.Controllers.V1
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// a Controller Which Provides Actions for
|
||||||
|
/// using Ai Service ...
|
||||||
|
/// </summary>
|
||||||
public class AIController : XIBaseV1Controller
|
public class AIController : XIBaseV1Controller
|
||||||
{
|
{
|
||||||
private readonly IXAIService aiService;
|
/// <summary>
|
||||||
|
/// Ai Provider ...
|
||||||
|
/// </summary>
|
||||||
|
private readonly IXAiProvider aiService;
|
||||||
|
|
||||||
|
//
|
||||||
|
#region Constructor ...
|
||||||
public AIController(
|
public AIController(
|
||||||
IXAIService aiService,
|
IXAiProvider aiService,
|
||||||
ILogger<XIBaseV1Controller> logger,
|
ILogger<XIBaseV1Controller> logger,
|
||||||
XAppConfiguration appConfiguration,
|
XAppConfiguration appConfiguration,
|
||||||
IXIdentityProvider identityProvider,
|
IXIdentityProvider identityProvider,
|
||||||
@@ -35,13 +47,26 @@ namespace xAiApi.Controllers.V1
|
|||||||
{
|
{
|
||||||
this.aiService = aiService;
|
this.aiService = aiService;
|
||||||
}
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
//
|
//
|
||||||
#region Actions ...
|
#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")]
|
[HttpGet("AskAI")]
|
||||||
[Authorize(Policy = XPolicies.EnabledUser)]
|
[Authorize(Policy = XPolicies.EnabledUser)]
|
||||||
public async Task<ActionResult<string>> AskAI(
|
public async Task<ActionResult<XAiMessageDto>> AskAI(
|
||||||
[FromQuery] string prompt,
|
[FromQuery] string prompt,
|
||||||
|
[FromQuery] string projectId = null,
|
||||||
|
[FromQuery] string conversationId = null,
|
||||||
CancellationToken cancellationToken = default
|
CancellationToken cancellationToken = default
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
@@ -50,43 +75,18 @@ namespace xAiApi.Controllers.V1
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
//
|
//
|
||||||
|
var userInfo = await GetUserInfo();
|
||||||
var result = await aiService
|
var result = await aiService
|
||||||
.GetTextResponseAsync(
|
.Ask(
|
||||||
prompt: prompt,
|
prompt: prompt,
|
||||||
|
userInfo: userInfo,
|
||||||
|
projectId: projectId,
|
||||||
|
conversationId: conversationId,
|
||||||
cancellationToken: cancellationToken
|
cancellationToken: cancellationToken
|
||||||
);
|
);
|
||||||
|
|
||||||
//
|
//
|
||||||
return Ok(result);
|
return Ok(result.ToDynamicObject());
|
||||||
}
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -100,6 +100,8 @@ namespace xAiApi.Controllers.V1
|
|||||||
[Authorize(Policy = XPolicies.EnabledUser)]
|
[Authorize(Policy = XPolicies.EnabledUser)]
|
||||||
public async Task AskAIStream(
|
public async Task AskAIStream(
|
||||||
[FromQuery] string prompt,
|
[FromQuery] string prompt,
|
||||||
|
[FromQuery] string projectId = null,
|
||||||
|
[FromQuery] string conversationId = null,
|
||||||
CancellationToken cancellationToken = default
|
CancellationToken cancellationToken = default
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
@@ -113,69 +115,37 @@ namespace xAiApi.Controllers.V1
|
|||||||
.Append("Content-Type", "text/event-stream");
|
.Append("Content-Type", "text/event-stream");
|
||||||
|
|
||||||
//
|
//
|
||||||
// Retrieving Stream ...
|
var userInfo = await GetUserInfo();
|
||||||
var stream = aiService
|
var stream = aiService
|
||||||
.GetTextReponseStreamAsync(
|
.AskStream(
|
||||||
prompt: prompt,
|
prompt: prompt,
|
||||||
|
userInfo: userInfo,
|
||||||
|
projectId: projectId,
|
||||||
|
conversationId: conversationId,
|
||||||
cancellationToken: cancellationToken
|
cancellationToken: cancellationToken
|
||||||
);
|
);
|
||||||
|
|
||||||
//
|
|
||||||
await foreach (var message in stream)
|
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(
|
await Response.Body.WriteAsync(
|
||||||
msgBytes,
|
bytes,
|
||||||
0,
|
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)
|
// Flushing Stream ...
|
||||||
{
|
await Response.Body.FlushAsync(cancellationToken);
|
||||||
//
|
|
||||||
await Response.Body.WriteModelToStream(
|
|
||||||
model: message,
|
|
||||||
cancellationToken: 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
|
return dbSet
|
||||||
.Include(x => x.Conversations);
|
.Include(x => x.Conversations)
|
||||||
|
.ThenInclude(x => x.Messages);
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|||||||
Reference in New Issue
Block a user