mirror of
https://github.com/NecroticBamboo/DeepTrace.git
synced 2025-12-21 11:21:51 +00:00
DEEP-13, DEEP-39 AI Model completely reimplemented. Dashboard UI implemented. Namespace style changed
This commit is contained in:
parent
af6c75a5ac
commit
bfb3de9331
@ -2,12 +2,12 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System.Text;
|
||||
|
||||
namespace DeepTrace.Controllers
|
||||
namespace DeepTrace.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Route("api/[controller]")]
|
||||
public class DownloadController : Controller
|
||||
{
|
||||
[ApiController]
|
||||
[Route("api/[controller]")]
|
||||
public class DownloadController : Controller
|
||||
{
|
||||
private readonly IModelStorageService _modelService;
|
||||
|
||||
public DownloadController(IModelStorageService modelService)
|
||||
@ -27,5 +27,4 @@ namespace DeepTrace.Controllers
|
||||
FileDownloadName = modelName+".csv"
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -20,15 +20,15 @@
|
||||
</DialogActions>
|
||||
</MudDialog>
|
||||
@code {
|
||||
[CascadingParameter] MudDialogInstance? MudDialog { get; set; }
|
||||
[Parameter] public bool AllowCancel { get; set; }
|
||||
[Parameter] public string Text { get; set; } = "";
|
||||
[Parameter] public bool IsYesNoCancel { get; set; } = false;
|
||||
[CascadingParameter] MudDialogInstance? MudDialog { get; set; }
|
||||
[Parameter] public bool AllowCancel { get; set; }
|
||||
[Parameter] public string Text { get; set; } = "";
|
||||
[Parameter] public bool IsYesNoCancel { get; set; } = false;
|
||||
|
||||
void Submit() => MudDialog?.Close(DialogResult.Ok(true));
|
||||
void Submit() => MudDialog?.Close(DialogResult.Ok(true));
|
||||
|
||||
void Cancel() => MudDialog?.Cancel();
|
||||
void Cancel() => MudDialog?.Cancel();
|
||||
|
||||
void Yes() => MudDialog?.Close(DialogResult.Ok(true));
|
||||
void No() => MudDialog?.Close(DialogResult.Ok(false));
|
||||
void Yes() => MudDialog?.Close(DialogResult.Ok(true));
|
||||
void No() => MudDialog?.Close(DialogResult.Ok(false));
|
||||
}
|
||||
@ -7,10 +7,16 @@
|
||||
@inject IDialogService DialogService
|
||||
@inject IModelStorageService ModelService
|
||||
@inject ITrainedModelStorageService TrainedModelService
|
||||
@inject ILogger<MLProcessor> MLProcessorLogger
|
||||
@inject ILogger<ModelCard> Logger
|
||||
@inject IMLProcessorFactory MlProcessorFactory
|
||||
|
||||
<MudCard Class="mb-3">
|
||||
<style>
|
||||
.card {
|
||||
max-width: 250pt;
|
||||
}
|
||||
</style>
|
||||
|
||||
<MudCard Class="card mb-3">
|
||||
<MudCardHeader>
|
||||
<CardHeaderContent>
|
||||
<MudText Typo="Typo.h6">@Model?.Name</MudText>
|
||||
@ -21,6 +27,7 @@
|
||||
</MudCardHeader>
|
||||
<MudCardContent>
|
||||
<MudText>Current state: @_prediction.PredictedLabel</MudText>
|
||||
<MudText>@_updated.ToString("HH:mm:ss")</MudText>
|
||||
</MudCardContent>
|
||||
</MudCard>
|
||||
|
||||
@ -30,6 +37,8 @@
|
||||
|
||||
private ModelDefinition _modelDefinition = new();
|
||||
private Prediction _prediction = new();
|
||||
private IMLProcessor? _mlProcessor;
|
||||
private DateTime _updated = DateTime.MinValue;
|
||||
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||
{
|
||||
@ -38,6 +47,7 @@
|
||||
return;
|
||||
}
|
||||
_modelDefinition = (await ModelService.Load(Model.Id)) ?? _modelDefinition;
|
||||
_mlProcessor = MlProcessorFactory.Create();
|
||||
|
||||
#pragma warning disable CS4014
|
||||
Task.Run(PredictionLoop);
|
||||
@ -87,15 +97,20 @@
|
||||
await PredictAnomaly(startDate, endDate);
|
||||
startDate = endDate;
|
||||
}
|
||||
catch(Exception)
|
||||
catch(Exception e)
|
||||
{
|
||||
//ignore
|
||||
Logger.LogError(e, e.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Task PredictAnomaly(DateTime startDate, DateTime endDate)
|
||||
{
|
||||
if (Model == null || !Model.IsEnabled)
|
||||
{
|
||||
_prediction = new Prediction { PredictedLabel = "Idle" };
|
||||
return;
|
||||
}
|
||||
|
||||
// use automatic step value to always request 500 elements
|
||||
var seconds = (endDate - startDate).TotalSeconds / 500.0;
|
||||
@ -150,8 +165,9 @@
|
||||
);
|
||||
}
|
||||
|
||||
var mlProcessor = new MLProcessor(MLProcessorLogger);
|
||||
_prediction = await mlProcessor.Predict(Model, _modelDefinition, data);
|
||||
_prediction = await _mlProcessor!.Predict(Model, _modelDefinition, data);
|
||||
_updated = DateTime.Now;
|
||||
await InvokeAsync(StateHasChanged);
|
||||
}
|
||||
|
||||
private async Task ShowError(string text)
|
||||
|
||||
@ -9,7 +9,7 @@
|
||||
OnZoomed="OnZoomed"
|
||||
>
|
||||
@foreach (var ts in _currentData.Series)
|
||||
{
|
||||
{
|
||||
<ApexPointSeries TItem="TimeSeries"
|
||||
Name="@ts.Name"
|
||||
Items="@ts.Data"
|
||||
@ -18,41 +18,41 @@
|
||||
YAggregate="@(e => (decimal)e.Sum(e => e.Value))"
|
||||
ShowDataLabels="false"
|
||||
/>
|
||||
}
|
||||
}
|
||||
</ApexChart>
|
||||
|
||||
@code {
|
||||
|
||||
[CascadingParameter]
|
||||
protected bool IsDarkMode { get; set; }
|
||||
[CascadingParameter]
|
||||
protected bool IsDarkMode { get; set; }
|
||||
|
||||
[Parameter] public TimeSeriesData? Data { get; set; }
|
||||
[Parameter] public TimeSeriesData? Data { get; set; }
|
||||
|
||||
[Parameter] public DateTime? MinDate { get; set; }
|
||||
[Parameter] public DateTime? MaxDate { get; set; }
|
||||
[Parameter] public EventCallback<DateTime?> MinDateChanged { get; set; }
|
||||
[Parameter] public EventCallback<DateTime?> MaxDateChanged { get; set; }
|
||||
[Parameter] public DateTime? MinDate { get; set; }
|
||||
[Parameter] public DateTime? MaxDate { get; set; }
|
||||
[Parameter] public EventCallback<DateTime?> MinDateChanged { get; set; }
|
||||
[Parameter] public EventCallback<DateTime?> MaxDateChanged { get; set; }
|
||||
|
||||
private ApexChart<TimeSeries>? _chart;
|
||||
private ApexChartOptions<TimeSeries>? _options;
|
||||
private TimeSeriesData _currentData = new() { Series = { new () } };
|
||||
private ApexChart<TimeSeries>? _chart;
|
||||
private ApexChartOptions<TimeSeries>? _options;
|
||||
private TimeSeriesData _currentData = new() { Series = { new () } };
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
_options = CreateOptions();
|
||||
base.OnInitialized();
|
||||
}
|
||||
}
|
||||
|
||||
protected override async Task OnParametersSetAsync()
|
||||
{
|
||||
protected override async Task OnParametersSetAsync()
|
||||
{
|
||||
Console.WriteLine("OnParametersSet");
|
||||
|
||||
await UpdateChart();
|
||||
await base.OnParametersSetAsync();
|
||||
}
|
||||
}
|
||||
|
||||
private async Task UpdateChart()
|
||||
{
|
||||
private async Task UpdateChart()
|
||||
{
|
||||
if (Data == _currentData)
|
||||
return;
|
||||
|
||||
@ -67,10 +67,10 @@
|
||||
await _chart!.UpdateOptionsAsync(true, true, true);
|
||||
await InvokeAsync(StateHasChanged);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private ApexChartOptions<TimeSeries> CreateOptions()
|
||||
{
|
||||
private ApexChartOptions<TimeSeries> CreateOptions()
|
||||
{
|
||||
var backgroundColor = IsDarkMode ? "var(--mud-palette-surface)" : "#f3f3f3";
|
||||
var gridColor = IsDarkMode ? "var(--mud-palette-drawer-background)" : "#f3f3f3";
|
||||
var borderColor = IsDarkMode ? "var(--mud-palette-text-primary)" : "#e7e7e7";
|
||||
@ -151,10 +151,10 @@
|
||||
};
|
||||
|
||||
return options;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnZoomed(ZoomedData<TimeSeries> zoomedData)
|
||||
{
|
||||
private void OnZoomed(ZoomedData<TimeSeries> zoomedData)
|
||||
{
|
||||
if (zoomedData.XAxis?.Min == null && zoomedData.XAxis?.Max == null)
|
||||
return;
|
||||
|
||||
@ -176,6 +176,6 @@
|
||||
|
||||
MaxDate = xMax.UtcDateTime;
|
||||
MaxDateChanged.InvokeAsync(MaxDate);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -14,12 +14,12 @@
|
||||
<h4>@Text</h4>
|
||||
|
||||
<MudTextField T="string" ReadOnly="true" Text="@_progressText"></MudTextField>
|
||||
@if (_isTraining == false)
|
||||
@if (_isTraining == false && _evaluationMetrics != null)
|
||||
{
|
||||
<MudText>MicroAccuracy: @_evaluationMetrics!.MicroAccuracy.ToString("N2")</MudText>
|
||||
<MudText>MacroAccuracy: @_evaluationMetrics!.MacroAccuracy.ToString("N2")</MudText>
|
||||
<MudText>LogLoss: @_evaluationMetrics!.LogLoss.ToString("N2")</MudText>
|
||||
<MudText>LogLossReduction: @_evaluationMetrics!.LogLossReduction.ToString("N2")</MudText>
|
||||
<MudText>MicroAccuracy: @_evaluationMetrics.MicroAccuracy.ToString("N6")</MudText>
|
||||
<MudText>MacroAccuracy: @_evaluationMetrics.MacroAccuracy.ToString("N6")</MudText>
|
||||
<MudText>LogLoss: @_evaluationMetrics.LogLoss.ToString("N6")</MudText>
|
||||
<MudText>LogLossReduction: @_evaluationMetrics.LogLossReduction.ToString("N6")</MudText>
|
||||
}
|
||||
|
||||
|
||||
@ -29,32 +29,43 @@
|
||||
</DialogActions>
|
||||
</MudDialog>
|
||||
@code {
|
||||
[CascadingParameter] MudDialogInstance? MudDialog { get; set; }
|
||||
[Parameter] public MLProcessor? Processor { get; set; }
|
||||
[Parameter] public ModelDefinition? Model { get; set; }
|
||||
[Parameter] public string Text { get; set; } = "";
|
||||
[CascadingParameter] MudDialogInstance? MudDialog { get; set; }
|
||||
[Parameter] public MLProcessor? Processor { get; set; }
|
||||
[Parameter] public ModelDefinition? Model { get; set; }
|
||||
[Parameter] public string Text { get; set; } = "";
|
||||
|
||||
private string _progressText = "";
|
||||
private bool _isTraining = true;
|
||||
private MLEvaluationMetrics? _evaluationMetrics;
|
||||
private string _progressText = "";
|
||||
private bool _isTraining = true;
|
||||
private MLEvaluationMetrics? _evaluationMetrics;
|
||||
|
||||
void Submit() => MudDialog?.Close(DialogResult.Ok(true));
|
||||
void Submit() => MudDialog?.Close(DialogResult.Ok(true));
|
||||
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||
{
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||
{
|
||||
if (!firstRender || Processor==null || Model==null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
_evaluationMetrics = await Processor.Train(Model, UpdateProgress);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_progressText = "ERROR: " + e.Message;
|
||||
}
|
||||
finally
|
||||
{
|
||||
_isTraining = false;
|
||||
await InvokeAsync(StateHasChanged);
|
||||
}
|
||||
}
|
||||
|
||||
private async void UpdateProgress(string message)
|
||||
{
|
||||
private async void UpdateProgress(string message)
|
||||
{
|
||||
_progressText = message;
|
||||
await InvokeAsync(StateHasChanged);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -29,4 +29,55 @@ public class DataSourceDefinition
|
||||
public string Description { get; set; } = string.Empty;
|
||||
|
||||
public override string ToString() => Name;
|
||||
|
||||
public List<string> GetColumnNames()
|
||||
{
|
||||
var measureNames = new[] { "min", "max", "avg", "mean" };
|
||||
var columnNames = new List<string>();
|
||||
foreach (var item in Queries)
|
||||
{
|
||||
columnNames.AddRange(measureNames.Select(x => $"{item.Query}_{x}"));
|
||||
}
|
||||
return columnNames;
|
||||
}
|
||||
|
||||
public static string ConvertToCsv(List<TimeSeriesDataSet> source)
|
||||
{
|
||||
var data = "";
|
||||
for (var i = 0; i < source.Count; i++)
|
||||
{
|
||||
|
||||
var queryData = source[i];
|
||||
var min = queryData.Data.Min(x => x.Value);
|
||||
var max = queryData.Data.Max(x => x.Value);
|
||||
var avg = queryData.Data.Average(x => x.Value);
|
||||
var mean = queryData.Data.Sum(x => x.Value) / queryData.Data.Count;
|
||||
|
||||
data += min + "," + max + "," + avg + "," + mean + ",";
|
||||
|
||||
}
|
||||
|
||||
return data.TrimEnd(',');
|
||||
}
|
||||
|
||||
public static float[] ToFeatures(List<TimeSeriesDataSet> source)
|
||||
{
|
||||
var data = new float[source.Count * 4];
|
||||
for (var i = 0; i < source.Count; i++)
|
||||
{
|
||||
|
||||
var queryData = source[i];
|
||||
var min = queryData.Data.Min(x => x.Value);
|
||||
var max = queryData.Data.Max(x => x.Value);
|
||||
var avg = queryData.Data.Average(x => x.Value);
|
||||
var mean = queryData.Data.Sum(x => x.Value) / queryData.Data.Count;
|
||||
|
||||
data[i*4 + 0] = min;
|
||||
data[i*4 + 1] = max;
|
||||
data[i*4 + 2] = avg;
|
||||
data[i*4 + 3] = mean;
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
namespace DeepTrace.Data
|
||||
namespace DeepTrace.Data;
|
||||
|
||||
public class IntervalDefinition
|
||||
{
|
||||
public class IntervalDefinition
|
||||
{
|
||||
public IntervalDefinition() { }
|
||||
public IntervalDefinition(DateTime from, DateTime to, string name)
|
||||
{
|
||||
@ -18,5 +18,4 @@
|
||||
|
||||
public List<TimeSeriesDataSet> Data { get; set; } = new();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -5,10 +5,12 @@ using System;
|
||||
using System.Linq;
|
||||
using System.IO;
|
||||
using System.Collections.Generic;
|
||||
namespace DeepTrace
|
||||
namespace DeepTrace;
|
||||
|
||||
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
|
||||
|
||||
public partial class MLModel1
|
||||
{
|
||||
public partial class MLModel1
|
||||
{
|
||||
/// <summary>
|
||||
/// model input class for MLModel1.
|
||||
/// </summary>
|
||||
@ -164,6 +166,8 @@ namespace DeepTrace
|
||||
|
||||
#endregion
|
||||
|
||||
#pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
|
||||
|
||||
private static string MLNetModelPath = Path.GetFullPath("MLModel1.zip");
|
||||
|
||||
public static readonly Lazy<PredictionEngine<ModelInput, ModelOutput>> PredictEngine = new Lazy<PredictionEngine<ModelInput, ModelOutput>>(() => CreatePredictEngine(), true);
|
||||
@ -185,5 +189,4 @@ namespace DeepTrace
|
||||
ITransformer mlModel = mlContext.Model.Load(MLNetModelPath, out var _);
|
||||
return mlContext.Model.CreatePredictionEngine<ModelInput, ModelOutput>(mlModel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -9,10 +9,10 @@ using Microsoft.ML.Trainers.FastTree;
|
||||
using Microsoft.ML.Trainers;
|
||||
using Microsoft.ML;
|
||||
|
||||
namespace DeepTrace
|
||||
namespace DeepTrace;
|
||||
|
||||
public partial class MLModel1
|
||||
{
|
||||
public partial class MLModel1
|
||||
{
|
||||
/// <summary>
|
||||
/// Retrains model using the pipeline generated as part of the training process. For more information on how to load data, see aka.ms/loaddata.
|
||||
/// </summary>
|
||||
@ -60,5 +60,4 @@ namespace DeepTrace
|
||||
|
||||
return pipeline;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
using MongoDB.Bson.Serialization.Attributes;
|
||||
using MongoDB.Bson;
|
||||
using System.Text;
|
||||
using DeepTrace.ML;
|
||||
|
||||
namespace DeepTrace.Data;
|
||||
|
||||
@ -21,22 +22,15 @@ public class ModelDefinition
|
||||
public string AIparameters { get; set; } = string.Empty;
|
||||
public List<IntervalDefinition> IntervalDefinitionList { get; set; } = new();
|
||||
|
||||
public List<string> GetColumnNames()
|
||||
{
|
||||
var measureNames = new[] { "min", "max", "avg", "mean" };
|
||||
var columnNames = new List<string>();
|
||||
foreach (var item in DataSource.Queries)
|
||||
{
|
||||
columnNames.AddRange(measureNames.Select(x => $"{item.Query}_{x}"));
|
||||
}
|
||||
columnNames.Add("Name");
|
||||
return columnNames;
|
||||
}
|
||||
public List<string> GetColumnNames() => DataSource.GetColumnNames()
|
||||
.Concat(new[] { "Name" })
|
||||
.ToList()
|
||||
;
|
||||
|
||||
public string ToCsv()
|
||||
{
|
||||
var current = IntervalDefinitionList.First();
|
||||
var headers = string.Join(",", GetColumnNames().Select(x=>$"\"{x}\""));
|
||||
var headers = string.Join(",", GetColumnNames().Select(x => $"\"{x}\""));
|
||||
|
||||
|
||||
var writer = new StringBuilder();
|
||||
@ -45,30 +39,24 @@ public class ModelDefinition
|
||||
foreach (var currentInterval in IntervalDefinitionList)
|
||||
{
|
||||
var source = currentInterval.Data;
|
||||
string data = ConvertToCsv(source);
|
||||
data += "," + currentInterval.Name;
|
||||
string data = DataSourceDefinition.ConvertToCsv(source);
|
||||
data += $",\"{currentInterval.Name}\"";
|
||||
writer.AppendLine(data);
|
||||
}
|
||||
|
||||
return writer.ToString();
|
||||
}
|
||||
|
||||
public static string ConvertToCsv(List<TimeSeriesDataSet> source)
|
||||
public IEnumerable<MLInputData> ToInput()
|
||||
{
|
||||
var data = "";
|
||||
for (var i = 0; i < source.Count; i++)
|
||||
foreach (var currentInterval in IntervalDefinitionList)
|
||||
{
|
||||
|
||||
var queryData = source[i];
|
||||
var min = queryData.Data.Min(x => x.Value);
|
||||
var max = queryData.Data.Max(x => x.Value);
|
||||
var avg = queryData.Data.Average(x => x.Value);
|
||||
var mean = queryData.Data.Sum(x => x.Value) / queryData.Data.Count;
|
||||
|
||||
data += min + "," + max + "," + avg + "," + mean + ",";
|
||||
|
||||
var source = currentInterval.Data;
|
||||
yield return new MLInputData
|
||||
{
|
||||
Features = DataSourceDefinition.ToFeatures(source),
|
||||
Label = currentInterval.Name
|
||||
};
|
||||
}
|
||||
|
||||
return data+"\"ignoreMe\"";
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,9 +4,9 @@ namespace DeepTrace.Data;
|
||||
|
||||
public class Prediction
|
||||
{
|
||||
[ColumnName(@"PredictedLabel")]
|
||||
public string PredictedLabel { get; set; }
|
||||
[ColumnName("PredictedLabel")]
|
||||
public string PredictedLabel { get; set; } = string.Empty;
|
||||
|
||||
[ColumnName(@"Score")]
|
||||
public float[] Score { get; set; }
|
||||
[ColumnName("Score")]
|
||||
public float[] Score { get; set; } = Array.Empty<float>();
|
||||
}
|
||||
|
||||
@ -1,14 +1,14 @@
|
||||
using MongoDB.Bson.Serialization.Attributes;
|
||||
using MongoDB.Bson;
|
||||
|
||||
namespace DeepTrace.Data
|
||||
namespace DeepTrace.Data;
|
||||
|
||||
public class TrainedModelDefinition
|
||||
{
|
||||
public class TrainedModelDefinition
|
||||
{
|
||||
[BsonId]
|
||||
public ObjectId? Id { get; set; }
|
||||
public bool IsEnabled { get; set; } = false;
|
||||
public string Name { get; set; } = string.Empty;
|
||||
public DataSourceDefinition? DataSource{ get; set;}
|
||||
public byte[] Value { get; set; } = Array.Empty<byte>(); //base64
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,47 +1,31 @@
|
||||
using DeepTrace.Data;
|
||||
using Microsoft.ML;
|
||||
using Microsoft.ML.Data;
|
||||
using Microsoft.ML.Trainers;
|
||||
|
||||
|
||||
namespace DeepTrace.ML
|
||||
namespace DeepTrace.ML;
|
||||
|
||||
public class EstimatorBuilder : IEstimatorBuilder
|
||||
{
|
||||
public class EstimatorBuilder : IEstimatorBuilder
|
||||
{
|
||||
public IEstimator<ITransformer> BuildPipeline(MLContext mlContext, ModelDefinition model)
|
||||
{
|
||||
IEstimator<ITransformer>? pipeline = null;
|
||||
var ds = model.DataSource;
|
||||
|
||||
var measureNames = new[] { "min", "max", "avg", "mean" };
|
||||
var columnNames = new List<string>();
|
||||
foreach (var item in ds.Queries)
|
||||
return
|
||||
mlContext.Transforms.NormalizeMinMax(inputColumnName: nameof(MLInputData.Features),outputColumnName: "Features")
|
||||
.Append(mlContext.Transforms.Conversion.MapValueToKey(inputColumnName: nameof(MLInputData.Label), outputColumnName: "Label"))
|
||||
// .AppendCacheCheckpoint(mlContext)
|
||||
.Append(mlContext.MulticlassClassification.Trainers.OneVersusAll(
|
||||
binaryEstimator: mlContext.BinaryClassification.Trainers.LbfgsLogisticRegression(
|
||||
new LbfgsLogisticRegressionBinaryTrainer.Options
|
||||
{
|
||||
var estimators = measureNames.Select(x => mlContext.Transforms.Text.FeaturizeText(inputColumnName: $"{item.Query}_{x}", outputColumnName: $"{item.Query}_{x}"));
|
||||
columnNames.AddRange(measureNames.Select(x => $"{item.Query}_{x}"));
|
||||
|
||||
foreach (var e in estimators)
|
||||
{
|
||||
if (pipeline == null)
|
||||
{
|
||||
pipeline = e;
|
||||
}
|
||||
else
|
||||
{
|
||||
pipeline = pipeline.Append(e);
|
||||
}
|
||||
L1Regularization = 1F,
|
||||
L2Regularization = 1F,
|
||||
LabelColumnName = "Label",
|
||||
FeatureColumnName = "Features"
|
||||
}
|
||||
))
|
||||
)
|
||||
.Append(mlContext.Transforms.Conversion.MapKeyToValue(nameof(MLOutputData.PredictedLabel), inputColumnName: "PredictedLabel"));
|
||||
|
||||
}
|
||||
|
||||
pipeline = pipeline!
|
||||
.Append(mlContext.Transforms.Concatenate(@"Features", columnNames.ToArray()))
|
||||
.Append(mlContext.Transforms.Conversion.MapValueToKey(outputColumnName: @"Name", inputColumnName: @"Name"))
|
||||
.Append(mlContext.Transforms.NormalizeMinMax(@"Features", @"Features"))
|
||||
.Append(mlContext.MulticlassClassification.Trainers.OneVersusAll(binaryEstimator: mlContext.BinaryClassification.Trainers.LbfgsLogisticRegression(new LbfgsLogisticRegressionBinaryTrainer.Options() { L1Regularization = 1F, L2Regularization = 1F, LabelColumnName = @"Name", FeatureColumnName = @"Features" }), labelColumnName: @"Name"))
|
||||
.Append(mlContext.Transforms.Conversion.MapKeyToValue(outputColumnName: @"PredictedLabel", inputColumnName: @"PredictedLabel"));
|
||||
|
||||
return pipeline;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,10 +1,9 @@
|
||||
using DeepTrace.Data;
|
||||
using Microsoft.ML;
|
||||
|
||||
namespace DeepTrace.ML
|
||||
namespace DeepTrace.ML;
|
||||
|
||||
public interface IEstimatorBuilder
|
||||
{
|
||||
public interface IEstimatorBuilder
|
||||
{
|
||||
IEstimator<ITransformer> BuildPipeline(MLContext mlContext, ModelDefinition model);
|
||||
}
|
||||
}
|
||||
@ -10,3 +10,8 @@ public interface IMLProcessor
|
||||
void Import(byte[] data);
|
||||
Task<Prediction> Predict(TrainedModelDefinition trainedModel, ModelDefinition model, List<TimeSeriesDataSet> data);
|
||||
}
|
||||
|
||||
public interface IMLProcessorFactory
|
||||
{
|
||||
IMLProcessor Create();
|
||||
}
|
||||
|
||||
@ -1,11 +1,10 @@
|
||||
using PrometheusAPI;
|
||||
|
||||
namespace DeepTrace.ML
|
||||
namespace DeepTrace.ML;
|
||||
|
||||
public interface IMeasure
|
||||
{
|
||||
public interface IMeasure
|
||||
{
|
||||
public string Name { get; }
|
||||
void Reset();
|
||||
float Calculate(IEnumerable<TimeSeries> data);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
namespace DeepTrace.ML
|
||||
namespace DeepTrace.ML;
|
||||
|
||||
public class MLEvaluationMetrics
|
||||
{
|
||||
public class MLEvaluationMetrics
|
||||
{
|
||||
public MLEvaluationMetrics()
|
||||
{
|
||||
|
||||
@ -12,5 +12,4 @@
|
||||
public double LogLoss { get; set; }
|
||||
public double LogLossReduction { get; set; }
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -7,6 +7,21 @@ namespace DeepTrace.ML;
|
||||
|
||||
public record ModelRecord(MLContext Context, DataViewSchema Schema, ITransformer Transformer);
|
||||
|
||||
public class MLInputData
|
||||
{
|
||||
public string Label { get; set; } = "Normal operation";
|
||||
public float[] Features { get; set; } = Array.Empty<float>();
|
||||
|
||||
}
|
||||
|
||||
public class MLOutputData
|
||||
{
|
||||
public string PredictedLabel { get; set; } = string.Empty;
|
||||
|
||||
public float[] Score { get; set; } = Array.Empty<float>();
|
||||
}
|
||||
|
||||
|
||||
public static class MLHelpers
|
||||
{
|
||||
public static byte[] ExportSingleModel( ModelRecord model)
|
||||
@ -32,10 +47,22 @@ public static class MLHelpers
|
||||
|
||||
await File.WriteAllTextAsync(fileName, csv);
|
||||
|
||||
return LoadFromCsv(mlContext, model, fileName);
|
||||
return (LoadFromCsv(mlContext, model, fileName), fileName);
|
||||
}
|
||||
|
||||
public static (IDataView View, string FileName) LoadFromCsv(MLContext mlContext, ModelDefinition model, string fileName)
|
||||
public static Task<IDataView> ToInput(MLContext mlContext, ModelDefinition model)
|
||||
{
|
||||
var input = model.ToInput().ToList();
|
||||
|
||||
// VectorType attribute with dynamic dimension
|
||||
// https://github.com/dotnet/machinelearning/issues/164
|
||||
var schemaDef = SchemaDefinition.Create(typeof(MLInputData));
|
||||
schemaDef["Features"].ColumnType = new VectorDataViewType(NumberDataViewType.Single, input.First().Features.Length );
|
||||
|
||||
return Task.FromResult(mlContext.Data.LoadFromEnumerable(input, schemaDef));
|
||||
}
|
||||
|
||||
public static IDataView LoadFromCsv(MLContext mlContext, ModelDefinition model, string fileName)
|
||||
{
|
||||
var columnNames = model.GetColumnNames();
|
||||
var columns = columnNames
|
||||
@ -43,8 +70,14 @@ public static class MLHelpers
|
||||
.ToArray()
|
||||
;
|
||||
|
||||
var view = mlContext.Data.LoadFromTextFile(fileName, columns, separatorChar: ',', hasHeader: true, allowQuoting: true, trimWhitespace: true);
|
||||
var view = mlContext.Data.LoadFromTextFile(
|
||||
fileName,
|
||||
columns,
|
||||
separatorChar: ',',
|
||||
hasHeader: true,
|
||||
allowQuoting: true,
|
||||
trimWhitespace: true);
|
||||
|
||||
return (view, fileName);
|
||||
return view;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,32 +1,51 @@
|
||||
using DeepTrace.Data;
|
||||
using Microsoft.ML;
|
||||
using Microsoft.ML.Data;
|
||||
using PrometheusAPI;
|
||||
using System.Data;
|
||||
using static DeepTrace.MLModel1;
|
||||
|
||||
namespace DeepTrace.ML
|
||||
namespace DeepTrace.ML;
|
||||
|
||||
internal class MLProcessorFactory : IMLProcessorFactory
|
||||
{
|
||||
public class MLProcessor : IMLProcessor
|
||||
private readonly ILogger<MLProcessor> _logger;
|
||||
private IEstimatorBuilder _estimatorBuilder;
|
||||
|
||||
public MLProcessorFactory(ILogger<MLProcessor> logger, IEstimatorBuilder estimatorBuilder)
|
||||
{
|
||||
_logger = logger;
|
||||
_estimatorBuilder = estimatorBuilder;
|
||||
}
|
||||
|
||||
public IMLProcessor Create() => new MLProcessor(_logger, _estimatorBuilder);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Wrapper for ML.NET operations.
|
||||
/// </summary>
|
||||
public class MLProcessor : IMLProcessor
|
||||
{
|
||||
private readonly ILogger<MLProcessor> _logger;
|
||||
private MLContext _mlContext = new MLContext();
|
||||
private EstimatorBuilder _estimatorBuilder = new EstimatorBuilder();
|
||||
private IEstimatorBuilder _estimatorBuilder;
|
||||
private DataViewSchema? _schema;
|
||||
private ITransformer? _transformer;
|
||||
private static string _signature = "DeepTrace-Model-v1-" + typeof(MLProcessor).Name;
|
||||
private readonly ILogger<MLProcessor> _logger;
|
||||
private PredictionEngine<MLInputData, MLOutputData>? _predictionEngine;
|
||||
|
||||
public MLProcessor(ILogger<MLProcessor> logger)
|
||||
public MLProcessor(ILogger<MLProcessor> logger, IEstimatorBuilder estimatorBuilder)
|
||||
{
|
||||
_logger = logger;
|
||||
_estimatorBuilder = estimatorBuilder;
|
||||
}
|
||||
|
||||
private string Name { get; set; } = "TestModel";
|
||||
|
||||
public async Task<MLEvaluationMetrics> Train(ModelDefinition modelDef, Action<string> log)
|
||||
{
|
||||
_logger.LogInformation("Training started");
|
||||
|
||||
Name = modelDef.Name;
|
||||
var pipeline = _estimatorBuilder.BuildPipeline(_mlContext, modelDef);
|
||||
var (data, filename) = await MLHelpers.Convert(_mlContext, modelDef);
|
||||
var data = await MLHelpers.ToInput(_mlContext, modelDef);
|
||||
|
||||
DataOperationsCatalog.TrainTestData dataSplit = _mlContext.Data.TrainTestSplit(data, testFraction: 0.2);
|
||||
|
||||
@ -35,13 +54,13 @@ namespace DeepTrace.ML
|
||||
{
|
||||
_schema = data.Schema;
|
||||
_transformer = pipeline.Fit(dataSplit.TrainSet);
|
||||
|
||||
return Evaluate(dataSplit.TestSet);
|
||||
}
|
||||
finally
|
||||
{
|
||||
File.Delete(filename);
|
||||
_logger.LogInformation("Training finished");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void LogEvents(Action<string> log, LoggingEventArgs e)
|
||||
@ -56,8 +75,10 @@ namespace DeepTrace.ML
|
||||
|
||||
private MLEvaluationMetrics Evaluate(IDataView testData)
|
||||
{
|
||||
// https://learn.microsoft.com/en-us/dotnet/api/microsoft.ml.standardtrainerscatalog.lbfgslogisticregression?view=ml-dotnet
|
||||
|
||||
var predictions = _transformer!.Transform(testData);
|
||||
var metrics = _mlContext.MulticlassClassification.Evaluate(predictions, "Name");
|
||||
var metrics = _mlContext.MulticlassClassification.Evaluate(predictions, nameof(MLInputData.Label));
|
||||
var evaluationMetrics = new MLEvaluationMetrics()
|
||||
{
|
||||
MicroAccuracy = metrics.MicroAccuracy,
|
||||
@ -110,28 +131,25 @@ namespace DeepTrace.ML
|
||||
(_mlContext, _schema, _transformer) = MLHelpers.ImportSingleModel(bytes);
|
||||
}
|
||||
|
||||
public async Task<Prediction> Predict(TrainedModelDefinition trainedModel, ModelDefinition model, List<TimeSeriesDataSet> data)
|
||||
public Task<Prediction> Predict(TrainedModelDefinition trainedModel, ModelDefinition model, List<TimeSeriesDataSet> data)
|
||||
{
|
||||
Name = trainedModel.Name;
|
||||
|
||||
if (_transformer == null )
|
||||
Import(trainedModel.Value);
|
||||
var headers = string.Join(",", model.GetColumnNames().Select(x => $"\"{x}\""));
|
||||
var row = ModelDefinition.ConvertToCsv(data);
|
||||
|
||||
var csv = headers+"\n"+row;
|
||||
var fileName = Path.GetTempFileName();
|
||||
try
|
||||
if (_predictionEngine == null)
|
||||
{
|
||||
await File.WriteAllTextAsync(fileName, csv);
|
||||
|
||||
var (dataView, _) = MLHelpers.LoadFromCsv(_mlContext, model, fileName);
|
||||
|
||||
var predictionEngine = _mlContext.Model.CreatePredictionEngine<IDataView, Prediction>(_transformer);
|
||||
var prediction = predictionEngine.Predict(dataView);
|
||||
return prediction;
|
||||
_predictionEngine = _mlContext.Model.CreatePredictionEngine<MLInputData, MLOutputData>(_transformer, _schema);
|
||||
}
|
||||
finally
|
||||
|
||||
var input = new MLInputData
|
||||
{
|
||||
File.Delete(fileName);
|
||||
}
|
||||
}
|
||||
Features = DataSourceDefinition.ToFeatures(data)
|
||||
};
|
||||
|
||||
var prediction = _predictionEngine.Predict( input );
|
||||
|
||||
return Task.FromResult( new Prediction { PredictedLabel = prediction.PredictedLabel, Score = prediction.Score } );
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
using PrometheusAPI;
|
||||
|
||||
namespace DeepTrace.ML
|
||||
namespace DeepTrace.ML;
|
||||
|
||||
public class MeasureMin : IMeasure
|
||||
{
|
||||
public class MeasureMin : IMeasure
|
||||
{
|
||||
public string Name => "Min";
|
||||
public float Calculate(IEnumerable<TimeSeries> data) =>
|
||||
data
|
||||
@ -12,34 +12,34 @@ namespace DeepTrace.ML
|
||||
;
|
||||
|
||||
public void Reset() { }
|
||||
}
|
||||
}
|
||||
|
||||
public class MeasureMax : IMeasure
|
||||
{
|
||||
public class MeasureMax : IMeasure
|
||||
{
|
||||
public string Name => "Max";
|
||||
public float Calculate(IEnumerable<TimeSeries> data) => data.Max(x => x.Value);
|
||||
public void Reset() { }
|
||||
}
|
||||
}
|
||||
|
||||
public class MeasureAvg : IMeasure
|
||||
{
|
||||
public class MeasureAvg : IMeasure
|
||||
{
|
||||
public string Name => "Avg";
|
||||
public float Calculate(IEnumerable<TimeSeries> data) => data.Average(x => x.Value);
|
||||
public void Reset() { }
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// WARNING: Only works with fixed length interval
|
||||
/// </summary>
|
||||
public class MeasureSum : IMeasure
|
||||
{
|
||||
/// <summary>
|
||||
/// WARNING: Only works with fixed length interval
|
||||
/// </summary>
|
||||
public class MeasureSum : IMeasure
|
||||
{
|
||||
public string Name => "Sum";
|
||||
public float Calculate(IEnumerable<TimeSeries> data) => data.Sum(x => x.Value);
|
||||
public void Reset() { }
|
||||
}
|
||||
}
|
||||
|
||||
public class MeasureMedian : IMeasure
|
||||
{
|
||||
public class MeasureMedian : IMeasure
|
||||
{
|
||||
public string Name => "Median";
|
||||
|
||||
public float Calculate(IEnumerable<TimeSeries> data)
|
||||
@ -47,10 +47,10 @@ namespace DeepTrace.ML
|
||||
|
||||
public void Reset() { }
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public class MeasureDiff<T> : IMeasure where T : IMeasure, new()
|
||||
{
|
||||
public class MeasureDiff<T> : IMeasure where T : IMeasure, new()
|
||||
{
|
||||
private T _measure = new();
|
||||
public string Name => "Diff_"+_measure.Name;
|
||||
|
||||
@ -75,15 +75,13 @@ namespace DeepTrace.ML
|
||||
_measure.Reset();
|
||||
_prev = float.NaN;
|
||||
}
|
||||
}
|
||||
|
||||
public class MeasureDiffMin : MeasureDiff<MeasureMin> { }
|
||||
public class MeasureDiffMax : MeasureDiff<MeasureMax> { }
|
||||
public class MeasureDiffAvg : MeasureDiff<MeasureAvg> { }
|
||||
/// <summary>
|
||||
/// WARNING: Only works with fixed length interval
|
||||
/// </summary>
|
||||
public class MeasureDiffSum : MeasureDiff<MeasureSum> { }
|
||||
public class MeasureDiffMedian : MeasureDiff<MeasureMedian> { }
|
||||
|
||||
}
|
||||
|
||||
public class MeasureDiffMin : MeasureDiff<MeasureMin> { }
|
||||
public class MeasureDiffMax : MeasureDiff<MeasureMax> { }
|
||||
public class MeasureDiffAvg : MeasureDiff<MeasureAvg> { }
|
||||
/// <summary>
|
||||
/// WARNING: Only works with fixed length interval
|
||||
/// </summary>
|
||||
public class MeasureDiffSum : MeasureDiff<MeasureSum> { }
|
||||
public class MeasureDiffMedian : MeasureDiff<MeasureMedian> { }
|
||||
|
||||
@ -58,8 +58,8 @@
|
||||
int pos = i;
|
||||
|
||||
<MudItem xs="10">
|
||||
@*<MudTextField Label="Query" @bind-Value="_queryForm.Source.Queries[pos].Query" Variant="Variant.Text" InputType="InputType.Search" Lines="2" />*@
|
||||
<MudAutocomplete Label="Query" @bind-Value="_queryForm.Source.Queries[pos].Query" Lines="1" Variant="Variant.Text" SearchFunc="@SearchForQuery"></MudAutocomplete>
|
||||
<MudTextField Label="Query" @bind-Value="_queryForm.Source.Queries[pos].Query" Variant="Variant.Text" InputType="InputType.Search" Lines="2" />
|
||||
@*<MudAutocomplete Label="Query" @bind-Value="_queryForm.Source.Queries[pos].Query" Lines="1" Variant="Variant.Text" SearchFunc="@SearchForQuery"></MudAutocomplete>*@
|
||||
</MudItem>
|
||||
<MudItem xs="1">
|
||||
<MudIconButton Icon="@Icons.Material.Outlined.Add" Variant="Variant.Outlined" aria-label="add" OnClick="@(() => AddQuery(pos))" />
|
||||
|
||||
@ -2,12 +2,12 @@
|
||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace DeepTrace.Pages
|
||||
namespace DeepTrace.Pages;
|
||||
|
||||
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
|
||||
[IgnoreAntiforgeryToken]
|
||||
public class ErrorModel : PageModel
|
||||
{
|
||||
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
|
||||
[IgnoreAntiforgeryToken]
|
||||
public class ErrorModel : PageModel
|
||||
{
|
||||
public string? RequestId { get; set; }
|
||||
|
||||
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
|
||||
@ -23,5 +23,4 @@ namespace DeepTrace.Pages
|
||||
{
|
||||
RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -14,9 +14,9 @@ Welcome to your new app.
|
||||
@if (_trainedModels != null)
|
||||
{
|
||||
@foreach(TrainedModelDefinition model in _trainedModels)
|
||||
{
|
||||
{
|
||||
<ModelCard Model="@model"/>
|
||||
}
|
||||
}
|
||||
} else
|
||||
{
|
||||
<MudText>Nothing to display</MudText>
|
||||
@ -24,13 +24,13 @@ Welcome to your new app.
|
||||
|
||||
|
||||
@code{
|
||||
private List<TrainedModelDefinition> _trainedModels = new();
|
||||
private List<TrainedModelDefinition> _trainedModels = new();
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
base.OnInitialized();
|
||||
_trainedModels = await TrainedModelService.Load();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -18,7 +18,7 @@
|
||||
@inject IEstimatorBuilder EstimatorBuilder
|
||||
@inject NavigationManager NavManager
|
||||
@inject IJSRuntime Js
|
||||
@inject ILogger<MLProcessor> MLProcessorLogger
|
||||
@inject IMLProcessorFactory MlProcessorFactory
|
||||
|
||||
|
||||
<PageTitle>Training</PageTitle>
|
||||
@ -531,14 +531,14 @@
|
||||
|
||||
private async Task HandleTrain()
|
||||
{
|
||||
var mlProcessor = new MLProcessor(MLProcessorLogger);
|
||||
MLProcessorLogger.LogInformation("Training started");
|
||||
|
||||
var options = new DialogOptions
|
||||
{
|
||||
CloseOnEscapeKey = true
|
||||
};
|
||||
var parameters = new DialogParameters();
|
||||
|
||||
var mlProcessor = MlProcessorFactory.Create();
|
||||
|
||||
parameters.Add(nameof(Controls.TrainingDialog.Text), _modelForm!.CurrentModel.Name);
|
||||
parameters.Add(nameof(Controls.TrainingDialog.Processor), mlProcessor);
|
||||
parameters.Add(nameof(Controls.TrainingDialog.Model), _modelForm.CurrentModel);
|
||||
@ -546,7 +546,6 @@
|
||||
var d = DialogService.Show<Controls.TrainingDialog>("Training", parameters, options);
|
||||
var res = await d.Result;
|
||||
|
||||
MLProcessorLogger.LogInformation("Training finished");
|
||||
var bytes = mlProcessor.Export();
|
||||
|
||||
//save to Mongo
|
||||
|
||||
@ -29,6 +29,7 @@ builder.Services
|
||||
.AddSingleton<IModelStorageService, ModelStorageService>()
|
||||
.AddSingleton<ITrainedModelStorageService, TrainedModelStorageService>()
|
||||
.AddSingleton<IEstimatorBuilder, EstimatorBuilder>()
|
||||
.AddSingleton<IMLProcessorFactory, MLProcessorFactory>()
|
||||
;
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
using MongoDB.Bson;
|
||||
using MongoDB.Driver;
|
||||
|
||||
namespace DeepTrace.Services
|
||||
namespace DeepTrace.Services;
|
||||
|
||||
public class DataSourceStorageService : IDataSourceStorageService
|
||||
{
|
||||
public class DataSourceStorageService : IDataSourceStorageService
|
||||
{
|
||||
|
||||
private const string MongoDBDatabaseName = "DeepTrace";
|
||||
private const string MongoDBCollection = "Sources";
|
||||
@ -54,5 +54,4 @@ namespace DeepTrace.Services
|
||||
|
||||
await collection.DeleteOneAsync($"_id = {source.Id}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,10 +2,10 @@
|
||||
using MongoDB.Bson.Serialization.Attributes;
|
||||
using MongoDB.Bson;
|
||||
|
||||
namespace DeepTrace.Services
|
||||
namespace DeepTrace.Services;
|
||||
|
||||
public class DataSourceStorage : DataSourceDefinition, IEquatable<DataSourceStorage>
|
||||
{
|
||||
public class DataSourceStorage : DataSourceDefinition, IEquatable<DataSourceStorage>
|
||||
{
|
||||
[BsonId]
|
||||
public ObjectId? Id { get; set; }
|
||||
|
||||
@ -27,12 +27,11 @@ namespace DeepTrace.Services
|
||||
{
|
||||
return Id?.GetHashCode() ?? base.GetHashCode();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public interface IDataSourceStorageService
|
||||
{
|
||||
public interface IDataSourceStorageService
|
||||
{
|
||||
Task Delete(DataSourceStorage source, bool ignoreNotStored = false);
|
||||
Task<List<DataSourceStorage>> Load();
|
||||
Task Store(DataSourceStorage source);
|
||||
}
|
||||
}
|
||||
@ -3,14 +3,13 @@ using MongoDB.Bson;
|
||||
using DeepTrace.Data;
|
||||
using System.Text;
|
||||
|
||||
namespace DeepTrace.Services
|
||||
{
|
||||
namespace DeepTrace.Services;
|
||||
|
||||
public interface IModelStorageService
|
||||
{
|
||||
|
||||
public interface IModelStorageService
|
||||
{
|
||||
Task Delete(ModelDefinition source, bool ignoreNotStored = false);
|
||||
Task<List<ModelDefinition>> Load();
|
||||
Task<ModelDefinition?> Load(BsonObjectId id);
|
||||
Task Store(ModelDefinition source);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,11 +1,10 @@
|
||||
using DeepTrace.Data;
|
||||
|
||||
namespace DeepTrace.Services
|
||||
namespace DeepTrace.Services;
|
||||
|
||||
public interface ITrainedModelStorageService
|
||||
{
|
||||
public interface ITrainedModelStorageService
|
||||
{
|
||||
Task Delete(TrainedModelDefinition source, bool ignoreNotStored = false);
|
||||
Task<List<TrainedModelDefinition>> Load();
|
||||
Task Store(TrainedModelDefinition source);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,10 +2,10 @@
|
||||
using MongoDB.Bson;
|
||||
using MongoDB.Driver;
|
||||
|
||||
namespace DeepTrace.Services
|
||||
namespace DeepTrace.Services;
|
||||
|
||||
public class ModelStorageService : IModelStorageService
|
||||
{
|
||||
public class ModelStorageService : IModelStorageService
|
||||
{
|
||||
|
||||
private const string MongoDBDatabaseName = "DeepTrace";
|
||||
private const string MongoDBCollection = "Models";
|
||||
@ -30,8 +30,9 @@ namespace DeepTrace.Services
|
||||
{
|
||||
var db = _client.GetDatabase(MongoDBDatabaseName);
|
||||
var collection = db.GetCollection<ModelDefinition>(MongoDBCollection);
|
||||
var res = (await (await collection.FindAsync($"{{_id:ObjectId(\"{id}\")}}")).ToListAsync()).FirstOrDefault();
|
||||
return res;
|
||||
|
||||
var res = await (await collection.FindAsync($"{{ _id : ObjectId(\"{id}\") }}")).ToListAsync();
|
||||
return res.FirstOrDefault();
|
||||
}
|
||||
|
||||
public async Task Store(ModelDefinition source)
|
||||
@ -64,5 +65,4 @@ namespace DeepTrace.Services
|
||||
|
||||
await collection.DeleteOneAsync(filter: new BsonDocument("_id", source.Id));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,10 +2,10 @@
|
||||
using MongoDB.Bson;
|
||||
using MongoDB.Driver;
|
||||
|
||||
namespace DeepTrace.Services
|
||||
namespace DeepTrace.Services;
|
||||
|
||||
public class TrainedModelStorageService: ITrainedModelStorageService
|
||||
{
|
||||
public class TrainedModelStorageService: ITrainedModelStorageService
|
||||
{
|
||||
private const string MongoDBDatabaseName = "DeepTrace";
|
||||
private const string MongoDBCollection = "TrainedModels";
|
||||
|
||||
@ -54,5 +54,4 @@ namespace DeepTrace.Services
|
||||
|
||||
await collection.DeleteOneAsync(filter: new BsonDocument("_id", source.Id));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -10,7 +10,7 @@
|
||||
</div>
|
||||
|
||||
@code {
|
||||
// Demonstrates how a parent component can supply parameters
|
||||
[Parameter]
|
||||
public string? Title { get; set; }
|
||||
// Demonstrates how a parent component can supply parameters
|
||||
[Parameter]
|
||||
public string? Title { get; set; }
|
||||
}
|
||||
|
||||
@ -6,10 +6,10 @@ using System.Text.Json.Serialization;
|
||||
using System.Text.Json;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace PrometheusAPI
|
||||
namespace PrometheusAPI;
|
||||
|
||||
public static class JsonSetializerSetup
|
||||
{
|
||||
public static class JsonSetializerSetup
|
||||
{
|
||||
private static JsonSerializerOptions _options = new JsonSerializerOptions
|
||||
{
|
||||
AllowTrailingCommas = true,
|
||||
@ -21,5 +21,4 @@ namespace PrometheusAPI
|
||||
};
|
||||
|
||||
public static JsonSerializerOptions Options => _options;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
using System.Text.Json;
|
||||
|
||||
namespace PrometheusAPI
|
||||
namespace PrometheusAPI;
|
||||
|
||||
public class PrometheusClient
|
||||
{
|
||||
public class PrometheusClient
|
||||
{
|
||||
private readonly HttpClient _client;
|
||||
|
||||
public PrometheusClient(HttpClient client)
|
||||
@ -115,5 +115,4 @@ namespace PrometheusAPI
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace PrometheusAPI
|
||||
namespace PrometheusAPI;
|
||||
|
||||
internal class TimeSeriesCoverter : JsonConverter<TimeSeries?>
|
||||
{
|
||||
internal class TimeSeriesCoverter : JsonConverter<TimeSeries?>
|
||||
{
|
||||
public override TimeSeries? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||
{
|
||||
if (reader.TokenType != JsonTokenType.StartArray)
|
||||
@ -48,5 +48,4 @@ namespace PrometheusAPI
|
||||
writer.WriteEndArray();
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user