Enhanced logging, diagnostics, and robustness throughout
Added NLog-based logging and diagnostics to Console and WPF apps, with programmatic configuration and support for debugger output. Refactored apps to use dependency injection and Microsoft.Extensions.Hosting. Improved output layer extraction and fallback logic in detection/recognition, including objectness-class probability multiplication. Added crop saving for diagnostics. Introduced new CLI options for diagnostics. MainViewModel and MainWindow now use DI and log errors. NumberRecognitionEngine supports logging, crop saving, and robust fallback. Added Python diagnostic script. Improved error handling and argument parsing.
This commit is contained in:
parent
769afc08fb
commit
d2206a00cb
14 changed files with 571 additions and 78 deletions
|
|
@ -9,6 +9,9 @@
|
|||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="NLog" Version="6.1.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="10.0.3" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging" Version="10.0.3" />
|
||||
<PackageReference Include="NLog.Extensions.Logging" Version="6.1.1" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\AIFotoONLUS.Core\AIFotoONLUS.Core.csproj" />
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:converters="clr-namespace:AIFotoONLUS.WPF.Converters"
|
||||
StartupUri="MainWindow.xaml">
|
||||
>
|
||||
<Application.Resources>
|
||||
<ResourceDictionary>
|
||||
<converters:InverseBoolConverter x:Key="InverseBoolConverter" />
|
||||
|
|
|
|||
|
|
@ -1,8 +1,78 @@
|
|||
using System;
|
||||
using System.Windows;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using NLog;
|
||||
using NLog.Config;
|
||||
using NLog.Targets;
|
||||
using NLog.Extensions.Logging;
|
||||
using AIFotoONLUS.WPF.ViewModels;
|
||||
|
||||
namespace AIFotoONLUS.WPF
|
||||
{
|
||||
public partial class App : System.Windows.Application
|
||||
{
|
||||
private IHost? _host;
|
||||
|
||||
protected override async void OnStartup(StartupEventArgs e)
|
||||
{
|
||||
base.OnStartup(e);
|
||||
|
||||
// configure NLog programmatically to write to console
|
||||
var nlogConfig = new LoggingConfiguration();
|
||||
var consoleTarget = new ColoredConsoleTarget("console")
|
||||
{
|
||||
Layout = "${longdate}|${level:uppercase=true}|${logger}|${message} ${exception:format=toString}"
|
||||
};
|
||||
var debugTarget = new DebuggerTarget("debug")
|
||||
{
|
||||
Layout = "${longdate}|${level:uppercase=true}|${logger}|${message} ${exception:format=toString}"
|
||||
};
|
||||
nlogConfig.AddTarget(consoleTarget);
|
||||
nlogConfig.AddTarget(debugTarget);
|
||||
nlogConfig.AddRule(NLog.LogLevel.Debug, NLog.LogLevel.Fatal, consoleTarget);
|
||||
nlogConfig.AddRule(NLog.LogLevel.Debug, NLog.LogLevel.Fatal, debugTarget);
|
||||
LogManager.Configuration = nlogConfig;
|
||||
// ensure existing loggers pick up the new configuration
|
||||
LogManager.ReconfigExistingLoggers();
|
||||
|
||||
_host = Host.CreateDefaultBuilder()
|
||||
.ConfigureLogging(logging =>
|
||||
{
|
||||
logging.ClearProviders();
|
||||
// write also to the VS Output (Debug) provider
|
||||
logging.AddDebug();
|
||||
logging.SetMinimumLevel(Microsoft.Extensions.Logging.LogLevel.Debug);
|
||||
logging.AddNLog();
|
||||
})
|
||||
.ConfigureServices((context, services) =>
|
||||
{
|
||||
services.AddSingleton<MainViewModel>();
|
||||
services.AddSingleton<MainWindow>();
|
||||
})
|
||||
.Build();
|
||||
|
||||
await _host.StartAsync().ConfigureAwait(false);
|
||||
|
||||
// emit a startup message to verify logging pipeline
|
||||
var startupLogger = _host.Services.GetRequiredService<ILogger<App>>();
|
||||
startupLogger.LogInformation("Host started and logging configured");
|
||||
|
||||
var main = _host.Services.GetRequiredService<MainWindow>();
|
||||
main.Show();
|
||||
}
|
||||
|
||||
protected override async void OnExit(ExitEventArgs e)
|
||||
{
|
||||
if (_host != null)
|
||||
{
|
||||
await _host.StopAsync().ConfigureAwait(false);
|
||||
_host.Dispose();
|
||||
}
|
||||
// flush NLog to ensure all messages are written before exit
|
||||
try { LogManager.Flush(); } catch { }
|
||||
base.OnExit(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,10 +6,11 @@ namespace AIFotoONLUS.WPF
|
|||
{
|
||||
public partial class MainWindow : Window
|
||||
{
|
||||
private MainViewModel _vm = new();
|
||||
private readonly MainViewModel _vm;
|
||||
|
||||
public MainWindow()
|
||||
public MainWindow(MainViewModel vm)
|
||||
{
|
||||
_vm = vm ?? throw new ArgumentNullException(nameof(vm));
|
||||
InitializeComponent();
|
||||
DataContext = _vm;
|
||||
}
|
||||
|
|
@ -17,7 +18,7 @@ namespace AIFotoONLUS.WPF
|
|||
protected override void OnClosed(EventArgs e)
|
||||
{
|
||||
base.OnClosed(e);
|
||||
_vm.Dispose();
|
||||
(_vm as IDisposable)?.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
using AIFotoONLUS.Core;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Collections.ObjectModel;
|
||||
|
|
@ -82,8 +83,14 @@ namespace AIFotoONLUS.WPF.ViewModels
|
|||
public RelayCommand ProcessCommand { get; }
|
||||
public RelayCommand CancelCommand { get; }
|
||||
|
||||
public MainViewModel()
|
||||
private readonly ILogger<MainViewModel>? _logger;
|
||||
private readonly ILoggerFactory? _loggerFactory;
|
||||
|
||||
public MainViewModel(ILogger<MainViewModel>? logger, ILoggerFactory? loggerFactory)
|
||||
{
|
||||
_logger = logger;
|
||||
_loggerFactory = loggerFactory;
|
||||
|
||||
BrowseImagesCommand = new RelayCommand(_ => BrowseFolder(isModel: false));
|
||||
BrowseModelsCommand = new RelayCommand(_ => BrowseFolder(isModel: true));
|
||||
LoadModelsCommand = new RelayCommand(_ => LoadModels());
|
||||
|
|
@ -91,9 +98,16 @@ namespace AIFotoONLUS.WPF.ViewModels
|
|||
CancelCommand = new RelayCommand(_ => Cancel(), _ => IsProcessing);
|
||||
|
||||
// load prefs
|
||||
var prefs = Preferences.Load();
|
||||
if (!string.IsNullOrWhiteSpace(prefs.imagesDir)) ImagesDirectory = prefs.imagesDir;
|
||||
if (!string.IsNullOrWhiteSpace(prefs.modelsDir)) ModelsDirectory = prefs.modelsDir;
|
||||
try
|
||||
{
|
||||
var prefs = Preferences.Load();
|
||||
if (!string.IsNullOrWhiteSpace(prefs.imagesDir)) ImagesDirectory = prefs.imagesDir;
|
||||
if (!string.IsNullOrWhiteSpace(prefs.modelsDir)) ModelsDirectory = prefs.modelsDir;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger?.LogWarning(ex, "Failed to load preferences");
|
||||
}
|
||||
}
|
||||
|
||||
private void BrowseFolder(bool isModel)
|
||||
|
|
@ -121,13 +135,14 @@ namespace AIFotoONLUS.WPF.ViewModels
|
|||
ConfidenceThreshold = 0.5,
|
||||
NmsThreshold = 0.4
|
||||
};
|
||||
|
||||
_engine = new NumberRecognitionEngine(_cfg);
|
||||
var logger = _loggerFactory?.CreateLogger<NumberRecognitionEngine>();
|
||||
_engine = new NumberRecognitionEngine(_cfg, logger);
|
||||
Status = "Models loaded";
|
||||
Preferences.Save(ImagesDirectory, ModelsDirectory);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger?.LogError(ex, "Error loading models");
|
||||
System.Windows.MessageBox.Show(ex.Message, "Error loading models", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
Status = "Error loading models";
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue