using Inspectron.Statistics; using Lindt.Colorballs.Duo.Utils; using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection.PortableExecutable; using Ninject; using Serilog; using VisionBuilder.UI.Common; using VisionBuilder.UI.Common.Commands; using VisionBuilder.UI.Common.Processing; namespace VisionBuilder.UI.Statistics { public class VisionBuilderStatistics:IVisionBuilderModule,IDisposable { private CsvStatistics? _csvStatistics; private readonly VisionBuilderStatisticsSettings _settings; private string _filePath; private readonly IRecognitionControl _recognitionControl; private readonly ILoadingService _loadingService; private DateTime _startTime; private string _currentRecipe; private string _fileName; private string _directoryPath; private int _total = 0; private int _errors = 0; private const string BY_EVENTS_FILE_NAME = "statistics_by_events.csv"; private const string MONTHLY_FILE_NAME = "statistics_month.csv"; private const string EMPTY_DATE = ""; private const string EMPTY_TIME = ""; private const string DATE_FORMAT = "dd.MM.yyyy"; private const string TIME_FORMAT = "HH:mm:ss"; private const string TIME_FORMAT_MS = "HH:mm:ss:fff"; public bool DoNotDeleteTempFiles { get; set; } = false; public VisionBuilderStatistics(VisionBuilderStatisticsSettings settings, IRecognitionControl recognitionControl, ILoadingService loadingService) { _settings = settings; _recognitionControl = recognitionControl; _loadingService = loadingService; } public string Metadata { get; set; } = ""; private void _recognitionControl_SessionEnded(SessionEndedEvent obj) { if (_csvStatistics == null) { Log.Warning("Session ended but CSV statistics is null, nothing to do."); return; } var endedAt = obj.SessionEnded; _endTime = endedAt; Log.Information("Start processing statistics"); _loadingService.StartLoading("Writing statistics for " + _settings.CameraName); try { _csvStatistics.WriteLine([_startTime.ToString(DATE_FORMAT), _startTime.ToString(TIME_FORMAT), endedAt.ToString(DATE_FORMAT), endedAt.ToString(TIME_FORMAT), "", "", ""]); _csvStatistics.Dispose(); _csvStatistics = null; WriteFinalStatistics(); } finally { _loadingService.StopLoading("Writing statistics for " + _settings.CameraName); Log.Information("End processing statistics"); } } private void _recognitionControl_ImageProcessed(ImageProcessedEvent obj) { var sw = Stopwatch.StartNew(); _total++; if (obj.HasError) { _errors++; RecordBadImage(obj.ErrorNames.ToArray()); } sw.Stop(); Log.Debug($"Recording statistics took {sw.ElapsedMilliseconds} ms"); } private void _recognitionControl_SessionStarted(SessionStartedEvent obj) { _startTime = obj.SessionStarted; _total = 0; _errors= 0; _currentRecipe = obj.RecipeName; _fileName = BY_EVENTS_FILE_NAME; _directoryPath = PathSettingsUtils.ConvertVariables(_settings.PathTemplate, _startTime, _startTime, obj.RecipeName, cameraName: _settings.CameraName); _filePath = Path.Combine(_directoryPath, _fileName); var headers = new[] { _settings.StartDateColumnName, _settings.StartTimeColumnName, _settings.EndDateColumnName, _settings.EndTimeColumnName, _settings.ErrorTimeColumnName, _settings.ProductColumnName, _settings.ErrorColumnName, _settings.MetadataColumnName }; if (!Directory.Exists(Path.GetDirectoryName(_filePath))) { Directory.CreateDirectory(Path.GetDirectoryName(_filePath)); } _csvStatistics = new CsvStatistics(_filePath, headers); _csvStatistics.WriteLine([_startTime.ToString(DATE_FORMAT), _startTime.ToString(TIME_FORMAT)]); // session started _defects = new ConcurrentDictionary(); } ConcurrentDictionary _defects = new(); private DateTime _endTime; private void RecordBadImage(string[] defectNames) { _csvStatistics.WriteLine( [_startTime.ToString(DATE_FORMAT), _startTime.ToString(TIME_FORMAT), EMPTY_DATE, EMPTY_TIME, DateTime.Now.ToString(DATE_FORMAT+" "+TIME_FORMAT_MS), _currentRecipe, defectNames[0], Metadata] ); foreach (var defectName in defectNames) { _defects.AddOrUpdate(defectName, 1, (key, oldValue) => oldValue + 1); } } private void WriteMonthStatistics() { var startDate = _startTime.Date; var startTime = _startTime; var endDate = _endTime.Date; var endTime = _endTime; var monthFilePath = Path.Combine(_directoryPath, MONTHLY_FILE_NAME); var monthStatistics = new CsvStatistics(monthFilePath, [ ]); monthStatistics.WriteLine( ["Start", _startTime.ToString($"{DATE_FORMAT} {TIME_FORMAT}")] ); monthStatistics.WriteLine([ _settings.MetadataColumnName, Metadata ]); monthStatistics.WriteLine( [_settings.ProductColumnName, _currentRecipe] ); monthStatistics.WriteLine( [_settings.ErrorColumnName, "Amount"] ); foreach (var defect in _defects.OrderBy(x=>x.Key)) { monthStatistics.WriteLine( [defect.Key, defect.Value.ToString()] ); } monthStatistics.WriteLine([]); monthStatistics.WriteLine( ["Total error images", _errors.ToString()] ); monthStatistics.WriteLine( ["Total produced(including errors)", _total.ToString()] ); var percentage = _total > 0 ? (double)_errors / _total * 100 : 0; monthStatistics.WriteLine( ["Error rate", percentage.ToString("F2") + "%"] ); monthStatistics.WriteLine( [ "End", _endTime.ToString($"{DATE_FORMAT} {TIME_FORMAT}") ]); monthStatistics.WriteLine([]); monthStatistics.WriteLine([]); monthStatistics.Dispose(); } private void WriteFinalStatistics() { try { Log.Debug("Writing month statistics"); WriteMonthStatistics(); } catch (Exception e) { Log.Error("Error writing statistics for " + _settings.CameraName+ "\n"+ e); } _csvStatistics?.Dispose(); _csvStatistics = null; } public void InitializeModule() { _recognitionControl.SessionStarted += _recognitionControl_SessionStarted; _recognitionControl.ImageProcessed += _recognitionControl_ImageProcessed; _recognitionControl.SessionEnded += _recognitionControl_SessionEnded; } public void Dispose() { _csvStatistics?.Dispose(); _recognitionControl.SessionStarted -= _recognitionControl_SessionStarted; _recognitionControl.ImageProcessed -= _recognitionControl_ImageProcessed; _recognitionControl.SessionEnded -= _recognitionControl_SessionEnded; } } }