Initial commit
This commit is contained in:
@@ -0,0 +1,152 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using RobotNet10.NavigationTune.Shared.Interfaces;
|
||||
using RobotNet10.NavigationTune.Shared.Models;
|
||||
|
||||
namespace RobotNet10.NavigationTune.Controllers;
|
||||
|
||||
/// <summary>
|
||||
/// REST API controller for tuning advisor - re-analyze tests and apply suggestions
|
||||
/// </summary>
|
||||
[ApiController]
|
||||
[Route("api/[controller]")]
|
||||
public class TuningAdvisorController(
|
||||
ITuningAdvisor tuningAdvisor,
|
||||
ITestRepository testRepository,
|
||||
IParameterManager parameterManager,
|
||||
ILogger<TuningAdvisorController> logger) : ControllerBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Re-analyze a completed test run using telemetry provided in the request body.
|
||||
/// Note: Telemetry data is not persisted to database, so the client must supply it.
|
||||
/// The primary analysis is done automatically in the orchestrator after test completion.
|
||||
/// </summary>
|
||||
[HttpPost("analyze/{testRunId}")]
|
||||
public async Task<ActionResult<TuningReport>> AnalyzeTestRun(
|
||||
Guid testRunId, [FromBody] List<TelemetryData>? telemetry = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
var testRun = await testRepository.GetByIdAsync(testRunId);
|
||||
if (testRun == null)
|
||||
return NotFound(new { error = $"Test run {testRunId} not found" });
|
||||
|
||||
if (testRun.Status != TestStatus.Completed)
|
||||
return BadRequest(new { error = "Only completed tests can be analyzed" });
|
||||
|
||||
var parameterSet = await parameterManager.GetByIdAsync(testRun.ParameterSetId);
|
||||
if (parameterSet == null)
|
||||
return NotFound(new { error = $"Parameter set {testRun.ParameterSetId} not found" });
|
||||
|
||||
if (telemetry == null || telemetry.Count < 10)
|
||||
return BadRequest(new { error = "Telemetry data is required for analysis (min 10 samples). Telemetry is not stored in the database; it is only available during test execution via SignalR." });
|
||||
|
||||
var metrics = testRun.Metrics;
|
||||
if (metrics == null)
|
||||
return BadRequest(new { error = "No metrics available for this test run" });
|
||||
|
||||
var report = tuningAdvisor.Analyze(telemetry, metrics, parameterSet);
|
||||
report.TestRunId = testRunId;
|
||||
|
||||
return Ok(report);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogError(ex, "Error analyzing test run {TestRunId}", testRunId);
|
||||
return StatusCode(500, new { error = "Failed to analyze test run", details = ex.Message });
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Apply selected suggestions to a parameter set (returns new set, does not persist).
|
||||
/// </summary>
|
||||
[HttpPost("apply")]
|
||||
public async Task<ActionResult<NavigationParameterSet>> ApplySuggestions(
|
||||
[FromBody] ApplySuggestionsRequest request)
|
||||
{
|
||||
try
|
||||
{
|
||||
var parameterSet = await parameterManager.GetByIdAsync(request.ParameterSetId);
|
||||
if (parameterSet == null)
|
||||
return NotFound(new { error = $"Parameter set {request.ParameterSetId} not found" });
|
||||
|
||||
var selectedSuggestions = request.Report.Suggestions
|
||||
.Where(s => request.SuggestionIds.Contains(s.Id))
|
||||
.ToList();
|
||||
|
||||
if (selectedSuggestions.Count == 0)
|
||||
return BadRequest(new { error = "No valid suggestions selected" });
|
||||
|
||||
var modified = tuningAdvisor.ApplyAllSuggestions(parameterSet, selectedSuggestions);
|
||||
return Ok(modified);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogError(ex, "Error applying suggestions");
|
||||
return StatusCode(500, new { error = "Failed to apply suggestions", details = ex.Message });
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Apply suggestions and save as a new parameter set.
|
||||
/// </summary>
|
||||
[HttpPost("apply-and-save")]
|
||||
public async Task<ActionResult<NavigationParameterSet>> ApplyAndSave(
|
||||
[FromBody] ApplyAndSaveRequest request)
|
||||
{
|
||||
try
|
||||
{
|
||||
var parameterSet = await parameterManager.GetByIdAsync(request.ParameterSetId);
|
||||
if (parameterSet == null)
|
||||
return NotFound(new { error = $"Parameter set {request.ParameterSetId} not found" });
|
||||
|
||||
var selectedSuggestions = request.Report.Suggestions
|
||||
.Where(s => request.SuggestionIds.Contains(s.Id))
|
||||
.ToList();
|
||||
|
||||
if (selectedSuggestions.Count == 0)
|
||||
return BadRequest(new { error = "No valid suggestions selected" });
|
||||
|
||||
var modified = tuningAdvisor.ApplyAllSuggestions(parameterSet, selectedSuggestions);
|
||||
|
||||
// Create new parameter set with unique name
|
||||
modified.Id = Guid.NewGuid();
|
||||
modified.Name = request.NewParameterSetName
|
||||
?? $"{parameterSet.Name}_tuned_{DateTime.UtcNow:yyyyMMdd_HHmmss}";
|
||||
modified.Description = $"Auto-tuned from '{parameterSet.Name}'. Applied {selectedSuggestions.Count} suggestion(s).";
|
||||
modified.IsDefault = false;
|
||||
modified.CreatedAt = DateTime.UtcNow;
|
||||
modified.Version = parameterSet.Version + 1;
|
||||
|
||||
await parameterManager.SaveAsync(modified);
|
||||
|
||||
return Ok(modified);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogError(ex, "Error applying and saving suggestions");
|
||||
return StatusCode(500, new { error = "Failed to apply and save suggestions", details = ex.Message });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Request model for applying suggestions to a parameter set.
|
||||
/// </summary>
|
||||
public class ApplySuggestionsRequest
|
||||
{
|
||||
public Guid ParameterSetId { get; set; }
|
||||
public List<Guid> SuggestionIds { get; set; } = new();
|
||||
public TuningReport Report { get; set; } = null!;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Request model for applying suggestions and saving as a new parameter set.
|
||||
/// </summary>
|
||||
public class ApplyAndSaveRequest
|
||||
{
|
||||
public Guid ParameterSetId { get; set; }
|
||||
public List<Guid> SuggestionIds { get; set; } = new();
|
||||
public TuningReport Report { get; set; } = null!;
|
||||
public string? NewParameterSetName { get; set; }
|
||||
}
|
||||
Reference in New Issue
Block a user