Initial commit

This commit is contained in:
2026-07-03 16:37:12 +07:00
commit 63b8c1ea8b
1931 changed files with 640587 additions and 0 deletions

View File

@@ -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; }
}