diff --git a/DeepTrace/Pages/Evaluate.razor b/DeepTrace/Pages/Evaluate.razor
new file mode 100644
index 0000000..e010660
--- /dev/null
+++ b/DeepTrace/Pages/Evaluate.razor
@@ -0,0 +1,249 @@
+@page "/evaluate"
+@using CsvHelper;
+@using DeepTrace.Controls
+@using DeepTrace.Data;
+@using DeepTrace.ML;
+@using DeepTrace.Services;
+@using Microsoft.ML;
+@using System.Data;
+@using MudBlazor;
+@using PrometheusAPI;
+@using System.ComponentModel.DataAnnotations;
+@using Microsoft.ML.Data;
+@using Microsoft.ML.TimeSeries;
+@using System.Globalization;
+
+@inject PrometheusClient Prometheus
+@inject IDialogService DialogService
+@inject IDataSourceStorageService StorageService
+@inject IMLProcessorFactory MlProcessorFactory
+
+DataSources
+
+
+
+
Evaluate test data
+
+Upload CSV containing TimeStamp, Label and at least one feature column. ML model will be created and evauated against these serries.
+
+
+
+
+
+
+
+
+
+ Import
+
+
+
+
+ @* Evaluate *@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+@code {
+
+ [CascadingParameter]
+ protected bool IsDarkMode { get; set; }
+
+ private bool IsChartHidden => DisplayData == null || DisplayData.Series.Count == 0;
+ private bool IsChartShown => !IsChartHidden;
+
+ private DateTime? MinDate { get; set; }
+
+ private DateTime? MaxDate { get; set; }
+
+ private TimeSeriesData? DisplayData { get; set; }
+
+ private string[] _palette = new[]
+ {
+ "#F44336", "#E91E63", "#9C27B0", "#673AB7", "#3F51B5",
+ "#FFEBEE", "#FCE4EC", "#F3E5F5", "#EDE7F6", "#E8EAF6",
+ "#FFCDD2", "#F8BBD0", "#E1BEE7", "#D1C4E9", "#C5CAE9",
+ "#EF9A9A", "#F48FB1", "#CE93D8", "#B39DDB", "#9FA8DA",
+ "#E57373", "#F06292", "#BA68C8", "#9575CD", "#7986CB",
+ "#EF5350", "#EC407A", "#AB47BC", "#7E57C2", "#5C6BC0",
+ "#E53935", "#D81B60", "#8E24AA", "#5E35B1", "#3949AB"
+ };
+
+ private async Task HandleEvaluate(IBrowserFile file)
+ {
+ try
+ {
+ await HandleImportInternal(file);
+ }
+ catch (Exception e)
+ {
+ await ShowError($"Can't import: {e.Message}");
+ }
+ }
+
+ private record DataLabels(DateTime TimeStamp, string Label);
+
+ private async Task HandleImportInternal(IBrowserFile file)
+ {
+ using var mem = new MemoryStream();
+ // https://stackoverflow.com/questions/67066860/blazorinputfile-synchronous-reads-are-not-supported
+ await file.OpenReadStream(file.Size).CopyToAsync(mem);
+ mem.Position = 0;
+
+ using (var reader = new StreamReader(mem))
+ using (var csv = new CsvReader(reader, CultureInfo.InvariantCulture))
+ {
+ csv.Read();
+ csv.ReadHeader();
+
+ if (csv.HeaderRecord == null)
+ return;
+
+ var headers = csv.HeaderRecord.Select((x,i) => (x,i)).ToDictionary(x => x.x, x => x.i, StringComparer.OrdinalIgnoreCase);
+ var timeStampColId = headers["TimeStamp"];
+ var labelColId = headers["Label"];
+
+ var series = new Dictionary();
+ for (var i = 0; i < headers.Count; i++)
+ {
+ if (i == timeStampColId || i == labelColId)
+ continue;
+
+ series[csv.HeaderRecord[i]] = new()
+ {
+ Name = csv.HeaderRecord[i],
+ Color = _palette[i % _palette.Length]
+ };
+ }
+
+ var labels = new List();
+
+ while (csv.Read())
+ {
+ var v = csv.GetField(timeStampColId);
+ if (!DateTime.TryParse(v, out var timeStamp))
+ continue;
+ var label = csv.GetField(labelColId) ?? "No label";
+
+ labels.Add(new(TimeStamp: timeStamp, Label: label));
+
+ for( var i = 0; i < headers.Count; i++ )
+ {
+ if (i == timeStampColId || i == labelColId)
+ continue;
+
+ v = csv.GetField(i) ?? "0";
+ if (!float.TryParse(v, out var f))
+ f = 0.0F;
+ series[csv.HeaderRecord[i]].Data.Add(new(timeStamp, f) );
+ }
+ }
+
+ var data = new TimeSeriesData();
+ data.Series.AddRange(series.Values);
+ DisplayData = data;
+
+ var model = CreateModelDefinition(data, labels);
+ model.Name = file.Name;
+ await TrainModel(model);
+ }
+ await InvokeAsync(StateHasChanged);
+ }
+
+ private static ModelDefinition CreateModelDefinition(TimeSeriesData data, List labels)
+ {
+ var model = new ModelDefinition();
+
+ foreach( var ts in data.Series )
+ model.DataSource.Queries.Add(new(ts.Name, ts.Color));
+
+ ConvertToIntervals(model.IntervalDefinitionList, data, labels);
+
+ return model;
+ }
+
+ private static void ConvertToIntervals(List intervals, TimeSeriesData data, List labels)
+ {
+ for(var i=0; i("Training", parameters, options);
+ var _ = await d.Result;
+ }
+
+
+ private async Task ShowError(string text)
+ {
+ var options = new DialogOptions
+ {
+ CloseOnEscapeKey = true
+ };
+ var parameters = new DialogParameters();
+ parameters.Add("Text", text);
+
+ var d = DialogService.Show("Error", parameters, options);
+ await d.Result;
+ }
+
+}
diff --git a/DeepTrace/Shared/NavMenu.razor b/DeepTrace/Shared/NavMenu.razor
index 4963d00..c561875 100644
--- a/DeepTrace/Shared/NavMenu.razor
+++ b/DeepTrace/Shared/NavMenu.razor
@@ -1,7 +1,9 @@
Dashboard
Data sources
- Training
+ Training
+
+ Evaluate
About