4
4
package com .azure .ai .formrecognizer .documentanalysis ;
5
5
6
6
import com .azure .ai .formrecognizer .documentanalysis .administration .models .OperationStatus ;
7
+ import com .azure .ai .formrecognizer .documentanalysis .implementation .DocumentClassifiersImpl ;
7
8
import com .azure .ai .formrecognizer .documentanalysis .implementation .DocumentModelsImpl ;
8
9
import com .azure .ai .formrecognizer .documentanalysis .implementation .FormRecognizerClientImpl ;
9
10
import com .azure .ai .formrecognizer .documentanalysis .implementation .models .AnalyzeDocumentRequest ;
10
11
import com .azure .ai .formrecognizer .documentanalysis .implementation .models .AnalyzeResultOperation ;
12
+ import com .azure .ai .formrecognizer .documentanalysis .implementation .models .ClassifyDocumentRequest ;
11
13
import com .azure .ai .formrecognizer .documentanalysis .implementation .models .StringIndexType ;
12
14
import com .azure .ai .formrecognizer .documentanalysis .implementation .util .Transforms ;
13
15
import com .azure .ai .formrecognizer .documentanalysis .models .AnalyzeDocumentOptions ;
61
63
public final class DocumentAnalysisAsyncClient {
62
64
private final ClientLogger logger = new ClientLogger (DocumentAnalysisAsyncClient .class );
63
65
private final DocumentModelsImpl documentModelsImpl ;
66
+ private final DocumentClassifiersImpl documentClassifiersImpl ;
64
67
private final DocumentAnalysisServiceVersion serviceVersion ;
65
68
66
69
/**
@@ -72,6 +75,7 @@ public final class DocumentAnalysisAsyncClient {
72
75
*/
73
76
DocumentAnalysisAsyncClient (FormRecognizerClientImpl formRecognizerClientImpl , DocumentAnalysisServiceVersion serviceVersion ) {
74
77
this .documentModelsImpl = formRecognizerClientImpl .getDocumentModels ();
78
+ this .documentClassifiersImpl = formRecognizerClientImpl .getDocumentClassifiers ();
75
79
this .serviceVersion = serviceVersion ;
76
80
}
77
81
@@ -171,7 +175,7 @@ public final class DocumentAnalysisAsyncClient {
171
175
return beginAnalyzeDocumentFromUrl (documentUrl , modelId , analyzeDocumentOptions , Context .NONE );
172
176
}
173
177
174
- PollerFlux <OperationResult , AnalyzeResult >
178
+ private PollerFlux <OperationResult , AnalyzeResult >
175
179
beginAnalyzeDocumentFromUrl (String documentUrl , String modelId ,
176
180
AnalyzeDocumentOptions analyzeDocumentOptions ,
177
181
Context context ) {
@@ -329,7 +333,7 @@ public final class DocumentAnalysisAsyncClient {
329
333
return beginAnalyzeDocument (modelId , document , analyzeDocumentOptions , Context .NONE );
330
334
}
331
335
332
- PollerFlux <OperationResult , AnalyzeResult >
336
+ private PollerFlux <OperationResult , AnalyzeResult >
333
337
beginAnalyzeDocument (String modelId , BinaryData document ,
334
338
AnalyzeDocumentOptions analyzeDocumentOptions , Context context ) {
335
339
try {
@@ -380,6 +384,183 @@ public final class DocumentAnalysisAsyncClient {
380
384
}
381
385
}
382
386
387
+ /**
388
+ * Classify a given document using a document classifier.
389
+ * For more information on how to build a custom classifier model,
390
+ * see <a href="https://aka.ms/azsdk/formrecognizer/buildclassifiermodel"></a>
391
+ * <p>The service does not support cancellation of the long running operation and returns with an
392
+ * error message indicating absence of cancellation support.</p>
393
+ *
394
+ * <p><strong>Code sample</strong></p>
395
+ * <p> Analyze a document using the URL of the document. </p>
396
+ * <!-- src_embed com.azure.ai.formrecognizer.documentanalysis.DocumentAnalysisAsyncClient.beginClassifyDocumentFromUrl#string-string -->
397
+ * <pre>
398
+ * String documentUrl = "{document_url}";
399
+ * // analyze a receipt using prebuilt model
400
+ * String classifierId = "custom-trained-classifier-id";
401
+ *
402
+ * documentAnalysisAsyncClient.beginClassifyDocumentFromUrl(classifierId, documentUrl)
403
+ * // if polling operation completed, retrieve the final result.
404
+ * .flatMap(AsyncPollResponse::getFinalResult)
405
+ * .subscribe(analyzeResult -> {
406
+ * System.out.println(analyzeResult.getModelId());
407
+ * analyzeResult.getDocuments()
408
+ * .forEach(analyzedDocument -> System.out.printf("Doc Type: %s%n", analyzedDocument.getDocType()));
409
+ * });
410
+ *
411
+ * </pre>
412
+ * <!-- end com.azure.ai.formrecognizer.documentanalysis.DocumentAnalysisAsyncClient.beginClassifyDocumentFromUrl#string-string -->
413
+ *
414
+ * @param classifierId The unique classifier ID to be used. Use this to specify the custom classifier ID.
415
+ * @param documentUrl The URL of the document to analyze.
416
+ *
417
+ * @return A {@link PollerFlux} that polls the progress of the analyze document operation until it has completed, has failed,
418
+ * or has been cancelled. The completed operation returns an {@link AnalyzeResult}.
419
+ * @throws HttpResponseException If analyze operation fails and the {@link AnalyzeResultOperation} returns
420
+ * with an {@link OperationStatus#FAILED}..
421
+ * @throws IllegalArgumentException If {@code documentUrl} or {@code classifierId} is null.
422
+ */
423
+ @ ServiceMethod (returns = ReturnType .LONG_RUNNING_OPERATION )
424
+ public PollerFlux <OperationResult , AnalyzeResult >
425
+ beginClassifyDocumentFromUrl (String classifierId , String documentUrl ) {
426
+ return beginClassifyDocumentFromUrl (classifierId , documentUrl , Context .NONE );
427
+ }
428
+
429
+ private PollerFlux <OperationResult , AnalyzeResult >
430
+ beginClassifyDocumentFromUrl (String documentUrl , String classifierId ,
431
+ Context context ) {
432
+ try {
433
+ if (CoreUtils .isNullOrEmpty (documentUrl )) {
434
+ throw logger .logExceptionAsError (new IllegalArgumentException ("'documentUrl' is required and cannot"
435
+ + " be null or empty" ));
436
+ }
437
+ if (CoreUtils .isNullOrEmpty (classifierId )) {
438
+ throw logger .logExceptionAsError (new IllegalArgumentException ("'classifierId' is required and cannot"
439
+ + " be null or empty" ));
440
+ }
441
+
442
+ return new PollerFlux <>(
443
+ DEFAULT_POLL_INTERVAL ,
444
+ activationOperation (() ->
445
+ documentClassifiersImpl .classifyDocumentWithResponseAsync (classifierId ,
446
+ StringIndexType .UTF16CODE_UNIT ,
447
+ new ClassifyDocumentRequest ().setUrlSource (documentUrl ),
448
+ context )
449
+ .map (analyzeDocumentResponse ->
450
+ Transforms .toDocumentOperationResult (
451
+ analyzeDocumentResponse .getDeserializedHeaders ().getOperationLocation ())),
452
+ logger ),
453
+ pollingOperation (resultId ->
454
+ documentClassifiersImpl .getClassifyResultWithResponseAsync (classifierId , resultId , context )),
455
+ (activationResponse , pollingContext ) ->
456
+ Mono .error (new RuntimeException ("Cancellation is not supported" )),
457
+ fetchingOperation (resultId ->
458
+ documentClassifiersImpl .getClassifyResultWithResponseAsync (
459
+ classifierId ,
460
+ resultId ,
461
+ context ))
462
+ .andThen (after -> after
463
+ .map (modelSimpleResponse ->
464
+ Transforms .toAnalyzeResultOperation (modelSimpleResponse .getValue ().getAnalyzeResult ()))
465
+ .onErrorMap (Transforms ::mapToHttpResponseExceptionIfExists )));
466
+ } catch (RuntimeException ex ) {
467
+ return PollerFlux .error (ex );
468
+ }
469
+ }
470
+
471
+ /**
472
+ * Classify a given document using a document classifier.
473
+ * For more information on how to build a custom classifier model,
474
+ * see <a href="https://aka.ms/azsdk/formrecognizer/buildclassifiermodel"></a>
475
+ * <p>The service does not support cancellation of the long running operation and returns with an
476
+ * error message indicating absence of cancellation support.</p>
477
+ * <p>
478
+ * Note that the {@code data} passed must be replayable if retries are enabled (the default). In other words, the
479
+ * {@code Flux} must produce the same data each time it is subscribed to.
480
+ *
481
+ * <p><strong>Code sample</strong></p>
482
+ * <p> Analyze a document with configurable options.</p>
483
+ * <!-- src_embed com.azure.ai.formrecognizer.documentanalysis.DocumentAnalysisAsyncClient.beginAnalyzeDocument#string-BinaryData -->
484
+ * <pre>
485
+ * File document = new File("{local/file_path/fileName.jpg}");
486
+ * String modelId = "{model_id}";
487
+ * // Utility method to convert input stream to Binary Data
488
+ * BinaryData buffer = BinaryData.fromStream(new ByteArrayInputStream(Files.readAllBytes(document.toPath())));
489
+ *
490
+ * documentAnalysisAsyncClient.beginAnalyzeDocument(modelId, buffer)
491
+ * // if polling operation completed, retrieve the final result.
492
+ * .flatMap(AsyncPollResponse::getFinalResult)
493
+ * .subscribe(analyzeResult ->
494
+ * analyzeResult.getDocuments()
495
+ * .stream()
496
+ * .forEach(analyzedDocument ->
497
+ * analyzedDocument.getFields()
498
+ * .forEach((key, documentField) -> {
499
+ * System.out.printf("Field text: %s%n", key);
500
+ * System.out.printf("Field value data content: %s%n", documentField.getContent());
501
+ * System.out.printf("Confidence score: %.2f%n", documentField.getConfidence());
502
+ * })));
503
+ * </pre>
504
+ * <!-- end com.azure.ai.formrecognizer.documentanalysis.DocumentAnalysisAsyncClient.beginClassifyDocument#string-BinaryData -->
505
+ *
506
+ * @param classifierId The unique classifier ID to be used. Use this to specify the custom classifier ID.
507
+ * @param document The data of the document to analyze information from. For service supported file types, see:
508
+ * <a href="https://aka.ms/azsdk/formrecognizer/supportedfiles"></a>
509
+ * @return A {@link PollerFlux} that polls the progress of the analyze document operation until it has completed,
510
+ * has failed, or has been cancelled. The completed operation returns an {@link AnalyzeResult}.
511
+ * @throws HttpResponseException If analyze operation fails and returns with an {@link OperationStatus#FAILED}.
512
+ * @throws IllegalArgumentException If {@code document} or {@code classifierId} is null.
513
+ * @throws IllegalArgumentException If {@code document} length is null or unspecified.
514
+ * Use {@link BinaryData#fromStream(InputStream, Long)} to create an instance of the {@code document}
515
+ * from given {@link InputStream} with length.
516
+ */
517
+ @ ServiceMethod (returns = ReturnType .LONG_RUNNING_OPERATION )
518
+ public PollerFlux <OperationResult , AnalyzeResult >
519
+ beginClassifyDocument (String classifierId , BinaryData document ) {
520
+ return beginClassifyDocument (classifierId , document , Context .NONE );
521
+ }
522
+
523
+ private PollerFlux <OperationResult , AnalyzeResult >
524
+ beginClassifyDocument (String classifierId , BinaryData document , Context context ) {
525
+ try {
526
+ Objects .requireNonNull (document , "'document' is required and cannot be null." );
527
+ if (CoreUtils .isNullOrEmpty (classifierId )) {
528
+ throw logger .logExceptionAsError (new IllegalArgumentException ("'classifierId' is required and cannot"
529
+ + " be null or empty" ));
530
+ }
531
+
532
+ if (document .getLength () == null ) {
533
+ throw logger .logExceptionAsError (new IllegalArgumentException ("'document length' is required and cannot"
534
+ + " be null" ));
535
+ }
536
+
537
+ return new PollerFlux <>(
538
+ DEFAULT_POLL_INTERVAL ,
539
+ activationOperation (() ->
540
+ documentClassifiersImpl .classifyDocumentWithResponseAsync (classifierId ,
541
+ null ,
542
+ StringIndexType .UTF16CODE_UNIT ,
543
+ document ,
544
+ document .getLength (),
545
+ context )
546
+ .map (analyzeDocumentResponse -> Transforms .toDocumentOperationResult (
547
+ analyzeDocumentResponse .getDeserializedHeaders ().getOperationLocation ())),
548
+ logger ),
549
+ pollingOperation (
550
+ resultId -> documentClassifiersImpl .getClassifyResultWithResponseAsync (
551
+ classifierId , resultId , context )),
552
+ (activationResponse , pollingContext ) ->
553
+ Mono .error (new RuntimeException ("Cancellation is not supported" )),
554
+ fetchingOperation (resultId -> documentClassifiersImpl .getClassifyResultWithResponseAsync (
555
+ classifierId , resultId , context ))
556
+ .andThen (after -> after .map (modelSimpleResponse ->
557
+ Transforms .toAnalyzeResultOperation (modelSimpleResponse .getValue ().getAnalyzeResult ()))
558
+ .onErrorMap (Transforms ::mapToHttpResponseExceptionIfExists )));
559
+ } catch (RuntimeException ex ) {
560
+ return PollerFlux .error (ex );
561
+ }
562
+ }
563
+
383
564
/*
384
565
* Poller's POLLING operation.
385
566
*/
0 commit comments