Compare commits

..
3 Commits
5 changed files with 395 additions and 5 deletions
+85 -5
View File
@@ -191,6 +191,67 @@ namespace xAiModels.Extensions
return result;
}
/// <summary>
/// Validate a File Extraction Result ...
/// </summary>
/// <param name="source"></param>
/// <returns></returns>
public static bool IsValid(this XFileExtractionResult source)
{
//
var result =
!source.IsNullOrDefault() &&
(
source.Images.HasChild() ||
!source.Text.IsNullOrEmpty() ||
!source.AudioTranscript.IsNullOrEmpty()
);
return result;
}
/// <summary>
/// Converts a File Extraction Result to AI Contents ...
/// </summary>
/// <param name="source"></param>
/// <returns></returns>
public static IList<AIContent> ToAIContents(this XFileExtractionResult source)
{
//
var result = new List<AIContent>();
//
if (source.IsValid())
{
//
// Main Text ...
if (!source.Text.IsNullOrEmpty())
{
result.Add(new TextContent(source.Text));
}
//
// Images ...
if (source.Images.HasChild())
{
//
foreach (var img in source.Images)
{
result.Add(new DataContent(img.Bytes, img.MimeType));
}
}
//
// Transcripted Audio ...
if (!source.AudioTranscript.IsNullOrEmpty())
{
result.Add(new TextContent($"[Audio Transcript]\n{source.AudioTranscript}"));
}
}
//
return result;
}
/// <summary>
/// Check a Collection Contains Default Project for Specified Owner or not ...
/// </summary>
@@ -352,22 +413,42 @@ namespace xAiModels.Extensions
return result;
}
/// <summary>
/// Converts a Message Dto to ChatMessage ...
/// </summary>
/// <param name="source"></param>
/// <param name="additionalContents"></param>
/// <returns></returns>
public static ChatMessage ToChatMessages(
this XAiMessageDto source
this XAiMessageDto source,
IList<AIContent> additionalContents = null
)
{
//
// TODO: Handle Files Attached here ...
//
ChatMessage result = null;
//
if (!source.IsNullOrDefault())
{
//
var contents = new List<AIContent>
{
//
// Add Source Content ...
new TextContent(source.Content)
};
//
// Add Additional Content ...
if (additionalContents.HasChild())
{
contents.AddRange(additionalContents);
}
//
result = new ChatMessage
{
Contents = contents,
AuthorName =
source.Role == XAiChatRole.User &&
!source.Owner.IsNullOrDefault()
@@ -375,7 +456,6 @@ namespace xAiModels.Extensions
: string.Empty,
Role = source.Role.ToChatRole(),
MessageId = source.Id.ToString(),
Contents = [new TextContent(source.Content)]
};
}
+47
View File
@@ -1,4 +1,5 @@
using System;
using xModels.Dtos;
using System.Threading;
using xAiModels.Models.Dtos;
using System.Threading.Tasks;
@@ -251,5 +252,51 @@ namespace xAiModels.Interfaces
CancellationToken cancellationToken = default
);
#endregion
//
#region Query ...
/// <summary>
/// Query Projects ...
/// </summary>
/// <param name="ownerId"></param>
/// <param name="query"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
Task<XQueryResult<XAiProjectDto>> QueryProjects(
string ownerId,
XQuery query,
CancellationToken cancellationToken = default
);
/// <summary>
/// Query Conversations ...
/// </summary>
/// <param name="ownerId"></param>
/// <param name="projectId"></param>
/// <param name="query"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
Task<XQueryResult<XAiConversationDto>> QueryConversations(
string ownerId,
Guid projectId,
XQuery query,
CancellationToken cancellationToken = default
);
/// <summary>
/// Query Messages ...
/// </summary>
/// <param name="ownerId"></param>
/// <param name="conversationId"></param>
/// <param name="query"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
Task<XQueryResult<XAiMessageDto>> QueryMessages(
string ownerId,
Guid conversationId,
XQuery query,
CancellationToken cancellationToken = default
);
#endregion
}
}
+71
View File
@@ -0,0 +1,71 @@
using System.Collections.Generic;
namespace xAiModels.Models
{
/// <summary>
/// Holds File Extraction Result ...
/// </summary>
public class XFileExtractionResult
{
/// <summary>
/// Extracted String Content ...
/// </summary>
public string Text { get; set; } = string.Empty;
/// <summary>
/// Extracted Images for Vision Model ...
/// </summary>
public IList<XExtractedImage> Images { get; set; } = [];
/// <summary>
/// Extracted Content from Audio File ...
/// </summary>
public string AudioTranscript { get; set; } = string.Empty;
/// <summary>
/// Main File Name ...
/// </summary>
public string FileName { get; set; }
/// <summary>
/// Main File MIME Type ...
/// </summary>
public string MimeType { get; set; }
/// <summary>
/// Specified Fallback done using Images or not ...
/// </summary>
public bool UsedImageFallback { get; set; } = false;
/// <summary>
/// Error Message ...
/// </summary>
public string ErrorMessage { get; set; }
}
/// <summary>
/// Extracted Image ...
/// </summary>
public class XExtractedImage
{
/// <summary>
/// Content as Byte ...
/// </summary>
public byte[] Bytes { get; set; }
/// <summary>
/// MIME Type of Image ...
/// </summary>
public string MimeType { get; set; } = "image/png";
/// <summary>
/// for PDF Files ...
/// </summary>
public int? PageNumber { get; set; }
/// <summary>
/// Describe Image ...
/// </summary>
public string Description { get; set; }
}
}
@@ -134,7 +134,9 @@ namespace xAiModels.Providers.Enrichers
result.Owner = owner;
result.TitleResource = titleResource;
result.ProjectTitleResource = projectTitleResource;
result.ProjectTitle = projectTitleResource.Resource;
result.ProjectDescriptionResource = projectDescriptionResource;
result.ProjectDescription = projectDescriptionResource.Resource;
//
return result;
+190
View File
@@ -10,9 +10,12 @@ using xAiModels.Models.Dtos;
using xExceptions.Constants;
using System.Threading.Tasks;
using xCommons.Configurations;
using System.Linq.Expressions;
using xDataService.Extensions;
using xAiModels.Providers.Hubs;
using xAiModels.Interfaces.Dtos;
using xStringService.Interfaces;
using xAiModels.Models.Entities;
using System.Collections.Generic;
using Microsoft.AspNetCore.SignalR;
using xAiModels.Interfaces.Enrichers;
@@ -1097,6 +1100,193 @@ namespace xAiModels.Providers
}
#endregion
//
#region Query ...
/// <summary>
/// Query Projects ...
/// </summary>
/// <param name="ownerId"></param>
/// <param name="query"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public async Task<XQueryResult<XAiProjectDto>> QueryProjects(
string ownerId,
XQuery query,
CancellationToken cancellationToken = default
)
{
//
Expression<Func<XAiProject, bool>> predicate = null;
if (ownerId.IsNullOrEmpty())
{
predicate = x => x.OwnerId == ownerId;
}
//
var result = await projectRepositoryService.QueryAsync(
query: query,
predicate: predicate,
includeBuilder: null,
ignoreSoftDeleteds: true,
cancellationToken: cancellationToken,
orderBuilder: x => x.OrderBy(y => y.CreatedOn)
);
if (!result.IsNullOrDefault() &&
result.Items.HasChild())
{
//
result.Items = [..await EnrichRange(
sources: result.Items,
fillConversations: false,
fillConversationMessages: false,
cancellationToken: cancellationToken
)];
}
//
return result;
}
/// <summary>
/// Query Conversations ...
/// </summary>
/// <param name="ownerId"></param>
/// <param name="projectId"></param>
/// <param name="query"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public async Task<XQueryResult<XAiConversationDto>> QueryConversations(
string ownerId,
Guid projectId,
XQuery query,
CancellationToken cancellationToken = default
)
{
//
// Validate ...
if (projectId.IsDefaultGuid())
{
XException.InvalidArgs.Throw();
}
//
// Retrieve Project ...
var project = await projectRepositoryService.GetAsync(
id: projectId,
includeBuilder: null,
ignoreSoftDeleteds: true,
cancellationToken: cancellationToken
);
if (project.IsNullOrDefault())
{
XException.NotFound.Throw();
}
//
Expression<Func<XAiConversation, bool>> predicate = x =>
x.ProjectId == projectId;
if (ownerId.IsNullOrEmpty())
{
//
predicate = x =>
x.OwnerId == ownerId &&
x.ProjectId == projectId;
}
//
var result = await conversationRepositoryService.QueryAsync(
query: query,
predicate: predicate,
includeBuilder: null,
ignoreSoftDeleteds: true,
cancellationToken: cancellationToken,
orderBuilder: x => x.OrderBy(y => y.CreatedOn)
);
if (!result.IsNullOrDefault() &&
result.Items.HasChild())
{
//
result.Items = [..await EnrichRange(
fillMessages: false,
sources: result.Items,
cancellationToken: cancellationToken
)];
}
//
return result;
}
/// <summary>
/// Query Messages ...
/// </summary>
/// <param name="ownerId"></param>
/// <param name="conversationId"></param>
/// <param name="query"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public async Task<XQueryResult<XAiMessageDto>> QueryMessages(
string ownerId,
Guid conversationId,
XQuery query,
CancellationToken cancellationToken = default
)
{
//
// Validate ...
if (conversationId.IsDefaultGuid())
{
XException.InvalidArgs.Throw();
}
//
// Retrieve Conversation ...
var conversation = await conversationRepositoryService.GetAsync(
id: conversationId,
includeBuilder: null,
ignoreSoftDeleteds: true,
cancellationToken: cancellationToken
);
if (conversation.IsNullOrDefault())
{
XException.NotFound.Throw();
}
//
Expression<Func<XAiMessage, bool>> predicate = x =>
x.ConversationId == conversationId;
if (ownerId.IsNullOrEmpty())
{
//
predicate = x =>
x.OwnerId == ownerId &&
x.ConversationId == conversationId;
}
//
var result = await messageRepositoryService.QueryAsync(
query: query,
predicate: predicate,
includeBuilder: null,
ignoreSoftDeleteds: true,
cancellationToken: cancellationToken,
orderBuilder: x => x.OrderBy(y => y.CreatedOn)
);
if (!result.IsNullOrDefault() &&
result.Items.HasChild())
{
//
result.Items = [..await EnrichRange(
sources: result.Items,
cancellationToken: cancellationToken
)];
}
//
return result;
}
#endregion
//
#region Enrichers ...
/// <summary>