Repository navigation
Add preview document extraction providers with offline acceptance - #82
luisquintanilla wants to merge 7 commits into
Conversation
Implement PdfPig, Azure Content Understanding, Azure Document Intelligence, Mistral, and Vision adapters with offline acceptance and a pinned public-source core bootstrap. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
| private static ReadOnlyMemory<byte>? DecodeImage(JsonElement image) | ||
| { | ||
| if (!image.TryGetProperty("image_base64", out JsonElement base64) | ||
| || base64.ValueKind != JsonValueKind.String) | ||
| { | ||
| return null; | ||
| } | ||
|
|
||
| string raw = base64.GetString()!; | ||
| int comma = raw.IndexOf(','); | ||
| return Convert.FromBase64String(comma >= 0 ? raw[(comma + 1)..] : raw); | ||
| } |
There was a problem hiding this comment.
It's an honor to get to review one of your PRs.
Mistral returns images with their own type, but here they always end up as image/png.
The image_base64 field already contains the type, for example data:image/jpeg;base64,... for img-0.jpeg. You can see it in Mistral's OCR notebook. DecodeImage strips that part, and on line 249 the type is always image/png. So a JPEG is marked as PNG.
To fix it, pass the value to new DataContent(raw) when it starts with data:. It reads the type itself.
| private static ReadOnlyMemory<byte>? DecodeImage(JsonElement image) | |
| { | |
| if (!image.TryGetProperty("image_base64", out JsonElement base64) | |
| || base64.ValueKind != JsonValueKind.String) | |
| { | |
| return null; | |
| } | |
| string raw = base64.GetString()!; | |
| int comma = raw.IndexOf(','); | |
| return Convert.FromBase64String(comma >= 0 ? raw[(comma + 1)..] : raw); | |
| } | |
| private static DataContent? DecodeImage(JsonElement image) | |
| { | |
| if (!image.TryGetProperty("image_base64", out JsonElement base64) | |
| || base64.ValueKind != JsonValueKind.String) | |
| { | |
| return null; | |
| } | |
| string raw = base64.GetString()!; | |
| return raw.StartsWith("data:", StringComparison.OrdinalIgnoreCase) | |
| ? new DataContent(raw) | |
| : new DataContent(Convert.FromBase64String(raw), "image/png"); | |
| } |
I tried it on this branch, together with the call site change below, on .NET 8 and .NET 10. The Mistral tests pass, plus a JPEG test that fails without the fix. Invalid base64 is still rejected.
| ReadOnlyMemory<byte>? content = DecodeImage(image); | ||
| ExtractionDocumentSourceReference source = CreateImageSource(sourcePage, image); | ||
| ProviderAdapterHelpers.AddElement(section, new ExtractionDocumentImageElement() | ||
| { | ||
| Content = content is null ? null : new DataContent(content.Value, "image/png"), |
There was a problem hiding this comment.
And at the call site:
| ReadOnlyMemory<byte>? content = DecodeImage(image); | |
| ExtractionDocumentSourceReference source = CreateImageSource(sourcePage, image); | |
| ProviderAdapterHelpers.AddElement(section, new ExtractionDocumentImageElement() | |
| { | |
| Content = content is null ? null : new DataContent(content.Value, "image/png"), | |
| DataContent? content = DecodeImage(image); | |
| ExtractionDocumentSourceReference source = CreateImageSource(sourcePage, image); | |
| ProviderAdapterHelpers.AddElement(section, new ExtractionDocumentImageElement() | |
| { | |
| Content = content, |
Consume the sealed 20261102.1 core, remove shared response-capture graph, preserve source frames and native inspection, and retain sole text payloads with independent image descriptions and resource safety. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Map explicit Azure cell children with validated deferred ownership. Migrate all five providers to DocumentExtractionClient while preserving service lookup and resource ownership. Document the preview break and pending public dependency coordination. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Pin the integrated public source commit and tree, build four original core packages at fresh review version .4, and synchronize provider dependency and same-run artifact selection. Preserve native provider dependencies and document source-built preview provenance. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Summary
Add five independently consumable, unreleased
CommunityToolkit.DocumentExtraction.*provider packages: PdfPig,AzureContentUnderstanding, AzureDocumentIntelligence, Mistral and Vision.
All target .NET 8 and .NET 10 and derive from
DocumentExtractionClient.They exchange the shared Documents model; they do not depend on DataIngestion.
Keep the component together in this PR. Shared helpers, public-source bootstrap,
dependency configuration and owning CI are common infrastructure, not a new
public abstraction package. The providers have no dependencies on each other's
Toolkit packages.
Contract and mapping boundaries
Use the Documents input from
dotnet/extensions#7835,
commit
e08fe2eae1529a763d0d8d2e42a8d1feae153ed6, as the locked inputfor this preparation. Extraction comes from
dotnet/extensions#7588.
This is not a claim that either upstream API has formal approval or that its
packages have been publicly released.
The client performs completed-document extraction from a
Stream.There is no old-interface shim, page-streaming/Pipes addition, second document
model, renderer API, MEDI policy or shared operation/output/artifact framework.
Middleware preserves the delegating-client/builder composition pattern.
Caller streams and supplied SDK, HTTP and chat clients remain borrowed.
Mappings preserve ordered sections and mixed-content table cells, text roles,
table spans, measured geometry where reported, original page associations,
and explicit native inspection:
Image OCR/transcription is not a caption. Ancestors do not duplicate aggregate
child text. Native inspection is not a durable wire archive or a guarantee of
independence from borrowed provider lifetimes. Unsupported structured Vision
results are rejected without an extra fallback inference request.
Reproducible public prerequisite
The temporary bootstrap source is
https://github.com/luisquintanilla/extensions.git, pinned to:c03481c76b63c6820e1de6ed9da09d5ff1e9f495.f2e9d521223db1cf33fa8bcec5667da26b92cc49.10.0.401.10.10.0-review.20261104.4.The integrated commit preserves the locked Documents blobs and the accepted
abstract Extraction client in one public source tree. It replaces the older
interface-based bootstrap input; repinning to the earlier Extraction head
alone would have omitted the locked mixed-cell fixes.
Build the four original owning projects with their normal imports: AI
Abstractions, Documents Abstractions, Extraction Abstractions and Extraction.
Preserve the existing command-scoped
Features=recipe. No replacement project,handwritten nuspec, private overlay/feed/configuration, copied production DLL,
global SDK change or provider/native SDK upgrade is introduced.
Windows CI builds those actual packages and transfers them through a same-run
artifact to the Windows/Linux offline acceptance jobs. The candidate version is
not claimed available on a public package feed. Artifacts are not a NuGet
release or a permanent feed. Independently source-built archives are not
claimed byte-identical to earlier sealed private packages.
Readiness evidence
Current provider head:
db67441fd2b6cc94d2ff745d8172b705f2cf4e54.The readiness change touches five configuration/documentation files, not
provider implementations, native dependencies or the global SDK pin.
A fresh local public-source bootstrap packed all four original core projects.
Provider restore used the committed pins, followed by a nonincremental Release
build with zero warnings/errors, all ten test binaries passing, and inspection
of all five original provider packages. The local verification also checked
30 actual test-runtime core DLL/archive matches.
Provider workflow 41925266184
completed SUCCESS for this head. All three jobs passed: pinned public
upstream packing, Windows offline acceptance and Ubuntu offline acceptance.
Both platform jobs consumed the actual same-run core artifact and passed
restore, build, offline tests, pack and upload. Each provider build reported
zero warnings/errors.
Local, Windows and Ubuntu each passed 676/676, zero failures/skips.
These repeat the same suites on different environments, not 2,028 distinct test
cases. Hosted counts were read from the actual ten summaries on each platform.
Downloaded and inspected actual nonexpired artifacts from this run:
document-extraction-core-source-packages, ID13368927169.document-extraction-preview-packages-windows-latest, ID13368722630.document-extraction-preview-packages-ubuntu-latest, ID13368433009.The four core main archives contain twenty TFM DLL assets and record the pinned
upstream commit. Each platform artifact contains five provider main archives
at
1.0.0-preview.1, with both target DLLs, MIT licensing, packaged READMEs andthe fresh
.4core dependencies. No packages were released.GitHub tests the PR merge commit
313e3e6f465a1919502468441a462e368b043a15; provider/bootstrap/root build inputsmatch this head. Its seven additional files are unrelated MEVD/Sqlite changes.
No cross-build archive equality or separate portable-PDB audit is claimed.
Historical private
.3acceptance and the older interface-based 512-casehosted run remain separate evidence; neither substitutes for this new gate.
Review order
Release boundary
Offline replay validates mapping, contracts and resource handling, not live
recognition quality. Review readiness does not authorize upstream merges,
formal API approval, signing or package publication. MEDI remains a separate
consumer and is not a dependency of this PR.
Attribution
Useful native segmentation, geometry/role mapping and rendering-resource/test
patterns recover attributed work from closed, unmerged
CommunityToolkit/AI#3
(
37b34b1fbf0a6f265257f4b46d75b687e3cf0684) andCommunityToolkit/AI#14
(
f7ec65479ce9afe172579fb884d67f534dcf73e8).Their obsolete OCR abstraction, MEDI policy/enrichment flow, scanned-page
placeholders and text-only rendering are not revived.