using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using OrpaonVision.Core.Results;
using OrpaonVision.SiteApp.Runtime.Contracts;
using OrpaonVision.SiteApp.Runtime.Options;
using System.Text.Json;
namespace OrpaonVision.SiteApp.Runtime.Services;
///
/// 高级规则引擎服务实现。
/// 支持复杂规则配置、多条件判断、动态规则加载等功能。
///
public sealed class AdvancedRuleEngineService : IRuleEngineService, IDisposable
{
private readonly ILogger _logger;
private readonly RuntimeOptions _options;
private readonly Dictionary _rules;
private readonly object _lockObject = new();
private bool _isInitialized;
///
/// 构造函数。
///
public AdvancedRuleEngineService(ILogger logger, IOptions options)
{
_logger = logger;
_options = options.Value;
_rules = new Dictionary();
InitializeDefaultRules();
}
///
public Result Evaluate(int currentLayer, InferenceResultDto inference)
{
try
{
_logger.LogDebug("执行规则引擎评估:当前层={CurrentLayer},推理结果={Label},置信度={Confidence:F3}",
currentLayer, inference.Label, inference.Confidence);
if (!_isInitialized)
{
_logger.LogWarning("规则引擎未初始化,使用默认规则");
return EvaluateWithDefaultRule(currentLayer, inference);
}
// 获取当前层的规则
var layerRules = GetRulesForLayer(currentLayer);
if (layerRules.Count == 0)
{
_logger.LogWarning("第 {CurrentLayer} 层没有配置规则,使用默认规则", currentLayer);
return EvaluateWithDefaultRule(currentLayer, inference);
}
// 执行规则评估
var evaluationContext = new RuleEvaluationContext
{
CurrentLayer = currentLayer,
Inference = inference,
Timestamp = DateTime.UtcNow
};
var results = new List();
foreach (var rule in layerRules)
{
var result = EvaluateRule(rule, evaluationContext);
results.Add(result);
_logger.LogDebug("规则 {RuleName} 评估结果:{IsPass} - {Message}",
rule.Name, result.IsPass, result.Message);
// 如果是关键规则且失败,可以提前终止
if (!result.IsPass && rule.IsCritical)
{
_logger.LogInformation("关键规则 {RuleName} 失败,提前终止评估", rule.Name);
break;
}
}
// 汇总评估结果
var finalDecision = AggregateEvaluationResults(results, evaluationContext);
_logger.LogInformation("规则引擎评估完成:{DecisionCode} - {DecisionMessage}",
finalDecision.Code, finalDecision.Message);
return Result.Success(finalDecision, message: "规则判定完成");
}
catch (Exception ex)
{
var traceId = Guid.NewGuid().ToString("N");
_logger.LogError(ex, "规则引擎评估失败。TraceId: {TraceId}", traceId);
var result = Result.FromException(ex, "RULE_ENGINE_EVALUATION_FAILED", "规则引擎评估失败", traceId);
return Result.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
}
}
///
/// 初始化默认规则。
///
private void InitializeDefaultRules()
{
lock (_lockObject)
{
try
{
_logger.LogInformation("正在初始化默认规则...");
// 添加基础缺陷检测规则
var defectRule = new RuleDefinition
{
Name = "DefectDetection",
Description = "缺陷检测规则",
Layer = 0, // 适用于所有层
Conditions = new List
{
new()
{
Type = ConditionType.LabelEquals,
Parameter = "defect",
Operator = "equals",
ExpectedValue = "defect"
},
new()
{
Type = ConditionType.ConfidenceThreshold,
Parameter = "confidence",
Operator = ">=",
ExpectedValue = _options.NgConfidenceThreshold.ToString("F3")
}
},
Action = new RuleAction
{
Type = ActionType.MarkAsNG,
Parameters = new Dictionary
{
["reason"] = "检测到缺陷",
["severity"] = "high"
}
},
IsCritical = true,
Priority = 1,
Enabled = true
};
// 添加置信度规则
var confidenceRule = new RuleDefinition
{
Name = "ConfidenceCheck",
Description = "置信度检查规则",
Layer = 0, // 适用于所有层
Conditions = new List
{
new()
{
Type = ConditionType.ConfidenceThreshold,
Parameter = "confidence",
Operator = "<",
ExpectedValue = _options.NgConfidenceThreshold.ToString("F3")
}
},
Action = new RuleAction
{
Type = ActionType.MarkAsNG,
Parameters = new Dictionary
{
["reason"] = "置信度过低",
["severity"] = "medium"
}
},
IsCritical = false,
Priority = 2,
Enabled = true
};
// 添加正常通过规则
var passRule = new RuleDefinition
{
Name = "NormalPass",
Description = "正常通过规则",
Layer = 0, // 适用于所有层
Conditions = new List
{
new()
{
Type = ConditionType.LabelEquals,
Parameter = "normal",
Operator = "equals",
ExpectedValue = "normal"
},
new()
{
Type = ConditionType.ConfidenceThreshold,
Parameter = "confidence",
Operator = ">=",
ExpectedValue = _options.NgConfidenceThreshold.ToString("F3")
}
},
Action = new RuleAction
{
Type = ActionType.MarkAsOK,
Parameters = new Dictionary
{
["reason"] = "正常检测"
}
},
IsCritical = false,
Priority = 3,
Enabled = true
};
// 添加数量检查规则
var quantityRule = new RuleDefinition
{
Name = "QuantityCheck",
Description = "部件数量检查规则",
Layer = 0, // 适用于所有层
Conditions = new List
{
new()
{
Type = ConditionType.QuantityCheck,
Parameter = "",
Operator = "equals",
ExpectedValue = "3-5" // 期望3-5个部件
}
},
Action = new RuleAction
{
Type = ActionType.MarkAsNG,
Parameters = new Dictionary
{
["reason"] = "部件数量不符合要求",
["severity"] = "medium"
}
},
IsCritical = false,
Priority = 4,
Enabled = true
};
// 添加位置检查规则
var positionRule = new RuleDefinition
{
Name = "PositionCheck",
Description = "部件位置检查规则",
Layer = 0,
Conditions = new List
{
new()
{
Type = ConditionType.PositionCheck,
Parameter = "screw", // 检查螺丝位置
Operator = "within",
ExpectedValue = "100,100,50" // 圆形区域:中心(100,100),半径50
}
},
Action = new RuleAction
{
Type = ActionType.MarkAsNG,
Parameters = new Dictionary
{
["reason"] = "部件位置偏离",
["severity"] = "high"
}
},
IsCritical = true,
Priority = 5,
Enabled = true
};
// 添加到位检查规则
var placementRule = new RuleDefinition
{
Name = "PlacementCheck",
Description = "部件到位检查规则",
Layer = 0,
Conditions = new List
{
new()
{
Type = ConditionType.PlacementCheck,
Parameter = "",
Operator = "equals",
ExpectedValue = "bracket=2" // 期望2个支架
}
},
Action = new RuleAction
{
Type = ActionType.MarkAsNG,
Parameters = new Dictionary
{
["reason"] = "部件未完全到位",
["severity"] = "medium"
}
},
IsCritical = false,
Priority = 6,
Enabled = true
};
// 添加禁装检查规则
var forbiddenRule = new RuleDefinition
{
Name = "ForbiddenCheck",
Description = "禁装部件检查规则",
Layer = 0,
Conditions = new List
{
new()
{
Type = ConditionType.ForbiddenCheck,
Parameter = "",
Operator = "not_contains",
ExpectedValue = "wrong_part,temp_part" // 禁止错误的部件和临时部件
}
},
Action = new RuleAction
{
Type = ActionType.MarkAsNG,
Parameters = new Dictionary
{
["reason"] = "发现禁装部件",
["severity"] = "high"
}
},
IsCritical = true,
Priority = 7,
Enabled = true
};
// 添加顺序检查规则
var sequenceRule = new RuleDefinition
{
Name = "SequenceCheck",
Description = "装配顺序检查规则",
Layer = 0,
Conditions = new List
{
new()
{
Type = ConditionType.SequenceCheck,
Parameter = "",
Operator = "equals",
ExpectedValue = "base>bracket>screw>cover" // 期望装配顺序
}
},
Action = new RuleAction
{
Type = ActionType.MarkAsNG,
Parameters = new Dictionary
{
["reason"] = "装配顺序错误",
["severity"] = "high"
}
},
IsCritical = true,
Priority = 8,
Enabled = true
};
_rules["DefectDetection"] = defectRule;
_rules["ConfidenceCheck"] = confidenceRule;
_rules["NormalPass"] = passRule;
_rules["QuantityCheck"] = quantityRule;
_rules["PositionCheck"] = positionRule;
_rules["PlacementCheck"] = placementRule;
_rules["ForbiddenCheck"] = forbiddenRule;
_rules["SequenceCheck"] = sequenceRule;
_isInitialized = true;
_logger.LogInformation("默认规则初始化完成,共加载 {Count} 条规则", _rules.Count);
}
catch (Exception ex)
{
_logger.LogError(ex, "初始化默认规则失败");
}
}
}
///
/// 获取指定层的规则。
///
private List GetRulesForLayer(int layer)
{
return _rules.Values
.Where(rule => rule.Layer == 0 || rule.Layer == layer)
.Where(rule => rule.Enabled)
.OrderBy(rule => rule.Priority)
.ToList();
}
///
/// 评估单个规则。
///
private RuleEvaluationResult EvaluateRule(RuleDefinition rule, RuleEvaluationContext context)
{
try
{
var conditionResults = new List();
foreach (var condition in rule.Conditions)
{
var result = EvaluateCondition(condition, context);
conditionResults.Add(result);
// 如果是AND逻辑且有一个条件失败,可以提前退出
if (!result && rule.ConditionLogic == ConditionLogic.And)
{
break;
}
}
// 根据逻辑运算符确定最终结果
var isPass = rule.ConditionLogic == ConditionLogic.And
? conditionResults.All(r => r)
: conditionResults.Any(r => r);
var message = isPass
? $"规则 {rule.Name} 通过"
: $"规则 {rule.Name} 失败: {string.Join(", ", rule.Conditions.Select(c => c.Type))}";
return new RuleEvaluationResult
{
RuleName = rule.Name,
IsPass = isPass,
Message = message,
Action = isPass ? null : rule.Action,
ExecutionTime = DateTime.UtcNow
};
}
catch (Exception ex)
{
_logger.LogError(ex, "评估规则 {RuleName} 失败", rule.Name);
return new RuleEvaluationResult
{
RuleName = rule.Name,
IsPass = false,
Message = $"规则评估异常: {ex.Message}",
Action = new RuleAction
{
Type = ActionType.MarkAsNG,
Parameters = new Dictionary
{
["reason"] = "规则评估异常",
["severity"] = "high"
}
},
ExecutionTime = DateTime.UtcNow
};
}
}
///
/// 评估条件。
///
private bool EvaluateCondition(RuleCondition condition, RuleEvaluationContext context)
{
return condition.Type switch
{
ConditionType.LabelEquals => EvaluateLabelEquals(condition, context),
ConditionType.ConfidenceThreshold => EvaluateConfidenceThreshold(condition, context),
ConditionType.QuantityCheck => EvaluateQuantityCheck(condition, context),
ConditionType.PositionCheck => EvaluatePositionCheck(condition, context),
ConditionType.PlacementCheck => EvaluatePlacementCheck(condition, context),
ConditionType.ForbiddenCheck => EvaluateForbiddenCheck(condition, context),
ConditionType.SequenceCheck => EvaluateSequenceCheck(condition, context),
_ => false
};
}
///
/// 评估标签等于条件。
///
private bool EvaluateLabelEquals(RuleCondition condition, RuleEvaluationContext context)
{
var expectedLabel = condition.ExpectedValue;
var actualLabel = context.Inference.Label;
return condition.Operator switch
{
"equals" => actualLabel == expectedLabel,
"not_equals" => actualLabel != expectedLabel,
"contains" => actualLabel.Contains(expectedLabel),
"not_contains" => !actualLabel.Contains(expectedLabel),
_ => actualLabel == expectedLabel
};
}
///
/// 评估置信度阈值条件。
///
private bool EvaluateConfidenceThreshold(RuleCondition condition, RuleEvaluationContext context)
{
if (!decimal.TryParse(condition.ExpectedValue, out var threshold))
{
_logger.LogWarning("置信度阈值解析失败: {Value}", condition.ExpectedValue);
return false;
}
var actualConfidence = (decimal)context.Inference.Confidence;
return condition.Operator switch
{
">=" => actualConfidence >= threshold,
"<=" => actualConfidence <= threshold,
">" => actualConfidence > threshold,
"<" => actualConfidence < threshold,
"==" => actualConfidence == threshold,
"!=" => actualConfidence != threshold,
_ => actualConfidence >= threshold
};
}
///
/// 评估数量检查条件。
///
private bool EvaluateQuantityCheck(RuleCondition condition, RuleEvaluationContext context)
{
try
{
// 解析期望数量范围,格式如 "min-max" 或 "exact"
var expectedRange = condition.ExpectedValue;
var actualCount = context.Inference.Detections.Count;
_logger.LogDebug("数量检查:期望={ExpectedRange},实际={ActualCount}", expectedRange, actualCount);
if (expectedRange.Contains('-'))
{
// 范围检查,格式:min-max
var parts = expectedRange.Split('-');
if (parts.Length == 2 && int.TryParse(parts[0], out var min) && int.TryParse(parts[1], out var max))
{
return actualCount >= min && actualCount <= max;
}
}
else if (int.TryParse(expectedRange, out var exact))
{
// 精确数量检查
return actualCount == exact;
}
_logger.LogWarning("数量检查条件解析失败: {Value}", expectedRange);
return false;
}
catch (Exception ex)
{
_logger.LogError(ex, "数量检查评估失败");
return false;
}
}
///
/// 评估位置检查条件。
///
private bool EvaluatePositionCheck(RuleCondition condition, RuleEvaluationContext context)
{
try
{
// 解析期望位置,格式如 "x_min:x_max,y_min:y_max" 或 "center_x,center_y,radius"
var expectedPosition = condition.ExpectedValue;
var detections = context.Inference.Detections.Where(d => d.ClassName == condition.Parameter || string.IsNullOrEmpty(condition.Parameter)).ToList();
if (!detections.Any())
{
_logger.LogDebug("位置检查:未找到匹配的检测对象");
return false;
}
// 检查是否所有检测对象都在期望位置范围内
foreach (var detection in detections)
{
var isInRange = CheckPositionInRange(detection.CenterX, detection.CenterY, expectedPosition);
if (!isInRange)
{
_logger.LogDebug("位置检查失败:检测对象 {ClassName} 位置 ({X}, {Y}) 不在期望范围内 {Range}",
detection.ClassName, detection.CenterX, detection.CenterY, expectedPosition);
return false;
}
}
_logger.LogDebug("位置检查通过:所有 {Count} 个检测对象都在期望范围内", detections.Count);
return true;
}
catch (Exception ex)
{
_logger.LogError(ex, "位置检查评估失败");
return false;
}
}
///
/// 评估到位检查条件。
///
private bool EvaluatePlacementCheck(RuleCondition condition, RuleEvaluationContext context)
{
try
{
// 解析期望的到位状态,格式:className=expected_count
var placementRule = condition.ExpectedValue;
var parts = placementRule.Split('=');
if (parts.Length != 2 || !int.TryParse(parts[1], out var expectedCount))
{
_logger.LogWarning("到位检查条件解析失败: {Value}", placementRule);
return false;
}
var targetClass = parts[0];
var actualCount = context.Inference.Detections.Count(d => d.ClassName == targetClass);
_logger.LogDebug("到位检查:{ClassName} 期望={ExpectedCount},实际={ActualCount}",
targetClass, expectedCount, actualCount);
return actualCount >= expectedCount;
}
catch (Exception ex)
{
_logger.LogError(ex, "到位检查评估失败");
return false;
}
}
///
/// 评估禁装检查条件。
///
private bool EvaluateForbiddenCheck(RuleCondition condition, RuleEvaluationContext context)
{
try
{
// 检查是否存在禁用的部件
var forbiddenClasses = condition.ExpectedValue.Split(',', StringSplitOptions.RemoveEmptyEntries);
var detections = context.Inference.Detections;
foreach (var forbiddenClass in forbiddenClasses)
{
var forbiddenDetections = detections.Where(d => d.ClassName.Equals(forbiddenClass.Trim(), StringComparison.OrdinalIgnoreCase)).ToList();
if (forbiddenDetections.Any())
{
_logger.LogDebug("禁装检查失败:发现禁用部件 {ClassName},数量={Count}", forbiddenClass, forbiddenDetections.Count);
return false; // 发现禁用部件,检查失败
}
}
_logger.LogDebug("禁装检查通过:未发现禁用部件");
return true;
}
catch (Exception ex)
{
_logger.LogError(ex, "禁装检查评估失败");
return false;
}
}
///
/// 评估顺序检查条件。
///
private bool EvaluateSequenceCheck(RuleCondition condition, RuleEvaluationContext context)
{
try
{
// 解析期望顺序,格式如 "class1>class2>class3"
var expectedSequence = condition.ExpectedValue;
var sequenceParts = expectedSequence.Split('>', StringSplitOptions.RemoveEmptyEntries);
// 按Y坐标排序检测对象(假设装配顺序是从上到下)
var sortedDetections = context.Inference.Detections
.Where(d => sequenceParts.Contains(d.ClassName))
.OrderBy(d => d.CenterY)
.Select(d => d.ClassName)
.ToList();
var actualSequence = string.Join(">", sortedDetections);
var isCorrectOrder = actualSequence.Equals(expectedSequence, StringComparison.OrdinalIgnoreCase);
_logger.LogDebug("顺序检查:期望={Expected},实际={Actual},结果={Result}",
expectedSequence, actualSequence, isCorrectOrder ? "通过" : "失败");
return isCorrectOrder;
}
catch (Exception ex)
{
_logger.LogError(ex, "顺序检查评估失败");
return false;
}
}
///
/// 检查位置是否在指定范围内。
///
private static bool CheckPositionInRange(float centerX, float centerY, string rangeDefinition)
{
if (rangeDefinition.Contains(','))
{
// 圆形范围检查,格式:center_x,center_y,radius
var parts = rangeDefinition.Split(',');
if (parts.Length == 3 &&
float.TryParse(parts[0], out var expectedCenterX) &&
float.TryParse(parts[1], out var expectedCenterY) &&
float.TryParse(parts[2], out var radius))
{
var distance = Math.Sqrt(Math.Pow(centerX - expectedCenterX, 2) + Math.Pow(centerY - expectedCenterY, 2));
return distance <= radius;
}
}
else if (rangeDefinition.Contains(':'))
{
// 矩形范围检查,格式:x_min:x_max,y_min:y_max
var coordinates = rangeDefinition.Split(',');
if (coordinates.Length == 2)
{
var xRange = coordinates[0].Split(':');
var yRange = coordinates[1].Split(':');
if (xRange.Length == 2 && yRange.Length == 2 &&
float.TryParse(xRange[0], out var xMin) &&
float.TryParse(xRange[1], out var xMax) &&
float.TryParse(yRange[0], out var yMin) &&
float.TryParse(yRange[1], out var yMax))
{
return centerX >= xMin && centerX <= xMax && centerY >= yMin && centerY <= yMax;
}
}
}
return false;
}
///
/// 汇总评估结果。
///
private RuntimeDecisionDto AggregateEvaluationResults(List results, RuleEvaluationContext context)
{
var failedRules = results.Where(r => !r.IsPass).ToList();
var criticalFailures = failedRules.Where(r => r.Action?.Parameters?.ContainsKey("severity") == true &&
r.Action.Parameters["severity"].ToString() == "high").ToList();
var isPass = failedRules.Count == 0;
var decisionCode = isPass ? "RULE_PASS" : "RULE_NG";
var decisionMessage = isPass
? $"第 {context.CurrentLayer} 层所有规则通过"
: $"第 {context.CurrentLayer} 层规则失败: {string.Join(", ", failedRules.Select(r => r.RuleName))}";
// 如果有关键失败,提升消息级别
if (criticalFailures.Count > 0)
{
decisionCode = "RULE_CRITICAL_NG";
decisionMessage = $"第 {context.CurrentLayer} 层关键规则失败: {string.Join(", ", criticalFailures.Select(r => r.RuleName))}";
}
return new RuntimeDecisionDto
{
IsPass = isPass,
Code = decisionCode,
Message = decisionMessage
};
}
///
/// 使用默认规则评估。
///
private Result EvaluateWithDefaultRule(int currentLayer, InferenceResultDto inference)
{
var isPass = inference.Label == "normal" || inference.Label == "OK" || inference.Confidence < _options.NgConfidenceThreshold;
var decision = new RuntimeDecisionDto
{
IsPass = isPass,
Code = isPass ? "DEFAULT_RULE_PASS" : "DEFAULT_RULE_NG",
Message = isPass
? $"第 {currentLayer} 层默认规则通过。"
: $"第 {currentLayer} 层默认规则 NG:{inference.Label} (置信度: {inference.Confidence:F3})"
};
return Result.Success(decision, message: "默认规则判定完成");
}
///
/// 释放资源。
///
public void Dispose()
{
try
{
_rules.Clear();
_isInitialized = false;
_logger.LogInformation("规则引擎服务已释放");
}
catch (Exception ex)
{
_logger.LogError(ex, "释放规则引擎服务资源时发生错误");
}
}
}
#region 规则引擎内部类型
///
/// 规则定义。
///
internal sealed class RuleDefinition
{
public string Name { get; init; } = string.Empty;
public string Description { get; init; } = string.Empty;
public int Layer { get; init; }
public List Conditions { get; init; } = new();
public RuleAction Action { get; init; } = new();
public bool IsCritical { get; init; }
public int Priority { get; init; }
public bool Enabled { get; init; }
public ConditionLogic ConditionLogic { get; init; } = ConditionLogic.And;
}
///
/// 规则条件。
///
internal sealed class RuleCondition
{
public ConditionType Type { get; init; }
public string Parameter { get; init; } = string.Empty;
public string Operator { get; init; } = string.Empty;
public string ExpectedValue { get; init; } = string.Empty;
}
///
/// 规则动作。
///
internal sealed class RuleAction
{
public ActionType Type { get; init; }
public Dictionary Parameters { get; init; } = new();
}
///
/// 规则评估上下文。
///
internal sealed class RuleEvaluationContext
{
public int CurrentLayer { get; init; }
public InferenceResultDto Inference { get; init; } = new();
public DateTime Timestamp { get; init; }
}
///
/// 规则评估结果。
///
internal sealed class RuleEvaluationResult
{
public string RuleName { get; init; } = string.Empty;
public bool IsPass { get; init; }
public string Message { get; init; } = string.Empty;
public RuleAction? Action { get; init; }
public DateTime ExecutionTime { get; init; }
}
///
/// 条件类型。
///
internal enum ConditionType
{
LabelEquals,
ConfidenceThreshold,
QuantityCheck,
PositionCheck,
PlacementCheck,
ForbiddenCheck,
SequenceCheck
}
///
/// 动作类型。
///
internal enum ActionType
{
MarkAsOK,
MarkAsNG,
LogWarning,
Custom
}
///
/// 条件逻辑。
///
internal enum ConditionLogic
{
And,
Or
}
#endregion
#if false
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using OrpaonVision.Core.Results;
using OrpaonVision.SiteApp.Runtime.Contracts;
using OrpaonVision.SiteApp.Runtime.Options;
using System.Text.Json;
namespace OrpaonVision.SiteApp.Runtime.Services;
///
/// 高级规则引擎服务实现。
/// 支持复杂规则配置、多条件判断、动态规则加载等功能。
///
public sealed class AdvancedRuleEngineService : IRuleEngineService, IDisposable
{
private readonly ILogger _logger;
private readonly RuntimeOptions _options;
private readonly Dictionary _rules;
private readonly object _lockObject = new();
private bool _isInitialized;
///
/// 构造函数。
///
public AdvancedRuleEngineService(ILogger logger, IOptions options)
{
_logger = logger;
_options = options.Value;
_rules = new Dictionary();
InitializeDefaultRules();
}
///
public Result Evaluate(int currentLayer, InferenceResultDto inference)
{
try
{
_logger.LogDebug("执行规则引擎评估:当前层={CurrentLayer},推理结果={Label},置信度={Confidence:F3}",
currentLayer, inference.Label, inference.Confidence);
if (!_isInitialized)
{
_logger.LogWarning("规则引擎未初始化,使用默认规则");
return EvaluateWithDefaultRule(currentLayer, inference);
}
// 获取当前层的规则
var layerRules = GetRulesForLayer(currentLayer);
if (layerRules.Count == 0)
{
_logger.LogWarning("第 {CurrentLayer} 层没有配置规则,使用默认规则", currentLayer);
return EvaluateWithDefaultRule(currentLayer, inference);
}
// 执行规则评估
var evaluationContext = new RuleEvaluationContext
{
CurrentLayer = currentLayer,
Inference = inference,
Timestamp = DateTime.UtcNow
};
var results = new List();
foreach (var rule in layerRules)
{
var result = EvaluateRule(rule, evaluationContext);
results.Add(result);
_logger.LogDebug("规则 {RuleName} 评估结果:{IsPass} - {Message}",
rule.Name, result.IsPass, result.Message);
// 如果是关键规则且失败,可以提前终止
if (!result.IsPass && rule.IsCritical)
{
_logger.LogInformation("关键规则 {RuleName} 失败,提前终止评估", rule.Name);
break;
}
}
// 汇总评估结果
var finalDecision = AggregateEvaluationResults(results, evaluationContext);
_logger.LogInformation("规则引擎评估完成:{DecisionCode} - {DecisionMessage}",
finalDecision.Code, finalDecision.Message);
return Result.Success(finalDecision, message: "规则判定完成");
}
catch (Exception ex)
{
var traceId = Guid.NewGuid().ToString("N");
_logger.LogError(ex, "规则引擎评估失败。TraceId: {TraceId}", traceId);
var result = Result.FromException(ex, "RULE_ENGINE_EVALUATION_FAILED", "规则引擎评估失败", traceId);
return Result.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
}
}
///
/// 初始化默认规则。
///
private void InitializeDefaultRules()
{
lock (_lockObject)
{
try
{
_logger.LogInformation("正在初始化默认规则...");
// 添加基础缺陷检测规则
var defectRule = new RuleDefinition
{
Name = "DefectDetection",
Description = "缺陷检测规则",
Layer = 0, // 适用于所有层
Conditions = new List
{
new()
{
Type = ConditionType.LabelEquals,
Parameter = "defect",
Operator = "equals",
ExpectedValue = "defect"
},
new()
{
Type = ConditionType.ConfidenceThreshold,
Parameter = "confidence",
Operator = ">=",
ExpectedValue = _options.NgConfidenceThreshold.ToString("F3")
}
},
Action = new RuleAction
{
Type = ActionType.MarkAsNG,
Parameters = new Dictionary
{
["reason"] = "检测到缺陷",
["severity"] = "high"
}
},
IsCritical = true,
Priority = 1,
Enabled = true
};
// 添加置信度规则
var confidenceRule = new RuleDefinition
{
Name = "ConfidenceCheck",
Description = "置信度检查规则",
Layer = 0, // 适用于所有层
Conditions = new List
{
new()
{
Type = ConditionType.ConfidenceThreshold,
Parameter = "confidence",
Operator = "<",
ExpectedValue = _options.NgConfidenceThreshold.ToString("F3")
}
},
Action = new RuleAction
{
Type = ActionType.MarkAsNG,
Parameters = new Dictionary
{
["reason"] = "置信度过低",
["severity"] = "medium"
}
},
IsCritical = false,
Priority = 2,
Enabled = true
};
// 添加正常通过规则
var passRule = new RuleDefinition
{
Name = "NormalPass",
Description = "正常通过规则",
Layer = 0, // 适用于所有层
Conditions = new List
{
new()
{
Type = ConditionType.LabelEquals,
Parameter = "normal",
Operator = "equals",
ExpectedValue = "normal"
},
new()
{
Type = ConditionType.ConfidenceThreshold,
Parameter = "confidence",
Operator = ">=",
ExpectedValue = _options.NgConfidenceThreshold.ToString("F3")
}
},
Action = new RuleAction
{
Type = ActionType.MarkAsOK,
Parameters = new Dictionary
{
["reason"] = "正常检测"
}
},
IsCritical = false,
Priority = 3,
Enabled = true
};
// 添加数量检查规则
var quantityRule = new RuleDefinition
{
Name = "QuantityCheck",
Description = "部件数量检查规则",
Layer = 0, // 适用于所有层
Conditions = new List
{
new()
{
Type = ConditionType.QuantityCheck,
Parameter = "",
Operator = "equals",
ExpectedValue = "3-5" // 期望3-5个部件
}
},
Action = new RuleAction
{
Type = ActionType.MarkAsNG,
Parameters = new Dictionary
{
["reason"] = "部件数量不符合要求",
["severity"] = "medium"
}
},
IsCritical = false,
Priority = 4,
Enabled = true
};
// 添加位置检查规则
var positionRule = new RuleDefinition
{
Name = "PositionCheck",
Description = "部件位置检查规则",
Layer = 0,
Conditions = new List
{
new()
{
Type = ConditionType.PositionCheck,
Parameter = "screw", // 检查螺丝位置
Operator = "within",
ExpectedValue = "100,100,50" // 圆形区域:中心(100,100),半径50
}
},
Action = new RuleAction
{
Type = ActionType.MarkAsNG,
Parameters = new Dictionary
{
["reason"] = "部件位置偏离",
["severity"] = "high"
}
},
IsCritical = true,
Priority = 5,
Enabled = true
};
// 添加到位检查规则
var placementRule = new RuleDefinition
{
Name = "PlacementCheck",
Description = "部件到位检查规则",
Layer = 0,
Conditions = new List
{
new()
{
Type = ConditionType.PlacementCheck,
Parameter = "",
Operator = "equals",
ExpectedValue = "bracket=2" // 期望2个支架
}
},
Action = new RuleAction
{
Type = ActionType.MarkAsNG,
Parameters = new Dictionary
{
["reason"] = "部件未完全到位",
["severity"] = "medium"
}
},
IsCritical = false,
Priority = 6,
Enabled = true
};
// 添加禁装检查规则
var forbiddenRule = new RuleDefinition
{
Name = "ForbiddenCheck",
Description = "禁装部件检查规则",
Layer = 0,
Conditions = new List
{
new()
{
Type = ConditionType.ForbiddenCheck,
Parameter = "",
Operator = "not_contains",
ExpectedValue = "wrong_part,temp_part" // 禁止错误的部件和临时部件
}
},
Action = new RuleAction
{
Type = ActionType.MarkAsNG,
Parameters = new Dictionary
{
["reason"] = "发现禁装部件",
["severity"] = "high"
}
},
IsCritical = true,
Priority = 7,
Enabled = true
};
// 添加顺序检查规则
var sequenceRule = new RuleDefinition
{
Name = "SequenceCheck",
Description = "装配顺序检查规则",
Layer = 0,
Conditions = new List
{
new()
{
Type = ConditionType.SequenceCheck,
Parameter = "",
Operator = "equals",
ExpectedValue = "base>bracket>screw>cover" // 期望装配顺序
}
},
Action = new RuleAction
{
Type = ActionType.MarkAsNG,
Parameters = new Dictionary
{
["reason"] = "装配顺序错误",
["severity"] = "high"
}
},
IsCritical = true,
Priority = 8,
Enabled = true
};
_rules["DefectDetection"] = defectRule;
_rules["ConfidenceCheck"] = confidenceRule;
_rules["NormalPass"] = passRule;
_rules["QuantityCheck"] = quantityRule;
_rules["PositionCheck"] = positionRule;
_rules["PlacementCheck"] = placementRule;
_rules["ForbiddenCheck"] = forbiddenRule;
_rules["SequenceCheck"] = sequenceRule;
_isInitialized = true;
_logger.LogInformation("默认规则初始化完成,共加载 {Count} 条规则", _rules.Count);
}
catch (Exception ex)
{
_logger.LogError(ex, "初始化默认规则失败");
}
}
}
///
/// 获取指定层的规则。
///
private List GetRulesForLayer(int layer)
{
return _rules.Values
.Where(rule => rule.Layer == 0 || rule.Layer == layer)
.Where(rule => rule.Enabled)
.OrderBy(rule => rule.Priority)
.ToList();
}
///
/// 评估单个规则。
///
private RuleEvaluationResult EvaluateRule(RuleDefinition rule, RuleEvaluationContext context)
{
try
{
var conditionResults = new List();
foreach (var condition in rule.Conditions)
{
var result = EvaluateCondition(condition, context);
conditionResults.Add(result);
// 如果是AND逻辑且有一个条件失败,可以提前退出
if (!result && rule.ConditionLogic == ConditionLogic.And)
{
break;
}
}
// 根据逻辑运算符确定最终结果
var isPass = rule.ConditionLogic == ConditionLogic.And
? conditionResults.All(r => r)
: conditionResults.Any(r => r);
var message = isPass
? $"规则 {rule.Name} 通过"
: $"规则 {rule.Name} 失败: {string.Join(", ", rule.Conditions.Select(c => c.Type))}";
return new RuleEvaluationResult
{
RuleName = rule.Name,
IsPass = isPass,
Message = message,
Action = isPass ? null : rule.Action,
ExecutionTime = DateTime.UtcNow
};
}
catch (Exception ex)
{
_logger.LogError(ex, "评估规则 {RuleName} 失败", rule.Name);
return new RuleEvaluationResult
{
RuleName = rule.Name,
IsPass = false,
Message = $"规则评估异常: {ex.Message}",
Action = new RuleAction
{
Type = ActionType.MarkAsNG,
Parameters = new Dictionary
{
["reason"] = "规则评估异常",
["severity"] = "high"
}
},
ExecutionTime = DateTime.UtcNow
};
}
}
///
/// 评估条件。
///
private bool EvaluateCondition(RuleCondition condition, RuleEvaluationContext context)
{
return condition.Type switch
{
ConditionType.LabelEquals => EvaluateLabelEquals(condition, context),
ConditionType.ConfidenceThreshold => EvaluateConfidenceThreshold(condition, context),
ConditionType.QuantityCheck => EvaluateQuantityCheck(condition, context),
ConditionType.PositionCheck => EvaluatePositionCheck(condition, context),
ConditionType.PlacementCheck => EvaluatePlacementCheck(condition, context),
ConditionType.ForbiddenCheck => EvaluateForbiddenCheck(condition, context),
ConditionType.SequenceCheck => EvaluateSequenceCheck(condition, context),
_ => false
};
}
///
/// 评估标签等于条件。
///
private bool EvaluateLabelEquals(RuleCondition condition, RuleEvaluationContext context)
{
var expectedLabel = condition.ExpectedValue;
var actualLabel = context.Inference.Label;
return condition.Operator switch
{
"equals" => actualLabel == expectedLabel,
"not_equals" => actualLabel != expectedLabel,
"contains" => actualLabel.Contains(expectedLabel),
"not_contains" => !actualLabel.Contains(expectedLabel),
_ => actualLabel == expectedLabel
};
}
///
/// 评估置信度阈值条件。
///
private bool EvaluateConfidenceThreshold(RuleCondition condition, RuleEvaluationContext context)
{
if (!decimal.TryParse(condition.ExpectedValue, out var threshold))
{
_logger.LogWarning("置信度阈值解析失败: {Value}", condition.ExpectedValue);
return false;
}
var actualConfidence = (decimal)context.Inference.Confidence;
return condition.Operator switch
{
">=" => actualConfidence >= threshold,
"<=" => actualConfidence <= threshold,
">" => actualConfidence > threshold,
"<" => actualConfidence < threshold,
"==" => actualConfidence == threshold,
"!=" => actualConfidence != threshold,
_ => actualConfidence >= threshold
};
}
///
/// 评估数量检查条件。
///
private bool EvaluateQuantityCheck(RuleCondition condition, RuleEvaluationContext context)
{
try
{
// 解析期望数量范围,格式如 "min-max" 或 "exact"
var expectedRange = condition.ExpectedValue;
var actualCount = context.Inference.Detections.Count;
_logger.LogDebug("数量检查:期望={ExpectedRange},实际={ActualCount}", expectedRange, actualCount);
if (expectedRange.Contains('-'))
{
// 范围检查,格式:min-max
var parts = expectedRange.Split('-');
if (parts.Length == 2 && int.TryParse(parts[0], out var min) && int.TryParse(parts[1], out var max))
{
return actualCount >= min && actualCount <= max;
}
}
else if (int.TryParse(expectedRange, out var exact))
{
// 精确数量检查
return actualCount == exact;
}
_logger.LogWarning("数量检查条件解析失败: {Value}", expectedRange);
return false;
}
catch (Exception ex)
{
_logger.LogError(ex, "数量检查评估失败");
return false;
}
}
///
/// 评估位置检查条件。
///
private bool EvaluatePositionCheck(RuleCondition condition, RuleEvaluationContext context)
{
try
{
// 解析期望位置,格式如 "x_min:x_max,y_min:y_max" 或 "center_x,center_y,radius"
var expectedPosition = condition.ExpectedValue;
var detections = context.Inference.Detections.Where(d => d.ClassName == condition.Parameter || string.IsNullOrEmpty(condition.Parameter)).ToList();
if (!detections.Any())
{
_logger.LogDebug("位置检查:未找到匹配的检测对象");
return false;
}
// 检查是否所有检测对象都在期望位置范围内
foreach (var detection in detections)
{
var isInRange = CheckPositionInRange(detection.CenterX, detection.CenterY, expectedPosition);
if (!isInRange)
{
_logger.LogDebug("位置检查失败:检测对象 {ClassName} 位置 ({X}, {Y}) 不在期望范围内 {Range}",
detection.ClassName, detection.CenterX, detection.CenterY, expectedPosition);
return false;
}
}
_logger.LogDebug("位置检查通过:所有 {Count} 个检测对象都在期望范围内", detections.Count);
return true;
}
catch (Exception ex)
{
_logger.LogError(ex, "位置检查评估失败");
return false;
}
}
///
/// 评估到位检查条件。
///
private bool EvaluatePlacementCheck(RuleCondition condition, RuleEvaluationContext context)
{
try
{
// 解析期望的到位状态,格式:className=expected_count
var placementRule = condition.ExpectedValue;
var parts = placementRule.Split('=');
if (parts.Length != 2 || !int.TryParse(parts[1], out var expectedCount))
{
_logger.LogWarning("到位检查条件解析失败: {Value}", placementRule);
return false;
}
var targetClass = parts[0];
var actualCount = context.Inference.Detections.Count(d => d.ClassName == targetClass);
_logger.LogDebug("到位检查:{ClassName} 期望={ExpectedCount},实际={ActualCount}",
targetClass, expectedCount, actualCount);
return actualCount >= expectedCount;
}
catch (Exception ex)
{
_logger.LogError(ex, "到位检查评估失败");
return false;
}
}
///
/// 评估禁装检查条件。
///
private bool EvaluateForbiddenCheck(RuleCondition condition, RuleEvaluationContext context)
{
try
{
// 检查是否存在禁用的部件
var forbiddenClasses = condition.ExpectedValue.Split(',', StringSplitOptions.RemoveEmptyEntries);
var detections = context.Inference.Detections;
foreach (var forbiddenClass in forbiddenClasses)
{
var forbiddenDetections = detections.Where(d => d.ClassName.Equals(forbiddenClass.Trim(), StringComparison.OrdinalIgnoreCase)).ToList();
if (forbiddenDetections.Any())
{
_logger.LogDebug("禁装检查失败:发现禁用部件 {ClassName},数量={Count}", forbiddenClass, forbiddenDetections.Count);
return false; // 发现禁用部件,检查失败
}
}
_logger.LogDebug("禁装检查通过:未发现禁用部件");
return true;
}
catch (Exception ex)
{
_logger.LogError(ex, "禁装检查评估失败");
return false;
}
}
///
/// 评估顺序检查条件。
///
private bool EvaluateSequenceCheck(RuleCondition condition, RuleEvaluationContext context)
{
try
{
// 解析期望顺序,格式如 "class1>class2>class3"
var expectedSequence = condition.ExpectedValue;
var sequenceParts = expectedSequence.Split('>', StringSplitOptions.RemoveEmptyEntries);
// 按Y坐标排序检测对象(假设装配顺序是从上到下)
var sortedDetections = context.Inference.Detections
.Where(d => sequenceParts.Contains(d.ClassName))
.OrderBy(d => d.CenterY)
.Select(d => d.ClassName)
.ToList();
var actualSequence = string.Join(">", sortedDetections);
var isCorrectOrder = actualSequence.Equals(expectedSequence, StringComparison.OrdinalIgnoreCase);
_logger.LogDebug("顺序检查:期望={Expected},实际={Actual},结果={Result}",
expectedSequence, actualSequence, isCorrectOrder ? "通过" : "失败");
return isCorrectOrder;
}
catch (Exception ex)
{
_logger.LogError(ex, "顺序检查评估失败");
return false;
}
}
///
/// 检查位置是否在指定范围内。
///
private static bool CheckPositionInRange(float centerX, float centerY, string rangeDefinition)
{
if (rangeDefinition.Contains(','))
{
// 圆形范围检查,格式:center_x,center_y,radius
var parts = rangeDefinition.Split(',');
if (parts.Length == 3 &&
float.TryParse(parts[0], out var expectedCenterX) &&
float.TryParse(parts[1], out var expectedCenterY) &&
float.TryParse(parts[2], out var radius))
{
var distance = Math.Sqrt(Math.Pow(centerX - expectedCenterX, 2) + Math.Pow(centerY - expectedCenterY, 2));
return distance <= radius;
}
}
else if (rangeDefinition.Contains(':'))
{
// 矩形范围检查,格式:x_min:x_max,y_min:y_max
var coordinates = rangeDefinition.Split(',');
if (coordinates.Length == 2)
{
var xRange = coordinates[0].Split(':');
var yRange = coordinates[1].Split(':');
if (xRange.Length == 2 && yRange.Length == 2 &&
float.TryParse(xRange[0], out var xMin) &&
float.TryParse(xRange[1], out var xMax) &&
float.TryParse(yRange[0], out var yMin) &&
float.TryParse(yRange[1], out var yMax))
{
return centerX >= xMin && centerX <= xMax && centerY >= yMin && centerY <= yMax;
}
}
}
return false;
}
///
/// 汇总评估结果。
///
private RuntimeDecisionDto AggregateEvaluationResults(List results, RuleEvaluationContext context)
{
var failedRules = results.Where(r => !r.IsPass).ToList();
var criticalFailures = failedRules.Where(r => r.Action?.Parameters?.ContainsKey("severity") == true &&
r.Action.Parameters["severity"].ToString() == "high").ToList();
var isPass = failedRules.Count == 0;
var decisionCode = isPass ? "RULE_PASS" : "RULE_NG";
var decisionMessage = isPass
? $"第 {context.CurrentLayer} 层所有规则通过"
: $"第 {context.CurrentLayer} 层规则失败: {string.Join(", ", failedRules.Select(r => r.RuleName))}";
// 如果有关键失败,提升消息级别
if (criticalFailures.Count > 0)
{
decisionCode = "RULE_CRITICAL_NG";
decisionMessage = $"第 {context.CurrentLayer} 层关键规则失败: {string.Join(", ", criticalFailures.Select(r => r.RuleName))}";
}
return new RuntimeDecisionDto
{
IsPass = isPass,
Code = decisionCode,
Message = decisionMessage
};
}
///
/// 使用默认规则评估。
///
private Result EvaluateWithDefaultRule(int currentLayer, InferenceResultDto inference)
{
var isPass = inference.Label == "normal" || inference.Label == "OK" || inference.Confidence < _options.NgConfidenceThreshold;
var decision = new RuntimeDecisionDto
{
IsPass = isPass,
Code = isPass ? "DEFAULT_RULE_PASS" : "DEFAULT_RULE_NG",
Message = isPass
? $"第 {currentLayer} 层默认规则通过。"
: $"第 {currentLayer} 层默认规则 NG:{inference.Label} (置信度: {inference.Confidence:F3})"
};
return Result.Success(decision, message: "默认规则判定完成");
}
///
/// 释放资源。
///
public void Dispose()
{
try
{
_rules.Clear();
_isInitialized = false;
_logger.LogInformation("规则引擎服务已释放");
}
catch (Exception ex)
{
_logger.LogError(ex, "释放规则引擎服务资源时发生错误");
}
}
}
#region 规则引擎内部类型
///
/// 规则定义。
///
internal sealed class RuleDefinition
{
public string Name { get; init; } = string.Empty;
public string Description { get; init; } = string.Empty;
public int Layer { get; init; }
public List Conditions { get; init; } = new();
public RuleAction Action { get; init; } = new();
public bool IsCritical { get; init; }
public int Priority { get; init; }
public bool Enabled { get; init; }
public ConditionLogic ConditionLogic { get; init; } = ConditionLogic.And;
}
///
/// 规则条件。
///
internal sealed class RuleCondition
{
public ConditionType Type { get; init; }
public string Parameter { get; init; } = string.Empty;
public string Operator { get; init; } = string.Empty;
public string ExpectedValue { get; init; } = string.Empty;
}
///
/// 规则动作。
///
internal sealed class RuleAction
{
public ActionType Type { get; init; }
public Dictionary Parameters { get; init; } = new();
}
///
/// 规则评估上下文。
///
internal sealed class RuleEvaluationContext
{
public int CurrentLayer { get; init; }
public InferenceResultDto Inference { get; init; } = new();
public DateTime Timestamp { get; init; }
}
///
/// 规则评估结果。
///
internal sealed class RuleEvaluationResult
{
public string RuleName { get; init; } = string.Empty;
public bool IsPass { get; init; }
public string Message { get; init; } = string.Empty;
public RuleAction? Action { get; init; }
public DateTime ExecutionTime { get; init; }
}
///
/// 条件类型。
///
internal enum ConditionType
{
LabelEquals,
ConfidenceThreshold,
QuantityCheck,
PositionCheck,
PlacementCheck,
ForbiddenCheck,
SequenceCheck
}
///
/// 动作类型。
///
internal enum ActionType
{
MarkAsOK,
MarkAsNG,
LogWarning,
Custom
}
///
/// 条件逻辑。
///
internal enum ConditionLogic
{
And,
Or
}
#endregion
#endif