Spaces:
No application file
No application file
| using Microsoft.AspNetCore.Authorization; | |
| using Microsoft.AspNetCore.Mvc; | |
| using OptimAI.BRE.AIEngine.Application; | |
| using OptimAI.BRE.RuleEngine.Api; | |
| using OptimAI.BRE.Shared.Domain; | |
| namespace OptimAI.BRE.AIEngine.Api; | |
| [] | |
| [] | |
| [] | |
| public sealed class AiController : ControllerBase | |
| { | |
| private readonly IAiCreditAnalystService _aiService; | |
| private readonly IAiRuleGeneratorRepository _generatedRuleRepo; | |
| private readonly ITenantContextAccessor _tenantAccessor; | |
| private readonly IFieldCatalogRepository _fieldCatalogRepo; | |
| private readonly ILogger<AiController> _logger; | |
| public AiController( | |
| IAiCreditAnalystService aiService, | |
| IAiRuleGeneratorRepository generatedRuleRepo, | |
| ITenantContextAccessor tenantAccessor, | |
| IFieldCatalogRepository fieldCatalogRepo, | |
| ILogger<AiController> logger) | |
| { | |
| _aiService = aiService; | |
| _generatedRuleRepo = generatedRuleRepo; | |
| _tenantAccessor = tenantAccessor; | |
| _fieldCatalogRepo = fieldCatalogRepo; | |
| _logger = logger; | |
| } | |
| /// <summary> | |
| /// Generate BRE rule from natural language description using AI. | |
| /// </summary> | |
| [] | |
| [] | |
| [] | |
| public async Task<IActionResult> GenerateRule([FromBody] GenerateRuleRequest request, CancellationToken ct) | |
| { | |
| var availableFields = await _fieldCatalogRepo.GetFieldPathsAsync(_tenantAccessor.TenantId, ct); | |
| var ruleDefinition = await _aiService.GenerateRuleFromPromptAsync(new RuleGenerationRequest | |
| { | |
| UserPrompt = request.Prompt, | |
| ProductType = request.ProductType, | |
| AvailableFields = availableFields, | |
| TenantId = _tenantAccessor.TenantId, | |
| CreatedBy = _tenantAccessor.UserId | |
| }, ct); | |
| if (ruleDefinition == null) | |
| return BadRequest(new { error = "AI could not generate a rule from the provided description. Please be more specific." }); | |
| var savedId = await _generatedRuleRepo.SaveGeneratedRuleAsync(new AiGeneratedRuleRecord | |
| { | |
| TenantId = _tenantAccessor.TenantId, | |
| UserPrompt = request.Prompt, | |
| GeneratedRule = ruleDefinition, | |
| CreatedBy = _tenantAccessor.UserId | |
| }, ct); | |
| return Ok(new GeneratedRuleResponse | |
| { | |
| GenerationId = savedId, | |
| UserPrompt = request.Prompt, | |
| RuleDefinition = ruleDefinition, | |
| CanEdit = true, | |
| Message = "Rule generated successfully. Review and save to rule engine." | |
| }); | |
| } | |
| /// <summary> | |
| /// Run AI credit analysis on execution result. | |
| /// </summary> | |
| [] | |
| [] | |
| [] | |
| public async Task<IActionResult> AnalyzeCredit([FromBody] CreditAnalysisApiRequest request, CancellationToken ct) | |
| { | |
| var analysis = await _aiService.AnalyzeCreditAsync(new CreditAnalysisRequest | |
| { | |
| Data = request.ApplicationData, | |
| Decision = request.Decision, | |
| RiskScore = request.RiskScore, | |
| RiskCategory = request.RiskCategory, | |
| ProductCode = request.ProductCode, | |
| Deviations = request.Deviations.Select(d => new ExecutionDeviation | |
| { | |
| DeviationCode = d.Code, | |
| DeviationName = d.Name, | |
| Severity = Enum.Parse<Severity>(d.Severity, true), | |
| Reason = d.Reason | |
| }).ToList() | |
| }, ct); | |
| return Ok(analysis); | |
| } | |
| /// <summary> | |
| /// Analyze deviations and provide mitigation recommendations. | |
| /// </summary> | |
| [] | |
| [] | |
| [] | |
| public async Task<IActionResult> AnalyzeDeviations([FromBody] DeviationAnalysisApiRequest request, CancellationToken ct) | |
| { | |
| var analysis = await _aiService.AnalyzeDeviationsAsync(new DeviationAnalysisRequest | |
| { | |
| ApplicationData = request.ApplicationData, | |
| Deviations = request.Deviations.Select(d => new ExecutionDeviation | |
| { | |
| DeviationCode = d.Code, | |
| DeviationName = d.Name, | |
| Severity = Enum.Parse<Severity>(d.Severity, true), | |
| Reason = d.Reason, | |
| ActualValue = d.ActualValue, | |
| ExpectedValue = d.ExpectedValue, | |
| TenantId = _tenantAccessor.TenantId | |
| }).ToList() | |
| }, ct); | |
| return Ok(analysis); | |
| } | |
| /// <summary> | |
| /// Accept a generated rule and save to rule engine. | |
| /// </summary> | |
| [] | |
| [] | |
| public async Task<IActionResult> AcceptGeneratedRule(Guid generationId, [FromBody] AcceptRuleRequest request, CancellationToken ct) | |
| { | |
| var saved = await _generatedRuleRepo.AcceptRuleAsync(generationId, _tenantAccessor.TenantId, request.CategoryId, _tenantAccessor.UserId, ct); | |
| if (!saved) return NotFound(); | |
| return Ok(new { message = "Rule saved to rule engine successfully", ruleId = saved }); | |
| } | |
| /// <summary> | |
| /// Get AI generation history. | |
| /// </summary> | |
| [] | |
| [] | |
| public async Task<IActionResult> GetGenerationHistory([FromQuery] int page = 1, [FromQuery] int pageSize = 20, CancellationToken ct = default) | |
| { | |
| var history = await _generatedRuleRepo.GetHistoryAsync(_tenantAccessor.TenantId, page, pageSize, ct); | |
| return Ok(history); | |
| } | |
| } | |
| // DTOs | |
| public record GenerateRuleRequest | |
| { | |
| public string Prompt { get; init; } = default!; | |
| public string? ProductType { get; init; } | |
| } | |
| public record GeneratedRuleResponse | |
| { | |
| public Guid GenerationId { get; init; } | |
| public string UserPrompt { get; init; } = default!; | |
| public RuleDefinition RuleDefinition { get; init; } = default!; | |
| public bool CanEdit { get; init; } | |
| public string Message { get; init; } = default!; | |
| } | |
| public record CreditAnalysisApiRequest | |
| { | |
| public Dictionary<string, object> ApplicationData { get; init; } = new(); | |
| public string Decision { get; init; } = default!; | |
| public decimal RiskScore { get; init; } | |
| public string RiskCategory { get; init; } = default!; | |
| public string? ProductCode { get; init; } | |
| public List<DeviationDto> Deviations { get; init; } = new(); | |
| } | |
| public record DeviationAnalysisApiRequest | |
| { | |
| public Dictionary<string, object> ApplicationData { get; init; } = new(); | |
| public List<DeviationDto> Deviations { get; init; } = new(); | |
| } | |
| public record DeviationDto | |
| { | |
| public string Code { get; init; } = default!; | |
| public string Name { get; init; } = default!; | |
| public string Severity { get; init; } = default!; | |
| public string Reason { get; init; } = default!; | |
| public string? ActualValue { get; init; } | |
| public string? ExpectedValue { get; init; } | |
| } | |
| public record AcceptRuleRequest | |
| { | |
| public Guid? CategoryId { get; init; } | |
| } | |
| public class AiGeneratedRuleRecord | |
| { | |
| public Guid Id { get; set; } | |
| public Guid TenantId { get; set; } | |
| public string UserPrompt { get; set; } = default!; | |
| public RuleDefinition GeneratedRule { get; set; } = default!; | |
| public Guid? RuleId { get; set; } | |
| public bool? IsAccepted { get; set; } | |
| public Guid CreatedBy { get; set; } | |
| public DateTime CreatedAt { get; set; } = DateTime.UtcNow; | |
| } | |
| public interface IAiRuleGeneratorRepository | |
| { | |
| Task<Guid> SaveGeneratedRuleAsync(AiGeneratedRuleRecord record, CancellationToken ct = default); | |
| Task<bool> AcceptRuleAsync(Guid generationId, Guid tenantId, Guid? categoryId, Guid userId, CancellationToken ct = default); | |
| Task<List<AiGeneratedRuleRecord>> GetHistoryAsync(Guid tenantId, int page, int pageSize, CancellationToken ct = default); | |
| } | |
| public interface IFieldCatalogRepository | |
| { | |
| Task<List<string>> GetFieldPathsAsync(Guid tenantId, CancellationToken ct = default); | |
| Task<List<FieldCatalogDto>> GetCatalogAsync(Guid tenantId, string? category = null, CancellationToken ct = default); | |
| } | |
| public record FieldCatalogDto | |
| { | |
| public string FieldPath { get; init; } = default!; | |
| public string DisplayName { get; init; } = default!; | |
| public string DataType { get; init; } = default!; | |
| public string? Category { get; init; } | |
| public string? Description { get; init; } | |
| } | |