Compare commits

..
13 Commits
Author SHA1 Message Date
saherelm 26df2c7ebc last ... 2026-10-02 22:12:26 +03:30
saherelm 755eafa7d2 Add Support for Attaching Additional Contents to Specified Prompt Message when Converting to Chat Message, Specified For File Support ... 2026-09-30 23:12:39 +03:30
saherelm 47b2cbc0d2 last ... 2026-09-30 15:27:26 +03:30
saherelm f48b9257a3 last ... 2026-09-29 17:41:17 +03:30
saherelm 5d3601ba44 last ... 2026-09-28 22:36:16 +03:30
saherelm 33922537d5 last ... 2026-09-28 18:00:00 +03:30
saherelm 8e23a09f7b apply some changes on default ai resource titles ... 2026-09-28 17:49:50 +03:30
saherelm 2aa0607e85 last ... 2026-09-28 16:34:36 +03:30
saherelm a4dee3b5a4 last ... 2026-09-27 22:00:56 +03:30
saherelm 9f27b7825e last ... 2026-09-27 16:08:32 +03:30
saherelm eb27e9ce1f last ... 2026-09-25 19:48:23 +03:30
saherelm 490058d1a8 last ... 2026-09-19 17:03:16 +03:30
saherelm f9b5f1f6aa last ... 2026-09-06 08:46:01 +03:30
14 changed files with 1756 additions and 211 deletions
+1
View File
@@ -6,6 +6,7 @@ namespace xAiModels.Constants
public enum XAiModelProviderType
{
None,
OpenAI,
Ollama,
DeepSeek,
HuggingFace
+362 -4
View File
@@ -1,6 +1,14 @@
using System;
using System.Linq;
using xAiModels.Models;
using xModels.Extensions;
using xCommons.Extensions;
using xAiModels.Constants;
using xAiModels.Models.Dtos;
using xExceptions.Constants;
using Microsoft.Extensions.AI;
using xAiModels.Models.Entities;
using System.Collections.Generic;
namespace xAiModels.Extensions
{
@@ -20,7 +28,6 @@ namespace xAiModels.Extensions
var result =
!source.IsNullOrDefault() &&
!source.OwnerId.IsNullOrEmpty() &&
!source.Title.IsNullOrEmpty() &&
!source.Prompt.IsNullOrEmpty();
//
@@ -32,7 +39,6 @@ namespace xAiModels.Extensions
var result =
!source.IsNullOrDefault() &&
!source.OwnerId.IsNullOrEmpty() &&
!source.Title.IsNullOrEmpty() &&
!source.Prompt.IsNullOrEmpty();
//
@@ -50,7 +56,6 @@ namespace xAiModels.Extensions
var result =
!source.IsNullOrDefault() &&
!source.OwnerId.IsNullOrEmpty() &&
!source.Title.IsNullOrEmpty() &&
!source.ProjectId.IsNull() &&
!source.ProjectId.IsDefaultGuid();
@@ -63,7 +68,6 @@ namespace xAiModels.Extensions
var result =
!source.IsNullOrDefault() &&
!source.OwnerId.IsNullOrEmpty() &&
!source.Title.IsNullOrEmpty() &&
!source.ProjectId.IsNull() &&
!source.ProjectId.IsDefaultGuid();
@@ -104,5 +108,359 @@ namespace xAiModels.Extensions
//
return result;
}
/// <summary>
/// Validate a Model Descriptor ...
/// </summary>
/// <param name="source"></param>
/// <returns></returns>
public static bool IsValid(this XAiModelDescriptor source)
{
//
var result =
!source.IsNullOrDefault() &&
!source.Name.IsNullOrEmpty() &&
!source.Url.IsNullOrEmpty() &&
source.Url.IsValidUrl() &&
!source.LLM.IsNullOrEmpty() &&
source.Provider != Constants.XAiModelProviderType.None;
//
return result;
}
/// <summary>
/// Validate Specified Param ...
/// </summary>
/// <param name="source"></param>
/// <returns></returns>
public static bool IsValid(this XAiPromptParam source)
{
//
var result =
!source.IsNullOrDefault() &&
!source.Name.IsNullOrEmpty() &&
!source.Param.IsNullOrEmpty();
//
return result;
}
/// <summary>
/// Validate Specified Prompt ...
/// </summary>
/// <param name="source"></param>
/// <returns></returns>
public static bool IsValid(this XAiPromptDescriptor source)
{
//
var result =
!source.IsNullOrDefault() &&
!source.Name.IsNullOrEmpty() &&
!source.Template.IsNullOrEmpty();
if (!result)
{
return result;
}
//
if (source.Params.HasChild())
{
result =
result &&
source.Params.All(x => x.IsValid());
}
//
return result;
}
/// <summary>
/// Validate a Request for Retrieve Response in Controllers ...
/// </summary>
/// <param name="source"></param>
/// <returns></returns>
public static bool IsValid(this XAiResponseRequest source)
{
//
var result =
!source.IsNullOrDefault() &&
!source.Prompt.IsNullOrEmpty();
//
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>
/// <param name="source"></param>
/// <param name="ownerId"></param>
/// <returns></returns>
public static bool HasDefaultProject(
this IEnumerable<XAiProjectDto> source,
string ownerId
)
{
//
// Validate Args ...
if (source.HasChild() ||
ownerId.IsNullOrEmpty())
{
XException.InvalidArgs.Throw();
}
//
var item = source
.FirstOrDefault(x =>
x.Title
.ToNormalString()
.Contains(ownerId.ToNormalString()) &&
x.Title
.ToNormalString()
.Contains(XAiModelsConstants.DefaultXAiProjectDescriptionResourceID.ToNormalString())
);
//
var result = !item.IsNullOrDefault();
//
return result;
}
/// <summary>
/// Check a Collection Contains Default Conversation for Specified Project or not ...
/// </summary>
/// <param name="source"></param>
/// <param name="ownerId"></param>
/// <param name="projectId"></param>
/// <returns></returns>
public static bool HasDefaultConversation(
this IEnumerable<XAiConversationDto> source,
string ownerId,
Guid projectId
)
{
//
// Validate Args ...
if (source.HasChild() ||
projectId.IsDefaultGuid())
{
XException.InvalidArgs.Throw();
}
//
var item = source
.FirstOrDefault(x =>
x.Title
.ToNormalString()
.Contains(ownerId.ToNormalString()) &&
x.Title
.ToNormalString()
.Contains(projectId.ToString().ToNormalString()) &&
x.Title
.ToNormalString()
.Contains(XAiModelsConstants.DefaultXAiConversationTitleResourceID)
);
//
var result = !item.IsNullOrDefault();
//
return result;
}
/// <summary>
/// Retrieve Default Project Id from a Collection ...
/// </summary>
/// <param name="source"></param>
/// <param name="ownerId"></param>
/// <returns></returns>
public static Guid GetDafualtProject(
this IEnumerable<XAiProjectDto> source,
string ownerId
)
{
//
// Validate Args ...
if (!source.HasChild() ||
ownerId.IsNullOrEmpty())
{
XException.InvalidArgs.Throw();
}
//
var item = source
.FirstOrDefault(x =>
x.Title
.ToNormalString()
.Contains(ownerId.ToNormalString()) &&
x.Title
.ToNormalString()
.Contains(XAiModelsConstants.XAiProjectTitleIdentifier.ToNormalString())
);
if (item.IsNullOrDefault())
{
XException.NotFound.Throw();
}
//
return item.Id;
}
/// <summary>
/// Get Default Conversation Id from a Collection Contains ...
/// </summary>
/// <param name="source"></param>
/// <param name="ownerId"></param>
/// <param name="projectId"></param>
/// <returns></returns>
public static Guid GetDefaultConversation(
this IEnumerable<XAiConversationDto> source,
string ownerId,
Guid projectId
)
{
//
// Validate Args ...
if (!source.HasChild() ||
ownerId.IsNullOrEmpty() ||
projectId.IsDefaultGuid())
{
XException.InvalidArgs.Throw();
}
//
var item = source
.FirstOrDefault(x =>
x.Title
.ToNormalString()
.Contains(ownerId.ToNormalString()) &&
x.Title
.ToNormalString()
.Contains(XAiModelsConstants.XAiConversationTitleIdentifier.ToNormalString())
);
if (item.IsNullOrDefault())
{
XException.NotFound.Throw();
}
//
var result = item.Id;
//
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,
IList<AIContent> additionalContents = null
)
{
//
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()
? source.Owner.GetFullname()
: string.Empty,
Role = source.Role.ToChatRole(),
MessageId = source.Id.ToString(),
};
}
//
return result;
}
}
}
@@ -0,0 +1,12 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace xAiModels.Interfaces.Entities
{
public interface IXAiDocumentEntityHub
{
}
}
+198
View File
@@ -1,4 +1,5 @@
using System;
using xModels.Dtos;
using System.Threading;
using xAiModels.Models.Dtos;
using System.Threading.Tasks;
@@ -11,18 +12,51 @@ namespace xAiModels.Interfaces
/// </summary>
public interface IXAiDataProvider
{
//
#region Getters ...
/// <summary>
/// Retrieve Specified Project ...
/// </summary>
/// <param name="id"></param>
/// <param name="fillConversations"></param>
/// <param name="fillConversationMessages"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
Task<XAiProjectDto> GetProject(
Guid id,
bool fillConversations = false,
bool fillConversationMessages = false,
CancellationToken cancellationToken = default
);
/// <summary>
/// Retrieve Specified Conversation ...
/// </summary>
/// <param name="id"></param>
/// <param name="fillMessages"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
Task<XAiConversationDto> GetConversation(
Guid id,
bool fillMessages = false,
CancellationToken cancellationToken = default
);
#endregion
//
#region Loaders ...
/// <summary>
/// Load Projects List of Specified Owner ...
/// </summary>
/// <param name="ownerId"></param>
/// <param name="connectionId"></param>
/// <param name="fillConversations"></param>
/// <param name="fillConversationMessages"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
Task<IEnumerable<XAiProjectDto>> LoadProjects(
string ownerId,
string connectionId = null,
bool fillConversations = false,
bool fillConversationMessages = false,
CancellationToken cancellationToken = default
@@ -33,11 +67,13 @@ namespace xAiModels.Interfaces
/// </summary>
/// <param name="projectId"></param>
/// <param name="fillMessages"></param>
/// <param name="connectionId"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
Task<IEnumerable<XAiConversationDto>> LoadConversations(
Guid projectId,
bool fillMessages = false,
string connectionId = null,
CancellationToken cancellationToken = default
);
@@ -53,6 +89,120 @@ namespace xAiModels.Interfaces
);
#endregion
//
#region Enrichers ...
/// <summary>
/// Enrich Specified Item ...
/// </summary>
/// <param name="source"></param>
/// <param name="fillConversations"></param>
/// <param name="fillConversationMessages"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
Task<XAiProjectDto> Enrich(
XAiProjectDto source,
bool fillConversations = false,
bool fillConversationMessages = false,
CancellationToken cancellationToken = default
);
/// <summary>
/// Enrich Specified Items ...
/// </summary>
/// <param name="sources"></param>
/// <param name="fillConversations"></param>
/// <param name="fillConversationMessages"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
Task<IEnumerable<XAiProjectDto>> EnrichRange(
IEnumerable<XAiProjectDto> sources,
bool fillConversations = false,
bool fillConversationMessages = false,
CancellationToken cancellationToken = default
);
/// <summary>
/// Enrich Specified Item ...
/// </summary>
/// <param name="source"></param>
/// <param name="fillMessages"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
Task<XAiConversationDto> Enrich(
XAiConversationDto source,
bool fillMessages = false,
CancellationToken cancellationToken = default
);
/// <summary>
/// Enrich Specified Items ...
/// </summary>
/// <param name="sources"></param>
/// <param name="fillMessages"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
Task<IEnumerable<XAiConversationDto>> EnrichRange(
IEnumerable<XAiConversationDto> sources,
bool fillMessages = false,
CancellationToken cancellationToken = default
);
/// <summary>
/// Enrich Specified Item ...
/// </summary>
/// <param name="source"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
Task<XAiMessageDto> Enrich(
XAiMessageDto source,
CancellationToken cancellationToken = default
);
/// <summary>
/// Enrich Specified Items ...
/// </summary>
/// <param name="sources"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
Task<IEnumerable<XAiMessageDto>> EnrichRange(
IEnumerable<XAiMessageDto> sources,
CancellationToken cancellationToken = default
);
#endregion
//
#region Defaults ...
/// <summary>
/// Retrieve Default Project of Specified Owner ...
/// Create it if not Handled ...
/// </summary>
/// <param name="ownerId"></param>
/// <param name="connectionId"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
Task<XAiProjectDto> GetDefaultProject(
string ownerId,
string connectionId = null,
CancellationToken cancellationToken = default
);
/// <summary>
/// Retrieve Default Conversation of Specified Owner ...
/// Create it if not Handled ...
/// </summary>
/// <param name="ownerId"></param>
/// <param name="projectId"></param>
/// <param name="connectionId"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
Task<XAiConversationDto> GetDefaultConversation(
string ownerId,
Guid projectId,
string connectionId = null,
CancellationToken cancellationToken = default
);
#endregion
//
#region Creator/Adders ...
/// <summary>
@@ -73,12 +223,14 @@ namespace xAiModels.Interfaces
/// <summary>
/// Create Conversation ...
/// </summary>
/// <param name="ownerId"></param>
/// <param name="projectId"></param>
/// <param name="item"></param>
/// <param name="connectionId"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
Task<XAiConversationDto> CreateConversation(
string ownerId,
Guid projectId,
XAiConversationDto item = null,
string connectionId = null,
@@ -100,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
}
}
+1 -1
View File
@@ -65,7 +65,7 @@ namespace xAiModels.Models.Dtos
/// <summary>
/// Meta Data of MEssage in Json ...
/// </summary>
public string MeatDatas
public string MetaDatas
{
//
get => _metadata;
+61
View File
@@ -0,0 +1,61 @@
using System;
using System.ComponentModel.DataAnnotations;
using xModels.Base;
namespace xAiModels.Models.Entities
{
/// <summary>
/// Represents an embedd document in the AI system.
/// </summary>
public class XAiDocument : XBaseGuidIDEntity
{
/// <summary>
/// User Identifier ...
/// </summary>
/// <value></value>
[Required]
[StringLength(255)]
public string OwnerId { get; set; }
/// <summary>
/// Title of Document ...
/// </summary>
[StringLength(255)]
public string Title { get; set; }
/// <summary>
/// Content of Document ...
/// </summary>
public string Content { get; set; }
/// <summary>
/// Hash of the Document Content ...
/// </summary>
public string ContentHash { get; set; } = string.Empty;
/// <summary>
/// Embedding Model Identifier ...
/// </summary>
public string EmbeddingModel { get; set; } = string.Empty;
/// <summary>
/// Dimensions of the Embedding ...
/// </summary>
public int Dimensions { get; set; }
/// <summary>
/// Vector representation of the Document ...
/// </summary>
public byte[] Vector { get; set; } = [];
/// <summary>
/// Created Time ...
/// </summary>
public DateTime CreatedOn { get; set; }
/// <summary>
/// Updated Time ...
/// </summary>
public DateTime UpdatedAt { get; set; }
}
}
+1 -1
View File
@@ -61,7 +61,7 @@ namespace xAiModels.Models.Entities
/// <summary>
/// Meta Data of MEssage in Json ...
/// </summary>
public string MeatDatas
public string MetaDatas
{
//
get => _metadata;
+49
View File
@@ -0,0 +1,49 @@
namespace xAiModels.Models
{
/// <summary>
/// Describe Specified Prompt ...
/// </summary>
public class XAiPromptDescriptor
{
/// <summary>
/// Prompt Name ...
/// </summary>
public string Name { get; set; }
/// <summary>
/// Prompt Template ...
/// </summary>
public string Template { get; set; }
/// <summary>
/// Prompt Description ...
/// </summary>
public string Description { get; set; }
/// <summary>
/// Prompt Template Params ...
/// </summary>
public XAiPromptParam[] Params { get; set; } = [];
}
/// <summary>
/// Specified a Prompt Param ...
/// </summary>
public class XAiPromptParam
{
/// <summary>
/// Param Name ...
/// </summary>
public string Name { get; set; }
/// <summary>
/// Param Identifier ...
/// </summary>
public string Param { get; set; }
/// <summary>
/// Parma Description ...
/// </summary>
public string Description { get; set; }
}
}
+16
View File
@@ -0,0 +1,16 @@
using System;
using xModels.Base;
using xAiModels.Constants;
namespace xAiModels.Models
{
public class XAiResonseMessage : XBaseDto
{
public long Sequence { get; set; }
public Guid RespondTo { get; set; }
public string OwnerId { get; set; }
public string Content { get; set; }
public XAiChatRole Role { get; set; }
public DateTime RespondedOn { get; set; }
}
}
+25
View File
@@ -0,0 +1,25 @@
using System;
namespace xAiModels.Models
{
/// <summary>
/// /Request for a Response in Controllers ...
/// </summary>
public class XAiResponseRequest
{
/// <summary>
/// Prompt Text ...
/// </summary>
public string Prompt { get; set; }
/// <summary>
/// Specified Project Id ...
/// </summary>
public Guid ProjectId { get; set; }
/// <summary>
/// Specified Conversation Id ...
/// </summary>
public Guid ConversationId { get; set; }
}
}
+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;
File diff suppressed because it is too large Load Diff
+3 -2
View File
@@ -20,8 +20,7 @@
<!-- Icon Handling -->
<ItemGroup>
<None Include="../../Documents/Resources/Images/favicon.png" Link="icon.png" Pack="true"
PackagePath="\icon.png" />
<None Include="../../Documents/Resources/Images/favicon.png" Link="icon.png" Pack="true" PackagePath="\icon.png" />
</ItemGroup>
<!-- Local Modules -->
@@ -36,7 +35,9 @@
<!-- Dependencies -->
<ItemGroup>
<PackageReference Include="OpenAI" Version="2.14.0" />
<PackageReference Include="Microsoft.Extensions.AI" Version="10.4.1" />
<PackageReference Include="Microsoft.Extensions.AI.OpenAI" Version="10.10.0" />
</ItemGroup>
<!-- For XML Documentation Support -->