Skip to content

Commit 1702c62

Browse files
committed
✨ improved v2 error messages and exceptions
1 parent 9df30e4 commit 1702c62

File tree

61 files changed

+416
-266
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

61 files changed

+416
-266
lines changed

src/Mindee/Parsing/V2/ErrorItem.cs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
using System.Text.Json.Serialization;
2+
3+
namespace Mindee.Parsing.V2
4+
{
5+
/// <summary>
6+
/// Explicit details on a problem.
7+
/// </summary>
8+
public class ErrorItem
9+
{
10+
/// <summary>
11+
/// A JSON Pointer to the location of the body property.
12+
/// </summary>
13+
[JsonPropertyName("pointer")]
14+
public string Pointer { get; set; }
15+
16+
/// <summary>
17+
/// Explicit information on the issue.
18+
/// </summary>
19+
[JsonPropertyName("detail")]
20+
public string Detail { get; set; }
21+
}
22+
}

src/Mindee/Parsing/V2/ErrorResponse.cs

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,42 @@
1+
using System.Collections.Generic;
12
using System.Text.Json.Serialization;
23

34
namespace Mindee.Parsing.V2
45
{
56
/// <summary>
6-
/// Represent an error information from the API response.
7+
/// Error response detailing a problem. The format adheres to RFC 9457.
78
/// </summary>
89
public class ErrorResponse
910
{
1011
/// <summary>
11-
/// Detail relevant to the error.
12+
/// The HTTP status code returned by the server.
13+
/// </summary>
14+
[JsonPropertyName("status")]
15+
public int Status { get; set; }
16+
17+
/// <summary>
18+
/// A human-readable explanation specific to the occurrence of the problem.
1219
/// </summary>
1320
[JsonPropertyName("detail")]
1421
public string Detail { get; set; }
1522

1623
/// <summary>
17-
/// Http error code.
24+
/// A short, human-readable summary of the problem.
1825
/// </summary>
19-
[JsonPropertyName("status")]
20-
public int Status { get; set; }
26+
[JsonPropertyName("title")]
27+
public string Title { get; set; }
28+
29+
/// <summary>
30+
/// A machine-readable code specific to the occurrence of the problem.
31+
/// </summary>
32+
[JsonPropertyName("code")]
33+
public string Code { get; set; }
34+
35+
/// <summary>
36+
/// A list of explicit details on the problem.
37+
/// </summary>
38+
[JsonPropertyName("errors")]
39+
public List<ErrorItem> Errors { get; set; }
2140

2241
/// <summary>
2342
/// To make the error prettier to display.

src/Mindee/Parsing/V2/InferenceResult.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ public class InferenceResult
2525
/// RAG metadata.
2626
/// </summary>
2727
[JsonPropertyName("rag")]
28-
public RawText Rag { get; set; }
28+
public RagMetadata Rag { get; set; }
2929

3030
/// <summary>
3131
/// A prettier representation of the feature values.

src/Mindee/Parsing/V2/Job.cs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,19 @@
55
namespace Mindee.Parsing.V2
66
{
77
/// <summary>
8-
/// Defines an enqueued job.
8+
/// Information on the processing of a file sent to the Mindee API.
99
/// </summary>
1010
public class Job
1111
{
1212
/// <summary>
13-
/// Date and time the job was created at.
13+
/// Date and time of the Job creation.
1414
/// </summary>
1515
[JsonPropertyName("created_at")]
1616
[JsonConverter(typeof(DateTimeJsonConverter))]
1717
public DateTime CreatedAt { get; set; }
1818

1919
/// <summary>
20-
/// Unique identifier of the job.
20+
/// UUID of the Job.
2121
/// </summary>
2222
[JsonPropertyName("id")]
2323
public string Id { get; set; }
@@ -29,43 +29,43 @@ public class Job
2929
public string Status { get; set; }
3030

3131
/// <summary>
32-
/// An error encountered while processing the job.
32+
/// If an error occurred during processing, contains the problem details.
3333
/// </summary>
3434
[JsonPropertyName("error")]
3535
public ErrorResponse Error { get; set; }
3636

3737
/// <summary>
38-
/// ID of the model.
38+
/// UUID of the model to be used for the inference.
3939
/// </summary>
4040
[JsonPropertyName("model_id")]
4141
public string ModelId { get; set; }
4242

4343
/// <summary>
44-
/// Name of the file.
44+
/// Name of the file sent.
4545
/// </summary>
4646
[JsonPropertyName("file_name")]
4747
public string FileName { get; set; }
4848

4949
/// <summary>
50-
/// Optional Alias for the file.
50+
/// Optional alias sent for the file.
5151
/// </summary>
5252
[JsonPropertyName("file_alias")]
5353
public string FileAlias { get; set; }
5454

5555
/// <summary>
56-
/// URL to use for polling.
56+
/// URL to poll for the Job status.
5757
/// </summary>
5858
[JsonPropertyName("polling_url")]
5959
public string PollingUrl { get; set; }
6060

6161
/// <summary>
62-
/// URL to follow for the final result.
62+
/// URL to retrieve the inference results. Will be filled once the inference is ready.
6363
/// </summary>
6464
[JsonPropertyName("result_url")]
6565
public string ResultUrl { get; set; }
6666

6767
/// <summary>
68-
/// Webhooks to call.
68+
/// List of responses from webhooks called. Empty until processing is finished.
6969
/// </summary>
7070
[JsonPropertyName("webhooks")]
7171
public List<JobWebhook> Webhooks { get; set; }

tests/Mindee.IntegrationTests/DependencyInjectionTest.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -50,32 +50,32 @@ public void ShouldInitBothClients()
5050
public async Task ShouldMaintainAuthenticationAcrossMultipleRequests()
5151
{
5252
MindeeClient instance1ClientV1 = _services.GetRequiredService<MindeeClient>();
53-
var inputSource1 = new LocalInputSource(new FileInfo("Resources/file_types/pdf/blank_1.pdf"));
53+
var inputSource1 = new LocalInputSource(new FileInfo(Constants.RootDir + "file_types/pdf/blank_1.pdf"));
5454
var response1 = await instance1ClientV1.ParseAsync<InvoiceV4>(inputSource1);
5555
Assert.NotNull(response1);
5656
Assert.True(response1.Document != null, "First V1 request should return a valid document");
5757

5858
MindeeClient instance2ClientV1 = _services.GetRequiredService<MindeeClient>();
59-
var inputSource2 = new LocalInputSource(new FileInfo("Resources/file_types/pdf/blank_1.pdf"));
59+
var inputSource2 = new LocalInputSource(new FileInfo(Constants.RootDir + "file_types/pdf/blank_1.pdf"));
6060
var response2 = await instance2ClientV1.ParseAsync<InvoiceV4>(inputSource2);
6161
Assert.NotNull(response2);
6262
Assert.True(response2.Document != null, "Second V1 request should return a valid document");
6363

6464
MindeeClientV2 instance1ClientV2 = _services.GetRequiredService<MindeeClientV2>();
65-
var inputSource3 = new LocalInputSource(new FileInfo("Resources/file_types/pdf/blank_1.pdf"));
65+
var inputSource3 = new LocalInputSource(new FileInfo(Constants.RootDir + "file_types/pdf/blank_1.pdf"));
6666
var response3 = await instance1ClientV2.EnqueueInferenceAsync(
6767
inputSource3,
6868
new InferenceParameters(modelId: Environment.GetEnvironmentVariable("MindeeV2__Findoc__Model__Id")));
6969
Assert.NotNull(response3);
7070
Assert.True(response3.Job != null, "First V2 request should return a valid job");
7171

72-
var inputSource4 = new LocalInputSource(new FileInfo("Resources/file_types/pdf/blank_1.pdf"));
72+
var inputSource4 = new LocalInputSource(new FileInfo(Constants.RootDir + "file_types/pdf/blank_1.pdf"));
7373
var response4 = await instance1ClientV1.ParseAsync<InvoiceV4>(inputSource4);
7474
Assert.NotNull(response4);
7575
Assert.True(response4.Document != null, "Third V3 request should return a valid document");
7676

7777
MindeeClientV2 instance2ClientV2 = _services.GetRequiredService<MindeeClientV2>();
78-
var inputSource5 = new LocalInputSource(new FileInfo("Resources/file_types/pdf/blank_1.pdf"));
78+
var inputSource5 = new LocalInputSource(new FileInfo(Constants.RootDir + "file_types/pdf/blank_1.pdf"));
7979
var response5 = await instance2ClientV2.EnqueueInferenceAsync(
8080
inputSource5,
8181
new InferenceParameters(modelId: Environment.GetEnvironmentVariable("MindeeV2__Findoc__Model__Id")));

tests/Mindee.IntegrationTests/V1/Extraction/InvoiceSplitterAutoExtractionTest.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ public async Task GivenAPdf_ShouldExtractInvoicesStrict_MustSucceed()
2626
{
2727
var apiKey = Environment.GetEnvironmentVariable("Mindee__ApiKey");
2828
var client = TestingUtilities.GetOrGenerateMindeeClient(apiKey);
29-
var invoiceSplitterBytes = File.ReadAllBytes("Resources/v1/products/invoice_splitter/default_sample.pdf");
29+
var invoiceSplitterBytes = File.ReadAllBytes(Constants.V1ProductDir + "invoice_splitter/default_sample.pdf");
3030
var invoiceSplitterInputSource = new LocalInputSource(invoiceSplitterBytes, "default_sample.pdf");
3131
var response = await client.EnqueueAndParseAsync<InvoiceSplitterV1>(invoiceSplitterInputSource);
3232
InvoiceSplitterV1 inference = response.Document.Inference;
@@ -43,7 +43,7 @@ public async Task GivenAPdf_ShouldExtractInvoicesStrict_MustSucceed()
4343
await client.ParseAsync<InvoiceV4>(extractedPdfsStrict[0].AsInputSource());
4444

4545
string testStringRstInvoice0 = PrepareInvoiceReturn(
46-
"Resources/v1/products/invoices/response_v4/summary_full_invoice_p1.rst", invoice0.Document);
46+
Constants.V1ProductDir + "invoices/response_v4/summary_full_invoice_p1.rst", invoice0.Document);
4747

4848
double ratio = TestingUtilities.LevenshteinRatio(testStringRstInvoice0, invoice0.Document.ToString());
4949
Assert.True(ratio >= 0.90);

tests/Mindee.IntegrationTests/V1/MindeeClientTest.cs

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ public MindeeClientTest()
2525
[Fact]
2626
public async Task Parse_File_Standard_MultiplePages_MustSucceed()
2727
{
28-
var inputSource = new LocalInputSource("Resources/file_types/pdf/multipage_cut-2.pdf");
28+
var inputSource = new LocalInputSource(Constants.RootDir + "file_types/pdf/multipage_cut-2.pdf");
2929
var response = await _mindeeClient.ParseAsync<InvoiceV4>(inputSource);
3030
Assert.NotNull(response);
3131
Assert.Equal("success", response.ApiRequest.Status);
@@ -40,7 +40,7 @@ public async Task Parse_File_Standard_MultiplePages_MustSucceed()
4040
[Fact]
4141
public async Task Parse_File_Standard_SinglePage_MustSucceed()
4242
{
43-
var inputSource = new LocalInputSource("Resources/file_types/receipt.jpg");
43+
var inputSource = new LocalInputSource(Constants.RootDir + "file_types/receipt.jpg");
4444
var response = await _mindeeClient.ParseAsync<ReceiptV5>(inputSource);
4545
Assert.NotNull(response);
4646
Assert.Equal("success", response.ApiRequest.Status);
@@ -80,7 +80,7 @@ await Assert.ThrowsAsync<Mindee400Exception>(
8080
[Fact]
8181
public async Task Parse_File_Cropper_MustSucceed()
8282
{
83-
var inputSource = new LocalInputSource("Resources/file_types/receipt.jpg");
83+
var inputSource = new LocalInputSource(Constants.RootDir + "file_types/receipt.jpg");
8484
var predictOptions = new PredictOptions(cropper: true);
8585
var response = await _mindeeClient.ParseAsync<ReceiptV5>(inputSource, predictOptions);
8686
Assert.NotNull(response);
@@ -97,7 +97,7 @@ public async Task Parse_File_Cropper_MustSucceed()
9797
[Fact]
9898
public async Task Parse_File_Standard_AllWords_MustSucceed()
9999
{
100-
var inputSource = new LocalInputSource("Resources/file_types/receipt.jpg");
100+
var inputSource = new LocalInputSource(Constants.RootDir + "file_types/receipt.jpg");
101101
var predictOptions = new PredictOptions(allWords: true);
102102
var response = await _mindeeClient.ParseAsync<InvoiceV4>(inputSource, predictOptions);
103103
Assert.NotNull(response);
@@ -115,7 +115,7 @@ public async Task Parse_File_Standard_AllWords_MustSucceed()
115115
[Fact]
116116
public async Task Parse_File_Standard_FullText_MustSucceed()
117117
{
118-
var inputSource = new LocalInputSource("Resources/v1/products/international_id/default_sample.jpg");
118+
var inputSource = new LocalInputSource(Constants.V1ProductDir + "international_id/default_sample.jpg");
119119
var predictOptions = new PredictOptions(fullText: true);
120120
var response = await _mindeeClient.EnqueueAndParseAsync<InternationalIdV2>(inputSource, predictOptions);
121121
Assert.NotNull(response);
@@ -131,7 +131,7 @@ public async Task Parse_File_Standard_FullText_MustSucceed()
131131
[Fact]
132132
public async Task Parse_File_Standard_AllWords_And_Cropper_MustSucceed()
133133
{
134-
var inputSource = new LocalInputSource("Resources/file_types/receipt.jpg");
134+
var inputSource = new LocalInputSource(Constants.RootDir + "file_types/receipt.jpg");
135135
var predictOptions = new PredictOptions(allWords: true, cropper: true);
136136
var response = await _mindeeClient.ParseAsync<InvoiceV4>(
137137
inputSource, predictOptions);
@@ -151,15 +151,15 @@ public async Task Parse_File_Standard_AllWords_And_Cropper_MustSucceed()
151151
[Fact]
152152
public async Task Enqueue_File_Standard_SyncOnly_Async_MustFail()
153153
{
154-
var inputSource = new LocalInputSource("Resources/v1/products/passport/default_sample.jpg");
154+
var inputSource = new LocalInputSource(Constants.V1ProductDir + "passport/default_sample.jpg");
155155
await Assert.ThrowsAsync<Mindee403Exception>(
156156
() => _mindeeClient.EnqueueAsync<CropperV1>(inputSource));
157157
}
158158

159159
[Fact]
160160
public async Task Enqueue_File_Standard_AsyncOnly_Async_MustSucceed()
161161
{
162-
var inputSource = new LocalInputSource("Resources/v1/products/invoice_splitter/default_sample.pdf");
162+
var inputSource = new LocalInputSource(Constants.V1ProductDir + "invoice_splitter/default_sample.pdf");
163163
var response = await _mindeeClient.EnqueueAsync<InvoiceSplitterV1>(inputSource);
164164

165165
Assert.NotNull(response);
@@ -178,15 +178,15 @@ public async Task Enqueue_File_Standard_AsyncOnly_Async_MustSucceed()
178178
[Fact]
179179
public async Task Enqueue_File_Standard_AsyncOnly_Sync_MustFail()
180180
{
181-
var inputSource = new LocalInputSource("Resources/v1/products/invoice_splitter/default_sample.pdf");
181+
var inputSource = new LocalInputSource(Constants.V1ProductDir + "invoice_splitter/default_sample.pdf");
182182
await Assert.ThrowsAsync<Mindee403Exception>(
183183
() => _mindeeClient.ParseAsync<InvoiceSplitterV1>(inputSource));
184184
}
185185

186186
[Fact]
187187
public async Task EnqueueAndParse_File_Standard_AsyncOnly_Async_MustSucceed()
188188
{
189-
var inputSource = new LocalInputSource("Resources/v1/products/invoice_splitter/default_sample.pdf");
189+
var inputSource = new LocalInputSource(Constants.V1ProductDir + "invoice_splitter/default_sample.pdf");
190190
var pollingOptions = new AsyncPollingOptions();
191191
var response = await _mindeeClient.EnqueueAndParseAsync<InvoiceSplitterV1>(
192192
inputSource, pollingOptions: pollingOptions);
@@ -271,7 +271,7 @@ await Assert.ThrowsAsync<Mindee404Exception>(
271271
public async Task Enqueue_File_Generated_AsyncOnly_Sync_MustFail()
272272
{
273273
var endpoint = new CustomEndpoint("international_id", "mindee", "2");
274-
var inputSource = new LocalInputSource("Resources/v1/products/international_id/default_sample.jpg");
274+
var inputSource = new LocalInputSource(Constants.V1ProductDir + "international_id/default_sample.jpg");
275275
await Assert.ThrowsAsync<Mindee403Exception>(
276276
() => _mindeeClient.ParseAsync<GeneratedV1>(inputSource, endpoint));
277277
}
@@ -280,7 +280,7 @@ await Assert.ThrowsAsync<Mindee403Exception>(
280280
public async Task EnqueueAndParse_File_Generated_AsyncOnly_Async_MustSucceed()
281281
{
282282
var endpoint = new CustomEndpoint("international_id", "mindee", "2");
283-
var inputSource = new LocalInputSource("Resources/v1/products/international_id/default_sample.jpg");
283+
var inputSource = new LocalInputSource(Constants.V1ProductDir + "international_id/default_sample.jpg");
284284
var response = await _mindeeClient.EnqueueAndParseAsync<GeneratedV1>(inputSource, endpoint);
285285

286286
Assert.NotNull(response);

tests/Mindee.IntegrationTests/V1/Workflow/WorkflowTest.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@ public WorkflowTest()
1818
var apiKey1 = Environment.GetEnvironmentVariable("Mindee__ApiKey");
1919
_client = TestingUtilities.GetOrGenerateMindeeClient(apiKey1);
2020
_ragMatchInputSource = new LocalInputSource(
21-
"Resources/v1/products/financial_document/default_sample.jpg");
21+
Constants.V1ProductDir + "financial_document/default_sample.jpg");
2222
_ragNoMatchInputSource = new LocalInputSource(
23-
"Resources/v1/products/invoices/default_sample.jpg");
23+
Constants.V1ProductDir + "invoices/default_sample.jpg");
2424
_workflowId = Environment.GetEnvironmentVariable("Workflow__ID") ?? "";
2525
}
2626

tests/Mindee.IntegrationTests/V2/MindeeClientV2Test.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ public async Task Parse_File_Empty_MultiplePages_ParameterVariations_MustSucceed
4242
bool rawText, bool polygon, bool confidence)
4343
{
4444
var inputSource = new LocalInputSource(
45-
"Resources/file_types/pdf/multipage_cut-2.pdf");
45+
Constants.RootDir + "file_types/pdf/multipage_cut-2.pdf");
4646
var inferenceParams = new InferenceParameters(
4747
modelId: _findocModelId,
4848
rag: false,
@@ -107,7 +107,7 @@ public async Task Parse_File_Empty_MultiplePages_ParameterVariations_MustSucceed
107107
public async Task Parse_File_Filled_SinglePage_MustSucceed()
108108
{
109109
var inputSource = new LocalInputSource(
110-
"Resources/v1/products/financial_document/default_sample.jpg");
110+
Constants.V1ProductDir + "financial_document/default_sample.jpg");
111111
var inferenceParams = new InferenceParameters(
112112
modelId: _findocModelId);
113113

@@ -143,7 +143,7 @@ public async Task FailedWebhook_Retrieve_Job_MustSucceed()
143143
{
144144
string? webhookId = Environment.GetEnvironmentVariable("MindeeV2__Failure__Webhook__Id");
145145

146-
var inputSource = new LocalInputSource("Resources/file_types/pdf/multipage_cut-1.pdf");
146+
var inputSource = new LocalInputSource(Constants.RootDir + "file_types/pdf/multipage_cut-1.pdf");
147147
var inferenceParams = new InferenceParameters(
148148
modelId: _findocModelId, webhookIds: new List<string?> { webhookId });
149149

@@ -193,7 +193,7 @@ public async Task FailedWebhook_Retrieve_Job_MustSucceed()
193193
[Fact]
194194
public async Task Invalid_Model_MustThrowError()
195195
{
196-
var inputSource = new LocalInputSource("Resources/file_types/pdf/multipage_cut-2.pdf");
196+
var inputSource = new LocalInputSource(Constants.RootDir + "file_types/pdf/multipage_cut-2.pdf");
197197
var predictOptions = new InferenceParameters("INVALID MODEL ID");
198198
var ex = await Assert.ThrowsAsync<MindeeHttpExceptionV2>(
199199
() => _mindeeClientV2.EnqueueInferenceAsync(inputSource, predictOptions));
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
namespace Mindee.UnitTests
2+
{
3+
public static class Constants
4+
{
5+
public const string RootDir = "Resources/";
6+
7+
public const string V1RootDir = RootDir + "v1/";
8+
public const string V1ProductDir = V1RootDir + "products/";
9+
10+
public const string V2RootDir = RootDir + "v2/";
11+
}
12+
}

0 commit comments

Comments
 (0)