手动阀

This commit is contained in:
2026-04-06 22:08:38 +08:00
parent 0b150470be
commit 71e099ca8e
9 changed files with 920 additions and 6 deletions

View File

@@ -68,6 +68,9 @@ public static class ServiceCollectionExtensions
// 运行时部署快照管理服务
services.AddSingleton<OrpaonVision.Core.Training.IRuntimeDeploymentSnapshotAppService, OrpaonVision.ConfigApp.Infrastructure.Services.RuntimeDeploymentSnapshotAppService>();
// 规则校验服务
services.AddSingleton<OrpaonVision.Core.Training.IRuleValidationService, OrpaonVision.ConfigApp.Infrastructure.Services.RuleValidationService>();
// 用户权限管理服务
services.AddSingleton<IUserService, UserService>();
services.AddSingleton<IRoleService, RoleService>();

View File

@@ -42,19 +42,23 @@ public class ModelPackageAppService : IModelPackageAppService
private readonly ILogger<ModelPackageAppService> _logger;
private readonly ModelPackageOptions _options;
private readonly string _basePath;
private readonly IRuleValidationService _ruleValidationService;
/// <summary>
/// 初始化模型包应用服务。
/// </summary>
/// <param name="logger">日志记录器。</param>
/// <param name="options">模型包配置选项。</param>
/// <param name="options">配置选项。</param>
/// <param name="ruleValidationService">规则校验服务。</param>
public ModelPackageAppService(
ILogger<ModelPackageAppService> logger,
IOptions<ModelPackageOptions> options)
IOptions<ModelPackageOptions> options,
IRuleValidationService ruleValidationService)
{
_logger = logger;
_options = options.Value;
_basePath = _options.BasePath ?? "ModelPackages";
_ruleValidationService = ruleValidationService;
// 确保基础目录存在
if (!Directory.Exists(_basePath))
@@ -272,6 +276,31 @@ public class ModelPackageAppService : IModelPackageAppService
return Result<ModelPackageImportResultDto>.Fail(validationResult.Code, validationResult.Message);
}
// 校验规则快照包(如果存在)
var ruleSnapshotPath = Path.Combine(extractDir, "rules", "snapshot.ovpkg");
if (File.Exists(ruleSnapshotPath))
{
_logger.LogInformation("发现规则快照包,开始校验: {RuleSnapshotPath}", ruleSnapshotPath);
var ruleValidationResult = await _ruleValidationService.ValidateRuleSnapshotPackageAsync(ruleSnapshotPath, cancellationToken);
if (!ruleValidationResult.Succeeded)
{
// 清理失败的导入
if (Directory.Exists(extractDir))
{
Directory.Delete(extractDir, true);
}
return Result<ModelPackageImportResultDto>.Fail(ruleValidationResult.Code, $"规则快照包校验失败: {ruleValidationResult.Message}");
}
if (!ruleValidationResult.Data!.IsValid)
{
var errors = string.Join("; ", ruleValidationResult.Data.Errors);
_logger.LogWarning("规则快照包校验发现问题: {Errors}", errors);
// 可以选择是否将规则校验失败视为导入失败,这里仅记录警告
}
}
var importResult = new ModelPackageImportResultDto
{
ModelPackageId = packageId,

View File

@@ -0,0 +1,434 @@
using Microsoft.Extensions.Logging;
using OrpaonVision.Core.Results;
using OrpaonVision.Core.Training;
using OrpaonVision.Core.Training.Contracts;
using System.IO;
using System.IO.Compression;
using System.Text.Json;
using System.Text.Json.Schema;
namespace OrpaonVision.ConfigApp.Infrastructure.Services;
/// <summary>
/// 规则校验服务实现。
/// </summary>
public class RuleValidationService : IRuleValidationService
{
private readonly ILogger<RuleValidationService> _logger;
/// <summary>
/// 初始化规则校验服务。
/// </summary>
/// <param name="logger">日志记录器。</param>
public RuleValidationService(ILogger<RuleValidationService> logger)
{
_logger = logger;
}
/// <summary>
/// 校验规则快照包。
/// </summary>
public async Task<Result<RuleSnapshotValidationResultDto>> ValidateRuleSnapshotPackageAsync(
string packagePath,
CancellationToken cancellationToken = default)
{
try
{
_logger.LogInformation("开始校验规则快照包: {PackagePath}", packagePath);
if (!File.Exists(packagePath))
{
return Result<RuleSnapshotValidationResultDto>.Fail("PACKAGE_NOT_FOUND", "规则快照包文件不存在。");
}
var tempDir = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString("N"));
Directory.CreateDirectory(tempDir);
try
{
// 解压包文件
ZipFile.ExtractToDirectory(packagePath, tempDir);
// 校验各个部分
var layerOrderResult = await ValidateLayerOrderInPackageAsync(tempDir, cancellationToken);
var partCodeResult = await ValidatePartCodeUniquenessInPackageAsync(tempDir, cancellationToken);
var schemaResult = await ValidateSchemaInPackageAsync(tempDir, cancellationToken);
var validationResult = new RuleSnapshotValidationResultDto
{
IsValid = layerOrderResult.Succeeded && layerOrderResult.Data!.IsValid &&
partCodeResult.Succeeded && partCodeResult.Data!.IsValid &&
schemaResult.Succeeded && schemaResult.Data!.IsValid,
Errors = CombineErrors(layerOrderResult, partCodeResult, schemaResult),
Warnings = CombineWarnings(layerOrderResult, partCodeResult, schemaResult),
LayerOrderValidation = layerOrderResult.Data ?? new LayerOrderValidationResultDto(),
PartCodeUniquenessValidation = partCodeResult.Data ?? new PartCodeUniquenessValidationResultDto(),
SchemaValidation = schemaResult.Data ?? new SchemaValidationResultDto()
};
_logger.LogInformation("规则快照包校验完成: {PackagePath}, IsValid: {IsValid}",
packagePath, validationResult.IsValid);
return Result<RuleSnapshotValidationResultDto>.Success(validationResult);
}
finally
{
// 清理临时目录
if (Directory.Exists(tempDir))
{
Directory.Delete(tempDir, true);
}
}
}
catch (Exception ex)
{
var traceId = Guid.NewGuid().ToString("N");
_logger.LogError(ex, "校验规则快照包失败。TraceId: {TraceId}", traceId);
return Result<RuleSnapshotValidationResultDto>.FailWithTrace(
"VALIDATE_PACKAGE_FAILED", "校验规则快照包失败。", traceId, ex.Message);
}
}
/// <summary>
/// 校验层顺序。
/// </summary>
public async Task<Result<LayerOrderValidationResultDto>> ValidateLayerOrderAsync(
string[] layerOrderData,
string[] expectedOrder,
CancellationToken cancellationToken = default)
{
try
{
_logger.LogInformation("开始校验层顺序");
var errors = new List<string>();
var isValid = true;
// 检查层顺序是否匹配
if (layerOrderData.Length != expectedOrder.Length)
{
errors.Add($"层数量不匹配,期望: {expectedOrder.Length},实际: {layerOrderData.Length}");
isValid = false;
}
for (int i = 0; i < Math.Min(layerOrderData.Length, expectedOrder.Length); i++)
{
if (layerOrderData[i] != expectedOrder[i])
{
errors.Add($"第 {i + 1} 层不匹配,期望: {expectedOrder[i]},实际: {layerOrderData[i]}");
isValid = false;
}
}
var result = new LayerOrderValidationResultDto
{
IsValid = isValid,
Errors = errors.ToArray(),
ActualLayerOrder = layerOrderData,
ExpectedLayerOrder = expectedOrder
};
_logger.LogInformation("层顺序校验完成: IsValid: {IsValid}", isValid);
return Result<LayerOrderValidationResultDto>.Success(result);
}
catch (Exception ex)
{
var traceId = Guid.NewGuid().ToString("N");
_logger.LogError(ex, "校验层顺序失败。TraceId: {TraceId}", traceId);
return Result<LayerOrderValidationResultDto>.FailWithTrace(
"VALIDATE_LAYER_ORDER_FAILED", "校验层顺序失败。", traceId, ex.Message);
}
}
/// <summary>
/// 校验部件编码唯一性。
/// </summary>
public async Task<Result<PartCodeUniquenessValidationResultDto>> ValidatePartCodeUniquenessAsync(
string[] partCodes,
CancellationToken cancellationToken = default)
{
try
{
_logger.LogInformation("开始校验部件编码唯一性");
var errors = new List<string>();
var duplicateCodes = partCodes
.GroupBy(code => code)
.Where(group => group.Count() > 1)
.Select(group => group.Key)
.ToArray();
var isValid = duplicateCodes.Length == 0;
if (!isValid)
{
errors.AddRange(duplicateCodes.Select(code => $"部件编码 '{code}' 重复出现"));
}
var result = new PartCodeUniquenessValidationResultDto
{
IsValid = isValid,
Errors = errors.ToArray(),
DuplicatePartCodes = duplicateCodes,
AllPartCodes = partCodes
};
_logger.LogInformation("部件编码唯一性校验完成: IsValid: {IsValid}, DuplicateCount: {DuplicateCount}",
isValid, duplicateCodes.Length);
return Result<PartCodeUniquenessValidationResultDto>.Success(result);
}
catch (Exception ex)
{
var traceId = Guid.NewGuid().ToString("N");
_logger.LogError(ex, "校验部件编码唯一性失败。TraceId: {TraceId}", traceId);
return Result<PartCodeUniquenessValidationResultDto>.FailWithTrace(
"VALIDATE_PART_CODE_FAILED", "校验部件编码唯一性失败。", traceId, ex.Message);
}
}
/// <summary>
/// 校验Schema合法性。
/// </summary>
public async Task<Result<SchemaValidationResultDto>> ValidateSchemaAsync(
string[] schemaFiles,
CancellationToken cancellationToken = default)
{
try
{
_logger.LogInformation("开始校验Schema合法性");
var errors = new List<string>();
var warnings = new List<string>();
var validatedFiles = new List<string>();
var isValid = true;
foreach (var schemaFile in schemaFiles)
{
if (!File.Exists(schemaFile))
{
errors.Add($"Schema文件不存在: {schemaFile}");
isValid = false;
continue;
}
try
{
var schemaContent = await File.ReadAllTextAsync(schemaFile, cancellationToken);
// 简单的JSON Schema校验
if (!IsValidJson(schemaContent))
{
errors.Add($"Schema文件格式无效: {schemaFile}");
isValid = false;
}
else
{
validatedFiles.Add(schemaFile);
}
}
catch (Exception ex)
{
errors.Add($"读取Schema文件失败: {schemaFile}, 错误: {ex.Message}");
isValid = false;
}
}
var result = new SchemaValidationResultDto
{
IsValid = isValid,
Errors = errors.ToArray(),
Warnings = warnings.ToArray(),
SchemaVersion = "1.0", // 可以从配置中读取
ValidatedFiles = validatedFiles.ToArray()
};
_logger.LogInformation("Schema合法性校验完成: IsValid: {IsValid}, ValidatedFileCount: {ValidatedFileCount}",
isValid, validatedFiles.Count);
return Result<SchemaValidationResultDto>.Success(result);
}
catch (Exception ex)
{
var traceId = Guid.NewGuid().ToString("N");
_logger.LogError(ex, "校验Schema合法性失败。TraceId: {TraceId}", traceId);
return Result<SchemaValidationResultDto>.FailWithTrace(
"VALIDATE_SCHEMA_FAILED", "校验Schema合法性失败。", traceId, ex.Message);
}
}
#region
/// <summary>
/// 在包中校验层顺序。
/// </summary>
private async Task<Result<LayerOrderValidationResultDto>> ValidateLayerOrderInPackageAsync(
string packageDir,
CancellationToken cancellationToken)
{
var layerOrderFile = Path.Combine(packageDir, "rules", "layer-order.json");
if (!File.Exists(layerOrderFile))
{
return Result<LayerOrderValidationResultDto>.Fail("LAYER_ORDER_FILE_NOT_FOUND", "层顺序配置文件不存在。");
}
try
{
var layerOrderContent = await File.ReadAllTextAsync(layerOrderFile, cancellationToken);
var layerOrderData = JsonSerializer.Deserialize<string[]>(layerOrderContent) ?? Array.Empty<string>();
// 默认期望的层顺序 - 可以从配置中读取
var expectedOrder = new[] { "background", "foreground", "defect", "annotation" };
return await ValidateLayerOrderAsync(layerOrderData, expectedOrder, cancellationToken);
}
catch (Exception ex)
{
return Result<LayerOrderValidationResultDto>.Fail("PARSE_LAYER_ORDER_FAILED", $"解析层顺序配置失败: {ex.Message}");
}
}
/// <summary>
/// 在包中校验部件编码唯一性。
/// </summary>
private async Task<Result<PartCodeUniquenessValidationResultDto>> ValidatePartCodeUniquenessInPackageAsync(
string packageDir,
CancellationToken cancellationToken)
{
var partsFile = Path.Combine(packageDir, "rules", "parts.json");
if (!File.Exists(partsFile))
{
return Result<PartCodeUniquenessValidationResultDto>.Fail("PARTS_FILE_NOT_FOUND", "部件配置文件不存在。");
}
try
{
var partsContent = await File.ReadAllTextAsync(partsFile, cancellationToken);
var partsData = JsonSerializer.Deserialize<JsonElement>(partsContent);
var partCodes = new List<string>();
if (partsData.ValueKind == JsonValueKind.Array)
{
foreach (var part in partsData.EnumerateArray())
{
if (part.TryGetProperty("code", out var codeProperty))
{
partCodes.Add(codeProperty.GetString() ?? string.Empty);
}
}
}
return await ValidatePartCodeUniquenessAsync(partCodes.ToArray(), cancellationToken);
}
catch (Exception ex)
{
return Result<PartCodeUniquenessValidationResultDto>.Fail("PARSE_PARTS_FAILED", $"解析部件配置失败: {ex.Message}");
}
}
/// <summary>
/// 在包中校验Schema。
/// </summary>
private async Task<Result<SchemaValidationResultDto>> ValidateSchemaInPackageAsync(
string packageDir,
CancellationToken cancellationToken)
{
var schemaDir = Path.Combine(packageDir, "schema");
if (!Directory.Exists(schemaDir))
{
return Result<SchemaValidationResultDto>.Fail("SCHEMA_DIR_NOT_FOUND", "Schema目录不存在。");
}
var schemaFiles = Directory.GetFiles(schemaDir, "*.json", SearchOption.AllDirectories);
return await ValidateSchemaAsync(schemaFiles, cancellationToken);
}
/// <summary>
/// 检查是否为有效的JSON。
/// </summary>
private static bool IsValidJson(string jsonString)
{
try
{
JsonDocument.Parse(jsonString);
return true;
}
catch
{
return false;
}
}
/// <summary>
/// 合并错误信息。
/// </summary>
private static string[] CombineErrors(
Result<LayerOrderValidationResultDto> layerOrderResult,
Result<PartCodeUniquenessValidationResultDto> partCodeResult,
Result<SchemaValidationResultDto> schemaResult)
{
var errors = new List<string>();
if (!layerOrderResult.Succeeded)
{
errors.Add($"层顺序校验失败: {layerOrderResult.Message}");
}
else if (layerOrderResult.Data?.Errors.Length > 0)
{
errors.AddRange(layerOrderResult.Data.Errors);
}
if (!partCodeResult.Succeeded)
{
errors.Add($"部件编码校验失败: {partCodeResult.Message}");
}
else if (partCodeResult.Data?.Errors.Length > 0)
{
errors.AddRange(partCodeResult.Data.Errors);
}
if (!schemaResult.Succeeded)
{
errors.Add($"Schema校验失败: {schemaResult.Message}");
}
else if (schemaResult.Data?.Errors.Length > 0)
{
errors.AddRange(schemaResult.Data.Errors);
}
return errors.ToArray();
}
/// <summary>
/// 合并警告信息。
/// </summary>
private static string[] CombineWarnings(
Result<LayerOrderValidationResultDto> layerOrderResult,
Result<PartCodeUniquenessValidationResultDto> partCodeResult,
Result<SchemaValidationResultDto> schemaResult)
{
var warnings = new List<string>();
if (layerOrderResult.Succeeded && layerOrderResult.Data != null)
{
// 层顺序校验通常没有警告
}
if (partCodeResult.Succeeded && partCodeResult.Data != null)
{
// 部件编码校验通常没有警告
}
if (schemaResult.Succeeded && schemaResult.Data?.Warnings.Length > 0)
{
warnings.AddRange(schemaResult.Data.Warnings);
}
return warnings.ToArray();
}
#endregion
}

View File

@@ -448,11 +448,31 @@ public class RuntimeDeploymentSnapshotAppService : IRuntimeDeploymentSnapshotApp
if (snapshot != null)
{
snapshot.Status = RuntimeDeploymentSnapshotStatus.RolledBack;
snapshot.RolledBackAtUtc = DateTime.UtcNow;
snapshot.RolledBackBy = "System"; // 系统自动回滚
// 创建新的快照对象用于更新
var updatedSnapshot = new RuntimeDeploymentSnapshot
{
Id = snapshot.Id,
Name = snapshot.Name,
Description = snapshot.Description,
ProductTypeId = snapshot.ProductTypeId,
ProductTypeCode = snapshot.ProductTypeCode,
RuleVersionId = snapshot.RuleVersionId,
RuleVersionNo = snapshot.RuleVersionNo,
ModelPackageVersionId = snapshot.ModelPackageVersionId,
ModelPackageVersionNo = snapshot.ModelPackageVersionNo,
RuntimeParameterVersionId = snapshot.RuntimeParameterVersionId,
RuntimeParameterVersionNo = snapshot.RuntimeParameterVersionNo,
Status = RuntimeDeploymentSnapshotStatus.RolledBack,
CreatedAtUtc = snapshot.CreatedAtUtc,
CreatedBy = snapshot.CreatedBy,
ActivatedAtUtc = snapshot.ActivatedAtUtc,
ActivatedBy = snapshot.ActivatedBy,
RolledBackAtUtc = DateTime.UtcNow,
RolledBackBy = "System", // 系统自动回滚
MetadataJson = snapshot.MetadataJson
};
await SaveSnapshotAsync(snapshot, cancellationToken);
await SaveSnapshotAsync(updatedSnapshot, cancellationToken);
}
}
}

View File

@@ -0,0 +1,120 @@
namespace OrpaonVision.Core.Training.Contracts;
/// <summary>
/// 规则快照包校验结果。
/// </summary>
public sealed class RuleSnapshotValidationResultDto
{
/// <summary>
/// 是否通过校验。
/// </summary>
public bool IsValid { get; init; }
/// <summary>
/// 校验错误信息。
/// </summary>
public string[] Errors { get; init; } = Array.Empty<string>();
/// <summary>
/// 校验警告信息。
/// </summary>
public string[] Warnings { get; init; } = Array.Empty<string>();
/// <summary>
/// 层顺序校验结果。
/// </summary>
public LayerOrderValidationResultDto LayerOrderValidation { get; init; } = new();
/// <summary>
/// 部件编码唯一性校验结果。
/// </summary>
public PartCodeUniquenessValidationResultDto PartCodeUniquenessValidation { get; init; } = new();
/// <summary>
/// Schema合法性校验结果。
/// </summary>
public SchemaValidationResultDto SchemaValidation { get; init; } = new();
}
/// <summary>
/// 层顺序校验结果。
/// </summary>
public sealed class LayerOrderValidationResultDto
{
/// <summary>
/// 是否通过校验。
/// </summary>
public bool IsValid { get; init; }
/// <summary>
/// 错误信息。
/// </summary>
public string[] Errors { get; init; } = Array.Empty<string>();
/// <summary>
/// 实际层顺序。
/// </summary>
public string[] ActualLayerOrder { get; init; } = Array.Empty<string>();
/// <summary>
/// 期望层顺序。
/// </summary>
public string[] ExpectedLayerOrder { get; init; } = Array.Empty<string>();
}
/// <summary>
/// 部件编码唯一性校验结果。
/// </summary>
public sealed class PartCodeUniquenessValidationResultDto
{
/// <summary>
/// 是否通过校验。
/// </summary>
public bool IsValid { get; init; }
/// <summary>
/// 错误信息。
/// </summary>
public string[] Errors { get; init; } = Array.Empty<string>();
/// <summary>
/// 重复的部件编码。
/// </summary>
public string[] DuplicatePartCodes { get; init; } = Array.Empty<string>();
/// <summary>
/// 所有部件编码。
/// </summary>
public string[] AllPartCodes { get; init; } = Array.Empty<string>();
}
/// <summary>
/// Schema合法性校验结果。
/// </summary>
public sealed class SchemaValidationResultDto
{
/// <summary>
/// 是否通过校验。
/// </summary>
public bool IsValid { get; init; }
/// <summary>
/// 错误信息。
/// </summary>
public string[] Errors { get; init; } = Array.Empty<string>();
/// <summary>
/// 警告信息。
/// </summary>
public string[] Warnings { get; init; } = Array.Empty<string>();
/// <summary>
/// Schema版本。
/// </summary>
public string SchemaVersion { get; init; } = string.Empty;
/// <summary>
/// 校验的文件路径。
/// </summary>
public string[] ValidatedFiles { get; init; } = Array.Empty<string>();
}

View File

@@ -0,0 +1,52 @@
using OrpaonVision.Core.Results;
using OrpaonVision.Core.Training.Contracts;
namespace OrpaonVision.Core.Training;
/// <summary>
/// 规则校验服务接口。
/// </summary>
public interface IRuleValidationService
{
/// <summary>
/// 校验规则快照包。
/// </summary>
/// <param name="packagePath">包路径。</param>
/// <param name="cancellationToken">取消令牌。</param>
/// <returns>校验结果。</returns>
Task<Result<RuleSnapshotValidationResultDto>> ValidateRuleSnapshotPackageAsync(
string packagePath,
CancellationToken cancellationToken = default);
/// <summary>
/// 校验层顺序。
/// </summary>
/// <param name="layerOrderData">层顺序数据。</param>
/// <param name="expectedOrder">期望的层顺序。</param>
/// <param name="cancellationToken">取消令牌。</param>
/// <returns>校验结果。</returns>
Task<Result<LayerOrderValidationResultDto>> ValidateLayerOrderAsync(
string[] layerOrderData,
string[] expectedOrder,
CancellationToken cancellationToken = default);
/// <summary>
/// 校验部件编码唯一性。
/// </summary>
/// <param name="partCodes">部件编码列表。</param>
/// <param name="cancellationToken">取消令牌。</param>
/// <returns>校验结果。</returns>
Task<Result<PartCodeUniquenessValidationResultDto>> ValidatePartCodeUniquenessAsync(
string[] partCodes,
CancellationToken cancellationToken = default);
/// <summary>
/// 校验Schema合法性。
/// </summary>
/// <param name="schemaFiles">Schema文件路径列表。</param>
/// <param name="cancellationToken">取消令牌。</param>
/// <returns>校验结果。</returns>
Task<Result<SchemaValidationResultDto>> ValidateSchemaAsync(
string[] schemaFiles,
CancellationToken cancellationToken = default);
}

View File

@@ -71,6 +71,9 @@ namespace OrpaonVision.SiteApp.DependencyInjection
services.AddSingleton<IImageProcessingService, ImageProcessingService>();
services.AddSingleton<OptimizedMainWindowViewModel>();
// 一致性检查服务
services.AddSingleton<IConsistencyCheckService, ConsistencyCheckService>();
// 日志
services.AddLogging(builder =>
{

View File

@@ -0,0 +1,234 @@
namespace OrpaonVision.SiteApp.Runtime.Contracts;
/// <summary>
/// 一致性状态枚举。
/// </summary>
public enum ConsistencyStatus
{
/// <summary>
/// 正常。
/// </summary>
Ok,
/// <summary>
/// 警告。
/// </summary>
Warning,
/// <summary>
/// 错误。
/// </summary>
Error
}
/// <summary>
/// 健康状态枚举。
/// </summary>
public enum HealthStatus
{
/// <summary>
/// 健康。
/// </summary>
Healthy,
/// <summary>
/// 降级。
/// </summary>
Degraded,
/// <summary>
/// 不健康。
/// </summary>
Unhealthy
}
/// <summary>
/// 一致性检查结果。
/// </summary>
public sealed class ConsistencyCheckResult
{
/// <summary>
/// 检查时间戳。
/// </summary>
public DateTime CheckTimestamp { get; set; }
/// <summary>
/// 检查状态。
/// </summary>
public ConsistencyStatus Status { get; set; }
/// <summary>
/// 检查消息。
/// </summary>
public string Message { get; set; } = string.Empty;
/// <summary>
/// 相机是否连接。
/// </summary>
public bool CameraConnected { get; set; }
/// <summary>
/// YOLO是否初始化。
/// </summary>
public bool YoloInitialized { get; set; }
/// <summary>
/// 像素格式是否一致。
/// </summary>
public bool PixelFormatConsistent { get; set; }
/// <summary>
/// 像素格式检查详情。
/// </summary>
public List<string> PixelFormatDetails { get; set; } = new();
/// <summary>
/// 图像尺寸是否一致。
/// </summary>
public bool ImageSizeConsistent { get; set; }
/// <summary>
/// 图像尺寸检查详情。
/// </summary>
public List<string> ImageSizeDetails { get; set; } = new();
/// <summary>
/// 数据流完整性。
/// </summary>
public bool DataFlowIntegrity { get; set; }
/// <summary>
/// 数据流检查详情。
/// </summary>
public List<string> DataFlowDetails { get; set; } = new();
/// <summary>
/// 建议列表。
/// </summary>
public List<string> Recommendations { get; set; } = new();
}
/// <summary>
/// 健康检查结果。
/// </summary>
public sealed class HealthCheckResult
{
/// <summary>
/// 检查时间戳。
/// </summary>
public DateTime Timestamp { get; set; }
/// <summary>
/// 整体状态。
/// </summary>
public HealthStatus OverallStatus { get; set; }
/// <summary>
/// 相机健康状态。
/// </summary>
public ComponentHealth CameraHealth { get; set; } = new();
/// <summary>
/// YOLO健康状态。
/// </summary>
public ComponentHealth YoloHealth { get; set; } = new();
/// <summary>
/// 系统健康状态。
/// </summary>
public ComponentHealth SystemHealth { get; set; } = new();
/// <summary>
/// 健康检查摘要。
/// </summary>
public string Summary { get; set; } = string.Empty;
}
/// <summary>
/// 组件健康状态。
/// </summary>
public sealed class ComponentHealth
{
/// <summary>
/// 组件名称。
/// </summary>
public string ComponentName { get; set; } = string.Empty;
/// <summary>
/// 健康状态。
/// </summary>
public HealthStatus Status { get; set; }
/// <summary>
/// 详细信息。
/// </summary>
public List<string> Details { get; set; } = new();
/// <summary>
/// 指标数据。
/// </summary>
public Dictionary<string, object> Metrics { get; set; } = new();
}
/// <summary>
/// 像素格式检查结果。
/// </summary>
internal sealed class PixelFormatCheckResult
{
/// <summary>
/// 是否一致。
/// </summary>
public bool IsConsistent { get; set; }
/// <summary>
/// 检查详情。
/// </summary>
public List<string> Details { get; set; } = new();
/// <summary>
/// 建议列表。
/// </summary>
public List<string> Recommendations { get; set; } = new();
}
/// <summary>
/// 图像尺寸检查结果。
/// </summary>
internal sealed class ImageSizeCheckResult
{
/// <summary>
/// 是否一致。
/// </summary>
public bool IsConsistent { get; set; }
/// <summary>
/// 检查详情。
/// </summary>
public List<string> Details { get; set; } = new();
/// <summary>
/// 建议列表。
/// </summary>
public List<string> Recommendations { get; set; } = new();
}
/// <summary>
/// 数据流检查结果。
/// </summary>
internal sealed class DataFlowCheckResult
{
/// <summary>
/// 是否完整。
/// </summary>
public bool IsIntegrity { get; set; }
/// <summary>
/// 检查详情。
/// </summary>
public List<string> Details { get; set; } = new();
/// <summary>
/// 建议列表。
/// </summary>
public List<string> Recommendations { get; set; } = new();
}

View File

@@ -0,0 +1,19 @@
namespace OrpaonVision.SiteApp.Runtime.Contracts;
/// <summary>
/// 一致性检查服务接口。
/// </summary>
public interface IConsistencyCheckService
{
/// <summary>
/// 检查相机与推理服务的一致性。
/// </summary>
/// <returns>一致性检查结果。</returns>
Result<ConsistencyCheckResult> CheckCameraInferenceConsistency();
/// <summary>
/// 获取最小健康信息。
/// </summary>
/// <returns>健康检查结果。</returns>
Result<HealthCheckResult> GetMinimalHealthInfo();
}