-
Notifications
You must be signed in to change notification settings - Fork 4.5k
/
RecognizeCustomEntitiesOperation.cs
298 lines (256 loc) · 15.9 KB
/
RecognizeCustomEntitiesOperation.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Azure.AI.TextAnalytics.Models;
using Azure.AI.TextAnalytics.ServiceClients;
using Azure.Core;
using Azure.Core.Pipeline;
namespace Azure.AI.TextAnalytics
{
/// <summary> Pageable operation class for recognizing custom entites from multiple documents using long running operation. </summary>
public class RecognizeCustomEntitiesOperation : PageableOperation<RecognizeCustomEntitiesResultCollection>, IOperation<AsyncPageable<RecognizeCustomEntitiesResultCollection>>
{
internal readonly IDictionary<string, int> _idToIndexMap;
private readonly bool? _showStats;
private readonly string _jobId;
private readonly ServiceClient _serviceClient;
private readonly ClientDiagnostics _diagnostics;
private readonly OperationInternal<AsyncPageable<RecognizeCustomEntitiesResultCollection>> _operationInternal;
private TextAnalyticsOperationStatus _status;
private DateTimeOffset? _expiresOn;
private DateTimeOffset _lastModified;
private DateTimeOffset _createdOn;
private string _displayName;
private Page<RecognizeCustomEntitiesResultCollection> _firstPage;
/// <summary>
/// Gets an ID representing the operation that can be used to poll for the status
/// of the long-running operation.
/// </summary>
public override string Id { get; }
/// <summary>
/// Display Name of the operation.
/// </summary>
public virtual string DisplayName => _displayName;
/// <summary>
/// Time when the operation was created on.
/// </summary>
public virtual DateTimeOffset CreatedOn => _createdOn;
/// <summary>
/// Time when the operation will expire.
/// </summary>
public virtual DateTimeOffset? ExpiresOn => _expiresOn;
/// <summary>
/// Time when the operation was last modified on
/// </summary>
public virtual DateTimeOffset LastModified => _lastModified;
/// <summary>
/// Gets the status of the operation.
/// </summary>
public virtual TextAnalyticsOperationStatus Status => _status;
/// <summary>
/// Gets the final result of the long-running operation asynchronously.
/// </summary>
/// <remarks>
/// This property can be accessed only after the operation completes successfully (HasValue is true).
/// </remarks>
[EditorBrowsable(EditorBrowsableState.Never)]
public override AsyncPageable<RecognizeCustomEntitiesResultCollection> Value => _operationInternal.Value;
/// <summary>
/// Returns true if the long-running operation completed.
/// </summary>
public override bool HasCompleted => _operationInternal.HasCompleted;
/// <summary>
/// Returns true if the long-running operation completed successfully and has produced final result (accessible by Value property).
/// </summary>
public override bool HasValue => _operationInternal.HasValue;
/// <summary>
/// Initializes a new instance of the <see cref="RecognizeCustomEntitiesOperation"/> class.
/// </summary>
/// <param name="operationId">The ID of this operation.</param>
/// <param name="client">The client used to check for completion.</param>
/// <exception cref="ArgumentException"><paramref name="operationId"/> is an empty string or does not represent a valid continuation token from the <see cref="Id"/> property returned on the original operation.</exception>
/// <exception cref="ArgumentNullException"><paramref name="operationId"/> or <paramref name="client"/> is null.</exception>
public RecognizeCustomEntitiesOperation(string operationId, TextAnalyticsClient client)
{
Argument.AssertNotNullOrEmpty(operationId, nameof(operationId));
Argument.AssertNotNull(client, nameof(client));
try
{
OperationContinuationToken token = OperationContinuationToken.Deserialize(operationId);
_jobId = token.JobId;
_showStats = token.ShowStats;
_idToIndexMap = token.InputDocumentOrder;
}
catch (Exception e)
{
throw new ArgumentException($"Invalid value. Please use the {nameof(RecognizeCustomEntitiesOperation)}.{nameof(Id)} property value.", nameof(operationId), e);
}
Id = operationId;
_serviceClient = client.ServiceClient;
_diagnostics = _serviceClient.Diagnostics;
_operationInternal = new(this, _diagnostics, rawResponse: null);
}
/// <summary>
/// Initializes a new instance of the <see cref="RecognizeCustomEntitiesOperation"/> class.
/// </summary>
/// <param name="serviceClient">The client for communicating with the Text Analytics Azure Cognitive Service through its REST API.</param>
/// <param name="diagnostics">The client diagnostics for exception creation in case of failure.</param>
/// <param name="operationLocation">The address of the long-running operation. It can be obtained from the response headers upon starting the operation.</param>
/// <param name="idToIndexMap"></param>
/// <param name="showStats"></param>
internal RecognizeCustomEntitiesOperation(ServiceClient serviceClient, ClientDiagnostics diagnostics, string operationLocation, IDictionary<string, int> idToIndexMap, bool? showStats = default)
{
_serviceClient = serviceClient;
_diagnostics = diagnostics;
_idToIndexMap = idToIndexMap;
_showStats = showStats;
_operationInternal = new(this, _diagnostics, rawResponse: null);
_jobId = operationLocation.Split('/').Last().Split('?')[0];
Id = OperationContinuationToken.Serialize(_jobId, idToIndexMap, showStats);
}
/// <summary>
/// Initializes a new instance of the <see cref="RecognizeCustomEntitiesOperation"/> class. This constructor
/// is intended to be used for mocking only.
/// </summary>
protected RecognizeCustomEntitiesOperation()
{
}
/// <summary>
/// The last HTTP response received from the server.
/// </summary>
/// <remarks>
/// The last response returned from the server during the lifecycle of this instance.
/// An instance of <see cref="RecognizeCustomEntitiesOperation"/> sends requests to a server in UpdateStatusAsync, UpdateStatus, and other methods.
/// Responses from these requests can be accessed using GetRawResponse.
/// </remarks>
public override Response GetRawResponse() => _operationInternal.RawResponse;
/// <summary>
/// Calls the server to get updated status of the long-running operation.
/// </summary>
/// <param name="cancellationToken">A <see cref="CancellationToken"/> used for the service call.</param>
/// <returns>The HTTP response received from the server.</returns>
/// <remarks>
/// This operation will update the value returned from GetRawResponse and might update HasCompleted, HasValue, and Value.
/// </remarks>
public override Response UpdateStatus(CancellationToken cancellationToken = default) =>
_operationInternal.UpdateStatus(cancellationToken);
/// <summary>
/// Calls the server to get updated status of the long-running operation.
/// </summary>
/// <param name="cancellationToken">A <see cref="CancellationToken"/> used for the service call.</param>
/// <returns>The HTTP response received from the server.</returns>
/// <remarks>
/// This operation will update the value returned from GetRawResponse and might update HasCompleted, HasValue, and Value.
/// </remarks>
public override async ValueTask<Response> UpdateStatusAsync(CancellationToken cancellationToken = default) =>
await _operationInternal.UpdateStatusAsync(cancellationToken).ConfigureAwait(false);
/// <summary>
/// Periodically calls the server till the long-running operation completes.
/// </summary>
/// <param name="cancellationToken">A <see cref="CancellationToken"/> used for the periodical service calls.</param>
/// <returns>The last HTTP response received from the server.</returns>
/// <remarks>
/// This method will periodically call UpdateStatusAsync till HasCompleted is true, then return the final result of the operation.
/// </remarks>
public override async ValueTask<Response<AsyncPageable<RecognizeCustomEntitiesResultCollection>>> WaitForCompletionAsync(CancellationToken cancellationToken = default) =>
await _operationInternal.WaitForCompletionAsync(cancellationToken).ConfigureAwait(false);
/// <summary>
/// Periodically calls the server till the long-running operation completes.
/// </summary>
/// <param name="pollingInterval">
/// The interval between status requests to the server.
/// The interval can change based on information returned from the server.
/// For example, the server might communicate to the client that there is not reason to poll for status change sooner than some time.
/// </param>
/// <param name="cancellationToken">A <see cref="CancellationToken"/> used for the periodical service calls.</param>
/// <returns>The last HTTP response received from the server.</returns>
/// <remarks>
/// This method will periodically call UpdateStatusAsync till HasCompleted is true, then return the final result of the operation.
/// </remarks>
public override async ValueTask<Response<AsyncPageable<RecognizeCustomEntitiesResultCollection>>> WaitForCompletionAsync(TimeSpan pollingInterval, CancellationToken cancellationToken = default) =>
await _operationInternal.WaitForCompletionAsync(pollingInterval, cancellationToken).ConfigureAwait(false);
/// <summary>
/// Cancels a pending or running <see cref="RecognizeCustomEntitiesOperation"/>.
/// </summary>
/// <param name="cancellationToken">A <see cref="CancellationToken"/> controlling the request lifetime.</param>
public virtual void Cancel(CancellationToken cancellationToken = default) =>
_serviceClient.CancelAnalyzeActionsJob(_jobId, cancellationToken);
/// <summary>
/// Cancels a pending or running <see cref="RecognizeCustomEntitiesOperation"/>.
/// </summary>
/// <param name="cancellationToken">A <see cref="CancellationToken"/> controlling the request lifetime.</param>
/// <returns>A <see cref="Task"/> to track the service request.</returns>
public virtual async Task CancelAsync(CancellationToken cancellationToken = default) =>
await _serviceClient.CancelAnalyzeActionsJobAsync(_jobId, cancellationToken).ConfigureAwait(false);
/// <summary>
/// Gets the final result of the long-running operation asynchronously.
/// </summary>
/// <remarks>
/// Operation must complete successfully (HasValue is true) for it to provide values.
/// </remarks>
public override AsyncPageable<RecognizeCustomEntitiesResultCollection> GetValuesAsync(CancellationToken cancellationToken = default)
{
// Validates that the operation has completed successfully.
_ = _operationInternal.Value;
return CreateOperationValueAsync(cancellationToken);
}
/// <summary>
/// Gets the final result of the long-running operation in synchronously.
/// </summary>
/// <remarks>
/// Operation must complete successfully (HasValue is true) for it to provide values.
/// </remarks>
public override Pageable<RecognizeCustomEntitiesResultCollection> GetValues(CancellationToken cancellationToken = default)
{
// Validates that the operation has completed successfully.
_ = _operationInternal.Value;
Page<RecognizeCustomEntitiesResultCollection> NextPageFunc(string nextLink, int? pageSizeHint)
{
var response = _serviceClient.AnalyzeTextJobStatusNextPage(nextLink, pageSizeHint, _idToIndexMap, cancellationToken);
return Page.FromValues(new List<RecognizeCustomEntitiesResultCollection>() { Transforms.ConvertToRecognizeCustomEntitiesResultCollection(response.Value, _idToIndexMap) }, response.Value.NextLink, response.GetRawResponse());
}
return PageableHelpers.CreateEnumerable(_ => _firstPage, NextPageFunc);
}
private AsyncPageable<RecognizeCustomEntitiesResultCollection> CreateOperationValueAsync(CancellationToken cancellationToken = default)
{
async Task<Page<RecognizeCustomEntitiesResultCollection>> NextPageFunc(string nextLink, int? pageSizeHint)
{
var response = await _serviceClient.AnalyzeTextJobStatusNextPageAsync(nextLink, pageSizeHint, _idToIndexMap, cancellationToken).ConfigureAwait(false);
return Page.FromValues(new List<RecognizeCustomEntitiesResultCollection>() { Transforms.ConvertToRecognizeCustomEntitiesResultCollection(response.Value, _idToIndexMap) }, response.Value.NextLink, response.GetRawResponse());
}
return PageableHelpers.CreateAsyncEnumerable(_ => Task.FromResult(_firstPage), NextPageFunc);
}
async ValueTask<OperationState<AsyncPageable<RecognizeCustomEntitiesResultCollection>>> IOperation<AsyncPageable<RecognizeCustomEntitiesResultCollection>>.UpdateStateAsync(bool async, CancellationToken cancellationToken)
{
Response<AnalyzeTextJobState> response = async
? await _serviceClient.AnalyzeTextJobStatusAsync(_jobId, _showStats, null, null, _idToIndexMap, cancellationToken).ConfigureAwait(false)
: _serviceClient.AnalyzeTextJobStatus(_jobId, _showStats, null, null, _idToIndexMap, cancellationToken);
_displayName = response.Value.DisplayName;
_createdOn = response.Value.CreatedDateTime;
_expiresOn = response.Value.ExpirationDateTime;
_lastModified = response.Value.LastUpdatedDateTime;
_status = response.Value.Status;
Response rawResponse = response.GetRawResponse();
if (response.Value.Status == TextAnalyticsOperationStatus.Succeeded)
{
string nextLink = response.Value.NextLink;
_firstPage = Page.FromValues(new List<RecognizeCustomEntitiesResultCollection>() { Transforms.ConvertToRecognizeCustomEntitiesResultCollection(response.Value, _idToIndexMap) }, nextLink, rawResponse);
return OperationState<AsyncPageable<RecognizeCustomEntitiesResultCollection>>.Success(rawResponse, CreateOperationValueAsync(CancellationToken.None));
}
if (response.Value.Status == TextAnalyticsOperationStatus.Running || response.Value.Status == TextAnalyticsOperationStatus.NotStarted || response.Value.Status == TextAnalyticsOperationStatus.Cancelling)
{
return OperationState<AsyncPageable<RecognizeCustomEntitiesResultCollection>>.Pending(rawResponse);
}
if (response.Value.Status == TextAnalyticsOperationStatus.Cancelled)
{
return OperationState<AsyncPageable<RecognizeCustomEntitiesResultCollection>>.Failure(rawResponse, new RequestFailedException("The operation was canceled so no value is available."));
}
return OperationState<AsyncPageable<RecognizeCustomEntitiesResultCollection>>.Failure(rawResponse, new RequestFailedException(rawResponse));
}
}
}