Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,14 @@
import com.azure.ai.contentunderstanding.models.DocumentSource;
import com.azure.ai.contentunderstanding.models.AnalysisContent;
import com.azure.ai.contentunderstanding.models.ContentObjectField;
import com.azure.ai.contentunderstanding.models.UsageDetails;
import com.azure.core.credential.AzureKeyCredential;
import com.azure.core.util.polling.SyncPoller;
import com.azure.identity.DefaultAzureCredentialBuilder;

import java.util.Arrays;
import java.util.List;
import java.util.Map;

/**
* Sample demonstrating how to analyze invoices using Content Understanding service.
Expand Down Expand Up @@ -67,6 +69,43 @@ public static void main(String[] args) {
AnalysisResult result = operation.getFinalResult();
// END:ContentUnderstandingAnalyzeInvoice

// BEGIN:ContentUnderstandingAnalyzeInvoiceUsage
// Access usage details from the operation status (available after polling completes).
// Usage reports resource consumption for billing estimation:
//
// - documentPagesStandard/Basic/Minimal: Pages processed at each extraction tier.
// Standard = layout + OCR (scanned docs), Basic = OCR only, Minimal = digital formats
// (DOCX, XLSX, HTML, TXT) that need no OCR. Charged per 1,000 pages.
//
// - contextualizationTokens: Fixed-rate tokens charged by Content Understanding for
// preparing context, generating confidence scores, source grounding, and formatting
// output. Typically 1,000 tokens per page. Charged separately from LLM tokens.
//
// - tokens: Map of "{model}-input" / "{model}-output" token counts consumed by your
// Foundry model deployment (e.g. "gpt-4.1-input", "gpt-4.1-output"). These are
// billed on your Foundry deployment, not on Content Understanding.
//
// For full pricing details, see:
// https://learn.microsoft.com/azure/ai-services/content-understanding/pricing-explainer
UsageDetails usage = operation.waitForCompletion().getValue().getUsage();
if (usage != null) {
System.out.println("\nUsage Details:");
if (usage.getDocumentPagesStandard() != null) {
System.out.println(" Document pages (standard): " + usage.getDocumentPagesStandard());
}
Comment thread
chienyuanchang marked this conversation as resolved.
if (usage.getContextualizationTokens() != null) {
System.out.println(" Contextualization tokens: " + usage.getContextualizationTokens());
}
Map<String, Integer> tokens = usage.getTokens();
if (tokens != null && !tokens.isEmpty()) {
System.out.println(" Model tokens:");
for (Map.Entry<String, Integer> entry : tokens.entrySet()) {
System.out.println(" " + entry.getKey() + ": " + entry.getValue());
}
}
}
// END:ContentUnderstandingAnalyzeInvoiceUsage

System.out.println("Analysis operation completed");
System.out.println("Analysis result contains " + result.getContents().size() + " content(s)");

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,10 @@
import com.azure.ai.contentunderstanding.models.AnalysisContent;
import com.azure.ai.contentunderstanding.models.ContentObjectField;
import com.azure.ai.contentunderstanding.models.DocumentSource;
import com.azure.ai.contentunderstanding.models.UsageDetails;
import com.azure.core.util.polling.LongRunningOperationStatus;
import com.azure.core.util.polling.PollerFlux;
import org.junit.jupiter.api.Test;
import reactor.core.publisher.Mono;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
Expand All @@ -25,6 +26,7 @@

import java.util.Arrays;
import java.util.List;
import java.util.Map;

/**
* Async sample demonstrating how to analyze invoices using Content Understanding service.
Expand All @@ -51,16 +53,19 @@ public void testAnalyzeInvoiceAsync() {
PollerFlux<ContentAnalyzerAnalyzeOperationStatus, AnalysisResult> operation
= contentUnderstandingAsyncClient.beginAnalyze("prebuilt-invoice", Arrays.asList(input));

// Use reactive pattern: chain operations using flatMap
// Wait for the operation to complete and get the operation status
// In a real application, you would use subscribe() instead of block()
AnalysisResult result = operation.last().flatMap(pollResponse -> {
if (pollResponse.getStatus().isComplete()) {
return pollResponse.getFinalResult();
} else {
return Mono.error(
new RuntimeException("Polling completed unsuccessfully with status: " + pollResponse.getStatus()));
ContentAnalyzerAnalyzeOperationStatus operationStatus = operation.last().map(pollResponse -> {
if (!pollResponse.getStatus().isComplete()) {
throw new RuntimeException("Polling did not complete: " + pollResponse.getStatus());
}
if (pollResponse.getStatus() != LongRunningOperationStatus.SUCCESSFULLY_COMPLETED) {
throw new RuntimeException("Operation failed with status: " + pollResponse.getStatus());
}
return pollResponse.getValue();
}).block(); // block() is used here for testing; in production, use subscribe()
Comment thread
chienyuanchang marked this conversation as resolved.

AnalysisResult result = operationStatus.getResult();
// END:ContentUnderstandingAnalyzeInvoiceAsync

// BEGIN:Assertion_ContentUnderstandingAnalyzeInvoiceAsync
Expand All @@ -74,6 +79,36 @@ public void testAnalyzeInvoiceAsync() {
System.out.println("Analysis result contains " + result.getContents().size() + " content(s)");
// END:Assertion_ContentUnderstandingAnalyzeInvoiceAsync

// BEGIN:ContentUnderstandingAnalyzeInvoiceUsageAsync
// Get usage details from the operation status
UsageDetails usage = operationStatus.getUsage();
if (usage != null) {
System.out.println("\nUsage Details:");
if (usage.getDocumentPagesStandard() != null) {
System.out.println(" Document pages (standard): " + usage.getDocumentPagesStandard());
}
if (usage.getContextualizationTokens() != null) {
System.out.println(" Contextualization tokens: " + usage.getContextualizationTokens());
}
Map<String, Integer> tokens = usage.getTokens();
if (tokens != null && !tokens.isEmpty()) {
System.out.println(" Model tokens:");
for (Map.Entry<String, Integer> entry : tokens.entrySet()) {
System.out.println(" " + entry.getKey() + ": " + entry.getValue());
}
}
}
// END:ContentUnderstandingAnalyzeInvoiceUsageAsync

// BEGIN:Assertion_ContentUnderstandingAnalyzeInvoiceUsageAsync
assertNotNull(usage, "Usage details should not be null");
assertNotNull(usage.getDocumentPagesStandard(), "Document pages (standard) should not be null");
assertTrue(usage.getDocumentPagesStandard() > 0, "Document pages (standard) should be positive");
assertNotNull(usage.getTokens(), "Tokens should not be null");
assertTrue(!usage.getTokens().isEmpty(), "Tokens should not be empty");
System.out.println("Usage details validated successfully");
// END:Assertion_ContentUnderstandingAnalyzeInvoiceUsageAsync

// BEGIN:ContentUnderstandingExtractInvoiceFieldsAsync
// Get the document content (invoices are documents)
AnalysisContent firstContent = result.getContents().get(0);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import com.azure.ai.contentunderstanding.models.AnalysisContent;
import com.azure.ai.contentunderstanding.models.ContentObjectField;
import com.azure.ai.contentunderstanding.models.DocumentSource;
import com.azure.ai.contentunderstanding.models.UsageDetails;
import com.azure.core.util.polling.SyncPoller;
import org.junit.jupiter.api.Test;

Expand All @@ -25,6 +26,7 @@

import java.util.Arrays;
import java.util.List;
import java.util.Map;

/**
* Sample demonstrating how to analyze invoices using Content Understanding service.
Expand Down Expand Up @@ -67,6 +69,36 @@ public void testAnalyzeInvoice() {
System.out.println("Analysis result contains " + result.getContents().size() + " content(s)");
// END:Assertion_ContentUnderstandingAnalyzeInvoice

// BEGIN:ContentUnderstandingAnalyzeInvoiceUsage
// Get usage details from the operation status
UsageDetails usage = operation.waitForCompletion().getValue().getUsage();
if (usage != null) {
System.out.println("\nUsage Details:");
if (usage.getDocumentPagesStandard() != null) {
System.out.println(" Document pages (standard): " + usage.getDocumentPagesStandard());
}
if (usage.getContextualizationTokens() != null) {
System.out.println(" Contextualization tokens: " + usage.getContextualizationTokens());
}
Map<String, Integer> tokens = usage.getTokens();
if (tokens != null && !tokens.isEmpty()) {
System.out.println(" Model tokens:");
for (Map.Entry<String, Integer> entry : tokens.entrySet()) {
System.out.println(" " + entry.getKey() + ": " + entry.getValue());
}
}
}
// END:ContentUnderstandingAnalyzeInvoiceUsage

// BEGIN:Assertion_ContentUnderstandingAnalyzeInvoiceUsage
assertNotNull(usage, "Usage details should not be null");
assertNotNull(usage.getDocumentPagesStandard(), "Document pages (standard) should not be null");
assertTrue(usage.getDocumentPagesStandard() > 0, "Document pages (standard) should be positive");
assertNotNull(usage.getTokens(), "Tokens should not be null");
assertTrue(!usage.getTokens().isEmpty(), "Tokens should not be empty");
System.out.println("Usage details validated successfully");
// END:Assertion_ContentUnderstandingAnalyzeInvoiceUsage

// BEGIN:ContentUnderstandingExtractInvoiceFields
// Get the document content (invoices are documents)
AnalysisContent firstContent = result.getContents().get(0);
Expand Down