feat: add Azure Content Understanding with resumable lakehouse writes - #2698
feat: add Azure Content Understanding with resumable lakehouse writes#2698Rana Singh (ranadeepsingh) wants to merge 4 commits into
Conversation
## Summary Add a Scala-first Azure Content Understanding transformer and generated Python API. Support current GA and opt-in preview requests, explicit custom analyzer provisioning, and append-only operation journals in Spark tables and lakehouse paths. Add offline service, persistence, and generated-wrapper coverage plus Python/Scala usage documentation. ## Prompting Intent The engineer requested an easy-to-configure Content Understanding integration using current APIs that can run in Fabric. They also requested a persistence layer that retains completed work when large-document processing fails, and real-service experiments to guide the API and durability design. ## Linked Sources - Analyze API: https://learn.microsoft.com/en-us/rest/api/contentunderstanding/content-analyzers/analyze?view=rest-contentunderstanding-2025-11-01 - Result API: https://learn.microsoft.com/en-us/rest/api/contentunderstanding/content-analyzers/get-result?view=rest-contentunderstanding-2025-11-01 - Analyzer provisioning: https://learn.microsoft.com/en-us/rest/api/contentunderstanding/content-analyzers/create-or-replace?view=rest-contentunderstanding-2025-11-01 - API releases: https://learn.microsoft.com/en-us/azure/ai-services/content-understanding/whats-new - Model mappings: https://learn.microsoft.com/en-us/azure/ai-services/content-understanding/concepts/models-deployments - Service limits: https://learn.microsoft.com/en-us/azure/ai-services/content-understanding/service-limits - Result retention: https://learn.microsoft.com/en-us/azure/foundry/responsible-ai/content-understanding/data-privacy - Fabric credentials: https://learn.microsoft.com/en-us/fabric/data-engineering/notebookutils/notebookutils-credentials ## Rationale Use 2025-11-01 by default and make 2026-06-01-preview explicit. Preserve the complete operation JSON because live responses contain dynamic extraction fields, preview metadata, and top-level usage, and Running responses can already contain an empty result. Commit each operation handle before polling and each result independently. Keep uncertain submissions visible without automatically repeating billable POSTs. Canonical request hashes prevent silently reusing IDs for changed analysis requests. Driver-side single-writer orchestration trades throughput for bounded input batches and durable per-operation commits. Explicit ranges allow large-document progress without silently changing extraction context. Do not terminalize definite authentication or throttling rejections; stop so a later invocation can retry the same ID. Treat missing or expired result handles as distinct terminal retrieval failures so later documents can still complete. Keep HTTP 408/5xx submission outcomes uncertain rather than assuming that an error response proves the service did not accept a billable request. Use existing HTTP and Spark infrastructure without new dependencies. Require an explicit endpoint and validate operation URLs before forwarding credentials. Do not mutate resource defaults or change existing public JVM signatures. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
## Summary Leave response stream ownership with the enclosing HTTP response. Add large chunked/gzip recovery coverage and a deterministic faulting-close regression. Include the safe exception type in transport diagnostics. ## Prompting Intent The engineer requested a Content Understanding integration that preserves completed work for large-document jobs and runs in Fabric. During real-runtime validation, a response-bound scenario produced a generic transport failure, requiring investigation before publishing the feature. ## Linked Sources - Content Understanding result API: https://learn.microsoft.com/en-us/rest/api/contentunderstanding/content-analyzers/get-result?view=rest-contentunderstanding-2025-11-01 - HttpClient response resource ownership: https://hc.apache.org/httpcomponents-client-4.5.x/current/tutorial/html/fundamentals.html ## Rationale Closing an already-aborted entity stream in finally can replace the original ResponseTooLarge exception with an IOException. The HTTP response already owns and closes that stream, so remove the redundant close rather than suppressing arbitrary cleanup errors. A faulting stream reproduces the exception masking; public writer cases cover chunked and compressed responses and resumption. Retain only the IOException class name, not potentially sensitive exception messages, when distinguishing transport failures. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
Azure Pipelines: There may be pipelines that require an authorized user to comment /azp run to run. |
|
Hey Rana Singh (@ranadeepsingh) 👋! We use semantic commit messages to streamline the release process. Examples of commit messages with semantic prefixes:
To test your commit locally, please follow our guild on building from source. |
|
/azp run |
|
Azure Pipelines: Successfully started running 1 pipeline(s). |
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
The durable writer currently computes latest(journal.read()) over the full journal before filtering to batch IDs, which can cause significant unnecessary window/shuffle work as the journal grows.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Review tier: Lite
Findings: 1
New issues introduced by this change (1)
| Severity | Finding |
|---|---|
cognitive/src/main/scala/com/microsoft/azure/synapse/ml/services/contentunderstanding/ContentUnderstandingWriter.scala — In the writer loop, latest(journal.read()) computes a window over the entire journal and only… |
What changed in this PR
Adds a new SynapseML Cognitive Services integration for Azure Content Understanding, providing a Scala-first SparkML transformer with generated Python wrappers plus a durable, resumable journal writer for lakehouse/table persistence. This expands the cognitive module’s document/AI service stages with a reliability-focused write/resume workflow and accompanying docs/tests.
Changes:
- Introduces
ContentUnderstandingtransformer with request construction, validation, polling/submission modes, and analyzer provisioning APIs. - Adds
ContentUnderstandingWriterand persistence helpers (writeToTable/writeToPath/readTable/readPath) implementing append-only journaling and resumption. - Adds comprehensive Scala + Python tests and a new docs page linked into the website sidebar.
| File | Description |
|---|---|
| website/sidebars.js | Adds the new Content Understanding guide to the docs sidebar navigation. |
| docs/Explore Algorithms/AI Services/Content Understanding.md | New end-to-end documentation for configuration, durability semantics, and Scala/Python usage. |
| cognitive/src/main/scala/com/microsoft/azure/synapse/ml/services/contentunderstanding/ContentUnderstanding.scala | New SparkML stage implementing request/poll logic, validation, and analyzer provisioning APIs. |
| cognitive/src/main/scala/com/microsoft/azure/synapse/ml/services/contentunderstanding/ContentUnderstandingParams.scala | Defines service parameters, defaults, and Python wrapper overrides for bytes + param transfer. |
| cognitive/src/main/scala/com/microsoft/azure/synapse/ml/services/contentunderstanding/ContentUnderstandingPersistence.scala | Exposes durable writer/read helpers on the stage and emits Python convenience methods. |
| cognitive/src/main/scala/com/microsoft/azure/synapse/ml/services/contentunderstanding/ContentUnderstandingProtocol.scala | Implements bounded HTTP exchange, retry-delay parsing, safe operation-location validation, and decoding. |
| cognitive/src/main/scala/com/microsoft/azure/synapse/ml/services/contentunderstanding/ContentUnderstandingWriter.scala | Driver-side single-writer journaling orchestration for submit/poll/append + resume behavior. |
| cognitive/src/test/scala/com/microsoft/azure/synapse/ml/services/form/contentunderstanding/ContentUnderstandingWriterSuite.scala | Scala tests for journal durability/resumption, ID validation, and failure/rejection handling. |
| cognitive/src/test/scala/com/microsoft/azure/synapse/ml/services/form/contentunderstanding/ContentUnderstandingSuite.scala | Scala tests for request correctness, schema validation, error preservation, polling semantics, and provisioning. |
| cognitive/src/test/scala/com/microsoft/azure/synapse/ml/services/form/contentunderstanding/ContentUnderstandingStub.scala | HTTP stub infrastructure for deterministic offline testing of service behaviors and transport edge cases. |
| cognitive/src/test/python/synapsemltest/services/test_ContentUnderstanding.py | Python integration tests validating generated wrapper behavior, persistence, and analyzer provisioning calls. |
💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
## Summary Register ContentUnderstanding with the framework's typed transformer fuzzers, repairing the four failing core CI registration checks. Separate writer recovery, filesystem, fuzzing, and live PDF/DOCX coverage into dedicated files. Honor submit-only persistence, let poll mode use the version in its saved operation URL, and resolve output filesystems from the Spark session. Express the batch-ID journal filter before latest-state selection. Remove request data from the Python test fixture's response headers. Document the exact public signatures, raw REST calls, and the observed whole-document behavior of DOCX. ## Prompting Intent The engineer asked to investigate failing tests in microsoft#2698, make Content Understanding-specific unit and end-to-end failures identifiable, review every changed line for necessity and bugs, validate PDFs and DOCX against Azure, and make the PR's API and REST usage easy to understand. No Azure DevOps work-item ID was supplied. ## Linked Sources - Pull request and request context: microsoft#2698 - Failing Azure validation: https://msdata.visualstudio.com/b9b2accc-2d1c-45b3-9d24-0eb5d78cc47f/_build/results?buildId=234599208 - Exact-base comparison: https://msdata.visualstudio.com/b9b2accc-2d1c-45b3-9d24-0eb5d78cc47f/_build/results?buildId=234571994 - Test-header finding: microsoft#2698 (comment) - Journal-filter finding: microsoft#2698 (comment) - REST API: https://learn.microsoft.com/rest/api/contentunderstanding/content-analyzers/analyze?view=rest-contentunderstanding-2025-11-01 - Service limits: https://learn.microsoft.com/azure/ai-services/content-understanding/service-limits - API release notes: https://learn.microsoft.com/azure/ai-services/content-understanding/whats-new ## Rationale Ordinary TestBase suites did not satisfy the repository-wide experiment, serialization, Python and R fuzzer registration contract. A typed fuzzer repairs integration without suppressing checks or moving tests outside the existing CI selector. Scoped loopback fixtures keep offline tests independent of service credentials; real-service cases are explicitly opt-in. Three before-fix regressions establish the recovery/configuration defects. Submit mode now commits only accepted state, leaving result collection to a later analyze call. Poll-only requests do not require columns unrelated to the saved handle. Session-derived Hadoop configuration honors managed-runtime and session-specific filesystem settings. Live synthetic requests confirmed PDF range handling and DOCX text/table extraction, but a DOCX page range still returned the whole file. The guide therefore avoids promising DOCX page-level checkpoints. Existing public JVM signatures, journal schema, response retention, request identity checks, single-writer constraints and uncertain-submission protections remain intact. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
/azp run |
|
Azure Pipelines: Successfully started running 1 pipeline(s). |
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
The durable writer currently reuses transform-oriented schema validation and can unnecessarily reject valid inputs that already contain outputCol/errorCol.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Review tier: Lite
Findings: 1
New issues introduced by this change (1)
| Severity | Finding |
|---|---|
cognitive/src/main/scala/com/microsoft/azure/synapse/ml/services/contentunderstanding/ContentUnderstandingWriter.scala — ContentUnderstandingWriter.validateInput calls analyzer.validateInputSchema(dataset.schema), which… |
Issues resolved since last review (1)
| Severity | Finding |
|---|---|
cognitive/src/main/scala/com/microsoft/azure/synapse/ml/services/contentunderstanding/ContentUnderstandingWriter.scala — In the writer loop, latest(journal.read()) computes a window over the entire journal and only… View resolved comment |
## Summary Allow durable table and path writers to consume input columns with the same names as the stage's output and error columns. Keep overwrite protection in the transform and transformSchema paths, which actually add those columns. ## Prompting Intent Investigate failing tests in microsoft#2698, keep Content Understanding tests in dedicated files, review every change, validate PDF and DOCX processing with the Azure service, and explain the public API and raw REST contract. ## Linked Sources - Pull request: microsoft#2698 - Current-head review: microsoft#2698 (comment) - Guide: docs/Explore Algorithms/AI Services/Content Understanding.md ## Rationale Both durable writers reuse request-schema validation but return a separate operation journal rather than transformed input rows. Move the existing overwrite guard to getInternalTransformer instead of dropping input columns, adding a validation bypass, or changing public method signatures. Keep request type, source, endpoint, and parameter checks shared. Add a before/after writer regression plus explicit transform and transformSchema rejection coverage, and exercise the same input-name case in the dedicated live PDF/DOCX writer tests. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
/azp run |
|
Azure Pipelines: Successfully started running 1 pipeline(s). |
There was a problem hiding this comment.
Copilot review overview
🔵 Needs a closer look
The PR introduces a substantial new public feature spanning Scala REST/protocol logic, durable persistence semantics, generated Python surface area, and multiple test suites, which warrants final human review and full CI validation.
Review tier: Lite
Findings: None
Issues resolved since last review (2)
| Severity | Finding |
|---|---|
cognitive/src/main/scala/com/microsoft/azure/synapse/ml/services/contentunderstanding/ContentUnderstandingWriter.scala — ContentUnderstandingWriter.validateInput calls analyzer.validateInputSchema(dataset.schema), which… View resolved comment |
|
cognitive/src/main/scala/com/microsoft/azure/synapse/ml/services/contentunderstanding/ContentUnderstandingWriter.scala — In the writer loop, latest(journal.read()) computes a window over the entire journal and only… View resolved comment |
Suppressed comments (1)
Previously missed (1) — in code that hasn't changed since the last review.
cognitive/src/main/scala/com/microsoft/azure/synapse/ml/services/contentunderstanding/ContentUnderstandingWriter.scala:47
readTable/readPathcurrently accept null/blank destination names and (forreadPath) anyformatstring, even though writes explicitly restrict formats todelta/parquet. Adding the same input/format validation here would provide clearer, earlier errors and keep the public read API consistent with the write API.
|
Reviewed the suppressed reader-validation suggestion on f3a7963. The read helpers intentionally delegate destination/provider resolution to Spark and then validate the exact Content Understanding journal schema. An eight-case probe through the generated public API confirmed that null/empty/blank destinations and unknown/null providers raise rather than return data; no Content Understanding endpoint or credentials were configured. Spark reports parser/path/provider errors, including its existing NullPointerException for a null table name or provider. Additional wrapper checks would improve those two messages, but are not needed to reject invalid reads or protect the journal. I kept Spark read-provider resolution rather than imposing the write-only delta/parquet restriction on reads. Writes remain restricted because they must provide supported append semantics. All active review threads are resolved; full current-head CI and the exact-artifact Fabric run are still in progress. |
|
Final-head Azure build 234646332 verified the repair: all four formerly failing framework assertions, all 54 Content Understanding Scala tests, four Python integration tests and the generated constructor passed. 62/64 jobs succeeded. The image job failed during Azure task initialization before tests started because msdata.visualstudio.com received a *.azureedge.net certificate; the HF tests passed but result/coverage uploads hit the same TLS problem. I requested one failed-jobs-only retry of the same build/source using the stage retry API, with forceRetryAllJobs=false. No TLS checks were bypassed and no source or pipeline settings changed. Exact-head Fabric PDF/DOCX and Delta recovery results are already in the PR description. |
|
The bounded infrastructure retry completed successfully. Build 234646332 is green on merge 3dda7c4, testing head f3a7963. All 64 Azure jobs and 65 Azure check entries succeeded. Only the two previously failed jobs reran: image executed six passing tests with two pre-existing ignored cases; HF executed four passing tests. Both published test results and coverage successfully. The Content Understanding regression, generated API, and exact-artifact Fabric PDF/DOCX/Delta evidence is in the updated description. No source or TLS-validation changes were needed for the retry. Maintainer review remains required; the PR is not merged. |
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## master #2698 +/- ##
==========================================
+ Coverage 87.52% 87.68% +0.16%
==========================================
Files 341 346 +5
Lines 21035 21658 +623
Branches 2232 2277 +45
==========================================
+ Hits 18410 18990 +580
- Misses 2625 2668 +43
🚀 New features to boost your workflow:
|

What changes are proposed in this pull request?
Add Azure Content Understanding to SynapseML through a Scala transformer and
generated Python API. Analyze PDFs, DOCX files, and other service-supported
inputs. Save each accepted operation and completed result to a Fabric lakehouse
or Spark table so a later document failure does not discard earlier work.
The implementation calls the Content Understanding REST API directly through
SynapseML's JVM HTTP infrastructure. It does not require a Content Understanding
Python SDK. The default is GA
2025-11-01;2026-06-01-previewis an explicitopt-in.
Python quickstart
Use immutable document versions and stable unique string IDs. The example uses
the path as an ID, so files at those paths must not change during processing or
recovery. Configure
setDocumentUrlColinstead ofsetDocumentBytesColwhen theservice can read the source URL directly. Never configure both sources.
API signatures
All methods below are instance methods on
ContentUnderstanding.transform(dataset)outputCol, anderrorCol. Lazy until a Spark action.writeToTable(dataset, idCol, tableName, format="delta", batchSize=1)writeToPath(dataset, idCol, path, format="delta", batchSize=1)readTable(spark, tableName)readPath(spark, path, format="delta")createAnalyzer(definition: dict | str, allowReplace=False) -> strgetAnalyzer() -> strThe response fields are
operationLocation,id,status,httpStatus,rawResponse, anderror. Writer results expose those fields at the top level,plus
documentId,requestHash, andsequence.rawResponseretains the fulloperation JSON, including usage, extraction fields, warnings, and preview
metadata. Input document bytes are not copied into the journal.
Writers accept existing input columns named
outputColorerrorColbecausethey return a separate journal schema.
transformstill rejects thosecollisions rather than overwrite input.
Scala exposes the same operations:
Configure request options
Service options accept scalar and column setters, such as
setRange("1-2")or
setRangeCol("pageRange"). This also applies to the analyzer ID, inputsource, name, MIME type, model deployment map, string encoding, processing
location, API version, and authentication. Polling budgets, timeouts, response
size, and transform concurrency are scalar execution controls.
Poll-only
transformusessetOperationMode("poll")andsetOperationLocationCol("handle"). It needs neither the original documentcolumns nor the original API-version column; the saved URL supplies its version.
The durable writers require the original manifest to verify request identity.
Custom extraction, layout, and segmentation settings belong in an analyzer
definition:
Provisioning is never implicit in
transform. Resource defaults and modeldeployments remain administrator-owned. The service's
DefaultsNotSeterroris surfaced rather than repaired by changing shared configuration.
REST requests under the hood
POST {endpoint}/contentunderstanding/analyzers/{analyzerId}:analyze?api-version={version}GET {Operation-Location}PUT {endpoint}/contentunderstanding/analyzers/{analyzerId}?api-version={version}&allowReplace={bool}GET {endpoint}/contentunderstanding/analyzers/{analyzerId}?api-version={version}The analyze body uses
inputs: [{url: ...}]orinputs: [{data: "<base64>"}],with optional
name,mimeType, andrange.modelDeploymentsis a top-levelbody property.
stringEncodingandprocessingLocationare query parameters.Analyzer creation polls its management operation before returning the definition.
POST/PUT calls are not automatically retried, redirects are disabled, and GET
polling has a bounded retry budget.
Persistence contract and limits
each completed document or explicit PDF range gets its own result commit.
batchSizebounds collected input rows, not the number of results per commit. A single
document and response must still fit in memory.
Credential rotation is allowed. Changes behind an unchanged URL, analyzer
name, or deployment name cannot be detected.
Indeterminate submissions are recorded as
Unknownand are not automaticallyresubmitted. Polling credential/transport/response errors retain saved handles.
Missing or expired results become
ResultUnavailable, allowing later IDs toproceed.
duplicate submission. This is not an exactly-once external-service guarantee.
Saved handles also remain subject to the service's 24-hour result retention.
Service experiments that informed the design
Experiments used only synthetic inputs and existing authorized resources.
No shared defaults or model deployments were changed.
result; HTTP 200 can carryFailedSucceededis successful completion.2retained original page 2 and reported one basic document page of usagedocumentPagesMinimalusagepagesarray or a PDF-shaped usage object.range="2"still returned the whole document1-2and319-320of a synthetic 320-page PDF succeeded in earlier experimentsHow is this patch tested?
Remediation head:
f3a7963c217677e9b6564cc6736495e0f1bcdce4.FuzzingTestpassed all 10 active tests, including the four previously failing checks. One pre-existing getter/setter test remains ignored.PipelineTestCoverageSuitepassed, confirming CI still selects the separated suites.Four configuration/recovery regressions failed before the fixes and pass
afterward, including the writer's rejection of existing output/error column
names. Both table and path writers now accept those inputs, while
transformand
transformSchemastill reject overwrites before any service call.A 3,000-row journal-plan probe with 1,000 document IDs confirmed that
only the two selected IDs' metadata reaches the driver. Spark already pushed
the original filter below the window; the reordered code produces an identical
optimized plan. The change makes that intent explicit, not a claimed speedup.
The reported Azure failure was a PR-specific registration defect, not a flaky
service call. Build
234599208failed four coreFuzzingTestchecks becauseContentUnderstandinghad no typed framework fuzzer. The exact-base masterbuild passed those four checks. This revision adds
ContentUnderstandingFuzzingSuiteinstead of exempting the new class.Azure CI status
Build 234646332
tested PR merge
3dda7c401f3d9ca4f5e104abadd2f55ee193921e, whose parents arebase
8c7143875c843c649a817cf3e8ba9c7bee23689cand this headf3a7963c217677e9b6564cc6736495e0f1bcdce4.All four previously failing framework assertions passed in test run
1096850611. Azure also passed all 54 Content Understanding Scala tests, thefour Python integration tests, and the generated Python constructor test.
The five credential-gated live cases skipped in Azure and ran successfully
in the separate Fabric execution below.
Two of the 64 jobs initially failed outside Content Understanding:
UnitTests image*.azureedge.netinstead ofmsdata.visualstudio.com; no image tests started. Logs 915:39,69 and 918:15.PythonTests deep-learning-hfA single failed-jobs-only retry was requested on the same build at
2026-09-05 11:52 UTC and completed successfully at 12:21 UTC. The other 62 jobs
retained their passing first attempts. Image tests ran with six passes and two
pre-existing ignored cases; all four HF tests passed. Both jobs successfully
published their test results and coverage. All 64 jobs and all 65 Azure check
entries are now successful on the unchanged final source.
No source, pipeline, credentials, or TLS-validation settings were changed to
recover those infrastructure failures.
The line-by-line audit covered the REST protocol, authentication, persistence,
schema, generated Python, tests, and examples. All three review threads are
resolved. The final-head automated review has no active findings; the suppressed
suggestion about duplicating Spark read validation was
investigated and documented.
Maintainer review is still required; this PR has not been merged.
Exact-artifact Fabric evidence
The run used
fabric-spark-cliand generated Python from this PR, not theruntime-bundled SynapseML package. Runtime class-source checks verified the
loaded core and cognitive jar hashes.
application_1788607300979_00013.5.5.5.4.20260807.1f3a7963c217677e9b6564cc6736495e0f1bcdce4ae46e713ae2335f676ad2a1c475428209811e1d485c6b8a2170f5f6a053a66334af886a2cfaf26e64f04bafd4edcc9bbe2b0814d88f30c6270b5c6371aeee65a71afe0c016ca446c2511d7c23a1375befbb2efabc1d1d66519d060f84a7d2947The five dedicated cases exercised GA PDF ranges, GA DOCX text/table extraction,
preview DOCX metadata, mixed DOCX/PDF table recovery, and submit-only path
resumption. The mixed case committed the DOCX result before a later PDF result
exceeded a deliberate response cap, then resumed the same operation handles.
The table retained exactly four journal rows. Both live writer cases also used
input columns whose names matched the stage's output/error settings.
The 320-page synthetic PDF scenario independently preserved an earlier result
after a later response exceeded its cap, resumed original pages 319-320 without
replacing either handle, and retained four Delta journal rows. Repeating a
completed path write retained two rows. Preview PDF metadata, invoice extraction
with explicit model mappings, and persistence of a definite service failure also
passed.
Content Understanding tests now have dedicated files:
ContentUnderstandingSuite.scalaContentUnderstandingWriterSuite.scalaContentUnderstandingRecoverySuite.scalaContentUnderstandingFileSystemSuite.scalaContentUnderstandingFuzzingSuite.scalatest_ContentUnderstanding.pytest_ContentUnderstandingE2E.pyThe Scala suites remain in the existing document-service CI group. The live
suite skips when explicit credentials are absent. It creates only uniquely
named scratch output destinations and never provisions service resources.
Does this PR change any dependencies?
No dependency pins, workflows, release tooling, existing public JVM signatures,
or test exemptions were changed.
Does this PR add a new feature? If so, have you added samples on website?
The Content Understanding guide
includes Python/Scala signatures, REST mappings, Fabric credential handling,
PDF/DOCX guidance, analyzer configuration, recovery examples, and limits. It is
linked in the website sidebar.
Related Issues/PRs
No separate issue was supplied.