💡 Pełny działający przykład dostępny na GitHubie: parse-docx-to-markdown-chunks-dotnet

Stara metoda była bolesna

Chunkowanie Markdown oparte na nagłówkach jest ścieżką przygotowania pobierania w .NET, która zamienia pliki Office i PDF na tekst o rozmiarze sekcji przed ich osadzeniem. Bez tego zespoły często wrzucają cały plik Worda do jednego wektora. Akapit wprowadzający i klauzula obowiązkowa dzielą jedno osadzenie, więc wyszukiwanie kosinusowe ocenia niewłaściwą sekcję. Doświadczyłem tego na trzystronnym wewnętrznym przewodniku: każde zapytanie najpierw wyciągało blok tytułowy, ponieważ indeks nigdy nie widział struktury # / ## napisaną przez autorów.

Tworzenie własnego konwertera DOCX‑to‑Markdown oznacza przechodzenie przez style Open XML, mapowanie poziomów list i nadal niepowodzenia, gdy kolejny upload jest PDF, którego sformatowana ścieżka Markdown zwraca null. Okna tokenów o stałym rozmiarze ignorują te nagłówki. Nocne korpusy mieszają wtedy puste skorupy z ogromnymi podręcznikami, ponieważ nikt nie sprawdzał najpierw liczby stron ani rozmiaru.

Rzeczywisty koszt osadzania całych plików: odpowiedzi z niewłaściwych sekcji, zmarnowane wydatki na ekstrakcję przy niepotrzebnych uploadach oraz brak artefaktów chunk-01.md, które operatorzy mogą otworzyć podczas złej partii.

Jest lepszy sposób

GroupDocs.Parser dla .NET zastępuje to zamieszanie czterema skoncentrowanymi wywołaniami: GetDocumentInfo, GetFormattedText(FormattedTextMode.Markdown), GetText gdy Markdown jest null oraz mały przeglądnik nagłówków, który zapisuje chunk-NN.md. Ten sam typ Parser obsługuje parsowanie Word DOCX i awaryjny tekst PDF, więc masz jedną ścieżkę usługi C#.

You will need:

  • .NET 8 SDK
  • GroupDocs.Parser 26.10.0 (tymczasowa licencja)
  • Plik Word DOCX (przykład ma 3 strony / 14820 bajtów) oraz opcjonalnie PDF
dotnet add package GroupDocs.Parser --version 26.10.0

Nowy sposób: sprawdź, wyodrębnij, awaryjny fallback, podziel

Oto to samo przygotowanie pobierania po zmianie. Przykład konsolowy w parse-docx-to-markdown-chunks-dotnet zapisuje informacje, Markdown, tekst PDF i cztery fragmenty nagłówków dla dostarczonego DOCX.

Krok 1 – sprawdź za pomocą GetDocumentInfo

Zapytaj o typ pliku, liczbę stron i rozmiar przed opłaceniem pełnej ekstrakcji.

using var parser = new Parser(sourcePath);
var info = parser.GetDocumentInfo();

var sb = new StringBuilder();
sb.AppendLine($"Source: {Path.GetFileName(sourcePath)}");
sb.AppendLine($"File type: {info?.FileType}");
sb.AppendLine($"Pages: {info?.PageCount}");
sb.AppendLine($"Size: {info?.Size} bytes");
File.WriteAllText(outputPath, sb.ToString());

Zaloguj te fakty obok identyfikatora zadania. W przykładowym DOCX powinieneś zobaczyć dokument Microsoft Word Open XML, 3 strony i 14820 bajtów.

Krok 2 – preferuj Markdown z GetFormattedText

Dla Worda i formatów, które obsługują sformatowaną ekstrakcję, zachowaj nagłówki ATX dla podziału.

using var parser = new Parser(sourcePath);
using TextReader? reader = parser.GetFormattedText(
    new FormattedTextOptions(FormattedTextMode.Markdown));

if (reader == null)
{
    return null;
}

string markdown = reader.ReadToEnd();
File.WriteAllText(outputPath, markdown, Encoding.UTF8);
return markdown;

Null jest sygnałem do zmiany ścieżki, a nie awarią. Zapisz w UTF‑8, aby narzędzia do fragmentów i diffy git były czytelne.

Krok 3 – awaryjny fallback z GetText dla PDF

Gdy tryb Markdown zwraca null, utrzymaj plik w potoku z warstwą zwykłego tekstu.

using var parser = new Parser(sourcePath);
using TextReader? reader = parser.GetText();
if (reader == null)
{
    return null;
}

string text = reader.ReadToEnd();
File.WriteAllText(outputPath, text, Encoding.UTF8);
return text;

Oczekuj .txt, a nie wymyślonych nagłówków #. Przykładowy host zapisuje Result/sample-pdf.txt dla gałęzi PDF.

Krok 4 – podziel Markdown na # i

Przeglądaj linie; opróżnij, gdy pojawi się nowy ATX # lub ##; zapisz chunk-NN.md.

var chunks = new List<string>();
var current = new StringBuilder();
using (var reader = new StringReader(markdown))
{
    string? line;
    while ((line = reader.ReadLine()) != null)
    {
        bool isHeading = line.StartsWith("# ", StringComparison.Ordinal)
            || line.StartsWith("## ", StringComparison.Ordinal);
        if (isHeading && current.Length > 0)
        {
            chunks.Add(current.ToString().TrimEnd());
            current.Clear();
        }
        current.AppendLine(line);
    }
}

Najpierw usuń przestarzałe pliki chunk-*.md. Głębsze linie ### pozostają w bieżącej sekcji. Przykładowy DOCX generuje cztery pliki w Result/chunks/.

Kiedy powinienem zastąpić osadzanie całych plików tą ścieżką?

Zastąp osadzanie całych plików, gdy przyjmowanie miesza Word DOCX i PDF, a indeks potrzebuje Markdown o rozmiarze sekcji. Najpierw uruchom GetDocumentInfo, spróbuj Markdown dla plików Office, wywołaj GetText, gdy sformatowany czytnik jest null, i podziel tylko wtedy, gdy istnieją znaczniki # / ##. Pozostaw nieustrukturyzowany tekst PDF w spokoju, aż dodasz osobną politykę podziału. Ta kolejność odpowiada przykładowej aplikacji konsolowej i utrzymuje tryby awarii wyraźne dla operatorów.

Co się zmieniło dla operatorów

Przed Po
Jedno osadzenie na plik Jedno osadzenie na blok nagłówka
Niestandardowy Open XML Markdown Tryb Markdown GetFormattedText
PDF odrzucony przy null sformatowanym czytniku GetText zapisuje artefakt tekstowy
Brak taniego wstępnego sprawdzenia Liczba stron i rozmiar jako bramka

Zwolnij każdy Parser i TextReader. Zastosuj licencję lub tymczasową licencję przed nocnym wolumenem. Traktuj uploady jako nieufne dane wejściowe i parsuj w odizolowanym workerze.

Wypróbuj to na własnych plikach

Sklonuj parse-docx-to-markdown-chunks-dotnet, przywróć GroupDocs.Parser 26.10.0 i uruchom przeciwko documents/sample.docx. Następnie skieruj te same cztery metody na jeden ze swoich podręczników i otwórz wygenerowane pliki chunk-*.md.