Files
autodesk/DocumentAutomation/src/StandardsWorkbench.Core/StandardsModels.cs
T

78 lines
5.2 KiB
C#

using System.Security.Cryptography;
using System.Text.Json;
using DocumentAutomation.Shared;
namespace StandardsWorkbench.Core;
public sealed record StandardMetadata
{
public required string StandardId { get; init; }
public required string Code { get; init; }
public required string Title { get; init; }
public string Revision { get; init; } = "";
public DateOnly? EffectiveFrom { get; init; }
public required string SourceFileSha256 { get; init; }
public int PageCount { get; init; }
public bool TextLayerDetected { get; init; }
public DateTime ImportedAt { get; init; } = DateTime.UtcNow;
public string Status { get; init; } = "Imported";
}
public sealed record PdfPageText(int PageNumber, string Text, bool TextLayerDetected, string Status, IReadOnlyList<string> Blocks);
public sealed record StandardClause(string StandardId, string ClauseId, string Heading, string Text, int StartPage, int EndPage, double ExtractionConfidence);
public sealed record CandidateRule
{
public required string CandidateId { get; init; }
public required string StandardId { get; init; }
public required string ClauseId { get; init; }
public int SourcePage { get; init; }
public required string SourceText { get; init; }
public required string Title { get; init; }
public string[] Scope { get; init; } = ["DOCX"];
public string RuleKind { get; init; } = "ExpertReview";
public string Target { get; init; } = "Document";
public Dictionary<string, string> Parameters { get; init; } = [];
public string Severity { get; init; } = "Warning";
public string AutomationLevel { get; init; } = "Manual";
public double Confidence { get; init; }
public bool RequiresHumanApproval { get; init; } = true;
public string Status { get; init; } = "New";
}
public sealed record ApprovedRulesProfile
{
public required string StandardId { get; init; }
public required string Code { get; init; }
public required string Revision { get; init; }
public required string SourceFileSha256 { get; init; }
public string ProfileVersion { get; init; } = "1.0";
public string MinimumRulesEngineVersion { get; init; } = "1.0";
public DateTime ExportedAt { get; init; } = DateTime.UtcNow;
public IReadOnlyList<CandidateRule> Rules { get; init; } = [];
}
public interface IPdfOcrService { Task<PdfPageText> RecognizePageAsync(string pdfPath, int pageNumber, CancellationToken cancellationToken); }
public interface IStandardPdfService { Task<(StandardMetadata Metadata, IReadOnlyList<PdfPageText> Pages, IReadOnlyList<StandardClause> Clauses)> ImportAsync(string pdfPath, string code, string title, CancellationToken cancellationToken); }
public interface IOllamaService { Task<IReadOnlyList<string>> GetModelsAsync(CancellationToken cancellationToken); Task<CandidateRule?> SuggestCandidateAsync(StandardClause clause, string model, CancellationToken cancellationToken); }
public static class ProfileStore
{
public static string Sha256(string path) { using var stream = File.OpenRead(path); return Convert.ToHexString(SHA256.HashData(stream)).ToLowerInvariant(); }
public static void Export(string directory, ApprovedRulesProfile profile)
{
Directory.CreateDirectory(directory); var options = new JsonSerializerOptions { WriteIndented = true }; File.WriteAllText(Path.Combine(directory, "manifest.json"), JsonSerializer.Serialize(profile, options)); File.WriteAllText(Path.Combine(directory, "approved-rules.json"), JsonSerializer.Serialize(profile.Rules, options)); File.WriteAllText(Path.Combine(directory, "references.json"), JsonSerializer.Serialize(profile.Rules.Select(r => new { r.ClauseId, r.SourcePage, r.StandardId }), options)); File.WriteAllText(Path.Combine(directory, "signature.sha256"), Sha256(Path.Combine(directory, "approved-rules.json")));
}
}
public sealed class RulesEngine
{
public IReadOnlyList<RuleEvaluationResult> Evaluate(DocumentInspectionResult document, ApprovedRulesProfile profile)
=> profile.Rules.Where(r => r.Status is "Approved" or "Implemented" or "Tested").Select(r => EvaluateOne(document, r)).ToArray();
private static RuleEvaluationResult EvaluateOne(DocumentInspectionResult d, CandidateRule rule)
{
var status = rule.RuleKind switch { "SectionCount" => d.Sections > 0 ? RuleEvaluationStatus.Pass : RuleEvaluationStatus.Fail, "ContentControlPresence" => d.ContentControls > 0 ? RuleEvaluationStatus.Pass : RuleEvaluationStatus.Fail, "BookmarkPresence" => d.Bookmarks > 0 ? RuleEvaluationStatus.Pass : RuleEvaluationStatus.Fail, "CommentsAbsent" => d.Comments == 0 ? RuleEvaluationStatus.Pass : RuleEvaluationStatus.Fail, "TrackedChangesAbsent" => !d.HasTrackedChanges ? RuleEvaluationStatus.Pass : RuleEvaluationStatus.Fail, _ => RuleEvaluationStatus.NeedsReview };
return new RuleEvaluationResult { RuleId = rule.CandidateId, Status = status, Message = status == RuleEvaluationStatus.Pass ? "Проверка пройдена." : status == RuleEvaluationStatus.Fail ? "Проверка не пройдена." : "Требуется экспертная проверка.", ClauseId = rule.ClauseId, SourcePage = rule.SourcePage, DocumentLocation = rule.Target, CanAutoFix = false };
}
}