feat: implement multi-tenancy support across knowledge services and normalize TenantId to string type.
This commit is contained in:
@@ -5,10 +5,13 @@ namespace NexusReader.Application.Abstractions.Services;
|
||||
|
||||
public interface IKnowledgeService
|
||||
{
|
||||
Task<Result<KnowledgePacket>> GetKnowledgeAsync(string text, CancellationToken cancellationToken = default);
|
||||
Task<Result<KnowledgePacket>> GetGraphDataAsync(string text, CancellationToken cancellationToken = default);
|
||||
Task<Result<KnowledgePacket>> GetKnowledgeMapAsync(string text, CancellationToken cancellationToken = default);
|
||||
Task<Result<KnowledgePacket>> GetSummaryAndQuizAsync(string text, CancellationToken cancellationToken = default);
|
||||
Task<Result<KnowledgePacket>> GetKnowledgeAsync(string text, string tenantId, CancellationToken cancellationToken = default);
|
||||
Task<Result<KnowledgePacket>> GetGraphDataAsync(string text, string tenantId, CancellationToken cancellationToken = default);
|
||||
Task<Result<KnowledgePacket>> GetKnowledgeMapAsync(string text, string tenantId, CancellationToken cancellationToken = default);
|
||||
Task<Result<KnowledgePacket>> GetSummaryAndQuizAsync(string text, string tenantId, CancellationToken cancellationToken = default);
|
||||
Task<Result<List<RelevantContext>>> GetRelevantContextAsync(string query, string tenantId, CancellationToken cancellationToken = default);
|
||||
Task<Result<GroundednessResult>> VerifyGroundednessAsync(string answer, string context, string tenantId, CancellationToken cancellationToken = default);
|
||||
Task<Result> ClearCacheAsync(CancellationToken cancellationToken = default);
|
||||
}
|
||||
|
||||
public record GroundednessResult(float Score, string Rationale, bool IsGrounded);
|
||||
|
||||
@@ -1,51 +1,22 @@
|
||||
using FluentResults;
|
||||
using MediatR;
|
||||
using Microsoft.Extensions.AI;
|
||||
using NexusReader.Application.Abstractions.Services;
|
||||
|
||||
namespace NexusReader.Application.Commands.AI;
|
||||
|
||||
public record VerifyGroundednessCommand(string Answer, string Context) : IRequest<Result<GroundednessResult>>;
|
||||
|
||||
public record GroundednessResult(float Score, string Rationale, bool IsGrounded);
|
||||
public record VerifyGroundednessCommand(string Answer, string Context, string TenantId) : IRequest<Result<GroundednessResult>>;
|
||||
|
||||
public class VerifyGroundednessCommandHandler : IRequestHandler<VerifyGroundednessCommand, Result<GroundednessResult>>
|
||||
{
|
||||
private readonly IChatClient _chatClient;
|
||||
private readonly IKnowledgeService _knowledgeService;
|
||||
|
||||
public VerifyGroundednessCommandHandler(IChatClient chatClient)
|
||||
public VerifyGroundednessCommandHandler(IKnowledgeService knowledgeService)
|
||||
{
|
||||
_chatClient = chatClient;
|
||||
_knowledgeService = knowledgeService;
|
||||
}
|
||||
|
||||
public async Task<Result<GroundednessResult>> Handle(VerifyGroundednessCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
var systemPrompt = @"
|
||||
You are a Fact-Checking AI. Evaluate if the 'Answer' is supported by the 'Context'.
|
||||
Rate the groundedness from 0.0 to 1.0.
|
||||
Return ONLY a JSON object: { ""score"": 0.9, ""rationale"": ""string"", ""isGrounded"": true }
|
||||
";
|
||||
|
||||
var userPrompt = $"Context: {request.Context}\n\nAnswer: {request.Answer}";
|
||||
|
||||
try
|
||||
{
|
||||
var response = await _chatClient.GetResponseAsync(new List<ChatMessage>
|
||||
{
|
||||
new ChatMessage(ChatRole.System, systemPrompt),
|
||||
new ChatMessage(ChatRole.User, userPrompt)
|
||||
}, cancellationToken: cancellationToken);
|
||||
|
||||
var rawJson = response.Text?.Trim() ?? "{}";
|
||||
// Simple cleanup if needed
|
||||
rawJson = rawJson.Replace("```json", "").Replace("```", "").Trim();
|
||||
|
||||
var result = System.Text.Json.JsonSerializer.Deserialize<GroundednessResult>(rawJson, new System.Text.Json.JsonSerializerOptions { PropertyNameCaseInsensitive = true });
|
||||
|
||||
return result != null ? Result.Ok(result) : Result.Fail("Failed to parse groundedness result");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return Result.Fail(new Error("Failed to verify groundedness").CausedBy(ex));
|
||||
}
|
||||
return await _knowledgeService.VerifyGroundednessAsync(request.Answer, request.Context, request.TenantId, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,11 +9,8 @@ public static class DependencyInjection
|
||||
{
|
||||
services.AddMapsterConfiguration();
|
||||
|
||||
services.AddMediatR(config =>
|
||||
{
|
||||
config.RegisterServicesFromAssembly(typeof(DependencyInjection).Assembly);
|
||||
});
|
||||
|
||||
return services;
|
||||
}
|
||||
|
||||
public static System.Reflection.Assembly Assembly => typeof(DependencyInjection).Assembly;
|
||||
}
|
||||
|
||||
@@ -3,5 +3,6 @@ using NexusReader.Application.Abstractions.Messaging;
|
||||
namespace NexusReader.Application.Queries.Graph;
|
||||
|
||||
/// <param name="Text">Chapter or page content to extract the graph from.</param>
|
||||
public record GetKnowledgeGraphQuery(string Text) : IQuery<GraphDataDto>;
|
||||
/// <param name="TenantId">Tenant scope for knowledge extraction and caching.</param>
|
||||
public record GetKnowledgeGraphQuery(string Text, string TenantId) : IQuery<GraphDataDto>;
|
||||
|
||||
|
||||
@@ -18,20 +18,13 @@ internal sealed class GetKnowledgeGraphQueryHandler : IQueryHandler<GetKnowledge
|
||||
if (string.IsNullOrWhiteSpace(request.Text))
|
||||
return Result.Ok(new GraphDataDto());
|
||||
|
||||
var result = await _knowledgeService.GetGraphDataAsync(request.Text, cancellationToken);
|
||||
var result = await _knowledgeService.GetGraphDataAsync(request.Text, request.TenantId, cancellationToken);
|
||||
|
||||
if (result.IsFailed)
|
||||
return Result.Fail<GraphDataDto>(result.Errors);
|
||||
|
||||
var graph = result.Value.Graph;
|
||||
|
||||
if (graph is null)
|
||||
return Result.Ok(new GraphDataDto());
|
||||
|
||||
if (graph is null)
|
||||
return Result.Ok(new GraphDataDto());
|
||||
|
||||
return Result.Ok(graph);
|
||||
return graph is null ? Result.Ok(new GraphDataDto()) : Result.Ok(graph);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user