diff --git a/docs/code_samples/us_mail_v3_async.txt b/docs/code_samples/us_mail_v3_async.txt new file mode 100644 index 00000000..0ec748d5 --- /dev/null +++ b/docs/code_samples/us_mail_v3_async.txt @@ -0,0 +1,23 @@ +using Mindee; +using Mindee.Input; +using Mindee.Product.Us.UsMail; + +string apiKey = "my-api-key"; +string filePath = "/path/to/the/file.ext"; + +// Construct a new client +MindeeClient mindeeClient = new MindeeClient(apiKey); + +// Load an input source as a path string +// Other input types can be used, as mentioned in the docs +var inputSource = new LocalInputSource(filePath); + +// Call the product asynchronously with auto-polling +var response = await mindeeClient + .EnqueueAndParseAsync(inputSource); + +// Print a summary of all the predictions +System.Console.WriteLine(response.Document.ToString()); + +// Print only the document-level predictions +// System.Console.WriteLine(response.Document.Inference.Prediction.ToString()); diff --git a/docs/us_mail_v2.md b/docs/us_mail_v3.md similarity index 79% rename from docs/us_mail_v2.md rename to docs/us_mail_v3.md index f753f885..05b3ece9 100644 --- a/docs/us_mail_v2.md +++ b/docs/us_mail_v3.md @@ -27,7 +27,7 @@ var inputSource = new LocalInputSource(filePath); // Call the product asynchronously with auto-polling var response = await mindeeClient - .EnqueueAndParseAsync(inputSource); + .EnqueueAndParseAsync(inputSource); // Print a summary of all the predictions System.Console.WriteLine(response.Document.ToString()); @@ -39,7 +39,20 @@ System.Console.WriteLine(response.Document.ToString()); **Output (RST):** ```rst -:Sender Name: zed +######## +Document +######## +:Mindee ID: f9c36f59-977d-4ddc-9f2d-31c294c456ac +:Filename: default_sample.jpg + +Inference +######### +:Product: mindee/us_mail v3.0 +:Rotation applied: Yes + +Prediction +========== +:Sender Name: company zed :Sender Address: :City: Dallas :Complete Address: 54321 Elm Street, Dallas, Texas 54321 @@ -48,11 +61,12 @@ System.Console.WriteLine(response.Document.ToString()); :Street: 54321 Elm Street :Recipient Names: Jane Doe :Recipient Addresses: - +-----------------+-------------------------------------+-------------------+-------------+------------------------+-------+---------------------------+ - | City | Complete Address | Is Address Change | Postal Code | Private Mailbox Number | State | Street | - +=================+=====================================+===================+=============+========================+=======+===========================+ - | Detroit | 1234 Market Street PMB 4321, Det... | | 12345 | 4321 | MI | 1234 Market Street | - +-----------------+-------------------------------------+-------------------+-------------+------------------------+-------+---------------------------+ + +-----------------+-------------------------------------+-------------------+-------------+------------------------+-------+---------------------------+-----------------+ + | City | Complete Address | Is Address Change | Postal Code | Private Mailbox Number | State | Street | Unit | + +=================+=====================================+===================+=============+========================+=======+===========================+=================+ + | Detroit | 1234 Market Street PMB 4321, Det... | False | 12345 | 4321 | MI | 1234 Market Street | | + +-----------------+-------------------------------------+-------------------+-------------+------------------------+-------+---------------------------+-----------------+ +:Return to Sender: False ``` # Field Types @@ -78,13 +92,17 @@ The text field `StringField` extends `BaseField`, but also implements: * **Value** (`string`): corresponds to the field value. * **RawValue** (`string`): corresponds to the raw value as it appears on the document. +### BooleanField +The boolean field `BooleanField` extends BaseField, but also implements: +* **Value** (`bool?`): corresponds to the value of the field. + ## Specific Fields Fields which are specific to this product; they are not used in any other product. ### Recipient Addresses Field The addresses of the recipients. -A `UsMailV2RecipientAddress` implements the following attributes: +A `UsMailV3RecipientAddress` implements the following attributes: * **City** (`string`): The city of the recipient's address. * **Complete** (`string`): The complete address of the recipient. @@ -93,12 +111,13 @@ A `UsMailV2RecipientAddress` implements the following attributes: * **PrivateMailboxNumber** (`string`): The private mailbox number of the recipient's address. * **State** (`string`): Second part of the ISO 3166-2 code, consisting of two letters indicating the US State. * **Street** (`string`): The street of the recipient's address. +* **Unit** (`string`): The unit number of the recipient's address. Fields which are specific to this product; they are not used in any other product. ### Sender Address Field The address of the sender. -A `UsMailV2SenderAddress` implements the following attributes: +A `UsMailV3SenderAddress` implements the following attributes: * **City** (`string`): The city of the sender's address. * **Complete** (`string`): The complete address of the sender. @@ -107,10 +126,17 @@ A `UsMailV2SenderAddress` implements the following attributes: * **Street** (`string`): The street of the sender's address. # Attributes -The following fields are extracted for US Mail V2: +The following fields are extracted for US Mail V3: + +## Return to Sender +**IsReturnToSender**: Whether the mailing is marked as return to sender. + +```csharp +System.Console.WriteLine(result.Document.Inference.Prediction.IsReturnToSender.Value); +``` ## Recipient Addresses -**RecipientAddresses**(List<[UsMailV2RecipientAddress](#recipient-addresses-field)>): The addresses of the recipients. +**RecipientAddresses**(List<[UsMailV3RecipientAddress](#recipient-addresses-field)>): The addresses of the recipients. ```csharp foreach (var RecipientAddressesElem in result.Document.Inference.Prediction.RecipientAddresses) @@ -130,7 +156,7 @@ foreach (var RecipientNamesElem in result.Document.Inference.Prediction.Recipien ``` ## Sender Address -**SenderAddress**([UsMailV2SenderAddress](#sender-address-field)): The address of the sender. +**SenderAddress**([UsMailV3SenderAddress](#sender-address-field)): The address of the sender. ```csharp System.Console.WriteLine(result.Document.Inference.Prediction.SenderAddress.Value); diff --git a/src/Mindee.Cli/Program.cs b/src/Mindee.Cli/Program.cs index 92c7a4ef..c49817c4 100644 --- a/src/Mindee.Cli/Program.cs +++ b/src/Mindee.Cli/Program.cs @@ -57,9 +57,9 @@ Mindee.Product.Us.BankCheck.BankCheckV1Document >; using PredictUsMailCommand = Mindee.Cli.PredictCommand< - Mindee.Product.Us.UsMail.UsMailV2, - Mindee.Product.Us.UsMail.UsMailV2Document, - Mindee.Product.Us.UsMail.UsMailV2Document + Mindee.Product.Us.UsMail.UsMailV3, + Mindee.Product.Us.UsMail.UsMailV3Document, + Mindee.Product.Us.UsMail.UsMailV3Document >; using PredictUsPayrollCheckRegisterCommand = Mindee.Cli.PredictCommand< Mindee.Product.Us.PayrollCheckRegister.PayrollCheckRegisterV1, diff --git a/src/Mindee/Product/Us/UsMail/UsMailV3.cs b/src/Mindee/Product/Us/UsMail/UsMailV3.cs new file mode 100644 index 00000000..0abbc6aa --- /dev/null +++ b/src/Mindee/Product/Us/UsMail/UsMailV3.cs @@ -0,0 +1,20 @@ +using System.Text.Json.Serialization; +using Mindee.Http; +using Mindee.Parsing.Common; + +namespace Mindee.Product.Us.UsMail +{ + /// + /// US Mail API version 3 inference prediction. + /// + [Endpoint("us_mail", "3")] + public sealed class UsMailV3 : Inference + { + /// + /// The pages and the associated values which were detected on the document. + /// + [JsonPropertyName("pages")] + [JsonConverter(typeof(PagesJsonConverter))] + public override Pages Pages { get; set; } + } +} diff --git a/src/Mindee/Product/Us/UsMail/UsMailV3Document.cs b/src/Mindee/Product/Us/UsMail/UsMailV3Document.cs new file mode 100644 index 00000000..38255727 --- /dev/null +++ b/src/Mindee/Product/Us/UsMail/UsMailV3Document.cs @@ -0,0 +1,63 @@ +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.Json.Serialization; +using Mindee.Parsing; +using Mindee.Parsing.Standard; + +namespace Mindee.Product.Us.UsMail +{ + /// + /// US Mail API version 3.0 document data. + /// + public class UsMailV3Document : IPrediction + { + /// + /// Whether the mailing is marked as return to sender. + /// + [JsonPropertyName("is_return_to_sender")] + public BooleanField IsReturnToSender { get; set; } + + /// + /// The addresses of the recipients. + /// + [JsonPropertyName("recipient_addresses")] + [JsonConverter(typeof(ObjectListJsonConverter))] + public UsMailV3RecipientAddresses RecipientAddresses { get; set; } + + /// + /// The names of the recipients. + /// + [JsonPropertyName("recipient_names")] + public IList RecipientNames { get; set; } = new List(); + + /// + /// The address of the sender. + /// + [JsonPropertyName("sender_address")] + public UsMailV3SenderAddress SenderAddress { get; set; } + + /// + /// The name of the sender. + /// + [JsonPropertyName("sender_name")] + public StringField SenderName { get; set; } + + /// + /// A prettier representation of the current model values. + /// + public override string ToString() + { + string recipientNames = string.Join( + "\n " + string.Concat(Enumerable.Repeat(" ", 17)), + RecipientNames.Select(item => item)); + StringBuilder result = new StringBuilder(); + result.Append($":Sender Name: {SenderName}\n"); + result.Append($":Sender Address:{SenderAddress.ToFieldList()}"); + result.Append($":Recipient Names: {recipientNames}\n"); + result.Append($":Recipient Addresses:{RecipientAddresses}"); + result.Append($":Return to Sender: {IsReturnToSender}\n"); + return SummaryHelper.Clean(result.ToString()); + } + } +} diff --git a/src/Mindee/Product/Us/UsMail/UsMailV3RecipientAddress.cs b/src/Mindee/Product/Us/UsMail/UsMailV3RecipientAddress.cs new file mode 100644 index 00000000..88a54cdc --- /dev/null +++ b/src/Mindee/Product/Us/UsMail/UsMailV3RecipientAddress.cs @@ -0,0 +1,173 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Text.Json.Serialization; +using Mindee.Parsing; +using Mindee.Parsing.Standard; + +namespace Mindee.Product.Us.UsMail +{ + /// + /// The addresses of the recipients. + /// + public sealed class UsMailV3RecipientAddress : LineItemField + { + /// + /// The city of the recipient's address. + /// + [JsonPropertyName("city")] + public string City { get; set; } + + /// + /// The complete address of the recipient. + /// + [JsonPropertyName("complete")] + public string Complete { get; set; } + + /// + /// Indicates if the recipient's address is a change of address. + /// + [JsonPropertyName("is_address_change")] + public bool? IsAddressChange { get; set; } + + /// + /// The postal code of the recipient's address. + /// + [JsonPropertyName("postal_code")] + public string PostalCode { get; set; } + + /// + /// The private mailbox number of the recipient's address. + /// + [JsonPropertyName("private_mailbox_number")] + public string PrivateMailboxNumber { get; set; } + + /// + /// Second part of the ISO 3166-2 code, consisting of two letters indicating the US State. + /// + [JsonPropertyName("state")] + public string State { get; set; } + + /// + /// The street of the recipient's address. + /// + [JsonPropertyName("street")] + public string Street { get; set; } + + /// + /// The unit number of the recipient's address. + /// + [JsonPropertyName("unit")] + public string Unit { get; set; } + + private Dictionary TablePrintableValues() + { + return new Dictionary() + { + {"City", SummaryHelper.FormatString(City, 15)}, + {"Complete", SummaryHelper.FormatString(Complete, 35)}, + {"IsAddressChange", SummaryHelper.FormatBool(IsAddressChange)}, + {"PostalCode", SummaryHelper.FormatString(PostalCode)}, + {"PrivateMailboxNumber", SummaryHelper.FormatString(PrivateMailboxNumber)}, + {"State", SummaryHelper.FormatString(State)}, + {"Street", SummaryHelper.FormatString(Street, 25)}, + {"Unit", SummaryHelper.FormatString(Unit, 15)}, + }; + } + + /// + /// Output the line in a format suitable for inclusion in an rST table. + /// + public override string ToTableLine() + { + Dictionary printable = TablePrintableValues(); + return "| " + + String.Format("{0,-15}", printable["City"]) + + " | " + + String.Format("{0,-35}", printable["Complete"]) + + " | " + + String.Format("{0,-17}", printable["IsAddressChange"]) + + " | " + + String.Format("{0,-11}", printable["PostalCode"]) + + " | " + + String.Format("{0,-22}", printable["PrivateMailboxNumber"]) + + " | " + + String.Format("{0,-5}", printable["State"]) + + " | " + + String.Format("{0,-25}", printable["Street"]) + + " | " + + String.Format("{0,-15}", printable["Unit"]) + + " |"; + } + + /// + /// A prettier representation of the line values. + /// + public override string ToString() + { + Dictionary printable = PrintableValues(); + return "City: " + + printable["City"] + + ", Complete Address: " + + printable["Complete"] + + ", Is Address Change: " + + printable["IsAddressChange"] + + ", Postal Code: " + + printable["PostalCode"] + + ", Private Mailbox Number: " + + printable["PrivateMailboxNumber"] + + ", State: " + + printable["State"] + + ", Street: " + + printable["Street"] + + ", Unit: " + + printable["Unit"].Trim(); + } + + private Dictionary PrintableValues() + { + return new Dictionary() + { + {"City", SummaryHelper.FormatString(City)}, + {"Complete", SummaryHelper.FormatString(Complete)}, + {"IsAddressChange", SummaryHelper.FormatBool(IsAddressChange)}, + {"PostalCode", SummaryHelper.FormatString(PostalCode)}, + {"PrivateMailboxNumber", SummaryHelper.FormatString(PrivateMailboxNumber)}, + {"State", SummaryHelper.FormatString(State)}, + {"Street", SummaryHelper.FormatString(Street)}, + {"Unit", SummaryHelper.FormatString(Unit)}, + }; + } + } + + /// + /// The addresses of the recipients. + /// + public class UsMailV3RecipientAddresses : List + { + /// + /// Default string representation. + /// + public override string ToString() + { + if (this.Count == 0) + { + return "\n"; + } + int[] columnSizes = { 17, 37, 19, 13, 24, 7, 27, 17 }; + StringBuilder outStr = new StringBuilder("\n"); + outStr.Append(" " + SummaryHelper.LineSeparator(columnSizes, '-') + " "); + outStr.Append("| City "); + outStr.Append("| Complete Address "); + outStr.Append("| Is Address Change "); + outStr.Append("| Postal Code "); + outStr.Append("| Private Mailbox Number "); + outStr.Append("| State "); + outStr.Append("| Street "); + outStr.Append("| Unit "); + outStr.Append("|\n " + SummaryHelper.LineSeparator(columnSizes, '=')); + outStr.Append(SummaryHelper.ArrayToString(this, columnSizes)); + return outStr.ToString(); + } + } +} diff --git a/src/Mindee/Product/Us/UsMail/UsMailV3SenderAddress.cs b/src/Mindee/Product/Us/UsMail/UsMailV3SenderAddress.cs new file mode 100644 index 00000000..7f4908cc --- /dev/null +++ b/src/Mindee/Product/Us/UsMail/UsMailV3SenderAddress.cs @@ -0,0 +1,89 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Text.Json.Serialization; +using Mindee.Parsing; +using Mindee.Parsing.Standard; + +namespace Mindee.Product.Us.UsMail +{ + /// + /// The address of the sender. + /// + public sealed class UsMailV3SenderAddress + { + /// + /// The city of the sender's address. + /// + [JsonPropertyName("city")] + public string City { get; set; } + + /// + /// The complete address of the sender. + /// + [JsonPropertyName("complete")] + public string Complete { get; set; } + + /// + /// The postal code of the sender's address. + /// + [JsonPropertyName("postal_code")] + public string PostalCode { get; set; } + + /// + /// Second part of the ISO 3166-2 code, consisting of two letters indicating the US State. + /// + [JsonPropertyName("state")] + public string State { get; set; } + + /// + /// The street of the sender's address. + /// + [JsonPropertyName("street")] + public string Street { get; set; } + + /// + /// Output the object in a format suitable for inclusion in an rST field list. + /// + public string ToFieldList() + { + Dictionary printable = PrintableValues(); + return "\n" + + $" :City: {printable["City"]}\n" + + $" :Complete Address: {printable["Complete"]}\n" + + $" :Postal Code: {printable["PostalCode"]}\n" + + $" :State: {printable["State"]}\n" + + $" :Street: {printable["Street"]}\n"; + } + + /// + /// A prettier representation of the line values. + /// + public override string ToString() + { + Dictionary printable = PrintableValues(); + return "City: " + + printable["City"] + + ", Complete Address: " + + printable["Complete"] + + ", Postal Code: " + + printable["PostalCode"] + + ", State: " + + printable["State"] + + ", Street: " + + printable["Street"].Trim(); + } + + private Dictionary PrintableValues() + { + return new Dictionary() + { + {"City", SummaryHelper.FormatString(City)}, + {"Complete", SummaryHelper.FormatString(Complete)}, + {"PostalCode", SummaryHelper.FormatString(PostalCode)}, + {"State", SummaryHelper.FormatString(State)}, + {"Street", SummaryHelper.FormatString(Street)}, + }; + } + } +} diff --git a/tests/Mindee.UnitTests/Product/Us/UsMail/UsMailV3Test.cs b/tests/Mindee.UnitTests/Product/Us/UsMail/UsMailV3Test.cs new file mode 100644 index 00000000..b64e9d72 --- /dev/null +++ b/tests/Mindee.UnitTests/Product/Us/UsMail/UsMailV3Test.cs @@ -0,0 +1,41 @@ +using Mindee.Parsing.Common; +using Mindee.Product.Us.UsMail; + +namespace Mindee.UnitTests.Product.Us.UsMail +{ + [Trait("Category", "UsMailV3")] + public class UsMailV3Test + { + [Fact] + public async Task Predict_CheckEmpty() + { + var response = await GetPrediction("empty"); + var docPrediction = response.Document.Inference.Prediction; + Assert.Null(docPrediction.SenderName.Value); + Assert.Null(docPrediction.SenderAddress.City); + Assert.Null(docPrediction.SenderAddress.Complete); + Assert.Null(docPrediction.SenderAddress.PostalCode); + Assert.Null(docPrediction.SenderAddress.State); + Assert.Null(docPrediction.SenderAddress.Street); + Assert.Empty(docPrediction.RecipientNames); + Assert.Empty(docPrediction.RecipientAddresses); + Assert.Null(docPrediction.IsReturnToSender.Value); + } + + [Fact] + public async Task Predict_CheckSummary() + { + var response = await GetPrediction("complete"); + var expected = File.ReadAllText("Resources/products/us_mail/response_v3/summary_full.rst"); + Assert.Equal(expected, response.Document.ToString()); + } + + private static async Task> GetPrediction(string name) + { + string fileName = $"Resources/products/us_mail/response_v3/{name}.json"; + var mindeeAPi = UnitTestBase.GetMindeeApi(fileName); + return await mindeeAPi.PredictPostAsync( + UnitTestBase.GetFakePredictParameter()); + } + } +} diff --git a/tests/resources b/tests/resources index 984162b6..86f3c9de 160000 --- a/tests/resources +++ b/tests/resources @@ -1 +1 @@ -Subproject commit 984162b6c231125583ab42899ac1e3d7b46825f3 +Subproject commit 86f3c9de490a0f29e56cacee0cd63dbebfa86dc8