diff --git a/Controllers/XAiServiceControllerBase.cs b/Controllers/XAiServiceControllerBase.cs
index 85bf350..9eebff1 100644
--- a/Controllers/XAiServiceControllerBase.cs
+++ b/Controllers/XAiServiceControllerBase.cs
@@ -1,4 +1,5 @@
using System;
+using xModels.Dtos;
using System.Text.Json;
using System.Threading;
using xAiModels.Models;
@@ -164,14 +165,16 @@ namespace xAiApi.Controllers
#endregion
//
- #region Data Provided Actions ...
+ #region Loaders ...
///
/// Retrieve AI Projects ...
///
+ ///
///
///
[HttpGet("Projects")]
public async Task>> LoadProjects(
+ [FromQuery] bool includeDefaults = false,
CancellationToken cancellationToken = default
)
{
@@ -186,6 +189,7 @@ namespace xAiApi.Controllers
var result = await aiService.LoadProjects(
ownerId: userInfo.UserId,
connectionId: connectionId,
+ includeDefaults: includeDefaults,
cancellationToken: cancellationToken
);
@@ -282,7 +286,132 @@ namespace xAiApi.Controllers
return result;
}
}
+ #endregion
+ //
+ #region Queries ...
+ ///
+ /// Query Projects ...
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ [HttpGet("Projects/Query")]
+ public async Task>> QueryProjects(
+ [FromQuery] XQuery query,
+ CancellationToken cancellationToken = default
+ )
+ {
+ //
+ try
+ {
+ //
+ var userInfo = await GetUserInfo();
+ var connectionId = GetConnectionId();
+
+ //
+ var result = await aiService.QueryProjects(
+ query: query,
+ ownerId: userInfo.UserId,
+ cancellationToken: cancellationToken
+ );
+
+ //
+ return Ok(result);
+ }
+ catch (Exception ex)
+ {
+ //
+ var result = GetExceptionActionResult(ex);
+ return result;
+ }
+ }
+
+ ///
+ /// Query Conversations ...
+ ///
+ ///
+ ///
+ ///
+ ///
+ [HttpGet("Projects/{projectId}/Conversations/Query")]
+ public async Task>> QueryConversations(
+ [FromRoute] Guid projectId,
+ [FromQuery] XQuery query,
+ CancellationToken cancellationToken = default
+ )
+ {
+ //
+ try
+ {
+ //
+ var userInfo = await GetUserInfo();
+ var connectionId = GetConnectionId();
+
+ //
+ var result = await aiService.QueryConversations(
+ query: query,
+ projectId: projectId,
+ ownerId: userInfo.UserId,
+ cancellationToken: cancellationToken
+ );
+
+ //
+ return Ok(result);
+ }
+ catch (Exception ex)
+ {
+ //
+ var result = GetExceptionActionResult(ex);
+ return result;
+ }
+ }
+
+ ///
+ /// Query Messages ...
+ ///
+ ///
+ ///
+ ///
+ ///
+ [HttpGet("Conversations/{conversationId}/Messages/Query")]
+ public async Task>> QueryMessages(
+ [FromRoute] Guid conversationId,
+ [FromQuery] XQuery query,
+ CancellationToken cancellationToken = default
+ )
+ {
+ //
+ try
+ {
+ //
+ var userInfo = await GetUserInfo();
+ var connectionId = GetConnectionId();
+
+ //
+ var result = await aiService.QueryMessages(
+ query: query,
+ ownerId: userInfo.UserId,
+ conversationId: conversationId,
+ cancellationToken: cancellationToken
+ );
+
+ //
+ return Ok(result);
+ }
+ catch (Exception ex)
+ {
+ //
+ var result = GetExceptionActionResult(ex);
+ return result;
+ }
+ }
+ #endregion
+
+ //
+ #region Creators ...
///
/// Create an AI Project ...
///
@@ -333,7 +462,7 @@ namespace xAiApi.Controllers
//
var result = GetExceptionActionResult(ex);
return result;
- }
+ }
}
///
@@ -355,7 +484,7 @@ namespace xAiApi.Controllers
{
//
// Validate ...
- if (projectId.IsDefaultGuid() ||
+ if (projectId.IsDefaultGuid() ||
item.IsNullOrDefault())
{
XException.InvalidArgs.Throw();
@@ -390,9 +519,12 @@ namespace xAiApi.Controllers
//
var result = GetExceptionActionResult(ex);
return result;
- }
+ }
}
+ #endregion
+ //
+ #region Data Actions ...
///
/// Ask Question and Get Response ...
///
diff --git a/Interfaces/IXAiServiceBase.cs b/Interfaces/IXAiServiceBase.cs
index 7869fb4..582b6aa 100644
--- a/Interfaces/IXAiServiceBase.cs
+++ b/Interfaces/IXAiServiceBase.cs
@@ -1,4 +1,5 @@
using System;
+using xModels.Dtos;
using System.Net.Http;
using System.Threading;
using xAiModels.Models;
@@ -92,11 +93,13 @@ namespace xAiApi.Interfaces
///
///
///
+ ///
///
///
Task> LoadProjects(
string ownerId,
string connectionId = null,
+ bool includeDefaults = false,
CancellationToken cancellationToken = default
);
@@ -123,6 +126,49 @@ namespace xAiApi.Interfaces
Guid conversationId,
CancellationToken cancellationToken = default
);
+
+ ///
+ /// Query Projects ...
+ ///
+ ///
+ ///
+ ///
+ ///
+ Task> QueryProjects(
+ string ownerId,
+ XQuery query,
+ CancellationToken cancellationToken = default
+ );
+
+ ///
+ /// Query Conversations ...
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ Task> QueryConversations(
+ string ownerId,
+ Guid projectId,
+ XQuery query,
+ CancellationToken cancellationToken = default
+ );
+
+ ///
+ /// Query Messages ...
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ Task> QueryMessages(
+ string ownerId,
+ Guid conversationId,
+ XQuery query,
+ CancellationToken cancellationToken = default
+ );
///
/// Create an AI Project ...
diff --git a/Interfaces/IXAiServiceControllerBase.cs b/Interfaces/IXAiServiceControllerBase.cs
index c733f1f..e073f63 100644
--- a/Interfaces/IXAiServiceControllerBase.cs
+++ b/Interfaces/IXAiServiceControllerBase.cs
@@ -1,4 +1,5 @@
using System;
+using xModels.Dtos;
using System.Threading;
using xAiModels.Models;
using xAiModels.Models.Dtos;
@@ -38,14 +39,16 @@ namespace xAiApi.Interfaces
#endregion
//
- #region Data Provided Actions ...
+ #region Loaders ...
///
/// Retrieve AI Projects ...
///
+ ///
///
///
[HttpGet("Projects")]
Task>> LoadProjects(
+ [FromQuery] bool includeDefaults = false,
CancellationToken cancellationToken = default
);
@@ -72,7 +75,55 @@ namespace xAiApi.Interfaces
[FromRoute] Guid conversationId,
CancellationToken cancellationToken = default
);
+ #endregion
+ //
+ #region Queries ...
+ ///
+ /// Query Projects ...
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ [HttpGet("Projects/Query")]
+ Task>> QueryProjects(
+ [FromQuery] XQuery query,
+ CancellationToken cancellationToken = default
+ );
+
+ ///
+ /// Query Conversations ...
+ ///
+ ///
+ ///
+ ///
+ ///
+ [HttpGet("Projects/{projectId}/Conversations/Query")]
+ Task>> QueryConversations(
+ [FromRoute] Guid projectId,
+ [FromQuery] XQuery query,
+ CancellationToken cancellationToken = default
+ );
+
+ ///
+ /// Query Messages ...
+ ///
+ ///
+ ///
+ ///
+ ///
+ [HttpGet("Conversations/{conversationId}/Messages/Query")]
+ Task>> QueryMessages(
+ [FromRoute] Guid conversationId,
+ [FromQuery] XQuery query,
+ CancellationToken cancellationToken = default
+ );
+ #endregion
+
+ //
+ #region Creators ...
///
/// Create an AI Project ...
///
@@ -98,7 +149,10 @@ namespace xAiApi.Interfaces
[FromBody] XAiConversationDto item,
CancellationToken cancellationToken = default
);
+ #endregion
+ //
+ #region Data Actions ...
///
/// Ask Question and Get Response ...
///
diff --git a/Providers/XAIServiceBase.cs b/Providers/XAIServiceBase.cs
index 63acec0..30092fe 100644
--- a/Providers/XAIServiceBase.cs
+++ b/Providers/XAIServiceBase.cs
@@ -2,6 +2,7 @@ using System;
using OpenAI;
using OllamaSharp;
using System.Linq;
+using xModels.Dtos;
using System.Net.Http;
using System.Threading;
using xAiApi.Constants;
@@ -352,11 +353,13 @@ namespace xAiApi.Providers
///
///
///
+ ///
///
///
public async Task> LoadProjects(
string ownerId,
string connectionId = null,
+ bool includeDefaults = false,
CancellationToken cancellationToken = default
)
{
@@ -377,42 +380,50 @@ namespace xAiApi.Providers
);
//
- // Here we have to fill Conversations of Default Project ...
- var defaultProjectId = result.GetDafualtProject(ownerId);
- var defaultProject = result.FirstOrDefault(x => x.Id == defaultProjectId);
- result = result.Where(x => x.Id != defaultProjectId);
+ // Handle Defaults Including ...
+ if (includeDefaults)
+ {
+ //
+ // Here we have to fill Conversations of Default Project ...
+ var defaultProjectId = result.GetDafualtProject(ownerId);
+ var defaultProject = result.FirstOrDefault(x => x.Id == defaultProjectId);
+ result = result.Where(x => x.Id != defaultProjectId);
- //
- // Reading Conversations of Specified Default Project ...
- var defaultProjectConversations = await dataProvider.LoadConversations(
- fillMessages: false,
- connectionId: connectionId,
- projectId: defaultProjectId,
- cancellationToken: cancellationToken
- );
- var defaultConversationId = defaultProjectConversations.GetDefaultConversation(
- ownerId: ownerId,
- projectId: defaultProjectId
- );
- var defaultConversation = defaultProjectConversations.First(x => x.Id == defaultConversationId);
- defaultProjectConversations = defaultProjectConversations.Where(x => x.Id != defaultConversationId);
+ //
+ // Reading Conversations of Specified Default Project ...
+ var defaultProjectConversations = await dataProvider.LoadConversations(
+ fillMessages: false,
+ connectionId: connectionId,
+ projectId: defaultProjectId,
+ cancellationToken: cancellationToken
+ );
+ var defaultConversationId = defaultProjectConversations.GetDefaultConversation(
+ ownerId: ownerId,
+ projectId: defaultProjectId
+ );
+ var defaultConversation = defaultProjectConversations.First(x => x.Id == defaultConversationId);
+ defaultProjectConversations = defaultProjectConversations.Where(x => x.Id != defaultConversationId);
- //
- // Reading Default Conversations Messages ...
- var defaultConversationMessages = await dataProvider.LoadMessages(
- cancellationToken: cancellationToken,
- conversationId: defaultConversationId
- );
+ //
+ // Reading Default Conversations Messages ...
+ var defaultConversationMessages = await dataProvider.LoadMessages(
+ cancellationToken: cancellationToken,
+ conversationId: defaultConversationId
+ );
- //
- defaultConversation.Messages = [.. defaultConversationMessages];
- defaultProjectConversations = [defaultConversation, .. defaultProjectConversations];
- result = [defaultProject, .. result];
+ //
+ defaultConversation.Messages = [.. defaultConversationMessages.OrderByDescending(m => m.CreatedOn)];
+ defaultProjectConversations = [defaultConversation, .. defaultProjectConversations];
+ defaultProject.Conversations = [.. defaultProjectConversations];
+ result = [defaultProject, .. result];
+ }
//
return result;
}
+
+
///
/// Load Conversations of Specified AI Project ...
///
@@ -470,7 +481,7 @@ namespace xAiApi.Providers
);
//
- return result;
+ return result;
}
///
@@ -647,6 +658,7 @@ namespace xAiApi.Providers
Role = XAiChatRole.User,
CreatedOn = DateTime.UtcNow,
ConversationId = conversationId,
+ ConversationTitle = conversation.Title
};
promptMessage = await dataProvider.AddMessage(
item: promptMessage,
@@ -678,9 +690,10 @@ namespace xAiApi.Providers
{
Content = answer,
OwnerId = ownerId,
- Role = XAiChatRole.System,
CreatedOn = DateTime.UtcNow,
- ConversationId = conversationId
+ Role = XAiChatRole.Assistant,
+ ConversationId = conversationId,
+ ConversationTitle = conversation.Title
};
result = await dataProvider.AddMessage(
item: result,
@@ -891,6 +904,149 @@ namespace xAiApi.Providers
}
#endregion
+ //
+ #region Query ...
+ ///
+ /// Query Projects ...
+ ///
+ ///
+ ///
+ ///
+ ///
+ public async Task> QueryProjects(
+ string ownerId,
+ XQuery query,
+ CancellationToken cancellationToken = default
+ )
+ {
+ //
+ // Validate ...
+ if (ownerId.IsNullOrEmpty())
+ {
+ XException.InvalidArgs.Throw();
+ }
+
+ //
+ var result = await dataProvider.QueryProjects(
+ query: query,
+ ownerId: ownerId,
+ cancellationToken: cancellationToken
+ );
+
+ //
+ return result;
+ }
+
+ ///
+ /// Query Conversations ...
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public async Task> QueryConversations(
+ string ownerId,
+ Guid projectId,
+ XQuery query,
+ CancellationToken cancellationToken = default
+ )
+ {
+ //
+ // Validate ...
+ if (ownerId.IsNullOrEmpty() ||
+ projectId.IsDefaultGuid())
+ {
+ XException.InvalidArgs.Throw();
+ }
+
+ //
+ // Retrieve Project ...
+ var project = await dataProvider.GetProject(
+ id: projectId,
+ fillConversations: false,
+ fillConversationMessages: false,
+ cancellationToken: cancellationToken
+ );
+ if (project.IsNullOrDefault())
+ {
+ XException.NotFound.Throw();
+ }
+
+ //
+ // Validate Owner ...
+ if (ownerId != project.OwnerId)
+ {
+ XException.NotAllowed.Throw();
+ }
+
+ //
+ var result = await dataProvider.QueryConversations(
+ query: query,
+ ownerId: ownerId,
+ projectId: projectId,
+ cancellationToken: cancellationToken
+ );
+
+ //
+ return result;
+ }
+
+ ///
+ /// Query Messages ...
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public async Task> QueryMessages(
+ string ownerId,
+ Guid conversationId,
+ XQuery query,
+ CancellationToken cancellationToken = default
+ )
+ {
+ //
+ // Validate ...
+ if (ownerId.IsNullOrEmpty() ||
+ conversationId.IsDefaultGuid())
+ {
+ XException.InvalidArgs.Throw();
+ }
+
+ //
+ // Retrieve Conversation ...
+ var conversation = await dataProvider.GetConversation(
+ id: conversationId,
+ fillMessages: false,
+ cancellationToken: cancellationToken
+ );
+ if (conversation.IsNullOrDefault())
+ {
+ XException.NotFound.Throw();
+ }
+
+ //
+ // Validate Owner ...
+ if (ownerId != conversation.OwnerId)
+ {
+ XException.NotAllowed.Throw();
+ }
+
+ //
+ var result = await dataProvider.QueryMessages(
+ query: query,
+ ownerId: ownerId,
+ conversationId: conversationId,
+ cancellationToken: cancellationToken
+ );
+
+ //
+ return result;
+ }
+ #endregion
+
///
/// Base Dispose Action ...
///
@@ -916,49 +1072,45 @@ namespace xAiApi.Providers
//
var result = new List();
+ //
+ // Retrieve Introduction Prompt ...
+ var introductionPrompt = configuration.GetPrompt(XAiApiConstants.XAiApiIntroductionPromptName);
+ if (introductionPrompt.IsNullOrEmpty())
+ {
+ XException.InvalidData.Throw();
+ }
+
+ //
+ var introductionMessage = new ChatMessage(
+ role: ChatRole.System,
+ content: introductionPrompt
+ );
+
+ //
+ result.Add(introductionMessage);
+
+ //
+ if (!project.IsNullOrDefault() &&
+ !project.Prompt.IsNullOrEmpty())
+ {
+ //
+ // TODO: Handle Project Files Here ...
+ var projectMessage = new ChatMessage(
+ role: ChatRole.System,
+ contents: [new TextContent(project.Prompt)]
+ );
+ result.Add(projectMessage);
+ }
+
//
if (messages.HasChild())
{
//
- // if Messages Has Child, this means
- // Default Messages Handled before ...
- result = [.. messages.Select(m => m.ToChatMessages())];
- }
- else
- {
- //
- // If Message Has not any Childs, this means
- // First Asking Questions ...
-
- //
- // Retrieve Introduction Prompt ...
- var introductionPrompt = configuration.GetPrompt(XAiApiConstants.XAiApiIntroductionPromptName);
- if (introductionPrompt.IsNullOrEmpty())
- {
- XException.InvalidData.Throw();
- }
-
- //
- var introductionMessage = new ChatMessage(
- role: ChatRole.System,
- content: introductionPrompt
- );
-
- //
- result.Add(introductionMessage);
-
- //
- if (!project.IsNullOrDefault() &&
- !project.Prompt.IsNullOrEmpty())
- {
- //
- // TODO: Handle Project Files Here ...
- var projectMessage = new ChatMessage(
- role: ChatRole.System,
- contents: [new TextContent(project.Prompt)]
- );
- result.Add(projectMessage);
- }
+ // TODO: Here we can Implement Memory Management based on
+ // Last nth of Messages, or Summarization of Messages, etc ...
+ result = [..result, ..messages
+ .OrderBy(m => m.CreatedOn)
+ .Select(m => m.ToChatMessages())];
}
//