feat: add standards workbench and portable rules profiles
This commit is contained in:
@@ -0,0 +1,33 @@
|
||||
using System.Text.RegularExpressions;
|
||||
using StandardsWorkbench.Core;
|
||||
using UglyToad.PdfPig;
|
||||
|
||||
namespace StandardsWorkbench.Pdf;
|
||||
|
||||
public sealed class PdfStandardService : IStandardPdfService
|
||||
{
|
||||
public Task<(StandardMetadata Metadata, IReadOnlyList<PdfPageText> Pages, IReadOnlyList<StandardClause> Clauses)> ImportAsync(string pdfPath, string code, string title, CancellationToken cancellationToken)
|
||||
{
|
||||
if (!File.Exists(pdfPath)) throw new FileNotFoundException("PDF ГОСТа не найден.", pdfPath);
|
||||
return Task.Run(() =>
|
||||
{
|
||||
using var pdf = PdfDocument.Open(pdfPath); var pages = new List<PdfPageText>();
|
||||
foreach (var page in pdf.GetPages()) { cancellationToken.ThrowIfCancellationRequested(); var text = page.Text ?? ""; pages.Add(new PdfPageText(page.Number, text, text.Trim().Length > 0, text.Trim().Length > 0 ? "Extracted" : "OCR_REQUIRED", text.Split(Environment.NewLine, StringSplitOptions.RemoveEmptyEntries))); }
|
||||
var standardId = Regex.Replace(code.ToUpperInvariant(), "[^A-ZА-Я0-9]+", "-").Trim('-'); var clauses = ExtractClauses(standardId, pages); var meta = new StandardMetadata { StandardId = standardId, Code = code, Title = title, SourceFileSha256 = ProfileStore.Sha256(pdfPath), PageCount = pages.Count, TextLayerDetected = pages.Any(p => p.TextLayerDetected), ImportedAt = DateTime.UtcNow };
|
||||
return (meta, (IReadOnlyList<PdfPageText>)pages, (IReadOnlyList<StandardClause>)clauses);
|
||||
}, cancellationToken);
|
||||
}
|
||||
|
||||
private static List<StandardClause> ExtractClauses(string id, IReadOnlyList<PdfPageText> pages)
|
||||
{
|
||||
var result = new List<StandardClause>(); string? currentId = null; var currentText = new List<string>(); var start = 1;
|
||||
void Flush(int end) { if (currentId is not null) result.Add(new StandardClause(id, currentId, "", string.Join(Environment.NewLine, currentText), start, end, 0.85)); }
|
||||
foreach (var page in pages) foreach (var line in page.Text.Split('\n', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)) { var match = Regex.Match(line, "^(\\d+(?:\\.\\d+){0,5})[.)]?\\s+(.+)$"); if (match.Success) { Flush(page.PageNumber - 1); currentId = match.Groups[1].Value; currentText = [line]; start = page.PageNumber; } else if (currentId is not null) currentText.Add(line); }
|
||||
Flush(pages.Count); return result;
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class NoOpOcrService : IPdfOcrService
|
||||
{
|
||||
public Task<PdfPageText> RecognizePageAsync(string pdfPath, int pageNumber, CancellationToken cancellationToken) => Task.FromResult(new PdfPageText(pageNumber, "", false, "OCR_REQUIRED", []));
|
||||
}
|
||||
Reference in New Issue
Block a user