From 1a6e48aabf201f5987f2a53f9a768c9f55e5efbf Mon Sep 17 00:00:00 2001 From: sebastianMindee <130448732+sebastianMindee@users.noreply.github.com> Date: Tue, 17 Feb 2026 17:58:10 +0100 Subject: [PATCH 01/33] :recycle: completely separate v1 and v2 code --- src/Mindee.Cli/Commands/V1/PredictCommand.cs | 1 + .../ClientOptions/AsyncPollingOptions.cs | 77 +++++++++++++++++++ src/Mindee/Parsing/BaseLocalResponse.cs | 70 ----------------- src/Mindee/V1/Client.cs | 2 + src/Mindee/V2/Client.cs | 1 + .../Mindee.IntegrationTests/V1/ClientTest.cs | 1 + tests/Mindee.UnitTests/V1/ClientTest.cs | 1 + tests/Mindee.UnitTests/V2/ClientTest.cs | 1 + 8 files changed, 84 insertions(+), 70 deletions(-) create mode 100644 src/Mindee/ClientOptions/AsyncPollingOptions.cs delete mode 100644 src/Mindee/Parsing/BaseLocalResponse.cs diff --git a/src/Mindee.Cli/Commands/V1/PredictCommand.cs b/src/Mindee.Cli/Commands/V1/PredictCommand.cs index 790b5831a..12b22ff5a 100644 --- a/src/Mindee.Cli/Commands/V1/PredictCommand.cs +++ b/src/Mindee.Cli/Commands/V1/PredictCommand.cs @@ -1,5 +1,6 @@ using System.CommandLine; using System.Text.Json; +using Mindee.ClientOptions; using Mindee.Input; using Mindee.V1; using Mindee.V1.ClientOptions; diff --git a/src/Mindee/ClientOptions/AsyncPollingOptions.cs b/src/Mindee/ClientOptions/AsyncPollingOptions.cs new file mode 100644 index 000000000..a0a9a1002 --- /dev/null +++ b/src/Mindee/ClientOptions/AsyncPollingOptions.cs @@ -0,0 +1,77 @@ +using System; +using Mindee.Exceptions; + +namespace Mindee.ClientOptions +{ + /// + /// ResultOptions to pass for asynchronous parsing with polling. + /// + public sealed class AsyncPollingOptions + { + /// + /// ResultOptions to pass for asynchronous parsing with polling. + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + public AsyncPollingOptions(double initialDelaySec = 2.0, double intervalSec = 1.5, int maxRetries = 80) + { + var minInitialDelaySec = 1.0; + var minIntervalSec = 1.0; + var minRetries = 2; + if (initialDelaySec < minInitialDelaySec) + { + throw new MindeeException( + $"Cannot set initial polling delay to less than {Math.Floor(minInitialDelaySec)} second(s)."); + } + + if (intervalSec < minIntervalSec) + { + throw new MindeeException( + $"Cannot set polling interval to less than {Math.Floor(minIntervalSec)} second(s)."); + } + + if (maxRetries < minRetries) + { + throw new MindeeException($"Cannot set async retry to less than {minRetries} attempts."); + } + + InitialDelaySec = initialDelaySec; + IntervalSec = intervalSec; + MaxRetries = maxRetries; + InitialDelayMilliSec = (int)Math.Floor(InitialDelaySec * 1000); + IntervalMilliSec = (int)Math.Floor(IntervalSec * 1000); + } + + /// + /// Initial delay before the first polling attempt. + /// + public double InitialDelaySec { get; } + + /// + /// Delay between each polling attempt. + /// + public double IntervalSec { get; } + + /// + /// Total number of polling attempts. + /// + public int MaxRetries { get; } + + /// + /// Wait this many milliseconds between each polling attempt. + /// + public int InitialDelayMilliSec { get; } + + /// + /// Wait this many milliseconds before the first polling attempt. + /// + public int IntervalMilliSec { get; } + } +} diff --git a/src/Mindee/Parsing/BaseLocalResponse.cs b/src/Mindee/Parsing/BaseLocalResponse.cs deleted file mode 100644 index a9e55519f..000000000 --- a/src/Mindee/Parsing/BaseLocalResponse.cs +++ /dev/null @@ -1,70 +0,0 @@ -using System; -using System.IO; -using System.Security.Cryptography; -using System.Text; - -namespace Mindee.Parsing -{ - /// - /// A Mindee response saved locally. - /// - public abstract class BaseLocalResponse - { - /// - /// Load from a string. - /// - /// Will be decoded as UTF-8. - public BaseLocalResponse(string input) - { - FileBytes = Encoding.UTF8.GetBytes(input.Replace("\r", "").Replace("\n", "")); - } - - /// - /// Load from a file. - /// - /// Will be decoded as UTF-8. - public BaseLocalResponse(FileInfo input) - { - FileBytes = Encoding.UTF8.GetBytes( - File.ReadAllText(input.FullName).Replace("\r", "").Replace("\n", "")); - } - - /// - /// ResultFile as UTF-8 bytes. - /// - public byte[] FileBytes { get; } - - /// - /// Get the HMAC signature of the payload. - /// - /// Your secret key from the Mindee platform. - /// The generated HMAC signature. - public string GetHmacSignature(string secretKey) - { - var keyBytes = Encoding.UTF8.GetBytes(secretKey); - using var hmac = new HMACSHA256(keyBytes); - var hexString = BitConverter.ToString(hmac.ComputeHash(FileBytes)); - return hexString.Replace("-", "").ToLower(); - } - - /// - /// Verify that the payload's signature matches the one received from the server. - /// - /// Your secret key from the Mindee platform. - /// The signature from the "X-Mindee-Hmac-Signature" HTTP header. - /// - public bool IsValidHmacSignature(string secretKey, string signature) - { - return GetHmacSignature(secretKey) == signature.ToLower(); - } - - /// - /// Print the file as a UTF-8 string. - /// - /// - public override string ToString() - { - return Encoding.UTF8.GetString(FileBytes); - } - } -} diff --git a/src/Mindee/V1/Client.cs b/src/Mindee/V1/Client.cs index 3156ec0b3..9b8d0eedc 100644 --- a/src/Mindee/V1/Client.cs +++ b/src/Mindee/V1/Client.cs @@ -3,9 +3,11 @@ using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; +using Mindee.ClientOptions; using Mindee.Exceptions; using Mindee.Extensions.DependencyInjection; using Mindee.Input; +using Mindee.Parsing; using Mindee.Pdf; using Mindee.V1.ClientOptions; using Mindee.V1.Http; diff --git a/src/Mindee/V2/Client.cs b/src/Mindee/V2/Client.cs index d103cdb6b..a8253eebd 100644 --- a/src/Mindee/V2/Client.cs +++ b/src/Mindee/V2/Client.cs @@ -3,6 +3,7 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; +using Mindee.ClientOptions; using Mindee.Exceptions; using Mindee.Extensions.DependencyInjection; using Mindee.Input; diff --git a/tests/Mindee.IntegrationTests/V1/ClientTest.cs b/tests/Mindee.IntegrationTests/V1/ClientTest.cs index 3196d79f8..59a9be2c6 100644 --- a/tests/Mindee.IntegrationTests/V1/ClientTest.cs +++ b/tests/Mindee.IntegrationTests/V1/ClientTest.cs @@ -1,3 +1,4 @@ +using Mindee.ClientOptions; using Mindee.Exceptions; using Mindee.Input; using Mindee.V1; diff --git a/tests/Mindee.UnitTests/V1/ClientTest.cs b/tests/Mindee.UnitTests/V1/ClientTest.cs index 385d4f53a..f21bea1a4 100644 --- a/tests/Mindee.UnitTests/V1/ClientTest.cs +++ b/tests/Mindee.UnitTests/V1/ClientTest.cs @@ -1,5 +1,6 @@ using Microsoft.Extensions.Logging.Abstractions; using Mindee.Input; +using Mindee.Parsing; using Mindee.Pdf; using Mindee.V1; using Mindee.V1.Http; diff --git a/tests/Mindee.UnitTests/V2/ClientTest.cs b/tests/Mindee.UnitTests/V2/ClientTest.cs index 2123f5bc6..c5a3c40ec 100644 --- a/tests/Mindee.UnitTests/V2/ClientTest.cs +++ b/tests/Mindee.UnitTests/V2/ClientTest.cs @@ -1,4 +1,5 @@ using Mindee.Input; +using Mindee.Parsing; using Mindee.V2; using Mindee.V2.Http; using Mindee.V2.Parsing; From 2f8eb2eb930f6ae3c617fafeafedbf3029cdc0e6 Mon Sep 17 00:00:00 2001 From: sebastianMindee <130448732+sebastianMindee@users.noreply.github.com> Date: Fri, 20 Feb 2026 17:19:17 +0100 Subject: [PATCH 02/33] :boom: :recycle: Update syntaxes in V2 to accomodate for generics --- src/Mindee.Cli/Commands/V1/PredictCommand.cs | 3 +- .../ClientOptions/AsyncPollingOptions.cs | 77 ---------------- src/Mindee/Parsing/BaseLocalResponse.cs | 70 ++++++++++++++ src/Mindee/V1/Client.cs | 2 - .../{Inference.cs => ExtractionInference.cs} | 2 +- .../Product/BarcodeReader/BarcodeReaderV1.cs | 2 +- src/Mindee/V1/Product/Cropper/CropperV1.cs | 2 +- .../FinancialDocument/FinancialDocumentV1.cs | 2 +- .../BankAccountDetailsV1.cs | 2 +- .../BankAccountDetailsV2.cs | 2 +- .../V1/Product/Fr/CarteGrise/CarteGriseV1.cs | 2 +- .../V1/Product/Fr/HealthCard/HealthCardV1.cs | 2 +- src/Mindee/V1/Product/Fr/IdCard/IdCardV1.cs | 2 +- src/Mindee/V1/Product/Fr/IdCard/IdCardV2.cs | 2 +- src/Mindee/V1/Product/Fr/Payslip/PayslipV3.cs | 2 +- .../V1/Product/Generated/GeneratedV1.cs | 2 +- .../InternationalId/InternationalIdV2.cs | 2 +- src/Mindee/V1/Product/Invoice/InvoiceV4.cs | 2 +- .../InvoiceSplitter/InvoiceSplitterV1.cs | 2 +- .../MultiReceiptsDetectorV1.cs | 2 +- src/Mindee/V1/Product/Passport/PassportV1.cs | 2 +- src/Mindee/V1/Product/Receipt/ReceiptV4.cs | 2 +- src/Mindee/V1/Product/Receipt/ReceiptV5.cs | 2 +- .../V1/Product/Us/BankCheck/BankCheckV1.cs | 2 +- .../PayrollCheckRegisterV1.cs | 2 +- src/Mindee/V2/Client.cs | 91 ++++++++----------- src/Mindee/V2/Http/HttpApiV2.cs | 38 ++------ src/Mindee/V2/Http/MindeeApiV2.cs | 58 ++---------- src/Mindee/V2/Parsing/BaseResponse.cs | 10 +- .../V2/Parsing/Inference/BaseInference.cs | 9 +- src/Mindee/V2/Parsing/LocalResponse.cs | 5 +- src/Mindee/V2/Product/BaseProduct.cs | 25 +++++ .../V2/Product/Extraction/Extraction.cs | 26 ++++++ .../Product/Extraction/ExtractionResponse.cs | 5 +- .../Extraction/Params/ExtractionParameters.cs | 4 +- .../Mindee.IntegrationTests/V1/ClientTest.cs | 1 - .../Mindee.IntegrationTests/V2/ClientTest.cs | 7 +- tests/Mindee.UnitTests/V1/ClientTest.cs | 1 - .../V1/Parsing/Common/FullTextOcrTest.cs | 2 +- tests/Mindee.UnitTests/V2/ClientTest.cs | 9 +- .../V2/Input/LocalResponseTest.cs | 6 +- .../V2/Product/ExtractionTest.cs | 6 +- 42 files changed, 233 insertions(+), 264 deletions(-) delete mode 100644 src/Mindee/ClientOptions/AsyncPollingOptions.cs create mode 100644 src/Mindee/Parsing/BaseLocalResponse.cs rename src/Mindee/V1/Parsing/Common/{Inference.cs => ExtractionInference.cs} (97%) create mode 100644 src/Mindee/V2/Product/BaseProduct.cs create mode 100644 src/Mindee/V2/Product/Extraction/Extraction.cs diff --git a/src/Mindee.Cli/Commands/V1/PredictCommand.cs b/src/Mindee.Cli/Commands/V1/PredictCommand.cs index 12b22ff5a..46b010b4b 100644 --- a/src/Mindee.Cli/Commands/V1/PredictCommand.cs +++ b/src/Mindee.Cli/Commands/V1/PredictCommand.cs @@ -1,6 +1,5 @@ using System.CommandLine; using System.Text.Json; -using Mindee.ClientOptions; using Mindee.Input; using Mindee.V1; using Mindee.V1.ClientOptions; @@ -31,7 +30,7 @@ internal struct ParseOptions(string path, bool allWords, bool fullText, OutputTy class PredictCommand : Command where TDoc : IPrediction, new() where TPage : IPrediction, new() - where TInferenceModel : Inference, new() + where TInferenceModel : ExtractionInference, new() { private readonly Option _outputOption; private readonly Option? _allWordsOption; diff --git a/src/Mindee/ClientOptions/AsyncPollingOptions.cs b/src/Mindee/ClientOptions/AsyncPollingOptions.cs deleted file mode 100644 index a0a9a1002..000000000 --- a/src/Mindee/ClientOptions/AsyncPollingOptions.cs +++ /dev/null @@ -1,77 +0,0 @@ -using System; -using Mindee.Exceptions; - -namespace Mindee.ClientOptions -{ - /// - /// ResultOptions to pass for asynchronous parsing with polling. - /// - public sealed class AsyncPollingOptions - { - /// - /// ResultOptions to pass for asynchronous parsing with polling. - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - public AsyncPollingOptions(double initialDelaySec = 2.0, double intervalSec = 1.5, int maxRetries = 80) - { - var minInitialDelaySec = 1.0; - var minIntervalSec = 1.0; - var minRetries = 2; - if (initialDelaySec < minInitialDelaySec) - { - throw new MindeeException( - $"Cannot set initial polling delay to less than {Math.Floor(minInitialDelaySec)} second(s)."); - } - - if (intervalSec < minIntervalSec) - { - throw new MindeeException( - $"Cannot set polling interval to less than {Math.Floor(minIntervalSec)} second(s)."); - } - - if (maxRetries < minRetries) - { - throw new MindeeException($"Cannot set async retry to less than {minRetries} attempts."); - } - - InitialDelaySec = initialDelaySec; - IntervalSec = intervalSec; - MaxRetries = maxRetries; - InitialDelayMilliSec = (int)Math.Floor(InitialDelaySec * 1000); - IntervalMilliSec = (int)Math.Floor(IntervalSec * 1000); - } - - /// - /// Initial delay before the first polling attempt. - /// - public double InitialDelaySec { get; } - - /// - /// Delay between each polling attempt. - /// - public double IntervalSec { get; } - - /// - /// Total number of polling attempts. - /// - public int MaxRetries { get; } - - /// - /// Wait this many milliseconds between each polling attempt. - /// - public int InitialDelayMilliSec { get; } - - /// - /// Wait this many milliseconds before the first polling attempt. - /// - public int IntervalMilliSec { get; } - } -} diff --git a/src/Mindee/Parsing/BaseLocalResponse.cs b/src/Mindee/Parsing/BaseLocalResponse.cs new file mode 100644 index 000000000..a9e55519f --- /dev/null +++ b/src/Mindee/Parsing/BaseLocalResponse.cs @@ -0,0 +1,70 @@ +using System; +using System.IO; +using System.Security.Cryptography; +using System.Text; + +namespace Mindee.Parsing +{ + /// + /// A Mindee response saved locally. + /// + public abstract class BaseLocalResponse + { + /// + /// Load from a string. + /// + /// Will be decoded as UTF-8. + public BaseLocalResponse(string input) + { + FileBytes = Encoding.UTF8.GetBytes(input.Replace("\r", "").Replace("\n", "")); + } + + /// + /// Load from a file. + /// + /// Will be decoded as UTF-8. + public BaseLocalResponse(FileInfo input) + { + FileBytes = Encoding.UTF8.GetBytes( + File.ReadAllText(input.FullName).Replace("\r", "").Replace("\n", "")); + } + + /// + /// ResultFile as UTF-8 bytes. + /// + public byte[] FileBytes { get; } + + /// + /// Get the HMAC signature of the payload. + /// + /// Your secret key from the Mindee platform. + /// The generated HMAC signature. + public string GetHmacSignature(string secretKey) + { + var keyBytes = Encoding.UTF8.GetBytes(secretKey); + using var hmac = new HMACSHA256(keyBytes); + var hexString = BitConverter.ToString(hmac.ComputeHash(FileBytes)); + return hexString.Replace("-", "").ToLower(); + } + + /// + /// Verify that the payload's signature matches the one received from the server. + /// + /// Your secret key from the Mindee platform. + /// The signature from the "X-Mindee-Hmac-Signature" HTTP header. + /// + public bool IsValidHmacSignature(string secretKey, string signature) + { + return GetHmacSignature(secretKey) == signature.ToLower(); + } + + /// + /// Print the file as a UTF-8 string. + /// + /// + public override string ToString() + { + return Encoding.UTF8.GetString(FileBytes); + } + } +} diff --git a/src/Mindee/V1/Client.cs b/src/Mindee/V1/Client.cs index 9b8d0eedc..3156ec0b3 100644 --- a/src/Mindee/V1/Client.cs +++ b/src/Mindee/V1/Client.cs @@ -3,11 +3,9 @@ using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; -using Mindee.ClientOptions; using Mindee.Exceptions; using Mindee.Extensions.DependencyInjection; using Mindee.Input; -using Mindee.Parsing; using Mindee.Pdf; using Mindee.V1.ClientOptions; using Mindee.V1.Http; diff --git a/src/Mindee/V1/Parsing/Common/Inference.cs b/src/Mindee/V1/Parsing/Common/ExtractionInference.cs similarity index 97% rename from src/Mindee/V1/Parsing/Common/Inference.cs rename to src/Mindee/V1/Parsing/Common/ExtractionInference.cs index 0216e8cd6..4f20632d2 100644 --- a/src/Mindee/V1/Parsing/Common/Inference.cs +++ b/src/Mindee/V1/Parsing/Common/ExtractionInference.cs @@ -10,7 +10,7 @@ namespace Mindee.V1.Parsing.Common /// /// Page prediction (could be the same that TDocumentPrediction). /// Document prediction (could be the same that TPagePrediction). - public abstract class Inference + public abstract class ExtractionInference where TPagePrediction : IPrediction, new() where TDocumentPrediction : IPrediction, new() { diff --git a/src/Mindee/V1/Product/BarcodeReader/BarcodeReaderV1.cs b/src/Mindee/V1/Product/BarcodeReader/BarcodeReaderV1.cs index cc306a0b0..23621e7ad 100644 --- a/src/Mindee/V1/Product/BarcodeReader/BarcodeReaderV1.cs +++ b/src/Mindee/V1/Product/BarcodeReader/BarcodeReaderV1.cs @@ -8,7 +8,7 @@ namespace Mindee.V1.Product.BarcodeReader /// Barcode Reader API version 1 inference prediction. /// [Endpoint("barcode_reader", "1")] - public sealed class BarcodeReaderV1 : Inference + public sealed class BarcodeReaderV1 : ExtractionInference { /// /// The pages and the associated values which were detected on the document. diff --git a/src/Mindee/V1/Product/Cropper/CropperV1.cs b/src/Mindee/V1/Product/Cropper/CropperV1.cs index 6784b9929..a8e4bb222 100644 --- a/src/Mindee/V1/Product/Cropper/CropperV1.cs +++ b/src/Mindee/V1/Product/Cropper/CropperV1.cs @@ -8,7 +8,7 @@ namespace Mindee.V1.Product.Cropper /// Cropper API version 1 inference prediction. /// [Endpoint("cropper", "1")] - public sealed class CropperV1 : Inference + public sealed class CropperV1 : ExtractionInference { /// /// The pages and the associated values which were detected on the document. diff --git a/src/Mindee/V1/Product/FinancialDocument/FinancialDocumentV1.cs b/src/Mindee/V1/Product/FinancialDocument/FinancialDocumentV1.cs index 55c9739e2..be290470b 100644 --- a/src/Mindee/V1/Product/FinancialDocument/FinancialDocumentV1.cs +++ b/src/Mindee/V1/Product/FinancialDocument/FinancialDocumentV1.cs @@ -8,7 +8,7 @@ namespace Mindee.V1.Product.FinancialDocument /// Financial Document API version 1 inference prediction. /// [Endpoint("financial_document", "1")] - public sealed class FinancialDocumentV1 : Inference + public sealed class FinancialDocumentV1 : ExtractionInference { /// /// The pages and the associated values which were detected on the document. diff --git a/src/Mindee/V1/Product/Fr/BankAccountDetails/BankAccountDetailsV1.cs b/src/Mindee/V1/Product/Fr/BankAccountDetails/BankAccountDetailsV1.cs index fc8f4f836..4d923bebf 100644 --- a/src/Mindee/V1/Product/Fr/BankAccountDetails/BankAccountDetailsV1.cs +++ b/src/Mindee/V1/Product/Fr/BankAccountDetails/BankAccountDetailsV1.cs @@ -8,7 +8,7 @@ namespace Mindee.V1.Product.Fr.BankAccountDetails /// Bank Account Details API version 1 inference prediction. /// [Endpoint("bank_account_details", "1")] - public sealed class BankAccountDetailsV1 : Inference + public sealed class BankAccountDetailsV1 : ExtractionInference { /// /// The pages and the associated values which were detected on the document. diff --git a/src/Mindee/V1/Product/Fr/BankAccountDetails/BankAccountDetailsV2.cs b/src/Mindee/V1/Product/Fr/BankAccountDetails/BankAccountDetailsV2.cs index f3af6459d..66cefe3c8 100644 --- a/src/Mindee/V1/Product/Fr/BankAccountDetails/BankAccountDetailsV2.cs +++ b/src/Mindee/V1/Product/Fr/BankAccountDetails/BankAccountDetailsV2.cs @@ -8,7 +8,7 @@ namespace Mindee.V1.Product.Fr.BankAccountDetails /// Bank Account Details API version 2 inference prediction. /// [Endpoint("bank_account_details", "2")] - public sealed class BankAccountDetailsV2 : Inference + public sealed class BankAccountDetailsV2 : ExtractionInference { /// /// The pages and the associated values which were detected on the document. diff --git a/src/Mindee/V1/Product/Fr/CarteGrise/CarteGriseV1.cs b/src/Mindee/V1/Product/Fr/CarteGrise/CarteGriseV1.cs index 9f210fc60..9539ee0d1 100644 --- a/src/Mindee/V1/Product/Fr/CarteGrise/CarteGriseV1.cs +++ b/src/Mindee/V1/Product/Fr/CarteGrise/CarteGriseV1.cs @@ -8,7 +8,7 @@ namespace Mindee.V1.Product.Fr.CarteGrise /// Carte Grise API version 1 inference prediction. /// [Endpoint("carte_grise", "1")] - public sealed class CarteGriseV1 : Inference + public sealed class CarteGriseV1 : ExtractionInference { /// /// The pages and the associated values which were detected on the document. diff --git a/src/Mindee/V1/Product/Fr/HealthCard/HealthCardV1.cs b/src/Mindee/V1/Product/Fr/HealthCard/HealthCardV1.cs index 563d12418..dd01c8e5f 100644 --- a/src/Mindee/V1/Product/Fr/HealthCard/HealthCardV1.cs +++ b/src/Mindee/V1/Product/Fr/HealthCard/HealthCardV1.cs @@ -8,7 +8,7 @@ namespace Mindee.V1.Product.Fr.HealthCard /// Health Card API version 1 inference prediction. /// [Endpoint("french_healthcard", "1")] - public sealed class HealthCardV1 : Inference + public sealed class HealthCardV1 : ExtractionInference { /// /// The pages and the associated values which were detected on the document. diff --git a/src/Mindee/V1/Product/Fr/IdCard/IdCardV1.cs b/src/Mindee/V1/Product/Fr/IdCard/IdCardV1.cs index c51fb62c6..db3b878a7 100644 --- a/src/Mindee/V1/Product/Fr/IdCard/IdCardV1.cs +++ b/src/Mindee/V1/Product/Fr/IdCard/IdCardV1.cs @@ -8,7 +8,7 @@ namespace Mindee.V1.Product.Fr.IdCard /// Carte Nationale d'Identité API version 1 inference prediction. /// [Endpoint("idcard_fr", "1")] - public sealed class IdCardV1 : Inference + public sealed class IdCardV1 : ExtractionInference { /// /// The pages and the associated values which were detected on the document. diff --git a/src/Mindee/V1/Product/Fr/IdCard/IdCardV2.cs b/src/Mindee/V1/Product/Fr/IdCard/IdCardV2.cs index 005b812fb..8581605d6 100644 --- a/src/Mindee/V1/Product/Fr/IdCard/IdCardV2.cs +++ b/src/Mindee/V1/Product/Fr/IdCard/IdCardV2.cs @@ -8,7 +8,7 @@ namespace Mindee.V1.Product.Fr.IdCard /// Carte Nationale d'Identité API version 2 inference prediction. /// [Endpoint("idcard_fr", "2")] - public sealed class IdCardV2 : Inference + public sealed class IdCardV2 : ExtractionInference { /// /// The pages and the associated values which were detected on the document. diff --git a/src/Mindee/V1/Product/Fr/Payslip/PayslipV3.cs b/src/Mindee/V1/Product/Fr/Payslip/PayslipV3.cs index daf742794..8f71e6db0 100644 --- a/src/Mindee/V1/Product/Fr/Payslip/PayslipV3.cs +++ b/src/Mindee/V1/Product/Fr/Payslip/PayslipV3.cs @@ -8,7 +8,7 @@ namespace Mindee.V1.Product.Fr.Payslip /// Payslip API version 3 inference prediction. /// [Endpoint("payslip_fra", "3")] - public sealed class PayslipV3 : Inference + public sealed class PayslipV3 : ExtractionInference { /// /// The pages and the associated values which were detected on the document. diff --git a/src/Mindee/V1/Product/Generated/GeneratedV1.cs b/src/Mindee/V1/Product/Generated/GeneratedV1.cs index 881228f96..28bfd3514 100644 --- a/src/Mindee/V1/Product/Generated/GeneratedV1.cs +++ b/src/Mindee/V1/Product/Generated/GeneratedV1.cs @@ -5,7 +5,7 @@ namespace Mindee.V1.Product.Generated /// /// The definition for Generated Documents, API version 1. /// - public class GeneratedV1 : Inference + public class GeneratedV1 : ExtractionInference { } diff --git a/src/Mindee/V1/Product/InternationalId/InternationalIdV2.cs b/src/Mindee/V1/Product/InternationalId/InternationalIdV2.cs index e1dfb44b0..b8be8350b 100644 --- a/src/Mindee/V1/Product/InternationalId/InternationalIdV2.cs +++ b/src/Mindee/V1/Product/InternationalId/InternationalIdV2.cs @@ -8,7 +8,7 @@ namespace Mindee.V1.Product.InternationalId /// International ID API version 2 inference prediction. /// [Endpoint("international_id", "2")] - public sealed class InternationalIdV2 : Inference + public sealed class InternationalIdV2 : ExtractionInference { /// /// The pages and the associated values which were detected on the document. diff --git a/src/Mindee/V1/Product/Invoice/InvoiceV4.cs b/src/Mindee/V1/Product/Invoice/InvoiceV4.cs index 5a7d009be..9e5601325 100644 --- a/src/Mindee/V1/Product/Invoice/InvoiceV4.cs +++ b/src/Mindee/V1/Product/Invoice/InvoiceV4.cs @@ -8,7 +8,7 @@ namespace Mindee.V1.Product.Invoice /// Invoice API version 4 inference prediction. /// [Endpoint("invoices", "4")] - public sealed class InvoiceV4 : Inference + public sealed class InvoiceV4 : ExtractionInference { /// /// The pages and the associated values which were detected on the document. diff --git a/src/Mindee/V1/Product/InvoiceSplitter/InvoiceSplitterV1.cs b/src/Mindee/V1/Product/InvoiceSplitter/InvoiceSplitterV1.cs index f1c200613..35e334a63 100644 --- a/src/Mindee/V1/Product/InvoiceSplitter/InvoiceSplitterV1.cs +++ b/src/Mindee/V1/Product/InvoiceSplitter/InvoiceSplitterV1.cs @@ -8,7 +8,7 @@ namespace Mindee.V1.Product.InvoiceSplitter /// Invoice Splitter API version 1 inference prediction. /// [Endpoint("invoice_splitter", "1")] - public sealed class InvoiceSplitterV1 : Inference + public sealed class InvoiceSplitterV1 : ExtractionInference { /// /// The pages and the associated values which were detected on the document. diff --git a/src/Mindee/V1/Product/MultiReceiptsDetector/MultiReceiptsDetectorV1.cs b/src/Mindee/V1/Product/MultiReceiptsDetector/MultiReceiptsDetectorV1.cs index f54d5168b..1ef706889 100644 --- a/src/Mindee/V1/Product/MultiReceiptsDetector/MultiReceiptsDetectorV1.cs +++ b/src/Mindee/V1/Product/MultiReceiptsDetector/MultiReceiptsDetectorV1.cs @@ -8,7 +8,7 @@ namespace Mindee.V1.Product.MultiReceiptsDetector /// Multi Receipts Detector API version 1 inference prediction. /// [Endpoint("multi_receipts_detector", "1")] - public sealed class MultiReceiptsDetectorV1 : Inference + public sealed class MultiReceiptsDetectorV1 : ExtractionInference { /// /// The pages and the associated values which were detected on the document. diff --git a/src/Mindee/V1/Product/Passport/PassportV1.cs b/src/Mindee/V1/Product/Passport/PassportV1.cs index dfcb8031e..a952ae316 100644 --- a/src/Mindee/V1/Product/Passport/PassportV1.cs +++ b/src/Mindee/V1/Product/Passport/PassportV1.cs @@ -8,7 +8,7 @@ namespace Mindee.V1.Product.Passport /// Passport API version 1 inference prediction. /// [Endpoint("passport", "1")] - public sealed class PassportV1 : Inference + public sealed class PassportV1 : ExtractionInference { /// /// The pages and the associated values which were detected on the document. diff --git a/src/Mindee/V1/Product/Receipt/ReceiptV4.cs b/src/Mindee/V1/Product/Receipt/ReceiptV4.cs index 9fe7ad7ea..23b0df32e 100644 --- a/src/Mindee/V1/Product/Receipt/ReceiptV4.cs +++ b/src/Mindee/V1/Product/Receipt/ReceiptV4.cs @@ -7,7 +7,7 @@ namespace Mindee.V1.Product.Receipt /// The definition for Receipt, API version 4. /// [Endpoint("expense_receipts", "4")] - public sealed class ReceiptV4 : Inference + public sealed class ReceiptV4 : ExtractionInference { } } diff --git a/src/Mindee/V1/Product/Receipt/ReceiptV5.cs b/src/Mindee/V1/Product/Receipt/ReceiptV5.cs index f5f23e056..07504bf93 100644 --- a/src/Mindee/V1/Product/Receipt/ReceiptV5.cs +++ b/src/Mindee/V1/Product/Receipt/ReceiptV5.cs @@ -8,7 +8,7 @@ namespace Mindee.V1.Product.Receipt /// Receipt API version 5 inference prediction. /// [Endpoint("expense_receipts", "5")] - public sealed class ReceiptV5 : Inference + public sealed class ReceiptV5 : ExtractionInference { /// /// The pages and the associated values which were detected on the document. diff --git a/src/Mindee/V1/Product/Us/BankCheck/BankCheckV1.cs b/src/Mindee/V1/Product/Us/BankCheck/BankCheckV1.cs index e83b95fbb..d509bfe38 100644 --- a/src/Mindee/V1/Product/Us/BankCheck/BankCheckV1.cs +++ b/src/Mindee/V1/Product/Us/BankCheck/BankCheckV1.cs @@ -8,7 +8,7 @@ namespace Mindee.V1.Product.Us.BankCheck /// Bank Check API version 1 inference prediction. /// [Endpoint("bank_check", "1")] - public sealed class BankCheckV1 : Inference + public sealed class BankCheckV1 : ExtractionInference { /// /// The pages and the associated values which were detected on the document. diff --git a/src/Mindee/V1/Product/Us/PayrollCheckRegister/PayrollCheckRegisterV1.cs b/src/Mindee/V1/Product/Us/PayrollCheckRegister/PayrollCheckRegisterV1.cs index a2ce54b31..0d58f5fe8 100644 --- a/src/Mindee/V1/Product/Us/PayrollCheckRegister/PayrollCheckRegisterV1.cs +++ b/src/Mindee/V1/Product/Us/PayrollCheckRegister/PayrollCheckRegisterV1.cs @@ -7,7 +7,7 @@ namespace Mindee.V1.Product.Us.PayrollCheckRegister /// The definition for Payroll Check Register, API version 1. /// [Endpoint("payroll_check_register", "1")] - public sealed class PayrollCheckRegisterV1 : Inference + public sealed class PayrollCheckRegisterV1 : ExtractionInference { } } diff --git a/src/Mindee/V2/Client.cs b/src/Mindee/V2/Client.cs index a8253eebd..3c336e50c 100644 --- a/src/Mindee/V2/Client.cs +++ b/src/Mindee/V2/Client.cs @@ -3,14 +3,13 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; -using Mindee.ClientOptions; using Mindee.Exceptions; using Mindee.Extensions.DependencyInjection; using Mindee.Input; using Mindee.V2.ClientOptions; using Mindee.V2.Http; using Mindee.V2.Parsing; -using Mindee.V2.Parsing.Search; +using Mindee.V2.Product; using Mindee.V2.Product.Extraction; using Mindee.V2.Product.Extraction.Params; using SettingsV2 = Mindee.V2.Http.Settings; @@ -96,7 +95,7 @@ public Client(HttpApiV2 httpApi, ILoggerFactory logger = null) /// /// /// - /// + /// /// /// /// @@ -105,7 +104,7 @@ public Client(HttpApiV2 httpApi, ILoggerFactory logger = null) /// public async Task EnqueueAsync( InputSource inputSource - , BaseParameters parameters) + , ExtractionParameters extractionParameters) { switch (inputSource) { @@ -121,7 +120,7 @@ InputSource inputSource throw new MindeeInputException($"Unsupported input source {inputSource.GetType().Name}"); } - return await _mindeeApi.ReqPostEnqueueAsync(inputSource, parameters); + return await _mindeeApi.ReqPostEnqueueAsync(inputSource, extractionParameters); } /// @@ -130,9 +129,9 @@ InputSource inputSource /// /// The URL to poll to retrieve the job. /// - /// + /// /// - public async Task GetJobFromUrlAsync(string pollingUrl) + public async Task GetJobAsync(string pollingUrl) { _logger?.LogInformation("Getting Job at: {}", pollingUrl); @@ -141,7 +140,7 @@ public async Task GetJobFromUrlAsync(string pollingUrl) throw new ArgumentNullException(pollingUrl); } - return await _mindeeApi.ReqGetJobFromUrlAsync(pollingUrl); + return await _mindeeApi.ReqGetJobAsync(pollingUrl); } /// @@ -152,8 +151,8 @@ public async Task GetJobFromUrlAsync(string pollingUrl) /// /// /// - private async Task GetResultFromUrlAsync(string pollingUrl) - where TResponse : BaseResponse, new() + public async Task> GetResultAsync(string pollingUrl) + where TProduct : BaseProduct, new() { _logger?.LogInformation("Polling: {}", pollingUrl); @@ -161,46 +160,34 @@ private async Task GetResultFromUrlAsync(string pollingUrl { throw new ArgumentNullException(pollingUrl); } - return await _mindeeApi.ReqGetResultFromUrlAsync(pollingUrl); - } - - /// - /// Get the status of an inference that was previously enqueued. - /// Can be used for polling. - /// - /// The job id. - /// - /// - /// - public async Task GetResultAsync(string jobId) - where TResponse : BaseResponse, new() - { - _logger?.LogInformation("Polling: {}", jobId); - - if (string.IsNullOrWhiteSpace(jobId)) - { - throw new ArgumentNullException(jobId); - } - return await _mindeeApi.ReqGetResultAsync(jobId); + return await _mindeeApi.ReqGetInferenceAsync(pollingUrl); } /// - /// Get the status of an inference that was previously enqueued. - /// Can be used for polling. + /// Add the document to an async queue, poll, and parse when complete. /// - /// The job id. + /// + /// + /// + /// + /// + /// + /// /// /// /// - public async Task GetJobAsync(string jobId) + /// + public async Task EnqueueAndGetInferenceAsync( + InputSource inputSource + , ExtractionParameters extractionParameters) { - _logger?.LogInformation("Getting job {}", jobId); - - if (string.IsNullOrWhiteSpace(jobId)) + var response = + await EnqueueAndGetResultAsync(inputSource, extractionParameters); + if (response is ExtractionResponse extractionResponse) { - throw new ArgumentNullException(jobId); + return extractionResponse; } - return await _mindeeApi.ReqGetJobAsync(jobId); + throw new MindeeException($"Unexpected response type '{response.GetType().Name}'."); } /// @@ -210,17 +197,17 @@ public async Task GetJobAsync(string jobId) /// /// /// - /// - /// + /// + /// /// /// /// /// /// - public async Task EnqueueAndGetResultAsync( + public async Task> EnqueueAndGetResultAsync( InputSource inputSource - , BaseParameters parameters) - where TResponse : BaseResponse, new() + , ExtractionParameters extractionParameters) + where TProduct : BaseProduct, new() { switch (inputSource) { @@ -236,12 +223,12 @@ InputSource inputSource throw new MindeeInputException($"Unsupported input source {inputSource.GetType().Name}"); } - parameters.PollingOptions ??= new PollingOptions(); + extractionParameters.PollingOptions ??= new PollingOptions(); var enqueueResponse = await EnqueueAsync( inputSource, - parameters); - return await PollForResultsAsync(enqueueResponse, parameters.PollingOptions); + extractionParameters); + return await PollForResultsAsync(enqueueResponse, extractionParameters.PollingOptions); } /// @@ -266,9 +253,9 @@ public async Task SearchModels(string name = null, string modelT /// /// /// Thrown when maxRetries is reached and the result isn't ready. - private async Task PollForResultsAsync( + private async Task> PollForResultsAsync( JobResponse enqueueResponse, - PollingOptions pollingOptions) where TResponse : BaseResponse, new() + PollingOptions pollingOptions) where TProduct : BaseProduct, new() { var maxRetries = pollingOptions.MaxRetries + 1; var pollingUrl = enqueueResponse.Job.PollingUrl; @@ -287,7 +274,7 @@ private async Task PollForResultsAsync( retryCount, maxRetries); - response = await GetJobFromUrlAsync(pollingUrl); + response = await GetJobAsync(pollingUrl); if (response.Job.Error != null) { break; @@ -296,7 +283,7 @@ private async Task PollForResultsAsync( if (response.Job.Status.Equals("Processed")) { var resultUrl = response.Job.ResultUrl; - return await GetResultFromUrlAsync(resultUrl); + return await GetResultAsync(resultUrl); } retryCount++; diff --git a/src/Mindee/V2/Http/HttpApiV2.cs b/src/Mindee/V2/Http/HttpApiV2.cs index 67bac16ea..663be5259 100644 --- a/src/Mindee/V2/Http/HttpApiV2.cs +++ b/src/Mindee/V2/Http/HttpApiV2.cs @@ -1,5 +1,6 @@ #nullable enable +using System; using System.Text.Json; using System.Threading.Tasks; using Microsoft.Extensions.Logging; @@ -7,7 +8,7 @@ using Mindee.Input; using Mindee.V2.ClientOptions; using Mindee.V2.Parsing; -using Mindee.V2.Parsing.Search; +using Mindee.V2.Product; namespace Mindee.V2.Http { @@ -41,33 +42,13 @@ public abstract class HttpApiV2 /// Get a job for an enqueued document. /// /// The job ID as returned by the predict_async route. - public abstract Task ReqGetJobFromUrlAsync(string pollingUrl); - - /// - /// Get a job for an enqueued document. - /// - /// The job ID as returned by the predict_async route. - public abstract Task ReqGetJobAsync(string jobId); - - /// - /// Get a document inference. - /// - /// Url to poll. - public abstract Task ReqGetResultAsync(string inferenceId) where TResponse : BaseResponse, new(); + public abstract Task ReqGetJobAsync(string pollingUrl); /// /// Get a document inference. /// /// Url to poll. - public abstract Task ReqGetResultFromUrlAsync(string resultUrl) where TResponse : BaseResponse, new(); - - /// - /// Retrieves a list of models available for a given API key. - /// - /// Name of the model to search for. - /// Type of the model to search for. - /// - public abstract Task SearchModels(string? name, string? modelType); + public abstract Task> ReqGetInferenceAsync(string resultUrl) where TProduct : BaseProduct, new(); /// /// Get the error from the server return. @@ -98,10 +79,11 @@ protected ErrorResponse GetErrorFromContent(int statusCode, string? responseCont /// Attempt to deserialize a response from the server. /// /// - /// + /// + /// /// - protected TResponse DeserializeResponse(string? responseContent) - where TResponse : BaseResponse, new() + protected CommonResponse DeserializeResponse(string? responseContent, Type responseType) + where TProduct : BaseProduct, new() { Logger?.LogInformation("Parsing HTTP 2xx response ..."); @@ -109,9 +91,9 @@ protected TResponse DeserializeResponse(string? responseContent) { throw new MindeeException("Empty response from server."); } - var deserializedResult = JsonSerializer.Deserialize(responseContent); + var deserializedResult = JsonSerializer.Deserialize(responseContent, responseType); - if (deserializedResult is BaseResponse model) + if (deserializedResult is CommonResponse model) { model.RawResponse = responseContent; return (TResponse)model; diff --git a/src/Mindee/V2/Http/MindeeApiV2.cs b/src/Mindee/V2/Http/MindeeApiV2.cs index 6db263d59..f7fd6cc44 100644 --- a/src/Mindee/V2/Http/MindeeApiV2.cs +++ b/src/Mindee/V2/Http/MindeeApiV2.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Reflection; using System.Text.Json; using System.Threading.Tasks; using Microsoft.Extensions.Logging; @@ -10,7 +9,6 @@ using Mindee.Input; using Mindee.V2.ClientOptions; using Mindee.V2.Parsing; -using Mindee.V2.Parsing.Search; using Mindee.V2.Product; using Mindee.V2.Product.Extraction.Params; using RestSharp; @@ -64,40 +62,10 @@ BaseParameters parameters return HandleJobResponse(response); } - public override async Task SearchModels(string name, string modelType) - { - var request = new RestRequest("v2/search/models"); - Logger?.LogInformation("Fetching models..."); - if (!string.IsNullOrWhiteSpace(name)) - { - Logger?.LogInformation("Models matching name like {Name}", name); - request.AddParameter("name", name); - } - - if (!string.IsNullOrWhiteSpace(modelType)) - { - Logger?.LogInformation("Models matching model_type={ModelType}", modelType); - request.AddParameter("model_type", modelType); - } - - var response = await _httpClient.ExecuteGetAsync(request); - return handleSearchResponse(response); - } - - public override async Task ReqGetJobAsync(string jobId) - { - var request = new RestRequest($"v2/jobs/{jobId}"); - Logger?.LogInformation("HTTP GET to {RequestResource}...", _baseUrl + request.Resource); - var response = await _httpClient.ExecuteGetAsync(request); - Logger?.LogDebug("HTTP response: {ResponseContent}", response.Content); - var handledResponse = HandleJobResponse(response); - return handledResponse; - } - - public override async Task ReqGetJobFromUrlAsync(string pollingUrl) + public override async Task ReqGetJobAsync(string pollingUrl) { var request = new RestRequest(new Uri(pollingUrl)); - Logger?.LogInformation("HTTP GET to {RequestResource}...", request.Resource); + Logger?.LogInformation("HTTP GET to {RequestResource}...", _baseUrl + request.Resource); var response = await _httpClient.ExecuteGetAsync(request); Logger?.LogDebug("HTTP response: {ResponseContent}", response.Content); var handledResponse = HandleJobResponse(response); @@ -105,24 +73,14 @@ public override async Task ReqGetJobFromUrlAsync(string pollingUrl) } - public override async Task ReqGetResultAsync(string inferenceId) - { - var slug = typeof(TResponse).GetCustomAttribute(); - var request = new RestRequest($"v2/products/{slug}/results/{inferenceId}"); - Logger?.LogInformation("HTTP GET to {RequestResource}...", request.Resource); - var queueResponse = await _httpClient.ExecuteGetAsync(request); - return HandleProductResponse(queueResponse); - } - - public override async Task ReqGetResultFromUrlAsync(string resultUrl) + public override async Task> ReqGetInferenceAsync(string resultUrl) { var request = new RestRequest(new Uri(resultUrl)); Logger?.LogInformation("HTTP GET to {RequestResource}...", resultUrl); var queueResponse = await _httpClient.ExecuteGetAsync(request); - return HandleProductResponse(queueResponse); + return HandleProductResponse(queueResponse); } - private static void AddPredictRequestParameters(InputSource inputSource, BaseParameters parameters, RestRequest request) { switch (inputSource) @@ -230,8 +188,8 @@ private JobResponse HandleJobResponse(RestResponse restResponse) return model ?? throw new MindeeException("Couldn't deserialize JobResponse."); } - private TResponse HandleProductResponse(RestResponse restResponse) - where TResponse : BaseResponse, new() + private CommonResponse HandleProductResponse(RestResponse restResponse) + where TProduct : BaseProduct, new() { Logger?.LogDebug("HTTP response: {RestResponseContent}", restResponse.Content); @@ -243,7 +201,9 @@ private TResponse HandleProductResponse(RestResponse restResponse) GetErrorFromContent((int)restResponse.StatusCode, restResponse.Content)); } - return DeserializeResponse(restResponse.Content); + var responseType = typeof(TProduct).GetProperty("ResponseType")?.GetValue(null) as Type + ?? typeof(CommonResponse); + return DeserializeResponse(restResponse.Content, responseType); } } diff --git a/src/Mindee/V2/Parsing/BaseResponse.cs b/src/Mindee/V2/Parsing/BaseResponse.cs index d232c8e23..a9057338e 100644 --- a/src/Mindee/V2/Parsing/BaseResponse.cs +++ b/src/Mindee/V2/Parsing/BaseResponse.cs @@ -1,14 +1,16 @@ +using System; +using Mindee.V2.Product; + namespace Mindee.V2.Parsing { /// /// Base class for all responses from the V2 API. /// - public abstract class BaseResponse + public abstract class CommonResponse : BaseResponse where TProduct : BaseProduct, new() { /// - /// The raw server response. - /// This is not formatted in any way by the library and may contain newline and tab characters. + /// Type of product returned by this response /// - public string RawResponse { get; set; } + public static Type ReturnType => typeof(TProduct); } } diff --git a/src/Mindee/V2/Parsing/Inference/BaseInference.cs b/src/Mindee/V2/Parsing/Inference/BaseInference.cs index a27dc9701..ef522f59c 100644 --- a/src/Mindee/V2/Parsing/Inference/BaseInference.cs +++ b/src/Mindee/V2/Parsing/Inference/BaseInference.cs @@ -1,14 +1,15 @@ using System; using System.Text; using System.Text.Json.Serialization; -using Mindee.Parsing; +using Mindee.V1.Parsing; +using Mindee.V2.Parsing; -namespace Mindee.V2.Parsing.Inference +namespace Mindee.V2.Product.Extraction { /// - /// Base for all inference-based V2 products. + /// ExtractionInference object for the V2 API. /// - public abstract class BaseInference + public class ExtractionInference { /// diff --git a/src/Mindee/V2/Parsing/LocalResponse.cs b/src/Mindee/V2/Parsing/LocalResponse.cs index fde34ca66..77c303593 100644 --- a/src/Mindee/V2/Parsing/LocalResponse.cs +++ b/src/Mindee/V2/Parsing/LocalResponse.cs @@ -25,8 +25,9 @@ public LocalResponse(FileInfo input) : base(input) /// Typically used when wanting to load a V2 webhook callback. /// /// - public TResponse DeserializeResponse() - where TResponse : BaseResponse, new() + public TResponse DeserializeResponse() + where TProduct : BaseProduct, new() + where TResponse : CommonResponse, new() { var model = JsonSerializer.Deserialize(FileBytes); diff --git a/src/Mindee/V2/Product/BaseProduct.cs b/src/Mindee/V2/Product/BaseProduct.cs new file mode 100644 index 000000000..c11777378 --- /dev/null +++ b/src/Mindee/V2/Product/BaseProduct.cs @@ -0,0 +1,25 @@ +using System; + +namespace Mindee.V2.Product +{ + /// + /// Base class for all V2 products. + /// + public abstract class BaseProduct + { + /// + /// Type of the product's response. + /// + public static Type ResponseType; + + /// + /// Retrieves the parameters class for the product. + /// + public static Type ParametersType; + + /// + /// Retrieves the slug of the product. + /// + public static string Slug; + } +} diff --git a/src/Mindee/V2/Product/Extraction/Extraction.cs b/src/Mindee/V2/Product/Extraction/Extraction.cs new file mode 100644 index 000000000..1aeb1858c --- /dev/null +++ b/src/Mindee/V2/Product/Extraction/Extraction.cs @@ -0,0 +1,26 @@ +using System; +using Mindee.V2.Product.Extraction.Params; + +namespace Mindee.V2.Product.Extraction +{ + /// + /// Automatically extract structured data from any image or scanned document. + /// + public class Extraction : BaseProduct + { + /// + /// Type of the product's response. + /// + public static new Type ResponseType => typeof(ExtractionResponse); + + /// + /// Retrieves the parameters class for the product. + /// + public static new Type ParametersType => typeof(ExtractionParameters); + + /// + /// Retrieves the slug of the product. + /// + public static new string Slug => "extraction"; + } +} diff --git a/src/Mindee/V2/Product/Extraction/ExtractionResponse.cs b/src/Mindee/V2/Product/Extraction/ExtractionResponse.cs index 4d1caa290..2982f3550 100644 --- a/src/Mindee/V2/Product/Extraction/ExtractionResponse.cs +++ b/src/Mindee/V2/Product/Extraction/ExtractionResponse.cs @@ -4,10 +4,9 @@ namespace Mindee.V2.Product.Extraction { /// - /// Response for an extraction inference. + /// Represent an extraction response from Mindee V2 API. /// - [ProductSlug("extraction")] - public class ExtractionResponse : BaseResponse + public class ExtractionResponse : CommonResponse { /// /// Contents of the inference. diff --git a/src/Mindee/V2/Product/Extraction/Params/ExtractionParameters.cs b/src/Mindee/V2/Product/Extraction/Params/ExtractionParameters.cs index d6d80deed..38916e9f8 100644 --- a/src/Mindee/V2/Product/Extraction/Params/ExtractionParameters.cs +++ b/src/Mindee/V2/Product/Extraction/Params/ExtractionParameters.cs @@ -8,7 +8,7 @@ namespace Mindee.V2.Product.Extraction.Params { /// - /// Parameters for an extraction inference. + /// ResultOptions to pass when calling methods using the predict API V2. /// public class ExtractionParameters : BaseParameters { @@ -51,7 +51,7 @@ public class ExtractionParameters : BaseParameters public sealed override string Slug { get; protected set; } /// - /// Extraction parameters to set when sending a file. + /// ExtractionInference parameters to set when sending a file. /// /// /// diff --git a/tests/Mindee.IntegrationTests/V1/ClientTest.cs b/tests/Mindee.IntegrationTests/V1/ClientTest.cs index 59a9be2c6..3196d79f8 100644 --- a/tests/Mindee.IntegrationTests/V1/ClientTest.cs +++ b/tests/Mindee.IntegrationTests/V1/ClientTest.cs @@ -1,4 +1,3 @@ -using Mindee.ClientOptions; using Mindee.Exceptions; using Mindee.Input; using Mindee.V1; diff --git a/tests/Mindee.IntegrationTests/V2/ClientTest.cs b/tests/Mindee.IntegrationTests/V2/ClientTest.cs index b56f1096b..f10dc5ae8 100644 --- a/tests/Mindee.IntegrationTests/V2/ClientTest.cs +++ b/tests/Mindee.IntegrationTests/V2/ClientTest.cs @@ -1,8 +1,7 @@ using Mindee.Exceptions; using Mindee.Input; using Mindee.V2; -using Mindee.V2.Parsing.Inference; -using Mindee.V2.Product.Extraction; +using Mindee.V2.Parsing; using Mindee.V2.Product.Extraction.Params; namespace Mindee.IntegrationTests.V2 @@ -227,7 +226,7 @@ public async Task NotFound_Job_MustThrowError() public async Task NotFound_Inference_MustThrowError() { var ex = await Assert.ThrowsAsync(() => - _client.GetJobAsync("fc405e37-4ba4-4d03-aeba-533a8d1f0f21")); + _client.GetResultAsync("fc405e37-4ba4-4d03-aeba-533a8d1f0f21")); Assert.Equal(404, ex.Status); Assert.StartsWith("404-", ex.Code); } @@ -241,7 +240,7 @@ public async Task Url_InputSource_MustNotRaiseErrors() var inputSource = new UrlInputSource(new Uri(url)); var inferenceParams = new ExtractionParameters(_findocModelId); - var response = await _client.EnqueueAndGetResultAsync(inputSource, inferenceParams); + var response = await _client.EnqueueAndGetInferenceAsync(inputSource, inferenceParams); Assert.NotNull(response); Assert.NotNull(response.Inference); diff --git a/tests/Mindee.UnitTests/V1/ClientTest.cs b/tests/Mindee.UnitTests/V1/ClientTest.cs index f21bea1a4..385d4f53a 100644 --- a/tests/Mindee.UnitTests/V1/ClientTest.cs +++ b/tests/Mindee.UnitTests/V1/ClientTest.cs @@ -1,6 +1,5 @@ using Microsoft.Extensions.Logging.Abstractions; using Mindee.Input; -using Mindee.Parsing; using Mindee.Pdf; using Mindee.V1; using Mindee.V1.Http; diff --git a/tests/Mindee.UnitTests/V1/Parsing/Common/FullTextOcrTest.cs b/tests/Mindee.UnitTests/V1/Parsing/Common/FullTextOcrTest.cs index 20c7d358f..d0064fc5b 100644 --- a/tests/Mindee.UnitTests/V1/Parsing/Common/FullTextOcrTest.cs +++ b/tests/Mindee.UnitTests/V1/Parsing/Common/FullTextOcrTest.cs @@ -9,7 +9,7 @@ public class FullTextOcrTest { private static readonly JsonSerializerOptions JsonOptions = new() { PropertyNameCaseInsensitive = true }; - private Inference LoadInference() + private ExtractionInference LoadInference() { var json = File.ReadAllText(Constants.V1RootDir + "extras/full_text_ocr/complete.json"); var prediction = JsonSerializer.Deserialize>(json, JsonOptions); diff --git a/tests/Mindee.UnitTests/V2/ClientTest.cs b/tests/Mindee.UnitTests/V2/ClientTest.cs index c5a3c40ec..39c6b88b2 100644 --- a/tests/Mindee.UnitTests/V2/ClientTest.cs +++ b/tests/Mindee.UnitTests/V2/ClientTest.cs @@ -1,5 +1,4 @@ using Mindee.Input; -using Mindee.Parsing; using Mindee.V2; using Mindee.V2.Http; using Mindee.V2.Parsing; @@ -18,7 +17,7 @@ private Client MakeCustomMindeeClientV2(Mock predictable) predictable.Setup(x => x.ReqPostEnqueueAsync(It.IsAny(), It.IsAny()) ).ReturnsAsync(new JobResponse()); - predictable.Setup(x => x.ReqGetResultAsync(It.IsAny()) + predictable.Setup(x => x.ReqGetInferenceAsync(It.IsAny()) ).ReturnsAsync(new ExtractionResponse()); predictable.Setup(x => x.ReqGetJobAsync(It.IsAny()) @@ -52,11 +51,11 @@ public async Task Document_GetInference_Async() { var predictable = new Mock(); var mindeeClient = MakeCustomMindeeClientV2(predictable); - var response = await mindeeClient.GetResultAsync("dummy-id"); + var response = await mindeeClient.GetResultAsync("dummy-id"); Assert.NotNull(response); predictable.Verify( - p => p.ReqGetResultAsync(It.IsAny()), + p => p.ReqGetInferenceAsync(It.IsAny()), Times.AtMostOnce()); } @@ -78,7 +77,7 @@ public void Inference_LoadsLocally() { var localResponse = new LocalResponse( new FileInfo(Constants.V2RootDir + "products/extraction/financial_document/complete.json")); - ExtractionResponse locallyLoadedResponse = localResponse.DeserializeResponse(); + ExtractionResponse locallyLoadedResponse = localResponse.DeserializeResponse(); Assert.NotNull(locallyLoadedResponse); Assert.Equal("12345678-1234-1234-1234-123456789abc", locallyLoadedResponse.Inference.Model.Id); Assert.Equal("John Smith", diff --git a/tests/Mindee.UnitTests/V2/Input/LocalResponseTest.cs b/tests/Mindee.UnitTests/V2/Input/LocalResponseTest.cs index 1de635b28..1c1ce67ea 100644 --- a/tests/Mindee.UnitTests/V2/Input/LocalResponseTest.cs +++ b/tests/Mindee.UnitTests/V2/Input/LocalResponseTest.cs @@ -22,9 +22,9 @@ private static void AssertLocalResponse(LocalResponse localResponse) Assert.Equal(signature, localResponse.GetHmacSignature(secretKey)); Assert.True(localResponse.IsValidHmacSignature( secretKey, signature)); - ExtractionResponse extractionResponse = localResponse.DeserializeResponse(); - Assert.NotNull(extractionResponse); - Assert.NotNull(extractionResponse.Inference); + ExtractionResponse inferenceResponse = localResponse.DeserializeResponse(); + Assert.NotNull(inferenceResponse); + Assert.NotNull(inferenceResponse.Inference); } [Fact] diff --git a/tests/Mindee.UnitTests/V2/Product/ExtractionTest.cs b/tests/Mindee.UnitTests/V2/Product/ExtractionTest.cs index 0dd5b31b8..0b35c7c56 100644 --- a/tests/Mindee.UnitTests/V2/Product/ExtractionTest.cs +++ b/tests/Mindee.UnitTests/V2/Product/ExtractionTest.cs @@ -7,7 +7,7 @@ namespace Mindee.UnitTests.V2.Product { [Trait("Category", "V2")] [Trait("Category", "ExtractionInference")] - public class ExtractionTest + public class ExtractionInferenceTest { [Fact] public void FinancialDocument_WhenEmpty_MustHaveValidProperties() @@ -382,8 +382,8 @@ private static string NormalizeLineEndings(string input) private static ExtractionResponse GetInference(string path) { var localResponse = new LocalResponse( - File.ReadAllText(Constants.V2ProductDir + path)); - return localResponse.DeserializeResponse(); + File.ReadAllText(Constants.V2RootDir + path)); + return localResponse.DeserializeResponse(); } private void AssertInferenceResponse(ExtractionResponse response) From 9cc2f078bb576da140c90ad0059637f79a2fce83 Mon Sep 17 00:00:00 2001 From: sebastianMindee <130448732+sebastianMindee@users.noreply.github.com> Date: Mon, 23 Feb 2026 17:41:38 +0100 Subject: [PATCH 03/33] :sparkles: add crop & job info for products --- .../V2/Parsing/Inference/BaseInference.cs | 14 ++++--------- src/Mindee/V2/Product/Crop/Crop.cs | 16 +++++++++++++++ src/Mindee/V2/Product/Crop/CropResponse.cs | 3 +-- .../V2/Product/Crop/Params/CropParameters.cs | 4 ++-- .../V2/Product/Extraction/Extraction.cs | 11 ---------- .../V2/Product/Extraction/ExtractionResult.cs | 1 + .../Extraction/Params/ExtractionParameters.cs | 2 +- tests/Mindee.UnitTests/V2/Product/CropTest.cs | 20 +++++++++++++------ .../V2/Product/ExtractionTest.cs | 2 +- 9 files changed, 40 insertions(+), 33 deletions(-) create mode 100644 src/Mindee/V2/Product/Crop/Crop.cs diff --git a/src/Mindee/V2/Parsing/Inference/BaseInference.cs b/src/Mindee/V2/Parsing/Inference/BaseInference.cs index ef522f59c..6472a13fc 100644 --- a/src/Mindee/V2/Parsing/Inference/BaseInference.cs +++ b/src/Mindee/V2/Parsing/Inference/BaseInference.cs @@ -1,15 +1,14 @@ -using System; using System.Text; using System.Text.Json.Serialization; +using Mindee.Parsing; using Mindee.V1.Parsing; -using Mindee.V2.Parsing; -namespace Mindee.V2.Product.Extraction +namespace Mindee.V2.Parsing { /// - /// ExtractionInference object for the V2 API. + /// Base for all inference-based V2 products. /// - public class ExtractionInference + public abstract class BaseInference { /// @@ -36,11 +35,6 @@ public class ExtractionInference [JsonPropertyName("job")] public InferenceJob Job { get; set; } - /// - /// Type of the product's response. - /// - public virtual Type ResponseType { get; set; } - /// /// /// diff --git a/src/Mindee/V2/Product/Crop/Crop.cs b/src/Mindee/V2/Product/Crop/Crop.cs new file mode 100644 index 000000000..c80878235 --- /dev/null +++ b/src/Mindee/V2/Product/Crop/Crop.cs @@ -0,0 +1,16 @@ +using System; +using Mindee.V2.Product.Crop; + +namespace Mindee.V2.Product.Crop +{ + /// + /// Send a file to the asynchronous processing queue for a crop utility inference. + /// + public class Crop : BaseProduct + { + /// + /// Type of the product's response. + /// + public static new Type ResponseType => typeof(CropResponse); + } +} diff --git a/src/Mindee/V2/Product/Crop/CropResponse.cs b/src/Mindee/V2/Product/Crop/CropResponse.cs index 4f422efa7..f9221156a 100644 --- a/src/Mindee/V2/Product/Crop/CropResponse.cs +++ b/src/Mindee/V2/Product/Crop/CropResponse.cs @@ -6,8 +6,7 @@ namespace Mindee.V2.Product.Crop /// /// Represent a crop response from Mindee V2 API. /// - [ProductSlug("crop")] - public class CropResponse : BaseResponse + public class CropResponse : CommonResponse { /// /// Contents of the inference. diff --git a/src/Mindee/V2/Product/Crop/Params/CropParameters.cs b/src/Mindee/V2/Product/Crop/Params/CropParameters.cs index a48d3c412..8f63a8e4e 100644 --- a/src/Mindee/V2/Product/Crop/Params/CropParameters.cs +++ b/src/Mindee/V2/Product/Crop/Params/CropParameters.cs @@ -9,7 +9,7 @@ namespace Mindee.V2.Product.Crop.Params public class CropParameters : BaseParameters { /// - /// Slug for the crop product. + /// Slug for the extraction product. /// public sealed override string Slug { get; protected set; } @@ -22,7 +22,7 @@ public class CropParameters : BaseParameters /// public CropParameters( string modelId, - string alias = null, + string alias, List webhookIds = null, PollingOptions pollingOptions = null) : base(modelId, alias, webhookIds, pollingOptions) { diff --git a/src/Mindee/V2/Product/Extraction/Extraction.cs b/src/Mindee/V2/Product/Extraction/Extraction.cs index 1aeb1858c..27d08a03a 100644 --- a/src/Mindee/V2/Product/Extraction/Extraction.cs +++ b/src/Mindee/V2/Product/Extraction/Extraction.cs @@ -1,5 +1,4 @@ using System; -using Mindee.V2.Product.Extraction.Params; namespace Mindee.V2.Product.Extraction { @@ -12,15 +11,5 @@ public class Extraction : BaseProduct /// Type of the product's response. /// public static new Type ResponseType => typeof(ExtractionResponse); - - /// - /// Retrieves the parameters class for the product. - /// - public static new Type ParametersType => typeof(ExtractionParameters); - - /// - /// Retrieves the slug of the product. - /// - public static new string Slug => "extraction"; } } diff --git a/src/Mindee/V2/Product/Extraction/ExtractionResult.cs b/src/Mindee/V2/Product/Extraction/ExtractionResult.cs index 032a36cc4..003278d5f 100644 --- a/src/Mindee/V2/Product/Extraction/ExtractionResult.cs +++ b/src/Mindee/V2/Product/Extraction/ExtractionResult.cs @@ -1,6 +1,7 @@ using System.Text; using System.Text.Json.Serialization; using Mindee.Parsing; +using Mindee.V1.Parsing; using Mindee.V2.Parsing; using Mindee.V2.Parsing.Inference; using Mindee.V2.Parsing.Inference.Field; diff --git a/src/Mindee/V2/Product/Extraction/Params/ExtractionParameters.cs b/src/Mindee/V2/Product/Extraction/Params/ExtractionParameters.cs index 38916e9f8..fa8ff70c0 100644 --- a/src/Mindee/V2/Product/Extraction/Params/ExtractionParameters.cs +++ b/src/Mindee/V2/Product/Extraction/Params/ExtractionParameters.cs @@ -51,7 +51,7 @@ public class ExtractionParameters : BaseParameters public sealed override string Slug { get; protected set; } /// - /// ExtractionInference parameters to set when sending a file. + /// Extraction parameters to set when sending a file. /// /// /// diff --git a/tests/Mindee.UnitTests/V2/Product/CropTest.cs b/tests/Mindee.UnitTests/V2/Product/CropTest.cs index fada340a2..e0aedb751 100644 --- a/tests/Mindee.UnitTests/V2/Product/CropTest.cs +++ b/tests/Mindee.UnitTests/V2/Product/CropTest.cs @@ -11,19 +11,22 @@ public class CropTest [Fact] public void Crop_WhenSingle_MustHaveValidProperties() { - var response = GetInference("crop/crop_single.json"); + var response = GetInference("products/crop/crop_single.json"); AssertInferenceResponse(response); var inference = response.Inference; + // Validate inference metadata Assert.Equal("12345678-1234-1234-1234-123456789abc", inference.Id); Assert.Equal("test-model-id", inference.Model.Id); Assert.Equal("12345678-1234-1234-1234-jobid1234567", inference.Job.Id); + // Validate file metadata Assert.Equal("sample.jpeg", inference.File.Name); Assert.Equal(1, inference.File.PageCount); Assert.Equal("image/jpeg", inference.File.MimeType); + // Validate crops var crops = inference.Result.Crops; Assert.NotNull(crops); Assert.Single(crops); @@ -43,7 +46,7 @@ public void Crop_WhenSingle_MustHaveValidProperties() [Fact] public void Crop_WhenMultiple_MustHaveValidProperties() { - var response = GetInference("crop/crop_multiple.json"); + var response = GetInference("products/crop/crop_multiple.json"); AssertInferenceResponse(response); var inference = response.Inference; @@ -51,9 +54,11 @@ public void Crop_WhenMultiple_MustHaveValidProperties() var job = inference.Job; Assert.Equal("12345678-1234-1234-1234-jobid1234567", job.Id); + // Validate inference metadata Assert.Equal("12345678-1234-1234-1234-123456789abc", inference.Id); Assert.Equal("test-model-id", inference.Model.Id); + // Validate file metadata Assert.Equal("default_sample.jpg", inference.File.Name); Assert.Equal(1, inference.File.PageCount); Assert.Equal("image/jpeg", inference.File.MimeType); @@ -62,6 +67,7 @@ public void Crop_WhenMultiple_MustHaveValidProperties() Assert.NotNull(crops); Assert.Equal(2, crops.Count); + // Validate first crop item var firstCrop = crops[0]; Assert.Equal("invoice", firstCrop.ObjectType); Assert.Equal(0, firstCrop.Location.Page); @@ -73,6 +79,7 @@ public void Crop_WhenMultiple_MustHaveValidProperties() Assert.Equal(new Point(0.476, 0.979), firstPolygon[2]); Assert.Equal(new Point(0.214, 0.979), firstPolygon[3]); + // Validate second crop item var secondCrop = crops[1]; Assert.Equal("invoice", secondCrop.ObjectType); Assert.Equal(0, secondCrop.Location.Page); @@ -88,9 +95,10 @@ public void Crop_WhenMultiple_MustHaveValidProperties() [Fact(DisplayName = "crop_single.rst – RST display must be parsed and exposed")] public void RstDisplay_MustBeAccessible() { - var resp = GetInference("crop/crop_single.json"); + // Arrange + var resp = GetInference("products/crop/crop_single.json"); var rstReference = File.ReadAllText( - Constants.V2ProductDir + "crop/crop_single.rst"); + Constants.V2RootDir + "products/crop/crop_single.rst"); var inf = resp.Inference; @@ -114,8 +122,8 @@ private static string NormalizeLineEndings(string input) private static CropResponse GetInference(string path) { var localResponse = new LocalResponse( - File.ReadAllText(Constants.V2ProductDir + path)); - return localResponse.DeserializeResponse(); + File.ReadAllText(Constants.V2RootDir + path)); + return localResponse.DeserializeResponse(); } private void AssertInferenceResponse(CropResponse response) diff --git a/tests/Mindee.UnitTests/V2/Product/ExtractionTest.cs b/tests/Mindee.UnitTests/V2/Product/ExtractionTest.cs index 0b35c7c56..139274064 100644 --- a/tests/Mindee.UnitTests/V2/Product/ExtractionTest.cs +++ b/tests/Mindee.UnitTests/V2/Product/ExtractionTest.cs @@ -7,7 +7,7 @@ namespace Mindee.UnitTests.V2.Product { [Trait("Category", "V2")] [Trait("Category", "ExtractionInference")] - public class ExtractionInferenceTest + public class ExtractionTest { [Fact] public void FinancialDocument_WhenEmpty_MustHaveValidProperties() From dcdbc9d07b272580477abc3d4f13d7fff017f725 Mon Sep 17 00:00:00 2001 From: sebastianMindee <130448732+sebastianMindee@users.noreply.github.com> Date: Mon, 23 Feb 2026 19:00:45 +0100 Subject: [PATCH 04/33] :recycle: completely rehaul system to preserve types --- src/Mindee.Cli/Commands/V1/PredictCommand.cs | 2 +- .../{ExtractionInference.cs => Inference.cs} | 2 +- .../Product/BarcodeReader/BarcodeReaderV1.cs | 2 +- src/Mindee/V1/Product/Cropper/CropperV1.cs | 2 +- .../FinancialDocument/FinancialDocumentV1.cs | 2 +- .../BankAccountDetailsV1.cs | 2 +- .../BankAccountDetailsV2.cs | 2 +- .../V1/Product/Fr/CarteGrise/CarteGriseV1.cs | 2 +- .../V1/Product/Fr/HealthCard/HealthCardV1.cs | 2 +- src/Mindee/V1/Product/Fr/IdCard/IdCardV1.cs | 2 +- src/Mindee/V1/Product/Fr/IdCard/IdCardV2.cs | 2 +- src/Mindee/V1/Product/Fr/Payslip/PayslipV3.cs | 2 +- .../V1/Product/Generated/GeneratedV1.cs | 2 +- .../InternationalId/InternationalIdV2.cs | 2 +- src/Mindee/V1/Product/Invoice/InvoiceV4.cs | 2 +- .../InvoiceSplitter/InvoiceSplitterV1.cs | 2 +- .../MultiReceiptsDetectorV1.cs | 2 +- src/Mindee/V1/Product/Passport/PassportV1.cs | 2 +- src/Mindee/V1/Product/Receipt/ReceiptV4.cs | 2 +- src/Mindee/V1/Product/Receipt/ReceiptV5.cs | 2 +- .../V1/Product/Us/BankCheck/BankCheckV1.cs | 2 +- .../PayrollCheckRegisterV1.cs | 2 +- src/Mindee/V2/Client.cs | 80 +++++++++++++------ src/Mindee/V2/Http/HttpApiV2.cs | 29 ++++--- src/Mindee/V2/Http/MindeeApiV2.cs | 38 ++++++--- .../V2/Parsing/Inference/BaseInference.cs | 7 +- src/Mindee/V2/Parsing/LocalResponse.cs | 5 +- src/Mindee/V2/Product/BaseProduct.cs | 25 ------ src/Mindee/V2/Product/Crop/Crop.cs | 16 ---- src/Mindee/V2/Product/Crop/CropInference.cs | 6 ++ src/Mindee/V2/Product/Crop/CropResponse.cs | 3 +- .../V2/Product/Crop/Params/CropParameters.cs | 2 +- .../V2/Product/Extraction/Extraction.cs | 15 ---- .../Product/Extraction/ExtractionInference.cs | 5 ++ .../Product/Extraction/ExtractionResponse.cs | 3 +- .../Mindee.IntegrationTests/V2/ClientTest.cs | 3 +- .../V2/Product/CropTest.cs | 14 ++-- .../V2/Product/ExtractionTest.cs | 39 --------- .../V1/Parsing/Common/FullTextOcrTest.cs | 2 +- tests/Mindee.UnitTests/V2/ClientTest.cs | 8 +- .../V2/Input/LocalResponseTest.cs | 2 +- tests/Mindee.UnitTests/V2/Product/CropTest.cs | 2 +- .../V2/Product/ExtractionTest.cs | 2 +- 43 files changed, 165 insertions(+), 185 deletions(-) rename src/Mindee/V1/Parsing/Common/{ExtractionInference.cs => Inference.cs} (97%) delete mode 100644 src/Mindee/V2/Product/BaseProduct.cs delete mode 100644 src/Mindee/V2/Product/Crop/Crop.cs delete mode 100644 src/Mindee/V2/Product/Extraction/Extraction.cs diff --git a/src/Mindee.Cli/Commands/V1/PredictCommand.cs b/src/Mindee.Cli/Commands/V1/PredictCommand.cs index 46b010b4b..790b5831a 100644 --- a/src/Mindee.Cli/Commands/V1/PredictCommand.cs +++ b/src/Mindee.Cli/Commands/V1/PredictCommand.cs @@ -30,7 +30,7 @@ internal struct ParseOptions(string path, bool allWords, bool fullText, OutputTy class PredictCommand : Command where TDoc : IPrediction, new() where TPage : IPrediction, new() - where TInferenceModel : ExtractionInference, new() + where TInferenceModel : Inference, new() { private readonly Option _outputOption; private readonly Option? _allWordsOption; diff --git a/src/Mindee/V1/Parsing/Common/ExtractionInference.cs b/src/Mindee/V1/Parsing/Common/Inference.cs similarity index 97% rename from src/Mindee/V1/Parsing/Common/ExtractionInference.cs rename to src/Mindee/V1/Parsing/Common/Inference.cs index 4f20632d2..0216e8cd6 100644 --- a/src/Mindee/V1/Parsing/Common/ExtractionInference.cs +++ b/src/Mindee/V1/Parsing/Common/Inference.cs @@ -10,7 +10,7 @@ namespace Mindee.V1.Parsing.Common /// /// Page prediction (could be the same that TDocumentPrediction). /// Document prediction (could be the same that TPagePrediction). - public abstract class ExtractionInference + public abstract class Inference where TPagePrediction : IPrediction, new() where TDocumentPrediction : IPrediction, new() { diff --git a/src/Mindee/V1/Product/BarcodeReader/BarcodeReaderV1.cs b/src/Mindee/V1/Product/BarcodeReader/BarcodeReaderV1.cs index 23621e7ad..cc306a0b0 100644 --- a/src/Mindee/V1/Product/BarcodeReader/BarcodeReaderV1.cs +++ b/src/Mindee/V1/Product/BarcodeReader/BarcodeReaderV1.cs @@ -8,7 +8,7 @@ namespace Mindee.V1.Product.BarcodeReader /// Barcode Reader API version 1 inference prediction. /// [Endpoint("barcode_reader", "1")] - public sealed class BarcodeReaderV1 : ExtractionInference + public sealed class BarcodeReaderV1 : Inference { /// /// The pages and the associated values which were detected on the document. diff --git a/src/Mindee/V1/Product/Cropper/CropperV1.cs b/src/Mindee/V1/Product/Cropper/CropperV1.cs index a8e4bb222..6784b9929 100644 --- a/src/Mindee/V1/Product/Cropper/CropperV1.cs +++ b/src/Mindee/V1/Product/Cropper/CropperV1.cs @@ -8,7 +8,7 @@ namespace Mindee.V1.Product.Cropper /// Cropper API version 1 inference prediction. /// [Endpoint("cropper", "1")] - public sealed class CropperV1 : ExtractionInference + public sealed class CropperV1 : Inference { /// /// The pages and the associated values which were detected on the document. diff --git a/src/Mindee/V1/Product/FinancialDocument/FinancialDocumentV1.cs b/src/Mindee/V1/Product/FinancialDocument/FinancialDocumentV1.cs index be290470b..55c9739e2 100644 --- a/src/Mindee/V1/Product/FinancialDocument/FinancialDocumentV1.cs +++ b/src/Mindee/V1/Product/FinancialDocument/FinancialDocumentV1.cs @@ -8,7 +8,7 @@ namespace Mindee.V1.Product.FinancialDocument /// Financial Document API version 1 inference prediction. /// [Endpoint("financial_document", "1")] - public sealed class FinancialDocumentV1 : ExtractionInference + public sealed class FinancialDocumentV1 : Inference { /// /// The pages and the associated values which were detected on the document. diff --git a/src/Mindee/V1/Product/Fr/BankAccountDetails/BankAccountDetailsV1.cs b/src/Mindee/V1/Product/Fr/BankAccountDetails/BankAccountDetailsV1.cs index 4d923bebf..fc8f4f836 100644 --- a/src/Mindee/V1/Product/Fr/BankAccountDetails/BankAccountDetailsV1.cs +++ b/src/Mindee/V1/Product/Fr/BankAccountDetails/BankAccountDetailsV1.cs @@ -8,7 +8,7 @@ namespace Mindee.V1.Product.Fr.BankAccountDetails /// Bank Account Details API version 1 inference prediction. /// [Endpoint("bank_account_details", "1")] - public sealed class BankAccountDetailsV1 : ExtractionInference + public sealed class BankAccountDetailsV1 : Inference { /// /// The pages and the associated values which were detected on the document. diff --git a/src/Mindee/V1/Product/Fr/BankAccountDetails/BankAccountDetailsV2.cs b/src/Mindee/V1/Product/Fr/BankAccountDetails/BankAccountDetailsV2.cs index 66cefe3c8..f3af6459d 100644 --- a/src/Mindee/V1/Product/Fr/BankAccountDetails/BankAccountDetailsV2.cs +++ b/src/Mindee/V1/Product/Fr/BankAccountDetails/BankAccountDetailsV2.cs @@ -8,7 +8,7 @@ namespace Mindee.V1.Product.Fr.BankAccountDetails /// Bank Account Details API version 2 inference prediction. /// [Endpoint("bank_account_details", "2")] - public sealed class BankAccountDetailsV2 : ExtractionInference + public sealed class BankAccountDetailsV2 : Inference { /// /// The pages and the associated values which were detected on the document. diff --git a/src/Mindee/V1/Product/Fr/CarteGrise/CarteGriseV1.cs b/src/Mindee/V1/Product/Fr/CarteGrise/CarteGriseV1.cs index 9539ee0d1..9f210fc60 100644 --- a/src/Mindee/V1/Product/Fr/CarteGrise/CarteGriseV1.cs +++ b/src/Mindee/V1/Product/Fr/CarteGrise/CarteGriseV1.cs @@ -8,7 +8,7 @@ namespace Mindee.V1.Product.Fr.CarteGrise /// Carte Grise API version 1 inference prediction. /// [Endpoint("carte_grise", "1")] - public sealed class CarteGriseV1 : ExtractionInference + public sealed class CarteGriseV1 : Inference { /// /// The pages and the associated values which were detected on the document. diff --git a/src/Mindee/V1/Product/Fr/HealthCard/HealthCardV1.cs b/src/Mindee/V1/Product/Fr/HealthCard/HealthCardV1.cs index dd01c8e5f..563d12418 100644 --- a/src/Mindee/V1/Product/Fr/HealthCard/HealthCardV1.cs +++ b/src/Mindee/V1/Product/Fr/HealthCard/HealthCardV1.cs @@ -8,7 +8,7 @@ namespace Mindee.V1.Product.Fr.HealthCard /// Health Card API version 1 inference prediction. /// [Endpoint("french_healthcard", "1")] - public sealed class HealthCardV1 : ExtractionInference + public sealed class HealthCardV1 : Inference { /// /// The pages and the associated values which were detected on the document. diff --git a/src/Mindee/V1/Product/Fr/IdCard/IdCardV1.cs b/src/Mindee/V1/Product/Fr/IdCard/IdCardV1.cs index db3b878a7..c51fb62c6 100644 --- a/src/Mindee/V1/Product/Fr/IdCard/IdCardV1.cs +++ b/src/Mindee/V1/Product/Fr/IdCard/IdCardV1.cs @@ -8,7 +8,7 @@ namespace Mindee.V1.Product.Fr.IdCard /// Carte Nationale d'Identité API version 1 inference prediction. /// [Endpoint("idcard_fr", "1")] - public sealed class IdCardV1 : ExtractionInference + public sealed class IdCardV1 : Inference { /// /// The pages and the associated values which were detected on the document. diff --git a/src/Mindee/V1/Product/Fr/IdCard/IdCardV2.cs b/src/Mindee/V1/Product/Fr/IdCard/IdCardV2.cs index 8581605d6..005b812fb 100644 --- a/src/Mindee/V1/Product/Fr/IdCard/IdCardV2.cs +++ b/src/Mindee/V1/Product/Fr/IdCard/IdCardV2.cs @@ -8,7 +8,7 @@ namespace Mindee.V1.Product.Fr.IdCard /// Carte Nationale d'Identité API version 2 inference prediction. /// [Endpoint("idcard_fr", "2")] - public sealed class IdCardV2 : ExtractionInference + public sealed class IdCardV2 : Inference { /// /// The pages and the associated values which were detected on the document. diff --git a/src/Mindee/V1/Product/Fr/Payslip/PayslipV3.cs b/src/Mindee/V1/Product/Fr/Payslip/PayslipV3.cs index 8f71e6db0..daf742794 100644 --- a/src/Mindee/V1/Product/Fr/Payslip/PayslipV3.cs +++ b/src/Mindee/V1/Product/Fr/Payslip/PayslipV3.cs @@ -8,7 +8,7 @@ namespace Mindee.V1.Product.Fr.Payslip /// Payslip API version 3 inference prediction. /// [Endpoint("payslip_fra", "3")] - public sealed class PayslipV3 : ExtractionInference + public sealed class PayslipV3 : Inference { /// /// The pages and the associated values which were detected on the document. diff --git a/src/Mindee/V1/Product/Generated/GeneratedV1.cs b/src/Mindee/V1/Product/Generated/GeneratedV1.cs index 28bfd3514..881228f96 100644 --- a/src/Mindee/V1/Product/Generated/GeneratedV1.cs +++ b/src/Mindee/V1/Product/Generated/GeneratedV1.cs @@ -5,7 +5,7 @@ namespace Mindee.V1.Product.Generated /// /// The definition for Generated Documents, API version 1. /// - public class GeneratedV1 : ExtractionInference + public class GeneratedV1 : Inference { } diff --git a/src/Mindee/V1/Product/InternationalId/InternationalIdV2.cs b/src/Mindee/V1/Product/InternationalId/InternationalIdV2.cs index b8be8350b..e1dfb44b0 100644 --- a/src/Mindee/V1/Product/InternationalId/InternationalIdV2.cs +++ b/src/Mindee/V1/Product/InternationalId/InternationalIdV2.cs @@ -8,7 +8,7 @@ namespace Mindee.V1.Product.InternationalId /// International ID API version 2 inference prediction. /// [Endpoint("international_id", "2")] - public sealed class InternationalIdV2 : ExtractionInference + public sealed class InternationalIdV2 : Inference { /// /// The pages and the associated values which were detected on the document. diff --git a/src/Mindee/V1/Product/Invoice/InvoiceV4.cs b/src/Mindee/V1/Product/Invoice/InvoiceV4.cs index 9e5601325..5a7d009be 100644 --- a/src/Mindee/V1/Product/Invoice/InvoiceV4.cs +++ b/src/Mindee/V1/Product/Invoice/InvoiceV4.cs @@ -8,7 +8,7 @@ namespace Mindee.V1.Product.Invoice /// Invoice API version 4 inference prediction. /// [Endpoint("invoices", "4")] - public sealed class InvoiceV4 : ExtractionInference + public sealed class InvoiceV4 : Inference { /// /// The pages and the associated values which were detected on the document. diff --git a/src/Mindee/V1/Product/InvoiceSplitter/InvoiceSplitterV1.cs b/src/Mindee/V1/Product/InvoiceSplitter/InvoiceSplitterV1.cs index 35e334a63..f1c200613 100644 --- a/src/Mindee/V1/Product/InvoiceSplitter/InvoiceSplitterV1.cs +++ b/src/Mindee/V1/Product/InvoiceSplitter/InvoiceSplitterV1.cs @@ -8,7 +8,7 @@ namespace Mindee.V1.Product.InvoiceSplitter /// Invoice Splitter API version 1 inference prediction. /// [Endpoint("invoice_splitter", "1")] - public sealed class InvoiceSplitterV1 : ExtractionInference + public sealed class InvoiceSplitterV1 : Inference { /// /// The pages and the associated values which were detected on the document. diff --git a/src/Mindee/V1/Product/MultiReceiptsDetector/MultiReceiptsDetectorV1.cs b/src/Mindee/V1/Product/MultiReceiptsDetector/MultiReceiptsDetectorV1.cs index 1ef706889..f54d5168b 100644 --- a/src/Mindee/V1/Product/MultiReceiptsDetector/MultiReceiptsDetectorV1.cs +++ b/src/Mindee/V1/Product/MultiReceiptsDetector/MultiReceiptsDetectorV1.cs @@ -8,7 +8,7 @@ namespace Mindee.V1.Product.MultiReceiptsDetector /// Multi Receipts Detector API version 1 inference prediction. /// [Endpoint("multi_receipts_detector", "1")] - public sealed class MultiReceiptsDetectorV1 : ExtractionInference + public sealed class MultiReceiptsDetectorV1 : Inference { /// /// The pages and the associated values which were detected on the document. diff --git a/src/Mindee/V1/Product/Passport/PassportV1.cs b/src/Mindee/V1/Product/Passport/PassportV1.cs index a952ae316..dfcb8031e 100644 --- a/src/Mindee/V1/Product/Passport/PassportV1.cs +++ b/src/Mindee/V1/Product/Passport/PassportV1.cs @@ -8,7 +8,7 @@ namespace Mindee.V1.Product.Passport /// Passport API version 1 inference prediction. /// [Endpoint("passport", "1")] - public sealed class PassportV1 : ExtractionInference + public sealed class PassportV1 : Inference { /// /// The pages and the associated values which were detected on the document. diff --git a/src/Mindee/V1/Product/Receipt/ReceiptV4.cs b/src/Mindee/V1/Product/Receipt/ReceiptV4.cs index 23b0df32e..9fe7ad7ea 100644 --- a/src/Mindee/V1/Product/Receipt/ReceiptV4.cs +++ b/src/Mindee/V1/Product/Receipt/ReceiptV4.cs @@ -7,7 +7,7 @@ namespace Mindee.V1.Product.Receipt /// The definition for Receipt, API version 4. /// [Endpoint("expense_receipts", "4")] - public sealed class ReceiptV4 : ExtractionInference + public sealed class ReceiptV4 : Inference { } } diff --git a/src/Mindee/V1/Product/Receipt/ReceiptV5.cs b/src/Mindee/V1/Product/Receipt/ReceiptV5.cs index 07504bf93..f5f23e056 100644 --- a/src/Mindee/V1/Product/Receipt/ReceiptV5.cs +++ b/src/Mindee/V1/Product/Receipt/ReceiptV5.cs @@ -8,7 +8,7 @@ namespace Mindee.V1.Product.Receipt /// Receipt API version 5 inference prediction. /// [Endpoint("expense_receipts", "5")] - public sealed class ReceiptV5 : ExtractionInference + public sealed class ReceiptV5 : Inference { /// /// The pages and the associated values which were detected on the document. diff --git a/src/Mindee/V1/Product/Us/BankCheck/BankCheckV1.cs b/src/Mindee/V1/Product/Us/BankCheck/BankCheckV1.cs index d509bfe38..e83b95fbb 100644 --- a/src/Mindee/V1/Product/Us/BankCheck/BankCheckV1.cs +++ b/src/Mindee/V1/Product/Us/BankCheck/BankCheckV1.cs @@ -8,7 +8,7 @@ namespace Mindee.V1.Product.Us.BankCheck /// Bank Check API version 1 inference prediction. /// [Endpoint("bank_check", "1")] - public sealed class BankCheckV1 : ExtractionInference + public sealed class BankCheckV1 : Inference { /// /// The pages and the associated values which were detected on the document. diff --git a/src/Mindee/V1/Product/Us/PayrollCheckRegister/PayrollCheckRegisterV1.cs b/src/Mindee/V1/Product/Us/PayrollCheckRegister/PayrollCheckRegisterV1.cs index 0d58f5fe8..a2ce54b31 100644 --- a/src/Mindee/V1/Product/Us/PayrollCheckRegister/PayrollCheckRegisterV1.cs +++ b/src/Mindee/V1/Product/Us/PayrollCheckRegister/PayrollCheckRegisterV1.cs @@ -7,7 +7,7 @@ namespace Mindee.V1.Product.Us.PayrollCheckRegister /// The definition for Payroll Check Register, API version 1. /// [Endpoint("payroll_check_register", "1")] - public sealed class PayrollCheckRegisterV1 : ExtractionInference + public sealed class PayrollCheckRegisterV1 : Inference { } } diff --git a/src/Mindee/V2/Client.cs b/src/Mindee/V2/Client.cs index 3c336e50c..f5a3698bc 100644 --- a/src/Mindee/V2/Client.cs +++ b/src/Mindee/V2/Client.cs @@ -9,7 +9,6 @@ using Mindee.V2.ClientOptions; using Mindee.V2.Http; using Mindee.V2.Parsing; -using Mindee.V2.Product; using Mindee.V2.Product.Extraction; using Mindee.V2.Product.Extraction.Params; using SettingsV2 = Mindee.V2.Http.Settings; @@ -95,7 +94,7 @@ public Client(HttpApiV2 httpApi, ILoggerFactory logger = null) /// /// /// - /// + /// /// /// /// @@ -104,7 +103,7 @@ public Client(HttpApiV2 httpApi, ILoggerFactory logger = null) /// public async Task EnqueueAsync( InputSource inputSource - , ExtractionParameters extractionParameters) + , BaseParameters parameters) { switch (inputSource) { @@ -120,7 +119,7 @@ InputSource inputSource throw new MindeeInputException($"Unsupported input source {inputSource.GetType().Name}"); } - return await _mindeeApi.ReqPostEnqueueAsync(inputSource, extractionParameters); + return await _mindeeApi.ReqPostEnqueueAsync(inputSource, parameters); } /// @@ -131,7 +130,7 @@ InputSource inputSource /// /// /// - public async Task GetJobAsync(string pollingUrl) + public async Task GetJobFromUrlAsync(string pollingUrl) { _logger?.LogInformation("Getting Job at: {}", pollingUrl); @@ -140,7 +139,7 @@ public async Task GetJobAsync(string pollingUrl) throw new ArgumentNullException(pollingUrl); } - return await _mindeeApi.ReqGetJobAsync(pollingUrl); + return await _mindeeApi.ReqGetJobFromUrlAsync(pollingUrl); } /// @@ -151,8 +150,8 @@ public async Task GetJobAsync(string pollingUrl) /// /// /// - public async Task> GetResultAsync(string pollingUrl) - where TProduct : BaseProduct, new() + private async Task GetResultFromUrlAsync(string pollingUrl) + where TResponse : CommonInferenceResponse, new() { _logger?.LogInformation("Polling: {}", pollingUrl); @@ -160,7 +159,46 @@ public async Task> GetResultAsync(string poll { throw new ArgumentNullException(pollingUrl); } - return await _mindeeApi.ReqGetInferenceAsync(pollingUrl); + return await _mindeeApi.ReqGetResultFromUrlAsync(pollingUrl); + } + + /// + /// Get the status of an inference that was previously enqueued. + /// Can be used for polling. + /// + /// The job id. + /// + /// + /// + public async Task GetResultAsync(string jobId) + where TResponse : CommonInferenceResponse, new() + { + _logger?.LogInformation("Polling: {}", jobId); + + if (string.IsNullOrWhiteSpace(jobId)) + { + throw new ArgumentNullException(jobId); + } + return await _mindeeApi.ReqGetResultAsync(jobId); + } + + /// + /// Get the status of an inference that was previously enqueued. + /// Can be used for polling. + /// + /// The job id. + /// + /// + /// + public async Task GetJobAsync(string jobId) + { + _logger?.LogInformation("Getting job {}", jobId); + + if (string.IsNullOrWhiteSpace(jobId)) + { + throw new ArgumentNullException(jobId); + } + return await _mindeeApi.ReqGetJobAsync(jobId); } /// @@ -181,13 +219,7 @@ public async Task EnqueueAndGetInferenceAsync( InputSource inputSource , ExtractionParameters extractionParameters) { - var response = - await EnqueueAndGetResultAsync(inputSource, extractionParameters); - if (response is ExtractionResponse extractionResponse) - { - return extractionResponse; - } - throw new MindeeException($"Unexpected response type '{response.GetType().Name}'."); + return await EnqueueAndGetResultAsync(inputSource, extractionParameters); } /// @@ -204,10 +236,10 @@ InputSource inputSource /// /// /// - public async Task> EnqueueAndGetResultAsync( + public async Task EnqueueAndGetResultAsync( InputSource inputSource - , ExtractionParameters extractionParameters) - where TProduct : BaseProduct, new() + , BaseParameters extractionParameters) + where TResponse : CommonInferenceResponse, new() { switch (inputSource) { @@ -228,7 +260,7 @@ InputSource inputSource var enqueueResponse = await EnqueueAsync( inputSource, extractionParameters); - return await PollForResultsAsync(enqueueResponse, extractionParameters.PollingOptions); + return await PollForResultsAsync(enqueueResponse, extractionParameters.PollingOptions); } /// @@ -253,9 +285,9 @@ public async Task SearchModels(string name = null, string modelT /// /// /// Thrown when maxRetries is reached and the result isn't ready. - private async Task> PollForResultsAsync( + private async Task PollForResultsAsync( JobResponse enqueueResponse, - PollingOptions pollingOptions) where TProduct : BaseProduct, new() + PollingOptions pollingOptions) where TResponse : CommonInferenceResponse, new() { var maxRetries = pollingOptions.MaxRetries + 1; var pollingUrl = enqueueResponse.Job.PollingUrl; @@ -274,7 +306,7 @@ private async Task> PollForResultsAsync( retryCount, maxRetries); - response = await GetJobAsync(pollingUrl); + response = await GetJobFromUrlAsync(pollingUrl); if (response.Job.Error != null) { break; @@ -283,7 +315,7 @@ private async Task> PollForResultsAsync( if (response.Job.Status.Equals("Processed")) { var resultUrl = response.Job.ResultUrl; - return await GetResultAsync(resultUrl); + return await GetResultFromUrlAsync(resultUrl); } retryCount++; diff --git a/src/Mindee/V2/Http/HttpApiV2.cs b/src/Mindee/V2/Http/HttpApiV2.cs index 663be5259..685a42a17 100644 --- a/src/Mindee/V2/Http/HttpApiV2.cs +++ b/src/Mindee/V2/Http/HttpApiV2.cs @@ -1,6 +1,5 @@ #nullable enable -using System; using System.Text.Json; using System.Threading.Tasks; using Microsoft.Extensions.Logging; @@ -8,7 +7,6 @@ using Mindee.Input; using Mindee.V2.ClientOptions; using Mindee.V2.Parsing; -using Mindee.V2.Product; namespace Mindee.V2.Http { @@ -42,13 +40,25 @@ public abstract class HttpApiV2 /// Get a job for an enqueued document. /// /// The job ID as returned by the predict_async route. - public abstract Task ReqGetJobAsync(string pollingUrl); + public abstract Task ReqGetJobFromUrlAsync(string pollingUrl); + + /// + /// Get a job for an enqueued document. + /// + /// The job ID as returned by the predict_async route. + public abstract Task ReqGetJobAsync(string jobId); + + /// + /// Get a document inference. + /// + /// Url to poll. + public abstract Task ReqGetResultAsync(string inferenceId) where TResponse : CommonInferenceResponse, new(); /// /// Get a document inference. /// /// Url to poll. - public abstract Task> ReqGetInferenceAsync(string resultUrl) where TProduct : BaseProduct, new(); + public abstract Task ReqGetResultFromUrlAsync(string resultUrl) where TResponse : CommonInferenceResponse, new(); /// /// Get the error from the server return. @@ -79,11 +89,10 @@ protected ErrorResponse GetErrorFromContent(int statusCode, string? responseCont /// Attempt to deserialize a response from the server. /// /// - /// - /// + /// /// - protected CommonResponse DeserializeResponse(string? responseContent, Type responseType) - where TProduct : BaseProduct, new() + protected TResponse DeserializeResponse(string? responseContent) + where TResponse : CommonInferenceResponse, new() { Logger?.LogInformation("Parsing HTTP 2xx response ..."); @@ -91,9 +100,9 @@ protected CommonResponse DeserializeResponse(string? respons { throw new MindeeException("Empty response from server."); } - var deserializedResult = JsonSerializer.Deserialize(responseContent, responseType); + var deserializedResult = JsonSerializer.Deserialize(responseContent); - if (deserializedResult is CommonResponse model) + if (deserializedResult is CommonInferenceResponse model) { model.RawResponse = responseContent; return (TResponse)model; diff --git a/src/Mindee/V2/Http/MindeeApiV2.cs b/src/Mindee/V2/Http/MindeeApiV2.cs index f7fd6cc44..d58a1d9e2 100644 --- a/src/Mindee/V2/Http/MindeeApiV2.cs +++ b/src/Mindee/V2/Http/MindeeApiV2.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Reflection; using System.Text.Json; using System.Threading.Tasks; using Microsoft.Extensions.Logging; @@ -9,7 +10,6 @@ using Mindee.Input; using Mindee.V2.ClientOptions; using Mindee.V2.Parsing; -using Mindee.V2.Product; using Mindee.V2.Product.Extraction.Params; using RestSharp; #if NET6_0_OR_GREATER @@ -62,9 +62,9 @@ BaseParameters parameters return HandleJobResponse(response); } - public override async Task ReqGetJobAsync(string pollingUrl) + public override async Task ReqGetJobAsync(string jobId) { - var request = new RestRequest(new Uri(pollingUrl)); + var request = new RestRequest($"v2/jobs/{jobId}"); Logger?.LogInformation("HTTP GET to {RequestResource}...", _baseUrl + request.Resource); var response = await _httpClient.ExecuteGetAsync(request); Logger?.LogDebug("HTTP response: {ResponseContent}", response.Content); @@ -72,15 +72,35 @@ public override async Task ReqGetJobAsync(string pollingUrl) return handledResponse; } + public override async Task ReqGetJobFromUrlAsync(string pollingUrl) + { + var request = new RestRequest(new Uri(pollingUrl)); + Logger?.LogInformation("HTTP GET to {RequestResource}...", request.Resource); + var response = await _httpClient.ExecuteGetAsync(request); + Logger?.LogDebug("HTTP response: {ResponseContent}", response.Content); + var handledResponse = HandleJobResponse(response); + return handledResponse; + } + - public override async Task> ReqGetInferenceAsync(string resultUrl) + public override async Task ReqGetResultAsync(string inferenceId) + { + var slug = typeof(TResponse).GetCustomAttribute(); + var request = new RestRequest($"v2/products/{slug}/results/{inferenceId}"); + Logger?.LogInformation("HTTP GET to {RequestResource}...", request.Resource); + var queueResponse = await _httpClient.ExecuteGetAsync(request); + return HandleProductResponse(queueResponse); + } + + public override async Task ReqGetResultFromUrlAsync(string resultUrl) { var request = new RestRequest(new Uri(resultUrl)); Logger?.LogInformation("HTTP GET to {RequestResource}...", resultUrl); var queueResponse = await _httpClient.ExecuteGetAsync(request); - return HandleProductResponse(queueResponse); + return HandleProductResponse(queueResponse); } + private static void AddPredictRequestParameters(InputSource inputSource, BaseParameters parameters, RestRequest request) { switch (inputSource) @@ -188,8 +208,8 @@ private JobResponse HandleJobResponse(RestResponse restResponse) return model ?? throw new MindeeException("Couldn't deserialize JobResponse."); } - private CommonResponse HandleProductResponse(RestResponse restResponse) - where TProduct : BaseProduct, new() + private TResponse HandleProductResponse(RestResponse restResponse) + where TResponse : CommonInferenceResponse, new() { Logger?.LogDebug("HTTP response: {RestResponseContent}", restResponse.Content); @@ -201,9 +221,7 @@ private CommonResponse HandleProductResponse(RestResponse re GetErrorFromContent((int)restResponse.StatusCode, restResponse.Content)); } - var responseType = typeof(TProduct).GetProperty("ResponseType")?.GetValue(null) as Type - ?? typeof(CommonResponse); - return DeserializeResponse(restResponse.Content, responseType); + return DeserializeResponse(restResponse.Content); } } diff --git a/src/Mindee/V2/Parsing/Inference/BaseInference.cs b/src/Mindee/V2/Parsing/Inference/BaseInference.cs index 6472a13fc..52f1155f0 100644 --- a/src/Mindee/V2/Parsing/Inference/BaseInference.cs +++ b/src/Mindee/V2/Parsing/Inference/BaseInference.cs @@ -1,7 +1,7 @@ +using System; using System.Text; using System.Text.Json.Serialization; using Mindee.Parsing; -using Mindee.V1.Parsing; namespace Mindee.V2.Parsing { @@ -35,6 +35,11 @@ public abstract class BaseInference [JsonPropertyName("job")] public InferenceJob Job { get; set; } + /// + /// Type of the product's response. + /// + public virtual Type ResponseType { get; set; } + /// /// /// diff --git a/src/Mindee/V2/Parsing/LocalResponse.cs b/src/Mindee/V2/Parsing/LocalResponse.cs index 77c303593..b0071cf10 100644 --- a/src/Mindee/V2/Parsing/LocalResponse.cs +++ b/src/Mindee/V2/Parsing/LocalResponse.cs @@ -25,9 +25,8 @@ public LocalResponse(FileInfo input) : base(input) /// Typically used when wanting to load a V2 webhook callback. /// /// - public TResponse DeserializeResponse() - where TProduct : BaseProduct, new() - where TResponse : CommonResponse, new() + public TResponse DeserializeResponse() + where TResponse : CommonInferenceResponse, new() { var model = JsonSerializer.Deserialize(FileBytes); diff --git a/src/Mindee/V2/Product/BaseProduct.cs b/src/Mindee/V2/Product/BaseProduct.cs deleted file mode 100644 index c11777378..000000000 --- a/src/Mindee/V2/Product/BaseProduct.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System; - -namespace Mindee.V2.Product -{ - /// - /// Base class for all V2 products. - /// - public abstract class BaseProduct - { - /// - /// Type of the product's response. - /// - public static Type ResponseType; - - /// - /// Retrieves the parameters class for the product. - /// - public static Type ParametersType; - - /// - /// Retrieves the slug of the product. - /// - public static string Slug; - } -} diff --git a/src/Mindee/V2/Product/Crop/Crop.cs b/src/Mindee/V2/Product/Crop/Crop.cs deleted file mode 100644 index c80878235..000000000 --- a/src/Mindee/V2/Product/Crop/Crop.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System; -using Mindee.V2.Product.Crop; - -namespace Mindee.V2.Product.Crop -{ - /// - /// Send a file to the asynchronous processing queue for a crop utility inference. - /// - public class Crop : BaseProduct - { - /// - /// Type of the product's response. - /// - public static new Type ResponseType => typeof(CropResponse); - } -} diff --git a/src/Mindee/V2/Product/Crop/CropInference.cs b/src/Mindee/V2/Product/Crop/CropInference.cs index b9543c2bf..468242f27 100644 --- a/src/Mindee/V2/Product/Crop/CropInference.cs +++ b/src/Mindee/V2/Product/Crop/CropInference.cs @@ -1,3 +1,4 @@ +using System; using System.Text.Json.Serialization; using Mindee.V2.Parsing.Inference; @@ -14,6 +15,11 @@ public class CropInference : BaseInference [JsonPropertyName("result")] public CropResult Result { get; set; } + /// + /// Type of the product's response. + /// + public static new Type ResponseType => typeof(CropResponse); + /// /// String representation of the crop inference. /// diff --git a/src/Mindee/V2/Product/Crop/CropResponse.cs b/src/Mindee/V2/Product/Crop/CropResponse.cs index f9221156a..ef4ccf76d 100644 --- a/src/Mindee/V2/Product/Crop/CropResponse.cs +++ b/src/Mindee/V2/Product/Crop/CropResponse.cs @@ -6,7 +6,8 @@ namespace Mindee.V2.Product.Crop /// /// Represent a crop response from Mindee V2 API. /// - public class CropResponse : CommonResponse + [EndpointSlug("crop")] + public class CropResponse : CommonInferenceResponse { /// /// Contents of the inference. diff --git a/src/Mindee/V2/Product/Crop/Params/CropParameters.cs b/src/Mindee/V2/Product/Crop/Params/CropParameters.cs index 8f63a8e4e..93df7fad8 100644 --- a/src/Mindee/V2/Product/Crop/Params/CropParameters.cs +++ b/src/Mindee/V2/Product/Crop/Params/CropParameters.cs @@ -22,7 +22,7 @@ public class CropParameters : BaseParameters /// public CropParameters( string modelId, - string alias, + string alias = null, List webhookIds = null, PollingOptions pollingOptions = null) : base(modelId, alias, webhookIds, pollingOptions) { diff --git a/src/Mindee/V2/Product/Extraction/Extraction.cs b/src/Mindee/V2/Product/Extraction/Extraction.cs deleted file mode 100644 index 27d08a03a..000000000 --- a/src/Mindee/V2/Product/Extraction/Extraction.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; - -namespace Mindee.V2.Product.Extraction -{ - /// - /// Automatically extract structured data from any image or scanned document. - /// - public class Extraction : BaseProduct - { - /// - /// Type of the product's response. - /// - public static new Type ResponseType => typeof(ExtractionResponse); - } -} diff --git a/src/Mindee/V2/Product/Extraction/ExtractionInference.cs b/src/Mindee/V2/Product/Extraction/ExtractionInference.cs index 1cb1b4a58..a0522d5ad 100644 --- a/src/Mindee/V2/Product/Extraction/ExtractionInference.cs +++ b/src/Mindee/V2/Product/Extraction/ExtractionInference.cs @@ -24,6 +24,11 @@ public sealed class ExtractionInference : BaseInference [JsonPropertyName("result")] public ExtractionResult Result { get; set; } + /// + /// Type of the product's response. + /// + public static new Type ResponseType => typeof(ExtractionResponse); + /// /// A prettier representation. /// diff --git a/src/Mindee/V2/Product/Extraction/ExtractionResponse.cs b/src/Mindee/V2/Product/Extraction/ExtractionResponse.cs index 2982f3550..6c1e86444 100644 --- a/src/Mindee/V2/Product/Extraction/ExtractionResponse.cs +++ b/src/Mindee/V2/Product/Extraction/ExtractionResponse.cs @@ -6,7 +6,8 @@ namespace Mindee.V2.Product.Extraction /// /// Represent an extraction response from Mindee V2 API. /// - public class ExtractionResponse : CommonResponse + [EndpointSlug("extraction")] + public class ExtractionResponse : CommonInferenceResponse { /// /// Contents of the inference. diff --git a/tests/Mindee.IntegrationTests/V2/ClientTest.cs b/tests/Mindee.IntegrationTests/V2/ClientTest.cs index f10dc5ae8..e18221735 100644 --- a/tests/Mindee.IntegrationTests/V2/ClientTest.cs +++ b/tests/Mindee.IntegrationTests/V2/ClientTest.cs @@ -2,6 +2,7 @@ using Mindee.Input; using Mindee.V2; using Mindee.V2.Parsing; +using Mindee.V2.Product.Extraction; using Mindee.V2.Product.Extraction.Params; namespace Mindee.IntegrationTests.V2 @@ -226,7 +227,7 @@ public async Task NotFound_Job_MustThrowError() public async Task NotFound_Inference_MustThrowError() { var ex = await Assert.ThrowsAsync(() => - _client.GetResultAsync("fc405e37-4ba4-4d03-aeba-533a8d1f0f21")); + _client.GetResultAsync("fc405e37-4ba4-4d03-aeba-533a8d1f0f21")); Assert.Equal(404, ex.Status); Assert.StartsWith("404-", ex.Code); } diff --git a/tests/Mindee.IntegrationTests/V2/Product/CropTest.cs b/tests/Mindee.IntegrationTests/V2/Product/CropTest.cs index 3de43974f..54497c9e2 100644 --- a/tests/Mindee.IntegrationTests/V2/Product/CropTest.cs +++ b/tests/Mindee.IntegrationTests/V2/Product/CropTest.cs @@ -22,12 +22,14 @@ public CropTest() [Fact(Timeout = 180000)] public async Task Crop_DefaultSample_MustSucceed() { + // Arrange var inputSource = new LocalInputSource( - Constants.V2ProductDir + "crop/default_sample.jpg"); - var productParams = new CropParameters(_cropModelId); + Constants.V2RootDir + "products/crop/default_sample.jpg"); + var cropParameters = new CropParameters(_cropModelId); + var response = await _client.EnqueueAndGetResultAsync( - inputSource, productParams); + inputSource, cropParameters); Assert.NotNull(response); Assert.NotNull(response.Inference); @@ -40,12 +42,8 @@ public async Task Crop_DefaultSample_MustSucceed() Assert.NotNull(result); var crops = result.Crops; + Assert.NotNull(crops); Assert.Equal(2, crops.Count); - foreach (var crop in crops) - { - Assert.NotNull(crop.ObjectType); - Assert.NotNull(crop.Location); - } } } } diff --git a/tests/Mindee.IntegrationTests/V2/Product/ExtractionTest.cs b/tests/Mindee.IntegrationTests/V2/Product/ExtractionTest.cs index 9c02e6989..93ee70839 100644 --- a/tests/Mindee.IntegrationTests/V2/Product/ExtractionTest.cs +++ b/tests/Mindee.IntegrationTests/V2/Product/ExtractionTest.cs @@ -1,46 +1,7 @@ -using Mindee.Input; -using Mindee.V2; -using Mindee.V2.Product.Extraction; -using Mindee.V2.Product.Extraction.Params; - namespace Mindee.IntegrationTests.V2.Product { - [Trait("Category", "V2")] - [Trait("Category", "Integration")] public class ExtractionTest { - private readonly string? _extractionModelId; - private readonly Client _client; - - public ExtractionTest() - { - var apiKey = Environment.GetEnvironmentVariable("MindeeV2__ApiKey"); - _client = TestingUtilities.GetOrGenerateMindeeClientV2(apiKey); - _extractionModelId = Environment.GetEnvironmentVariable("MindeeV2__Findoc__Model__Id"); - } - - [Fact(Timeout = 180000)] - public async Task Extraction_DefaultSample_MustSucceed() - { - var inputSource = new LocalInputSource( - Constants.V2ProductDir + "extraction/financial_document/default_sample.jpg"); - var productParams = new ExtractionParameters(_extractionModelId); - - var response = await _client.EnqueueAndGetResultAsync( - inputSource, productParams); - - Assert.NotNull(response); - Assert.NotNull(response.Inference); - - var file = response.Inference.File; - Assert.NotNull(file); - Assert.Equal("default_sample.jpg", file.Name); - - var result = response.Inference.Result; - Assert.NotNull(result); - var fields = result.Fields; - Assert.NotNull(fields); - } } } diff --git a/tests/Mindee.UnitTests/V1/Parsing/Common/FullTextOcrTest.cs b/tests/Mindee.UnitTests/V1/Parsing/Common/FullTextOcrTest.cs index d0064fc5b..20c7d358f 100644 --- a/tests/Mindee.UnitTests/V1/Parsing/Common/FullTextOcrTest.cs +++ b/tests/Mindee.UnitTests/V1/Parsing/Common/FullTextOcrTest.cs @@ -9,7 +9,7 @@ public class FullTextOcrTest { private static readonly JsonSerializerOptions JsonOptions = new() { PropertyNameCaseInsensitive = true }; - private ExtractionInference LoadInference() + private Inference LoadInference() { var json = File.ReadAllText(Constants.V1RootDir + "extras/full_text_ocr/complete.json"); var prediction = JsonSerializer.Deserialize>(json, JsonOptions); diff --git a/tests/Mindee.UnitTests/V2/ClientTest.cs b/tests/Mindee.UnitTests/V2/ClientTest.cs index 39c6b88b2..2123f5bc6 100644 --- a/tests/Mindee.UnitTests/V2/ClientTest.cs +++ b/tests/Mindee.UnitTests/V2/ClientTest.cs @@ -17,7 +17,7 @@ private Client MakeCustomMindeeClientV2(Mock predictable) predictable.Setup(x => x.ReqPostEnqueueAsync(It.IsAny(), It.IsAny()) ).ReturnsAsync(new JobResponse()); - predictable.Setup(x => x.ReqGetInferenceAsync(It.IsAny()) + predictable.Setup(x => x.ReqGetResultAsync(It.IsAny()) ).ReturnsAsync(new ExtractionResponse()); predictable.Setup(x => x.ReqGetJobAsync(It.IsAny()) @@ -51,11 +51,11 @@ public async Task Document_GetInference_Async() { var predictable = new Mock(); var mindeeClient = MakeCustomMindeeClientV2(predictable); - var response = await mindeeClient.GetResultAsync("dummy-id"); + var response = await mindeeClient.GetResultAsync("dummy-id"); Assert.NotNull(response); predictable.Verify( - p => p.ReqGetInferenceAsync(It.IsAny()), + p => p.ReqGetResultAsync(It.IsAny()), Times.AtMostOnce()); } @@ -77,7 +77,7 @@ public void Inference_LoadsLocally() { var localResponse = new LocalResponse( new FileInfo(Constants.V2RootDir + "products/extraction/financial_document/complete.json")); - ExtractionResponse locallyLoadedResponse = localResponse.DeserializeResponse(); + ExtractionResponse locallyLoadedResponse = localResponse.DeserializeResponse(); Assert.NotNull(locallyLoadedResponse); Assert.Equal("12345678-1234-1234-1234-123456789abc", locallyLoadedResponse.Inference.Model.Id); Assert.Equal("John Smith", diff --git a/tests/Mindee.UnitTests/V2/Input/LocalResponseTest.cs b/tests/Mindee.UnitTests/V2/Input/LocalResponseTest.cs index 1c1ce67ea..4ff94d95c 100644 --- a/tests/Mindee.UnitTests/V2/Input/LocalResponseTest.cs +++ b/tests/Mindee.UnitTests/V2/Input/LocalResponseTest.cs @@ -22,7 +22,7 @@ private static void AssertLocalResponse(LocalResponse localResponse) Assert.Equal(signature, localResponse.GetHmacSignature(secretKey)); Assert.True(localResponse.IsValidHmacSignature( secretKey, signature)); - ExtractionResponse inferenceResponse = localResponse.DeserializeResponse(); + ExtractionResponse inferenceResponse = localResponse.DeserializeResponse(); Assert.NotNull(inferenceResponse); Assert.NotNull(inferenceResponse.Inference); } diff --git a/tests/Mindee.UnitTests/V2/Product/CropTest.cs b/tests/Mindee.UnitTests/V2/Product/CropTest.cs index e0aedb751..1d05b867c 100644 --- a/tests/Mindee.UnitTests/V2/Product/CropTest.cs +++ b/tests/Mindee.UnitTests/V2/Product/CropTest.cs @@ -123,7 +123,7 @@ private static CropResponse GetInference(string path) { var localResponse = new LocalResponse( File.ReadAllText(Constants.V2RootDir + path)); - return localResponse.DeserializeResponse(); + return localResponse.DeserializeResponse(); } private void AssertInferenceResponse(CropResponse response) diff --git a/tests/Mindee.UnitTests/V2/Product/ExtractionTest.cs b/tests/Mindee.UnitTests/V2/Product/ExtractionTest.cs index 139274064..69ee0627c 100644 --- a/tests/Mindee.UnitTests/V2/Product/ExtractionTest.cs +++ b/tests/Mindee.UnitTests/V2/Product/ExtractionTest.cs @@ -383,7 +383,7 @@ private static ExtractionResponse GetInference(string path) { var localResponse = new LocalResponse( File.ReadAllText(Constants.V2RootDir + path)); - return localResponse.DeserializeResponse(); + return localResponse.DeserializeResponse(); } private void AssertInferenceResponse(ExtractionResponse response) From 0f251b7d0726689be8d9d3caa272420373f007ba Mon Sep 17 00:00:00 2001 From: sebastianMindee <130448732+sebastianMindee@users.noreply.github.com> Date: Tue, 24 Feb 2026 11:19:25 +0100 Subject: [PATCH 05/33] :sparkles: add support for classification --- .../Params/ClassificationParameters.cs | 2 +- .../Product/Extraction/ExtractionInference.cs | 5 --- .../Product/Extraction/ExtractionResponse.cs | 2 +- .../Extraction/Params/ExtractionParameters.cs | 2 +- .../V2/Product/ClassificationTest.cs | 10 +++-- .../V2/Product/ExtractionTest.cs | 41 +++++++++++++++++++ .../V2/Product/ClassificationTest.cs | 5 +-- 7 files changed, 52 insertions(+), 15 deletions(-) diff --git a/src/Mindee/V2/Product/Classification/Params/ClassificationParameters.cs b/src/Mindee/V2/Product/Classification/Params/ClassificationParameters.cs index fc6e6526f..fd767788b 100644 --- a/src/Mindee/V2/Product/Classification/Params/ClassificationParameters.cs +++ b/src/Mindee/V2/Product/Classification/Params/ClassificationParameters.cs @@ -9,7 +9,7 @@ namespace Mindee.V2.Product.Classification.Params public class ClassificationParameters : BaseParameters { /// - /// Slug for the classification product. + /// Slug for the extraction product. /// public sealed override string Slug { get; protected set; } diff --git a/src/Mindee/V2/Product/Extraction/ExtractionInference.cs b/src/Mindee/V2/Product/Extraction/ExtractionInference.cs index a0522d5ad..1cb1b4a58 100644 --- a/src/Mindee/V2/Product/Extraction/ExtractionInference.cs +++ b/src/Mindee/V2/Product/Extraction/ExtractionInference.cs @@ -24,11 +24,6 @@ public sealed class ExtractionInference : BaseInference [JsonPropertyName("result")] public ExtractionResult Result { get; set; } - /// - /// Type of the product's response. - /// - public static new Type ResponseType => typeof(ExtractionResponse); - /// /// A prettier representation. /// diff --git a/src/Mindee/V2/Product/Extraction/ExtractionResponse.cs b/src/Mindee/V2/Product/Extraction/ExtractionResponse.cs index 6c1e86444..071fab776 100644 --- a/src/Mindee/V2/Product/Extraction/ExtractionResponse.cs +++ b/src/Mindee/V2/Product/Extraction/ExtractionResponse.cs @@ -4,7 +4,7 @@ namespace Mindee.V2.Product.Extraction { /// - /// Represent an extraction response from Mindee V2 API. + /// Response for an extraction inference. /// [EndpointSlug("extraction")] public class ExtractionResponse : CommonInferenceResponse diff --git a/src/Mindee/V2/Product/Extraction/Params/ExtractionParameters.cs b/src/Mindee/V2/Product/Extraction/Params/ExtractionParameters.cs index fa8ff70c0..d6d80deed 100644 --- a/src/Mindee/V2/Product/Extraction/Params/ExtractionParameters.cs +++ b/src/Mindee/V2/Product/Extraction/Params/ExtractionParameters.cs @@ -8,7 +8,7 @@ namespace Mindee.V2.Product.Extraction.Params { /// - /// ResultOptions to pass when calling methods using the predict API V2. + /// Parameters for an extraction inference. /// public class ExtractionParameters : BaseParameters { diff --git a/tests/Mindee.IntegrationTests/V2/Product/ClassificationTest.cs b/tests/Mindee.IntegrationTests/V2/Product/ClassificationTest.cs index 8750da7d4..d366ad8b8 100644 --- a/tests/Mindee.IntegrationTests/V2/Product/ClassificationTest.cs +++ b/tests/Mindee.IntegrationTests/V2/Product/ClassificationTest.cs @@ -22,19 +22,21 @@ public ClassificationTest() [Fact(Timeout = 180000)] public async Task Classification_DefaultSample_MustSucceed() { + // Arrange var inputSource = new LocalInputSource( - Constants.V2ProductDir + "classification/default_invoice.jpg"); - var productParams = new ClassificationParameters(_classificationModelId); + Constants.V2RootDir + "products/classification/default_sample.jpg"); + var classificationParameters = new ClassificationParameters(_classificationModelId); + var response = await _client.EnqueueAndGetResultAsync( - inputSource, productParams); + inputSource, classificationParameters); Assert.NotNull(response); Assert.NotNull(response.Inference); var file = response.Inference.File; Assert.NotNull(file); - Assert.Equal("default_invoice.jpg", file.Name); + Assert.Equal("default_sample.jpg", file.Name); var result = response.Inference.Result; Assert.NotNull(result); diff --git a/tests/Mindee.IntegrationTests/V2/Product/ExtractionTest.cs b/tests/Mindee.IntegrationTests/V2/Product/ExtractionTest.cs index 93ee70839..df5b37535 100644 --- a/tests/Mindee.IntegrationTests/V2/Product/ExtractionTest.cs +++ b/tests/Mindee.IntegrationTests/V2/Product/ExtractionTest.cs @@ -1,7 +1,48 @@ +using Mindee.Input; +using Mindee.V2; +using Mindee.V2.Product.Extraction; +using Mindee.V2.Product.Extraction.Params; + namespace Mindee.IntegrationTests.V2.Product { + [Trait("Category", "V2")] + [Trait("Category", "Integration")] public class ExtractionTest { + private readonly string? _extractionModelId; + private readonly Client _client; + + public ExtractionTest() + { + var apiKey = Environment.GetEnvironmentVariable("MindeeV2__ApiKey"); + _client = TestingUtilities.GetOrGenerateMindeeClientV2(apiKey); + _extractionModelId = Environment.GetEnvironmentVariable("MindeeV2__Findoc__Model__Id"); + } + + [Fact(Timeout = 180000)] + public async Task Extraction_DefaultSample_MustSucceed() + { + // Arrange + var inputSource = new LocalInputSource( + Constants.V2RootDir + "products/extraction/default_sample.jpg"); + var extractionParameters = new ExtractionParameters(_extractionModelId); + + + var response = await _client.EnqueueAndGetResultAsync( + inputSource, extractionParameters); + + Assert.NotNull(response); + Assert.NotNull(response.Inference); + + var file = response.Inference.File; + Assert.NotNull(file); + Assert.Equal("default_sample.jpg", file.Name); + + var result = response.Inference.Result; + Assert.NotNull(result); + var fields = result.Fields; + Assert.NotNull(fields); + } } } diff --git a/tests/Mindee.UnitTests/V2/Product/ClassificationTest.cs b/tests/Mindee.UnitTests/V2/Product/ClassificationTest.cs index 5eedcf29b..f645a426a 100644 --- a/tests/Mindee.UnitTests/V2/Product/ClassificationTest.cs +++ b/tests/Mindee.UnitTests/V2/Product/ClassificationTest.cs @@ -10,7 +10,7 @@ public class ClassificationTest [Fact] public void Classification_WhenSingle_MustHaveValidProperties() { - var response = GetInference("classification/classification_single.json"); + var response = GetInference("products/classification/classification_single.json"); AssertInferenceResponse(response); var inference = response.Inference; @@ -26,11 +26,10 @@ public void Classification_WhenSingle_MustHaveValidProperties() var classification = inference.Result.Classification; Assert.Equal("invoice", classification.DocumentType); } - private static ClassificationResponse GetInference(string path) { var localResponse = new LocalResponse( - File.ReadAllText(Constants.V2ProductDir + path)); + File.ReadAllText(Constants.V2RootDir + path)); return localResponse.DeserializeResponse(); } From a54b6af82fc5492f4c02b1901cd541e48f6b9a0b Mon Sep 17 00:00:00 2001 From: sebastianMindee <130448732+sebastianMindee@users.noreply.github.com> Date: Tue, 24 Feb 2026 12:01:00 +0100 Subject: [PATCH 06/33] :sparkles: add support for Ocr --- .../Params/ClassificationParameters.cs | 2 +- src/Mindee/V2/Product/Crop/CropInference.cs | 6 ---- .../V2/Product/Crop/Params/CropParameters.cs | 2 +- .../V2/Product/Extraction/ExtractionResult.cs | 1 - .../Mindee.IntegrationTests/V2/ClientTest.cs | 2 +- .../V2/Product/ClassificationTest.cs | 4 +-- .../V2/Product/ExtractionTest.cs | 3 +- tests/Mindee.UnitTests/V2/Product/OcrTest.cs | 31 +++---------------- 8 files changed, 10 insertions(+), 41 deletions(-) diff --git a/src/Mindee/V2/Product/Classification/Params/ClassificationParameters.cs b/src/Mindee/V2/Product/Classification/Params/ClassificationParameters.cs index fd767788b..fc6e6526f 100644 --- a/src/Mindee/V2/Product/Classification/Params/ClassificationParameters.cs +++ b/src/Mindee/V2/Product/Classification/Params/ClassificationParameters.cs @@ -9,7 +9,7 @@ namespace Mindee.V2.Product.Classification.Params public class ClassificationParameters : BaseParameters { /// - /// Slug for the extraction product. + /// Slug for the classification product. /// public sealed override string Slug { get; protected set; } diff --git a/src/Mindee/V2/Product/Crop/CropInference.cs b/src/Mindee/V2/Product/Crop/CropInference.cs index 468242f27..b9543c2bf 100644 --- a/src/Mindee/V2/Product/Crop/CropInference.cs +++ b/src/Mindee/V2/Product/Crop/CropInference.cs @@ -1,4 +1,3 @@ -using System; using System.Text.Json.Serialization; using Mindee.V2.Parsing.Inference; @@ -15,11 +14,6 @@ public class CropInference : BaseInference [JsonPropertyName("result")] public CropResult Result { get; set; } - /// - /// Type of the product's response. - /// - public static new Type ResponseType => typeof(CropResponse); - /// /// String representation of the crop inference. /// diff --git a/src/Mindee/V2/Product/Crop/Params/CropParameters.cs b/src/Mindee/V2/Product/Crop/Params/CropParameters.cs index 93df7fad8..a48d3c412 100644 --- a/src/Mindee/V2/Product/Crop/Params/CropParameters.cs +++ b/src/Mindee/V2/Product/Crop/Params/CropParameters.cs @@ -9,7 +9,7 @@ namespace Mindee.V2.Product.Crop.Params public class CropParameters : BaseParameters { /// - /// Slug for the extraction product. + /// Slug for the crop product. /// public sealed override string Slug { get; protected set; } diff --git a/src/Mindee/V2/Product/Extraction/ExtractionResult.cs b/src/Mindee/V2/Product/Extraction/ExtractionResult.cs index 003278d5f..032a36cc4 100644 --- a/src/Mindee/V2/Product/Extraction/ExtractionResult.cs +++ b/src/Mindee/V2/Product/Extraction/ExtractionResult.cs @@ -1,7 +1,6 @@ using System.Text; using System.Text.Json.Serialization; using Mindee.Parsing; -using Mindee.V1.Parsing; using Mindee.V2.Parsing; using Mindee.V2.Parsing.Inference; using Mindee.V2.Parsing.Inference.Field; diff --git a/tests/Mindee.IntegrationTests/V2/ClientTest.cs b/tests/Mindee.IntegrationTests/V2/ClientTest.cs index e18221735..7be617f5b 100644 --- a/tests/Mindee.IntegrationTests/V2/ClientTest.cs +++ b/tests/Mindee.IntegrationTests/V2/ClientTest.cs @@ -227,7 +227,7 @@ public async Task NotFound_Job_MustThrowError() public async Task NotFound_Inference_MustThrowError() { var ex = await Assert.ThrowsAsync(() => - _client.GetResultAsync("fc405e37-4ba4-4d03-aeba-533a8d1f0f21")); + _client.GetJobAsync("fc405e37-4ba4-4d03-aeba-533a8d1f0f21")); Assert.Equal(404, ex.Status); Assert.StartsWith("404-", ex.Code); } diff --git a/tests/Mindee.IntegrationTests/V2/Product/ClassificationTest.cs b/tests/Mindee.IntegrationTests/V2/Product/ClassificationTest.cs index d366ad8b8..ab6911adb 100644 --- a/tests/Mindee.IntegrationTests/V2/Product/ClassificationTest.cs +++ b/tests/Mindee.IntegrationTests/V2/Product/ClassificationTest.cs @@ -24,7 +24,7 @@ public async Task Classification_DefaultSample_MustSucceed() { // Arrange var inputSource = new LocalInputSource( - Constants.V2RootDir + "products/classification/default_sample.jpg"); + Constants.V2ProductDir + "classification/default_invoice.jpg"); var classificationParameters = new ClassificationParameters(_classificationModelId); @@ -36,7 +36,7 @@ public async Task Classification_DefaultSample_MustSucceed() var file = response.Inference.File; Assert.NotNull(file); - Assert.Equal("default_sample.jpg", file.Name); + Assert.Equal("default_invoice.jpg", file.Name); var result = response.Inference.Result; Assert.NotNull(result); diff --git a/tests/Mindee.IntegrationTests/V2/Product/ExtractionTest.cs b/tests/Mindee.IntegrationTests/V2/Product/ExtractionTest.cs index df5b37535..f736b93c9 100644 --- a/tests/Mindee.IntegrationTests/V2/Product/ExtractionTest.cs +++ b/tests/Mindee.IntegrationTests/V2/Product/ExtractionTest.cs @@ -22,9 +22,8 @@ public ExtractionTest() [Fact(Timeout = 180000)] public async Task Extraction_DefaultSample_MustSucceed() { - // Arrange var inputSource = new LocalInputSource( - Constants.V2RootDir + "products/extraction/default_sample.jpg"); + Constants.V2ProductDir + "extraction/financial_document/default_sample.jpg"); var extractionParameters = new ExtractionParameters(_extractionModelId); diff --git a/tests/Mindee.UnitTests/V2/Product/OcrTest.cs b/tests/Mindee.UnitTests/V2/Product/OcrTest.cs index feecc4e9e..4fc4a2852 100644 --- a/tests/Mindee.UnitTests/V2/Product/OcrTest.cs +++ b/tests/Mindee.UnitTests/V2/Product/OcrTest.cs @@ -10,14 +10,16 @@ public class OcrTest [Fact] public void Ocr_WhenSingle_MustHaveValidProperties() { - var response = GetInference("ocr/ocr_single.json"); + var response = GetInference("products/ocr/ocr_single.json"); AssertInferenceResponse(response); var inference = response.Inference; + // Validate inference metadata Assert.Equal("12345678-1234-1234-1234-123456789abc", inference.Id); Assert.Equal("test-model-id", inference.Model.Id); + // Validate file metadata Assert.Equal("default_sample.jpg", inference.File.Name); Assert.Equal(1, inference.File.PageCount); Assert.Equal("image/jpeg", inference.File.MimeType); @@ -38,36 +40,11 @@ public void Ocr_WhenSingle_MustHaveValidProperties() Assert.Equal(4, fifthWord.Polygon.Count); } - [Fact] - public void Ocr_WhenMultiple_MustHaveValidProperties() - { - var response = GetInference("ocr/ocr_multiple.json"); - AssertInferenceResponse(response); - - var inference = response.Inference; - - var job = inference.Job; - Assert.Equal("12345678-1234-1234-1234-jobid1234567", job.Id); - - var model = inference.Model; - Assert.NotNull(model); - - var pages = inference.Result.Pages; - Assert.NotNull(pages); - Assert.Equal(3, pages.Count); - - foreach (var page in pages) - { - Assert.NotNull(page.Words); - Assert.NotNull(page.Content); - Assert.IsType(page.Content); - } - } private static OcrResponse GetInference(string path) { var localResponse = new LocalResponse( - File.ReadAllText(Constants.V2ProductDir + path)); + File.ReadAllText(Constants.V2RootDir + path)); return localResponse.DeserializeResponse(); } From 761116a02b2010d9fb7ba1268488a727466a97ca Mon Sep 17 00:00:00 2001 From: sebastianMindee <130448732+sebastianMindee@users.noreply.github.com> Date: Tue, 24 Feb 2026 12:19:47 +0100 Subject: [PATCH 07/33] :sparkles: add support for split product --- .../V2/Product/ClassificationTest.cs | 1 - .../V2/Product/CropTest.cs | 3 +-- .../V2/Product/OcrTest.cs | 4 +-- .../V2/Product/SplitTest.cs | 5 ++-- tests/Mindee.UnitTests/V2/Product/CropTest.cs | 8 ------ .../V2/Product/ExtractionTest.cs | 2 +- tests/Mindee.UnitTests/V2/Product/OcrTest.cs | 27 +++++++++++++++++-- .../Mindee.UnitTests/V2/Product/SplitTest.cs | 6 ++--- 8 files changed, 35 insertions(+), 21 deletions(-) diff --git a/tests/Mindee.IntegrationTests/V2/Product/ClassificationTest.cs b/tests/Mindee.IntegrationTests/V2/Product/ClassificationTest.cs index ab6911adb..461d92550 100644 --- a/tests/Mindee.IntegrationTests/V2/Product/ClassificationTest.cs +++ b/tests/Mindee.IntegrationTests/V2/Product/ClassificationTest.cs @@ -22,7 +22,6 @@ public ClassificationTest() [Fact(Timeout = 180000)] public async Task Classification_DefaultSample_MustSucceed() { - // Arrange var inputSource = new LocalInputSource( Constants.V2ProductDir + "classification/default_invoice.jpg"); var classificationParameters = new ClassificationParameters(_classificationModelId); diff --git a/tests/Mindee.IntegrationTests/V2/Product/CropTest.cs b/tests/Mindee.IntegrationTests/V2/Product/CropTest.cs index 54497c9e2..643921a87 100644 --- a/tests/Mindee.IntegrationTests/V2/Product/CropTest.cs +++ b/tests/Mindee.IntegrationTests/V2/Product/CropTest.cs @@ -22,7 +22,6 @@ public CropTest() [Fact(Timeout = 180000)] public async Task Crop_DefaultSample_MustSucceed() { - // Arrange var inputSource = new LocalInputSource( Constants.V2RootDir + "products/crop/default_sample.jpg"); var cropParameters = new CropParameters(_cropModelId); @@ -43,7 +42,7 @@ public async Task Crop_DefaultSample_MustSucceed() var crops = result.Crops; Assert.NotNull(crops); - Assert.Equal(2, crops.Count); + Assert.Single(crops); } } } diff --git a/tests/Mindee.IntegrationTests/V2/Product/OcrTest.cs b/tests/Mindee.IntegrationTests/V2/Product/OcrTest.cs index 5c003b5da..7e8419849 100644 --- a/tests/Mindee.IntegrationTests/V2/Product/OcrTest.cs +++ b/tests/Mindee.IntegrationTests/V2/Product/OcrTest.cs @@ -24,10 +24,10 @@ public async Task Ocr_DefaultSample_MustSucceed() { var inputSource = new LocalInputSource( Constants.V2ProductDir + "ocr/default_sample.jpg"); - var productParams = new OcrParameters(_ocrModelId); + var ocrParameters = new OcrParameters(_ocrModelId); var response = await _client.EnqueueAndGetResultAsync( - inputSource, productParams); + inputSource, ocrParameters); Assert.NotNull(response); Assert.NotNull(response.Inference); diff --git a/tests/Mindee.IntegrationTests/V2/Product/SplitTest.cs b/tests/Mindee.IntegrationTests/V2/Product/SplitTest.cs index 72140337a..41a3abc50 100644 --- a/tests/Mindee.IntegrationTests/V2/Product/SplitTest.cs +++ b/tests/Mindee.IntegrationTests/V2/Product/SplitTest.cs @@ -24,10 +24,11 @@ public async Task Split_DefaultSample_MustSucceed() { var inputSource = new LocalInputSource( Constants.V2RootDir + "products/split/default_sample.pdf"); - var productParams = new SplitParameters(_splitModelId); + var splitParameters = new SplitParameters(_splitModelId); + var response = await _client.EnqueueAndGetResultAsync( - inputSource, productParams); + inputSource, splitParameters); Assert.NotNull(response); Assert.NotNull(response.Inference); diff --git a/tests/Mindee.UnitTests/V2/Product/CropTest.cs b/tests/Mindee.UnitTests/V2/Product/CropTest.cs index 1d05b867c..5642a11b9 100644 --- a/tests/Mindee.UnitTests/V2/Product/CropTest.cs +++ b/tests/Mindee.UnitTests/V2/Product/CropTest.cs @@ -16,17 +16,14 @@ public void Crop_WhenSingle_MustHaveValidProperties() var inference = response.Inference; - // Validate inference metadata Assert.Equal("12345678-1234-1234-1234-123456789abc", inference.Id); Assert.Equal("test-model-id", inference.Model.Id); Assert.Equal("12345678-1234-1234-1234-jobid1234567", inference.Job.Id); - // Validate file metadata Assert.Equal("sample.jpeg", inference.File.Name); Assert.Equal(1, inference.File.PageCount); Assert.Equal("image/jpeg", inference.File.MimeType); - // Validate crops var crops = inference.Result.Crops; Assert.NotNull(crops); Assert.Single(crops); @@ -54,11 +51,9 @@ public void Crop_WhenMultiple_MustHaveValidProperties() var job = inference.Job; Assert.Equal("12345678-1234-1234-1234-jobid1234567", job.Id); - // Validate inference metadata Assert.Equal("12345678-1234-1234-1234-123456789abc", inference.Id); Assert.Equal("test-model-id", inference.Model.Id); - // Validate file metadata Assert.Equal("default_sample.jpg", inference.File.Name); Assert.Equal(1, inference.File.PageCount); Assert.Equal("image/jpeg", inference.File.MimeType); @@ -67,7 +62,6 @@ public void Crop_WhenMultiple_MustHaveValidProperties() Assert.NotNull(crops); Assert.Equal(2, crops.Count); - // Validate first crop item var firstCrop = crops[0]; Assert.Equal("invoice", firstCrop.ObjectType); Assert.Equal(0, firstCrop.Location.Page); @@ -79,7 +73,6 @@ public void Crop_WhenMultiple_MustHaveValidProperties() Assert.Equal(new Point(0.476, 0.979), firstPolygon[2]); Assert.Equal(new Point(0.214, 0.979), firstPolygon[3]); - // Validate second crop item var secondCrop = crops[1]; Assert.Equal("invoice", secondCrop.ObjectType); Assert.Equal(0, secondCrop.Location.Page); @@ -95,7 +88,6 @@ public void Crop_WhenMultiple_MustHaveValidProperties() [Fact(DisplayName = "crop_single.rst – RST display must be parsed and exposed")] public void RstDisplay_MustBeAccessible() { - // Arrange var resp = GetInference("products/crop/crop_single.json"); var rstReference = File.ReadAllText( Constants.V2RootDir + "products/crop/crop_single.rst"); diff --git a/tests/Mindee.UnitTests/V2/Product/ExtractionTest.cs b/tests/Mindee.UnitTests/V2/Product/ExtractionTest.cs index 69ee0627c..aa585f564 100644 --- a/tests/Mindee.UnitTests/V2/Product/ExtractionTest.cs +++ b/tests/Mindee.UnitTests/V2/Product/ExtractionTest.cs @@ -290,7 +290,7 @@ public void StandardFieldTypes_mustHaveLocations() [Fact(DisplayName = "standard_field_types.rst – RST display must be parsed and exposed")] public void RstDisplay_mustBeAccessible() { - var resp = GetInference("extraction/standard_field_types.json"); + var resp = GetInference("products/extraction/standard_field_types.json"); var rstReference = File.ReadAllText( Constants.V2ProductDir + "extraction/standard_field_types.rst"); diff --git a/tests/Mindee.UnitTests/V2/Product/OcrTest.cs b/tests/Mindee.UnitTests/V2/Product/OcrTest.cs index 4fc4a2852..8f24c6468 100644 --- a/tests/Mindee.UnitTests/V2/Product/OcrTest.cs +++ b/tests/Mindee.UnitTests/V2/Product/OcrTest.cs @@ -15,11 +15,9 @@ public void Ocr_WhenSingle_MustHaveValidProperties() var inference = response.Inference; - // Validate inference metadata Assert.Equal("12345678-1234-1234-1234-123456789abc", inference.Id); Assert.Equal("test-model-id", inference.Model.Id); - // Validate file metadata Assert.Equal("default_sample.jpg", inference.File.Name); Assert.Equal(1, inference.File.PageCount); Assert.Equal("image/jpeg", inference.File.MimeType); @@ -40,6 +38,31 @@ public void Ocr_WhenSingle_MustHaveValidProperties() Assert.Equal(4, fifthWord.Polygon.Count); } + [Fact] + public void Ocr_WhenMultiple_MustHaveValidProperties() + { + var response = GetInference("products/ocr/ocr_multiple.json"); + AssertInferenceResponse(response); + + var inference = response.Inference; + + var job = inference.Job; + Assert.Equal("12345678-1234-1234-1234-jobid1234567", job.Id); + + var model = inference.Model; + Assert.NotNull(model); + + var pages = inference.Result.Pages; + Assert.NotNull(pages); + Assert.Equal(3, pages.Count); + + foreach (var page in pages) + { + Assert.NotNull(page.Words); + Assert.NotNull(page.Content); + Assert.IsType(page.Content); + } + } private static OcrResponse GetInference(string path) { diff --git a/tests/Mindee.UnitTests/V2/Product/SplitTest.cs b/tests/Mindee.UnitTests/V2/Product/SplitTest.cs index 28d21be4e..ac9906ab9 100644 --- a/tests/Mindee.UnitTests/V2/Product/SplitTest.cs +++ b/tests/Mindee.UnitTests/V2/Product/SplitTest.cs @@ -10,7 +10,7 @@ public class SplitTest [Fact] public void Split_WhenSingle_MustHaveValidProperties() { - var response = GetInference("split/split_single.json"); + var response = GetInference("products/split/split_single.json"); AssertInferenceResponse(response); var inference = response.Inference; @@ -34,7 +34,7 @@ public void Split_WhenSingle_MustHaveValidProperties() [Fact] public void Split_WhenMultiple_MustHaveValidProperties() { - var response = GetInference("split/split_multiple.json"); + var response = GetInference("products/split/split_multiple.json"); AssertInferenceResponse(response); var inference = response.Inference; @@ -66,7 +66,7 @@ public void Split_WhenMultiple_MustHaveValidProperties() private static SplitResponse GetInference(string path) { var localResponse = new LocalResponse( - File.ReadAllText(Constants.V2ProductDir + path)); + File.ReadAllText(Constants.V2RootDir + path)); return localResponse.DeserializeResponse(); } From bf41971c1bedbfd903786dad5e6ecf4699ce069d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ianar=C3=A9=20S=C3=A9vi?= Date: Wed, 25 Feb 2026 16:50:17 +0100 Subject: [PATCH 08/33] easier v2 product tests --- docs/code_samples/v2_extraction_polling.txt | 4 ++-- src/Mindee/V2/Client.cs | 12 ++++++------ .../V2/Product/ClassificationTest.cs | 5 ++--- .../V2/Product/CropTest.cs | 15 +++++++++------ .../V2/Product/ExtractionTest.cs | 5 ++--- .../Mindee.IntegrationTests/V2/Product/OcrTest.cs | 4 ++-- .../V2/Product/SplitTest.cs | 5 ++--- .../V2/Product/ClassificationTest.cs | 5 +++-- tests/Mindee.UnitTests/V2/Product/CropTest.cs | 10 +++++----- .../Mindee.UnitTests/V2/Product/ExtractionTest.cs | 4 ++-- tests/Mindee.UnitTests/V2/Product/OcrTest.cs | 6 +++--- tests/Mindee.UnitTests/V2/Product/SplitTest.cs | 6 +++--- 12 files changed, 41 insertions(+), 40 deletions(-) diff --git a/docs/code_samples/v2_extraction_polling.txt b/docs/code_samples/v2_extraction_polling.txt index 3678b1a1f..71615b7f4 100644 --- a/docs/code_samples/v2_extraction_polling.txt +++ b/docs/code_samples/v2_extraction_polling.txt @@ -11,7 +11,7 @@ string modelId = "MY_MODEL_ID"; // Construct a new client Client mindeeClient = new Client(apiKey); -// Set parameters +// Set inference parameters var productParams = new ExtractionParameters( modelId: modelId @@ -32,7 +32,7 @@ var productParams = new ExtractionParameters( var inputSource = new LocalInputSource(filePath); // Upload the file -var response = await mindeeClient.EnqueueAndGetResultAsync( +var response = await mindeeClient.EnqueueAndGetInferenceAsync( inputSource, productParams); // Print a summary of the response diff --git a/src/Mindee/V2/Client.cs b/src/Mindee/V2/Client.cs index f5a3698bc..a203e74b1 100644 --- a/src/Mindee/V2/Client.cs +++ b/src/Mindee/V2/Client.cs @@ -229,8 +229,8 @@ InputSource inputSource /// /// /// - /// - /// + /// + /// /// /// /// @@ -238,7 +238,7 @@ InputSource inputSource /// public async Task EnqueueAndGetResultAsync( InputSource inputSource - , BaseParameters extractionParameters) + , BaseParameters parameters) where TResponse : CommonInferenceResponse, new() { switch (inputSource) @@ -255,12 +255,12 @@ InputSource inputSource throw new MindeeInputException($"Unsupported input source {inputSource.GetType().Name}"); } - extractionParameters.PollingOptions ??= new PollingOptions(); + parameters.PollingOptions ??= new PollingOptions(); var enqueueResponse = await EnqueueAsync( inputSource, - extractionParameters); - return await PollForResultsAsync(enqueueResponse, extractionParameters.PollingOptions); + parameters); + return await PollForResultsAsync(enqueueResponse, parameters.PollingOptions); } /// diff --git a/tests/Mindee.IntegrationTests/V2/Product/ClassificationTest.cs b/tests/Mindee.IntegrationTests/V2/Product/ClassificationTest.cs index 461d92550..8750da7d4 100644 --- a/tests/Mindee.IntegrationTests/V2/Product/ClassificationTest.cs +++ b/tests/Mindee.IntegrationTests/V2/Product/ClassificationTest.cs @@ -24,11 +24,10 @@ public async Task Classification_DefaultSample_MustSucceed() { var inputSource = new LocalInputSource( Constants.V2ProductDir + "classification/default_invoice.jpg"); - var classificationParameters = new ClassificationParameters(_classificationModelId); - + var productParams = new ClassificationParameters(_classificationModelId); var response = await _client.EnqueueAndGetResultAsync( - inputSource, classificationParameters); + inputSource, productParams); Assert.NotNull(response); Assert.NotNull(response.Inference); diff --git a/tests/Mindee.IntegrationTests/V2/Product/CropTest.cs b/tests/Mindee.IntegrationTests/V2/Product/CropTest.cs index 643921a87..3de43974f 100644 --- a/tests/Mindee.IntegrationTests/V2/Product/CropTest.cs +++ b/tests/Mindee.IntegrationTests/V2/Product/CropTest.cs @@ -23,12 +23,11 @@ public CropTest() public async Task Crop_DefaultSample_MustSucceed() { var inputSource = new LocalInputSource( - Constants.V2RootDir + "products/crop/default_sample.jpg"); - var cropParameters = new CropParameters(_cropModelId); - + Constants.V2ProductDir + "crop/default_sample.jpg"); + var productParams = new CropParameters(_cropModelId); var response = await _client.EnqueueAndGetResultAsync( - inputSource, cropParameters); + inputSource, productParams); Assert.NotNull(response); Assert.NotNull(response.Inference); @@ -41,8 +40,12 @@ public async Task Crop_DefaultSample_MustSucceed() Assert.NotNull(result); var crops = result.Crops; - Assert.NotNull(crops); - Assert.Single(crops); + Assert.Equal(2, crops.Count); + foreach (var crop in crops) + { + Assert.NotNull(crop.ObjectType); + Assert.NotNull(crop.Location); + } } } } diff --git a/tests/Mindee.IntegrationTests/V2/Product/ExtractionTest.cs b/tests/Mindee.IntegrationTests/V2/Product/ExtractionTest.cs index f736b93c9..9c02e6989 100644 --- a/tests/Mindee.IntegrationTests/V2/Product/ExtractionTest.cs +++ b/tests/Mindee.IntegrationTests/V2/Product/ExtractionTest.cs @@ -24,11 +24,10 @@ public async Task Extraction_DefaultSample_MustSucceed() { var inputSource = new LocalInputSource( Constants.V2ProductDir + "extraction/financial_document/default_sample.jpg"); - var extractionParameters = new ExtractionParameters(_extractionModelId); - + var productParams = new ExtractionParameters(_extractionModelId); var response = await _client.EnqueueAndGetResultAsync( - inputSource, extractionParameters); + inputSource, productParams); Assert.NotNull(response); Assert.NotNull(response.Inference); diff --git a/tests/Mindee.IntegrationTests/V2/Product/OcrTest.cs b/tests/Mindee.IntegrationTests/V2/Product/OcrTest.cs index 7e8419849..5c003b5da 100644 --- a/tests/Mindee.IntegrationTests/V2/Product/OcrTest.cs +++ b/tests/Mindee.IntegrationTests/V2/Product/OcrTest.cs @@ -24,10 +24,10 @@ public async Task Ocr_DefaultSample_MustSucceed() { var inputSource = new LocalInputSource( Constants.V2ProductDir + "ocr/default_sample.jpg"); - var ocrParameters = new OcrParameters(_ocrModelId); + var productParams = new OcrParameters(_ocrModelId); var response = await _client.EnqueueAndGetResultAsync( - inputSource, ocrParameters); + inputSource, productParams); Assert.NotNull(response); Assert.NotNull(response.Inference); diff --git a/tests/Mindee.IntegrationTests/V2/Product/SplitTest.cs b/tests/Mindee.IntegrationTests/V2/Product/SplitTest.cs index 41a3abc50..72140337a 100644 --- a/tests/Mindee.IntegrationTests/V2/Product/SplitTest.cs +++ b/tests/Mindee.IntegrationTests/V2/Product/SplitTest.cs @@ -24,11 +24,10 @@ public async Task Split_DefaultSample_MustSucceed() { var inputSource = new LocalInputSource( Constants.V2RootDir + "products/split/default_sample.pdf"); - var splitParameters = new SplitParameters(_splitModelId); - + var productParams = new SplitParameters(_splitModelId); var response = await _client.EnqueueAndGetResultAsync( - inputSource, splitParameters); + inputSource, productParams); Assert.NotNull(response); Assert.NotNull(response.Inference); diff --git a/tests/Mindee.UnitTests/V2/Product/ClassificationTest.cs b/tests/Mindee.UnitTests/V2/Product/ClassificationTest.cs index f645a426a..5eedcf29b 100644 --- a/tests/Mindee.UnitTests/V2/Product/ClassificationTest.cs +++ b/tests/Mindee.UnitTests/V2/Product/ClassificationTest.cs @@ -10,7 +10,7 @@ public class ClassificationTest [Fact] public void Classification_WhenSingle_MustHaveValidProperties() { - var response = GetInference("products/classification/classification_single.json"); + var response = GetInference("classification/classification_single.json"); AssertInferenceResponse(response); var inference = response.Inference; @@ -26,10 +26,11 @@ public void Classification_WhenSingle_MustHaveValidProperties() var classification = inference.Result.Classification; Assert.Equal("invoice", classification.DocumentType); } + private static ClassificationResponse GetInference(string path) { var localResponse = new LocalResponse( - File.ReadAllText(Constants.V2RootDir + path)); + File.ReadAllText(Constants.V2ProductDir + path)); return localResponse.DeserializeResponse(); } diff --git a/tests/Mindee.UnitTests/V2/Product/CropTest.cs b/tests/Mindee.UnitTests/V2/Product/CropTest.cs index 5642a11b9..fada340a2 100644 --- a/tests/Mindee.UnitTests/V2/Product/CropTest.cs +++ b/tests/Mindee.UnitTests/V2/Product/CropTest.cs @@ -11,7 +11,7 @@ public class CropTest [Fact] public void Crop_WhenSingle_MustHaveValidProperties() { - var response = GetInference("products/crop/crop_single.json"); + var response = GetInference("crop/crop_single.json"); AssertInferenceResponse(response); var inference = response.Inference; @@ -43,7 +43,7 @@ public void Crop_WhenSingle_MustHaveValidProperties() [Fact] public void Crop_WhenMultiple_MustHaveValidProperties() { - var response = GetInference("products/crop/crop_multiple.json"); + var response = GetInference("crop/crop_multiple.json"); AssertInferenceResponse(response); var inference = response.Inference; @@ -88,9 +88,9 @@ public void Crop_WhenMultiple_MustHaveValidProperties() [Fact(DisplayName = "crop_single.rst – RST display must be parsed and exposed")] public void RstDisplay_MustBeAccessible() { - var resp = GetInference("products/crop/crop_single.json"); + var resp = GetInference("crop/crop_single.json"); var rstReference = File.ReadAllText( - Constants.V2RootDir + "products/crop/crop_single.rst"); + Constants.V2ProductDir + "crop/crop_single.rst"); var inf = resp.Inference; @@ -114,7 +114,7 @@ private static string NormalizeLineEndings(string input) private static CropResponse GetInference(string path) { var localResponse = new LocalResponse( - File.ReadAllText(Constants.V2RootDir + path)); + File.ReadAllText(Constants.V2ProductDir + path)); return localResponse.DeserializeResponse(); } diff --git a/tests/Mindee.UnitTests/V2/Product/ExtractionTest.cs b/tests/Mindee.UnitTests/V2/Product/ExtractionTest.cs index aa585f564..0dd5b31b8 100644 --- a/tests/Mindee.UnitTests/V2/Product/ExtractionTest.cs +++ b/tests/Mindee.UnitTests/V2/Product/ExtractionTest.cs @@ -290,7 +290,7 @@ public void StandardFieldTypes_mustHaveLocations() [Fact(DisplayName = "standard_field_types.rst – RST display must be parsed and exposed")] public void RstDisplay_mustBeAccessible() { - var resp = GetInference("products/extraction/standard_field_types.json"); + var resp = GetInference("extraction/standard_field_types.json"); var rstReference = File.ReadAllText( Constants.V2ProductDir + "extraction/standard_field_types.rst"); @@ -382,7 +382,7 @@ private static string NormalizeLineEndings(string input) private static ExtractionResponse GetInference(string path) { var localResponse = new LocalResponse( - File.ReadAllText(Constants.V2RootDir + path)); + File.ReadAllText(Constants.V2ProductDir + path)); return localResponse.DeserializeResponse(); } diff --git a/tests/Mindee.UnitTests/V2/Product/OcrTest.cs b/tests/Mindee.UnitTests/V2/Product/OcrTest.cs index 8f24c6468..feecc4e9e 100644 --- a/tests/Mindee.UnitTests/V2/Product/OcrTest.cs +++ b/tests/Mindee.UnitTests/V2/Product/OcrTest.cs @@ -10,7 +10,7 @@ public class OcrTest [Fact] public void Ocr_WhenSingle_MustHaveValidProperties() { - var response = GetInference("products/ocr/ocr_single.json"); + var response = GetInference("ocr/ocr_single.json"); AssertInferenceResponse(response); var inference = response.Inference; @@ -41,7 +41,7 @@ public void Ocr_WhenSingle_MustHaveValidProperties() [Fact] public void Ocr_WhenMultiple_MustHaveValidProperties() { - var response = GetInference("products/ocr/ocr_multiple.json"); + var response = GetInference("ocr/ocr_multiple.json"); AssertInferenceResponse(response); var inference = response.Inference; @@ -67,7 +67,7 @@ public void Ocr_WhenMultiple_MustHaveValidProperties() private static OcrResponse GetInference(string path) { var localResponse = new LocalResponse( - File.ReadAllText(Constants.V2RootDir + path)); + File.ReadAllText(Constants.V2ProductDir + path)); return localResponse.DeserializeResponse(); } diff --git a/tests/Mindee.UnitTests/V2/Product/SplitTest.cs b/tests/Mindee.UnitTests/V2/Product/SplitTest.cs index ac9906ab9..28d21be4e 100644 --- a/tests/Mindee.UnitTests/V2/Product/SplitTest.cs +++ b/tests/Mindee.UnitTests/V2/Product/SplitTest.cs @@ -10,7 +10,7 @@ public class SplitTest [Fact] public void Split_WhenSingle_MustHaveValidProperties() { - var response = GetInference("products/split/split_single.json"); + var response = GetInference("split/split_single.json"); AssertInferenceResponse(response); var inference = response.Inference; @@ -34,7 +34,7 @@ public void Split_WhenSingle_MustHaveValidProperties() [Fact] public void Split_WhenMultiple_MustHaveValidProperties() { - var response = GetInference("products/split/split_multiple.json"); + var response = GetInference("split/split_multiple.json"); AssertInferenceResponse(response); var inference = response.Inference; @@ -66,7 +66,7 @@ public void Split_WhenMultiple_MustHaveValidProperties() private static SplitResponse GetInference(string path) { var localResponse = new LocalResponse( - File.ReadAllText(Constants.V2RootDir + path)); + File.ReadAllText(Constants.V2ProductDir + path)); return localResponse.DeserializeResponse(); } From 6f83cd549a3548510ed62dbeaa95120272a8a9fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ianar=C3=A9=20S=C3=A9vi?= Date: Mon, 2 Mar 2026 16:54:49 +0100 Subject: [PATCH 09/33] test samples --- docs/code_samples/v2_croptxt | 26 ++++++++++++++++++++++++++ docs/code_samples/v2_splitxt | 26 ++++++++++++++++++++++++++ 2 files changed, 52 insertions(+) create mode 100644 docs/code_samples/v2_croptxt create mode 100644 docs/code_samples/v2_splitxt diff --git a/docs/code_samples/v2_croptxt b/docs/code_samples/v2_croptxt new file mode 100644 index 000000000..14f733afe --- /dev/null +++ b/docs/code_samples/v2_croptxt @@ -0,0 +1,26 @@ +using Mindee; +using Mindee.Input; +using Mindee.V2; +using Mindee.V2.Product.Crop.Params; + +string filePath = "/path/to/the/file.ext"; +string apiKey = "MY_API_KEY"; +string modelId = "MY_MODEL_ID"; + +// Construct a new client +Client mindeeClient = new Client(apiKey); + +// Set inference parameters +var productParams = new CropParameters( + modelId: modelId +); + +// Load a file from disk +var inputSource = new LocalInputSource(filePath); + +// Upload the file +var response = await mindeeClient.EnqueueAndGetInferenceAsync( + inputSource, productParams); + +// Print a summary of the response +System.Console.WriteLine(response.Inference.ToString()); diff --git a/docs/code_samples/v2_splitxt b/docs/code_samples/v2_splitxt new file mode 100644 index 000000000..095d08f71 --- /dev/null +++ b/docs/code_samples/v2_splitxt @@ -0,0 +1,26 @@ +using Mindee; +using Mindee.Input; +using Mindee.V2; +using Mindee.V2.Product.Split.Params; + +string filePath = "/path/to/the/file.ext"; +string apiKey = "MY_API_KEY"; +string modelId = "MY_MODEL_ID"; + +// Construct a new client +Client mindeeClient = new Client(apiKey); + +// Set inference parameters +var productParams = new SplitParameters( + modelId: modelId +); + +// Load a file from disk +var inputSource = new LocalInputSource(filePath); + +// Upload the file +var response = await mindeeClient.EnqueueAndGetInferenceAsync( + inputSource, productParams); + +// Print a summary of the response +System.Console.WriteLine(response.Inference.ToString()); From 7e3aeacc9a57b891251696114a3e0aa463305276 Mon Sep 17 00:00:00 2001 From: sebastianMindee <130448732+sebastianMindee@users.noreply.github.com> Date: Fri, 6 Mar 2026 12:11:05 +0100 Subject: [PATCH 10/33] fix syntaxes + add tests --- docs/code_samples/v2_classification.txt | 3 +-- docs/code_samples/v2_crop.txt | 3 +-- docs/code_samples/v2_croptxt | 26 ------------------- docs/code_samples/v2_ocr.txt | 3 +-- docs/code_samples/v2_split.txt | 3 +-- docs/code_samples/v2_splitxt | 26 ------------------- src/Mindee/V2/Client.cs | 21 --------------- .../Mindee.IntegrationTests/V2/ClientTest.cs | 2 +- .../V2/Input/LocalResponseTest.cs | 6 ++--- 9 files changed, 8 insertions(+), 85 deletions(-) delete mode 100644 docs/code_samples/v2_croptxt delete mode 100644 docs/code_samples/v2_splitxt diff --git a/docs/code_samples/v2_classification.txt b/docs/code_samples/v2_classification.txt index 001845c3f..af2d2fa1a 100644 --- a/docs/code_samples/v2_classification.txt +++ b/docs/code_samples/v2_classification.txt @@ -1,7 +1,6 @@ using Mindee; using Mindee.Input; using Mindee.V2; -using Mindee.V2.Product.Classification; using Mindee.V2.Product.Classification.Params; string filePath = "/path/to/the/file.ext"; @@ -20,7 +19,7 @@ var productParams = new ClassificationParameters( var inputSource = new LocalInputSource(filePath); // Upload the file -var response = await mindeeClient.EnqueueAndGetResultAsync( +var response = await mindeeClient.EnqueueAndGetInferenceAsync( inputSource, productParams); // Print a summary of the response diff --git a/docs/code_samples/v2_crop.txt b/docs/code_samples/v2_crop.txt index 8a9cbbd8a..cec59a8bc 100644 --- a/docs/code_samples/v2_crop.txt +++ b/docs/code_samples/v2_crop.txt @@ -1,7 +1,6 @@ using Mindee; using Mindee.Input; using Mindee.V2; -using Mindee.V2.Product.Crop; using Mindee.V2.Product.Crop.Params; string filePath = "/path/to/the/file.ext"; @@ -20,7 +19,7 @@ var productParams = new CropParameters( var inputSource = new LocalInputSource(filePath); // Upload the file -var response = await mindeeClient.EnqueueAndGetResultAsync( +var response = await mindeeClient.EnqueueAndGetInferenceAsync( inputSource, productParams); // Print a summary of the response diff --git a/docs/code_samples/v2_croptxt b/docs/code_samples/v2_croptxt deleted file mode 100644 index 14f733afe..000000000 --- a/docs/code_samples/v2_croptxt +++ /dev/null @@ -1,26 +0,0 @@ -using Mindee; -using Mindee.Input; -using Mindee.V2; -using Mindee.V2.Product.Crop.Params; - -string filePath = "/path/to/the/file.ext"; -string apiKey = "MY_API_KEY"; -string modelId = "MY_MODEL_ID"; - -// Construct a new client -Client mindeeClient = new Client(apiKey); - -// Set inference parameters -var productParams = new CropParameters( - modelId: modelId -); - -// Load a file from disk -var inputSource = new LocalInputSource(filePath); - -// Upload the file -var response = await mindeeClient.EnqueueAndGetInferenceAsync( - inputSource, productParams); - -// Print a summary of the response -System.Console.WriteLine(response.Inference.ToString()); diff --git a/docs/code_samples/v2_ocr.txt b/docs/code_samples/v2_ocr.txt index 0654e7246..8b85e8738 100644 --- a/docs/code_samples/v2_ocr.txt +++ b/docs/code_samples/v2_ocr.txt @@ -1,7 +1,6 @@ using Mindee; using Mindee.Input; using Mindee.V2; -using Mindee.V2.Product.Ocr; using Mindee.V2.Product.Ocr.Params; string filePath = "/path/to/the/file.ext"; @@ -20,7 +19,7 @@ var productParams = new OcrParameters( var inputSource = new LocalInputSource(filePath); // Upload the file -var response = await mindeeClient.EnqueueAndGetResultAsync( +var response = await mindeeClient.EnqueueAndGetInferenceAsync( inputSource, productParams); // Print a summary of the response diff --git a/docs/code_samples/v2_split.txt b/docs/code_samples/v2_split.txt index 1f3d0a071..c626727dd 100644 --- a/docs/code_samples/v2_split.txt +++ b/docs/code_samples/v2_split.txt @@ -1,7 +1,6 @@ using Mindee; using Mindee.Input; using Mindee.V2; -using Mindee.V2.Product.Split; using Mindee.V2.Product.Split.Params; string filePath = "/path/to/the/file.ext"; @@ -20,7 +19,7 @@ var productParams = new SplitParameters( var inputSource = new LocalInputSource(filePath); // Upload the file -var response = await mindeeClient.EnqueueAndGetResultAsync( +var response = await mindeeClient.EnqueueAndGetInferenceAsync( inputSource, productParams); // Print a summary of the response diff --git a/docs/code_samples/v2_splitxt b/docs/code_samples/v2_splitxt deleted file mode 100644 index 095d08f71..000000000 --- a/docs/code_samples/v2_splitxt +++ /dev/null @@ -1,26 +0,0 @@ -using Mindee; -using Mindee.Input; -using Mindee.V2; -using Mindee.V2.Product.Split.Params; - -string filePath = "/path/to/the/file.ext"; -string apiKey = "MY_API_KEY"; -string modelId = "MY_MODEL_ID"; - -// Construct a new client -Client mindeeClient = new Client(apiKey); - -// Set inference parameters -var productParams = new SplitParameters( - modelId: modelId -); - -// Load a file from disk -var inputSource = new LocalInputSource(filePath); - -// Upload the file -var response = await mindeeClient.EnqueueAndGetInferenceAsync( - inputSource, productParams); - -// Print a summary of the response -System.Console.WriteLine(response.Inference.ToString()); diff --git a/src/Mindee/V2/Client.cs b/src/Mindee/V2/Client.cs index a203e74b1..4ce074100 100644 --- a/src/Mindee/V2/Client.cs +++ b/src/Mindee/V2/Client.cs @@ -201,27 +201,6 @@ public async Task GetJobAsync(string jobId) return await _mindeeApi.ReqGetJobAsync(jobId); } - /// - /// Add the document to an async queue, poll, and parse when complete. - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - public async Task EnqueueAndGetInferenceAsync( - InputSource inputSource - , ExtractionParameters extractionParameters) - { - return await EnqueueAndGetResultAsync(inputSource, extractionParameters); - } - /// /// Add the document to an async queue, poll, and parse when complete. /// diff --git a/tests/Mindee.IntegrationTests/V2/ClientTest.cs b/tests/Mindee.IntegrationTests/V2/ClientTest.cs index 7be617f5b..fdddc0e37 100644 --- a/tests/Mindee.IntegrationTests/V2/ClientTest.cs +++ b/tests/Mindee.IntegrationTests/V2/ClientTest.cs @@ -241,7 +241,7 @@ public async Task Url_InputSource_MustNotRaiseErrors() var inputSource = new UrlInputSource(new Uri(url)); var inferenceParams = new ExtractionParameters(_findocModelId); - var response = await _client.EnqueueAndGetInferenceAsync(inputSource, inferenceParams); + var response = await _client.EnqueueAndGetResultAsync(inputSource, inferenceParams); Assert.NotNull(response); Assert.NotNull(response.Inference); diff --git a/tests/Mindee.UnitTests/V2/Input/LocalResponseTest.cs b/tests/Mindee.UnitTests/V2/Input/LocalResponseTest.cs index 4ff94d95c..1de635b28 100644 --- a/tests/Mindee.UnitTests/V2/Input/LocalResponseTest.cs +++ b/tests/Mindee.UnitTests/V2/Input/LocalResponseTest.cs @@ -22,9 +22,9 @@ private static void AssertLocalResponse(LocalResponse localResponse) Assert.Equal(signature, localResponse.GetHmacSignature(secretKey)); Assert.True(localResponse.IsValidHmacSignature( secretKey, signature)); - ExtractionResponse inferenceResponse = localResponse.DeserializeResponse(); - Assert.NotNull(inferenceResponse); - Assert.NotNull(inferenceResponse.Inference); + ExtractionResponse extractionResponse = localResponse.DeserializeResponse(); + Assert.NotNull(extractionResponse); + Assert.NotNull(extractionResponse.Inference); } [Fact] From 3a6ee58f95b6b48c2a381ce26ffff4f73e824701 Mon Sep 17 00:00:00 2001 From: sebastianMindee <130448732+sebastianMindee@users.noreply.github.com> Date: Fri, 6 Mar 2026 20:00:11 +0100 Subject: [PATCH 11/33] fix smoke tests --- docs/code_samples/v2_extraction_polling.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/code_samples/v2_extraction_polling.txt b/docs/code_samples/v2_extraction_polling.txt index 71615b7f4..3678b1a1f 100644 --- a/docs/code_samples/v2_extraction_polling.txt +++ b/docs/code_samples/v2_extraction_polling.txt @@ -11,7 +11,7 @@ string modelId = "MY_MODEL_ID"; // Construct a new client Client mindeeClient = new Client(apiKey); -// Set inference parameters +// Set parameters var productParams = new ExtractionParameters( modelId: modelId @@ -32,7 +32,7 @@ var productParams = new ExtractionParameters( var inputSource = new LocalInputSource(filePath); // Upload the file -var response = await mindeeClient.EnqueueAndGetInferenceAsync( +var response = await mindeeClient.EnqueueAndGetResultAsync( inputSource, productParams); // Print a summary of the response From 2027efd404f4e2a3c6343fdba32c8ee7331ce3be Mon Sep 17 00:00:00 2001 From: sebastianMindee <130448732+sebastianMindee@users.noreply.github.com> Date: Sat, 7 Mar 2026 01:13:22 +0100 Subject: [PATCH 12/33] fix smoke tests --- docs/code_samples/v2_classification.txt | 2 +- docs/code_samples/v2_crop.txt | 2 +- docs/code_samples/v2_ocr.txt | 2 +- docs/code_samples/v2_split.txt | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/code_samples/v2_classification.txt b/docs/code_samples/v2_classification.txt index af2d2fa1a..d960a85df 100644 --- a/docs/code_samples/v2_classification.txt +++ b/docs/code_samples/v2_classification.txt @@ -19,7 +19,7 @@ var productParams = new ClassificationParameters( var inputSource = new LocalInputSource(filePath); // Upload the file -var response = await mindeeClient.EnqueueAndGetInferenceAsync( +var response = await mindeeClient.EnqueueAndGetResultAsync( inputSource, productParams); // Print a summary of the response diff --git a/docs/code_samples/v2_crop.txt b/docs/code_samples/v2_crop.txt index cec59a8bc..567a78c26 100644 --- a/docs/code_samples/v2_crop.txt +++ b/docs/code_samples/v2_crop.txt @@ -19,7 +19,7 @@ var productParams = new CropParameters( var inputSource = new LocalInputSource(filePath); // Upload the file -var response = await mindeeClient.EnqueueAndGetInferenceAsync( +var response = await mindeeClient.EnqueueAndGetResultAsync( inputSource, productParams); // Print a summary of the response diff --git a/docs/code_samples/v2_ocr.txt b/docs/code_samples/v2_ocr.txt index 8b85e8738..28f3a426b 100644 --- a/docs/code_samples/v2_ocr.txt +++ b/docs/code_samples/v2_ocr.txt @@ -19,7 +19,7 @@ var productParams = new OcrParameters( var inputSource = new LocalInputSource(filePath); // Upload the file -var response = await mindeeClient.EnqueueAndGetInferenceAsync( +var response = await mindeeClient.EnqueueAndGetResultAsync( inputSource, productParams); // Print a summary of the response diff --git a/docs/code_samples/v2_split.txt b/docs/code_samples/v2_split.txt index c626727dd..414160197 100644 --- a/docs/code_samples/v2_split.txt +++ b/docs/code_samples/v2_split.txt @@ -19,7 +19,7 @@ var productParams = new SplitParameters( var inputSource = new LocalInputSource(filePath); // Upload the file -var response = await mindeeClient.EnqueueAndGetInferenceAsync( +var response = await mindeeClient.EnqueueAndGetResultAsync( inputSource, productParams); // Print a summary of the response From 787f791755acce8f11a0db7431f7921c02eaa138 Mon Sep 17 00:00:00 2001 From: sebastianMindee <130448732+sebastianMindee@users.noreply.github.com> Date: Sat, 7 Mar 2026 01:33:27 +0100 Subject: [PATCH 13/33] add imports to code samples again --- docs/code_samples/v2_classification.txt | 1 + docs/code_samples/v2_crop.txt | 1 + docs/code_samples/v2_ocr.txt | 1 + docs/code_samples/v2_split.txt | 1 + 4 files changed, 4 insertions(+) diff --git a/docs/code_samples/v2_classification.txt b/docs/code_samples/v2_classification.txt index d960a85df..001845c3f 100644 --- a/docs/code_samples/v2_classification.txt +++ b/docs/code_samples/v2_classification.txt @@ -1,6 +1,7 @@ using Mindee; using Mindee.Input; using Mindee.V2; +using Mindee.V2.Product.Classification; using Mindee.V2.Product.Classification.Params; string filePath = "/path/to/the/file.ext"; diff --git a/docs/code_samples/v2_crop.txt b/docs/code_samples/v2_crop.txt index 567a78c26..8a9cbbd8a 100644 --- a/docs/code_samples/v2_crop.txt +++ b/docs/code_samples/v2_crop.txt @@ -1,6 +1,7 @@ using Mindee; using Mindee.Input; using Mindee.V2; +using Mindee.V2.Product.Crop; using Mindee.V2.Product.Crop.Params; string filePath = "/path/to/the/file.ext"; diff --git a/docs/code_samples/v2_ocr.txt b/docs/code_samples/v2_ocr.txt index 28f3a426b..0654e7246 100644 --- a/docs/code_samples/v2_ocr.txt +++ b/docs/code_samples/v2_ocr.txt @@ -1,6 +1,7 @@ using Mindee; using Mindee.Input; using Mindee.V2; +using Mindee.V2.Product.Ocr; using Mindee.V2.Product.Ocr.Params; string filePath = "/path/to/the/file.ext"; diff --git a/docs/code_samples/v2_split.txt b/docs/code_samples/v2_split.txt index 414160197..1f3d0a071 100644 --- a/docs/code_samples/v2_split.txt +++ b/docs/code_samples/v2_split.txt @@ -1,6 +1,7 @@ using Mindee; using Mindee.Input; using Mindee.V2; +using Mindee.V2.Product.Split; using Mindee.V2.Product.Split.Params; string filePath = "/path/to/the/file.ext"; From 851b169a18a433f82c63c1fa874d2c0441727824 Mon Sep 17 00:00:00 2001 From: sebastianMindee <130448732+sebastianMindee@users.noreply.github.com> Date: Mon, 9 Mar 2026 21:43:13 +0100 Subject: [PATCH 14/33] :sparkles: add support for V2 in CLI --- src/Mindee.Cli/Commands/V1/PredictCommand.cs | 55 +++++---- .../Commands/V2/InferenceCommand.cs | 111 +++++++++--------- src/Mindee.Cli/Program.cs | 90 +++++--------- 3 files changed, 113 insertions(+), 143 deletions(-) diff --git a/src/Mindee.Cli/Commands/V1/PredictCommand.cs b/src/Mindee.Cli/Commands/V1/PredictCommand.cs index 790b5831a..061157284 100644 --- a/src/Mindee.Cli/Commands/V1/PredictCommand.cs +++ b/src/Mindee.Cli/Commands/V1/PredictCommand.cs @@ -163,32 +163,35 @@ private void PrintToConsole( { switch (options.Output) { - case OutputType.Full: - if (options.AllWords && response.Document.Ocr != null) - { - console.Write("#############\nDocument Text\n#############\n::\n"); - var ocr = response.Document.Ocr.ToString().Replace("\n", "\n "); - console.Write(" " + ocr + "\n\n"); - } - else if (options.FullText && response.Document.Inference.Extras.FullTextOcr != null) - { - console.Write("#############\nDocument Text\n#############\n::\n"); - var ocr = response.Document.Inference.Extras.FullTextOcr.Replace("\n", "\n "); - console.Write(" " + ocr + "\n\n"); - } - console.Write(response.Document.ToString()); - break; - case OutputType.Summary: - console.Write(response.Document.Inference.Prediction.ToString()); - break; - case OutputType.Raw: - using (var jsonDocument = JsonDocument.Parse(response.RawResponse)) - { - console.WriteLine(JsonSerializer.Serialize(jsonDocument, _jsonSerializerOptions)); - } - break; - default: - throw new ArgumentOutOfRangeException($"Unknown output type: {options.Output}."); + console.Write(JsonSerializer.Serialize(response, _jsonSerializerOptions)); + } + else + { + if (options.AllWords && response.Document.Ocr != null) + { + console.Write("#############\nDocument Text\n#############\n::\n"); + var ocr = response.Document.Ocr.ToString().Replace("\n", "\n "); + console.Write(" " + ocr + "\n\n"); + } + else if (options.FullText && response.Document.Inference.Extras.FullTextOcr != null) + { + console.Write("#############\nDocument Text\n#############\n::\n"); + var ocr = response.Document.Inference.Extras.FullTextOcr.Replace("\n", "\n "); + console.Write(" " + ocr + "\n\n"); + } + + switch (options.Output) + { + case OutputType.Full: + console.Write(response.Document.ToString()); + break; + case OutputType.Summary: + console.Write(response.Document.Inference.Prediction.ToString()); + break; + case OutputType.Raw: + console.Write(response.RawResponse); + break; + } } } } diff --git a/src/Mindee.Cli/Commands/V2/InferenceCommand.cs b/src/Mindee.Cli/Commands/V2/InferenceCommand.cs index cfb2901b0..6d827b7e3 100644 --- a/src/Mindee.Cli/Commands/V2/InferenceCommand.cs +++ b/src/Mindee.Cli/Commands/V2/InferenceCommand.cs @@ -1,6 +1,7 @@ using System.CommandLine; using System.Text.Json; using Mindee.Input; +using Mindee.V2; using Mindee.V2.Parsing; using Mindee.V2.Product.Classification; using Mindee.V2.Product.Classification.Params; @@ -12,7 +13,6 @@ using Mindee.V2.Product.Ocr.Params; using Mindee.V2.Product.Split; using Mindee.V2.Product.Split.Params; -using V2Client = Mindee.V2.Client; namespace Mindee.Cli.Commands.V2 { @@ -69,18 +69,12 @@ class InferenceCommand : Command private readonly Option? _confidenceOption; private readonly Option? _polygonsOption; private readonly Option? _textContextOption; - private readonly Option _modelIdOption; + private readonly Argument _modelIdArgument; private readonly Argument _pathArgument; public InferenceCommand(InferenceCommandOptions options) : base(options.Name, options.Description) { - _modelIdOption = - new Option("--model-id", "-m") { Description = "ID of the model to use", Required = true }; - Options.Add(_modelIdOption); - var apiKeyOption = new Option("--api-key", "-k") { Description = "Mindee V2 API key." }; - Options.Add(apiKeyOption); // Will not be used at this step, only here for help display purposes. - _productName = options.Name; _aliasOption = new Option("--alias", "-a") { @@ -91,7 +85,7 @@ public InferenceCommand(InferenceCommandOptions options) if (options.Rag) { - _ragOption = new Option("--rag", "-g") + _ragOption = new Option("--rag") { Description = "Enable RAG context. Only valid for 'extraction' product.", DefaultValueFactory = _ => false @@ -99,11 +93,13 @@ public InferenceCommand(InferenceCommandOptions options) Options.Add(_ragOption); } + _modelIdArgument = new Argument("model ID") { Description = "ID of the model to use" }; + Arguments.Add(_modelIdArgument); + _outputOption = new Option("--output", "-o") { Description = "Specify how to output the data. \n" + "- summary: a basic summary (default)\n" + - "- full: detail extraction results, including options\n" + "- raw: full JSON object\n", DefaultValueFactory = _ => OutputType.Summary }; @@ -114,7 +110,7 @@ public InferenceCommand(InferenceCommandOptions options) _rawTextOption = new Option("--raw-text", "-r") { Description = - "To get all the words in the current document. False by default.", + "To get all the words in the current document. Only supported in some plans. False by default.", DefaultValueFactory = _ => false }; Options.Add(_rawTextOption); @@ -125,7 +121,7 @@ public InferenceCommand(InferenceCommandOptions options) _confidenceOption = new Option("--confidence", "-c") { Description = - "To retrieve confidence scores from the extraction. False by default.", + "To retrieve confidence scores from the extraction. Only supported in some plans. False by default.", DefaultValueFactory = _ => false }; Options.Add(_confidenceOption); @@ -136,7 +132,7 @@ public InferenceCommand(InferenceCommandOptions options) _polygonsOption = new Option("--polygon", "-p") { Description = - "To retrieve bounding boxes from the extraction. False by default.", + "To retrieve bounding boxes from the extraction. Only supported in some plans. False by default.", DefaultValueFactory = _ => false }; Options.Add(_polygonsOption); @@ -147,7 +143,7 @@ public InferenceCommand(InferenceCommandOptions options) _textContextOption = new Option("--text-context", "-t") { Description = - "To add text context to your API call. False by default.", + "To add text context to your API call. Only supported in some plans. False by default.", DefaultValueFactory = _ => null }; Options.Add(_textContextOption); @@ -157,12 +153,12 @@ public InferenceCommand(InferenceCommandOptions options) Arguments.Add(_pathArgument); } - public void ConfigureAction(V2Client mindeeClientV2) + public void ConfigureAction(Client mindeeClient) { this.SetAction(parseResult => { var path = parseResult.GetValue(_pathArgument)!; - var modelId = parseResult.GetValue(_modelIdOption)!; + var modelId = parseResult.GetValue(_modelIdArgument)!; var rag = _ragOption != null && parseResult.GetValue(_ragOption); string? alias = null; if (_aliasOption != null) @@ -181,15 +177,14 @@ public void ConfigureAction(V2Client mindeeClientV2) var output = parseResult.GetValue(_outputOption); - var handler = new Handler(mindeeClientV2); + var handler = new Handler(mindeeClient); return handler - .InvokeAsync(_productName, modelId, path, alias, rag, rawText, confidence, polygon, textContext, - output) + .InvokeAsync(_productName, modelId, path, alias, rag, rawText, confidence, polygon, textContext, output) .GetAwaiter().GetResult(); }); } - public class Handler(V2Client mindeeClient) + public class Handler(Client mindeeClient) { private readonly JsonSerializerOptions _jsonSerializerOptions = new() { @@ -208,7 +203,7 @@ public async Task InvokeAsync(string product, string modelId, string path, private async Task EnqueueAndGetResultAsync(InferenceOptions options, string productName) { var inputSource = new LocalInputSource(options.Path); - BaseResponse response = productName switch + CommonInferenceResponse response = productName switch { "classification" => await mindeeClient.EnqueueAndGetResultAsync( inputSource, new ClassificationParameters(options.ModelId, options.Alias)), @@ -233,49 +228,53 @@ private async Task EnqueueAndGetResultAsync(InferenceOptions options, strin private void PrintToConsole( TextWriter console, InferenceOptions options, - BaseResponse response) + CommonInferenceResponse response) { - var validTypes = new[] - { - typeof(ClassificationResponse), typeof(CropResponse), typeof(OcrResponse), - typeof(SplitResponse), typeof(ExtractionResponse) - }; - - if (!validTypes.Contains(response.GetType())) + if (options.Output == OutputType.Raw) { - return; + console.Write(JsonSerializer.Serialize(response, _jsonSerializerOptions)); } + else + { + var validTypes = new[] + { + typeof(ClassificationResponse), typeof(CropResponse), typeof(OcrResponse), + typeof(SplitResponse), typeof(ExtractionResponse) + }; - dynamic dynResponse = response; + if (validTypes.Contains(response.GetType())) + { + dynamic dynResponse = response; - switch (options.Output) - { - case OutputType.Full: if (options.RawText && dynResponse.Inference.ActiveOptions.RawText) { - console.Write("#############\nRaw Text\n#############\n::\n"); - var rawText = dynResponse.Inference.Result.RawText.ToString().Replace("\n", "\n "); - console.Write(" " + rawText + "\n\n"); - } - if (options.Rag && dynResponse.Inference.ActiveOptions.Rag) - { - console.Write("#############\nRetrieval-Augmented Generation\n#############\n::\n"); - var rawText = dynResponse.Inference.Result.Rag.ToString().Replace("\n", "\n "); - console.Write(" " + rawText + "\n\n"); - } - console.Write(dynResponse.Inference.ToString()); - break; - case OutputType.Summary: - console.Write(dynResponse.Inference.Result.ToString()); - break; - case OutputType.Raw: - using (var jsonDocument = JsonDocument.Parse(response.RawResponse)) - { - console.WriteLine(JsonSerializer.Serialize(jsonDocument, _jsonSerializerOptions)); + if (options.RawText && dynResponse.Inference.ActiveOptions.RawText) + { + console.Write("#############\nDocument Text\n#############\n::\n"); + var rawText = dynResponse.Inference.Result.RawText.ToString().Replace("\n", "\n "); + console.Write(" " + rawText + "\n\n"); + } + else if (options.Rag && dynResponse.Inference.ActiveOptions.Rag) + { + console.Write("#############\nDocument Text\n#############\n::\n"); + var rawText = dynResponse.Inference.Result.Rag.ToString().Replace("\n", "\n "); + console.Write(" " + rawText + "\n\n"); + } + + switch (options.Output) + { + case OutputType.Full: + console.Write(dynResponse.Inference.ToString()); + break; + case OutputType.Summary: + console.Write(dynResponse.Inference.Result.ToString()); + break; + case OutputType.Raw: + console.Write(response.RawResponse); + break; + } } - break; - default: - throw new ArgumentOutOfRangeException($"Unknown output type: {options.Output}."); + } } } } diff --git a/src/Mindee.Cli/Program.cs b/src/Mindee.Cli/Program.cs index d78585c6c..915b5894c 100644 --- a/src/Mindee.Cli/Program.cs +++ b/src/Mindee.Cli/Program.cs @@ -1,8 +1,6 @@ using System.CommandLine; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; using Mindee.Cli.Commands.V2; using Mindee.Extensions.DependencyInjection; using CommandOptions = Mindee.Cli.Commands.V1.CommandOptions; @@ -81,8 +79,6 @@ Mindee.V1.Product.Receipt.ReceiptV5Document, Mindee.V1.Product.Receipt.ReceiptV5Document >; -using SettingsV1 = Mindee.V1.Http.Settings; -using SettingsV2 = Mindee.V2.Http.Settings; using V1Client = Mindee.V1.Client; using V2Client = Mindee.V2.Client; @@ -104,7 +100,7 @@ return await root.Parse(args).InvokeAsync(); -static void BuildV1Commands(Command v1Command, IServiceProvider services, string[] args) +static void BuildV1Commands(Command v1Command, V1Client mindeeClient) { var apiKeyOption = new Option("--api-key", "-k") { Description = "Mindee V2 API key." }; @@ -135,151 +131,123 @@ static void BuildV1Commands(Command v1Command, IServiceProvider services, string var barcodeReaderCmd = new PredictBarcodeReaderCommand(new CommandOptions( "barcode-reader", "Barcode Reader", false, false, true, false)); - barcodeReaderCmd.ConfigureAction(mindeeV1Client); + barcodeReaderCmd.ConfigureAction(mindeeClient); v1Command.Subcommands.Add(barcodeReaderCmd); var cropperCmd = new PredictCropperCommand(new CommandOptions( "cropper", "Cropper", false, false, true, false)); - cropperCmd.ConfigureAction(mindeeV1Client); + cropperCmd.ConfigureAction(mindeeClient); v1Command.Subcommands.Add(cropperCmd); var financialDocumentCmd = new PredictFinancialDocumentCommand(new CommandOptions( "financial-document", "Financial Document", true, false, true, true)); - financialDocumentCmd.ConfigureAction(mindeeV1Client); + financialDocumentCmd.ConfigureAction(mindeeClient); v1Command.Subcommands.Add(financialDocumentCmd); var bankAccountDetailsCmd = new PredictBankAccountDetailsCommand(new CommandOptions( "fr-bank-account-details", "FR Bank Account Details", false, false, true, false)); - bankAccountDetailsCmd.ConfigureAction(mindeeV1Client); + bankAccountDetailsCmd.ConfigureAction(mindeeClient); v1Command.Subcommands.Add(bankAccountDetailsCmd); var carteGriseCmd = new PredictCarteGriseCommand(new CommandOptions( "fr-carte-grise", "FR Carte Grise", false, false, true, false)); - carteGriseCmd.ConfigureAction(mindeeV1Client); + carteGriseCmd.ConfigureAction(mindeeClient); v1Command.Subcommands.Add(carteGriseCmd); var healthCardCmd = new PredictHealthCardCommand(new CommandOptions( "fr-health-card", "FR Health Card", false, false, false, true)); - healthCardCmd.ConfigureAction(mindeeV1Client); + healthCardCmd.ConfigureAction(mindeeClient); v1Command.Subcommands.Add(healthCardCmd); var idCardCmd = new PredictIdCardCommand(new CommandOptions( "fr-carte-nationale-d-identite", "FR Carte Nationale d'Identité", false, false, true, false)); - idCardCmd.ConfigureAction(mindeeV1Client); + idCardCmd.ConfigureAction(mindeeClient); v1Command.Subcommands.Add(idCardCmd); var payslipCmd = new PredictPayslipCommand(new CommandOptions( "fr-payslip", "FR Payslip", false, false, false, true)); - payslipCmd.ConfigureAction(mindeeV1Client); + payslipCmd.ConfigureAction(mindeeClient); v1Command.Subcommands.Add(payslipCmd); var internationalIdCmd = new PredictInternationalIdCommand(new CommandOptions( "international-id", "International ID", false, true, false, true)); - internationalIdCmd.ConfigureAction(mindeeV1Client); + internationalIdCmd.ConfigureAction(mindeeClient); v1Command.Subcommands.Add(internationalIdCmd); var invoiceCmd = new PredictInvoiceCommand(new CommandOptions( "invoice", "Invoice", true, false, true, true)); - invoiceCmd.ConfigureAction(mindeeV1Client); + invoiceCmd.ConfigureAction(mindeeClient); v1Command.Subcommands.Add(invoiceCmd); var invoiceSplitterCmd = new PredictInvoiceSplitterCommand(new CommandOptions( "invoice-splitter", "Invoice Splitter", false, false, false, true)); - invoiceSplitterCmd.ConfigureAction(mindeeV1Client); + invoiceSplitterCmd.ConfigureAction(mindeeClient); v1Command.Subcommands.Add(invoiceSplitterCmd); var multiReceiptsDetectorCmd = new PredictMultiReceiptsDetectorCommand(new CommandOptions( "multi-receipts-detector", "Multi Receipts Detector", false, false, true, false)); - multiReceiptsDetectorCmd.ConfigureAction(mindeeV1Client); + multiReceiptsDetectorCmd.ConfigureAction(mindeeClient); v1Command.Subcommands.Add(multiReceiptsDetectorCmd); var passportCmd = new PredictPassportCommand(new CommandOptions( "passport", "Passport", false, false, true, false)); - passportCmd.ConfigureAction(mindeeV1Client); + passportCmd.ConfigureAction(mindeeClient); v1Command.Subcommands.Add(passportCmd); var receiptCmd = new PredictReceiptCommand(new CommandOptions( "receipt", "Receipt", true, false, true, true)); - receiptCmd.ConfigureAction(mindeeV1Client); + receiptCmd.ConfigureAction(mindeeClient); v1Command.Subcommands.Add(receiptCmd); var bankCheckCmd = new PredictBankCheckCommand(new CommandOptions( "us-bank-check", "US Bank Check", false, false, true, false)); - bankCheckCmd.ConfigureAction(mindeeV1Client); + bankCheckCmd.ConfigureAction(mindeeClient); v1Command.Subcommands.Add(bankCheckCmd); } -static void BuildV2Commands(Command v2Command, IServiceProvider services, string[] args) +static void BuildV2Commands(Command v2Command, V2Client mindeeClient) { - var apiKeyOption = new Option("--api-key", "-k") { Description = "Mindee V2 API key." }; - v2Command.Validators.Add(commandResult => - { - try - { - _ = services.GetRequiredService>().Value; - } - catch (OptionsValidationException) - { - commandResult.AddError("Mindee V2 API key is missing. Please provide it via the '--api-key' option or your configured environment variable."); - } - }); - v2Command.Add(apiKeyOption); - var parseResult = v2Command.Parse(args); - var apiKey = parseResult.GetValue(apiKeyOption); - V2Client mindeeV2Client; - - if (apiKey != null) - { - mindeeV2Client = new V2Client(apiKey); - } - else - { - mindeeV2Client = services.GetRequiredService(); - } - var searchModelsCmd = new SearchModelsCommand(); - searchModelsCmd.ConfigureAction(mindeeV2Client); - v2Command.Add(searchModelsCmd); var classificationCmd = new InferenceCommand(new InferenceCommandOptions("classification", "Classification utility.", false, false, false, false, false)); v2Command.Subcommands.Add(classificationCmd); - classificationCmd.ConfigureAction(mindeeV2Client); + classificationCmd.ConfigureAction(mindeeClient); var cropCmd = new InferenceCommand(new InferenceCommandOptions("crop", "Crop utility.", false, false, false, false, false)); v2Command.Subcommands.Add(cropCmd); - cropCmd.ConfigureAction(mindeeV2Client); + cropCmd.ConfigureAction(mindeeClient); var extractionCmd = new InferenceCommand(new InferenceCommandOptions("extraction", "Generic all-purpose extraction.", true, true, true, true, true)); v2Command.Subcommands.Add(extractionCmd); - extractionCmd.ConfigureAction(mindeeV2Client); + extractionCmd.ConfigureAction(mindeeClient); var ocrCmd = new InferenceCommand(new InferenceCommandOptions("ocr", "OCR utility.", false, false, false, false, false)); v2Command.Subcommands.Add(ocrCmd); - ocrCmd.ConfigureAction(mindeeV2Client); + ocrCmd.ConfigureAction(mindeeClient); var splitCmd = new InferenceCommand(new InferenceCommandOptions("split", "Split utility.", false, false, false, false, false)); v2Command.Subcommands.Add(splitCmd); - splitCmd.ConfigureAction(mindeeV2Client); + splitCmd.ConfigureAction(mindeeClient); } -static RootCommand BuildCommandLine(IServiceProvider services, string[] args) +static RootCommand BuildCommandLine(IServiceProvider services) { var root = new RootCommand(); - var v1Command = new Command("v1", "Mindee V1 product commands."); - BuildV1Commands(v1Command, services, args); - var v2Command = new Command("v2", "Mindee V2 product commands."); - BuildV2Commands(v2Command, services, args); - root.Add(v1Command); - root.Add(v2Command); + var v1Command = new Command("v1", "Mindee V1 product commands"); + var mindeeClientV1 = services.GetRequiredService(); + BuildV1Commands(v1Command, mindeeClientV1); + var v2Command = new Command("v2", "Mindee V2 product commands"); + var mindeeClientV2 = services.GetRequiredService(); + BuildV2Commands(v2Command, mindeeClientV2); var silentOption = new Option("--silent") { From e0ffecb794d9e4a2bd7ec9fa64f8b3ddd8c5e70b Mon Sep 17 00:00:00 2001 From: sebastianMindee <130448732+sebastianMindee@users.noreply.github.com> Date: Wed, 11 Mar 2026 10:07:44 +0100 Subject: [PATCH 15/33] temp --- src/Mindee.Cli/Commands/V1/PredictCommand.cs | 4 +- .../Commands/V2/InferenceCommand.cs | 9 ++- src/Mindee.Cli/Program.cs | 61 +++++++++---------- 3 files changed, 39 insertions(+), 35 deletions(-) diff --git a/src/Mindee.Cli/Commands/V1/PredictCommand.cs b/src/Mindee.Cli/Commands/V1/PredictCommand.cs index 061157284..7ffbefd46 100644 --- a/src/Mindee.Cli/Commands/V1/PredictCommand.cs +++ b/src/Mindee.Cli/Commands/V1/PredictCommand.cs @@ -1,5 +1,6 @@ using System.CommandLine; using System.Text.Json; +using Microsoft.Extensions.DependencyInjection; using Mindee.Input; using Mindee.V1; using Mindee.V1.ClientOptions; @@ -93,10 +94,11 @@ public PredictCommand(CommandOptions options) Arguments.Add(_pathArgument); } - public void ConfigureAction(V1Client mindeeClientV1) + public void ConfigureAction(IServiceProvider services) { this.SetAction(parseResult => { + var mindeeClientV1 = services.GetRequiredService(); var path = parseResult.GetValue(_pathArgument)!; var allWords = _allWordsOption != null && parseResult.GetValue(_allWordsOption); var fullText = _fullTextOption != null && parseResult.GetValue(_fullTextOption); diff --git a/src/Mindee.Cli/Commands/V2/InferenceCommand.cs b/src/Mindee.Cli/Commands/V2/InferenceCommand.cs index 6d827b7e3..abb2aa24a 100644 --- a/src/Mindee.Cli/Commands/V2/InferenceCommand.cs +++ b/src/Mindee.Cli/Commands/V2/InferenceCommand.cs @@ -1,5 +1,6 @@ using System.CommandLine; using System.Text.Json; +using Microsoft.Extensions.DependencyInjection; using Mindee.Input; using Mindee.V2; using Mindee.V2.Parsing; @@ -13,6 +14,7 @@ using Mindee.V2.Product.Ocr.Params; using Mindee.V2.Product.Split; using Mindee.V2.Product.Split.Params; +using V2Client = Mindee.V2.Client; namespace Mindee.Cli.Commands.V2 { @@ -85,7 +87,7 @@ public InferenceCommand(InferenceCommandOptions options) if (options.Rag) { - _ragOption = new Option("--rag") + _ragOption = new Option("--rag", "-g") { Description = "Enable RAG context. Only valid for 'extraction' product.", DefaultValueFactory = _ => false @@ -153,10 +155,11 @@ public InferenceCommand(InferenceCommandOptions options) Arguments.Add(_pathArgument); } - public void ConfigureAction(Client mindeeClient) + public void ConfigureAction(IServiceProvider services) { this.SetAction(parseResult => { + var mindeeClientV2 = services.GetRequiredService(); var path = parseResult.GetValue(_pathArgument)!; var modelId = parseResult.GetValue(_modelIdArgument)!; var rag = _ragOption != null && parseResult.GetValue(_ragOption); @@ -177,7 +180,7 @@ public void ConfigureAction(Client mindeeClient) var output = parseResult.GetValue(_outputOption); - var handler = new Handler(mindeeClient); + var handler = new Handler(mindeeClientV2); return handler .InvokeAsync(_productName, modelId, path, alias, rag, rawText, confidence, polygon, textContext, output) .GetAwaiter().GetResult(); diff --git a/src/Mindee.Cli/Program.cs b/src/Mindee.Cli/Program.cs index 915b5894c..45ec3f840 100644 --- a/src/Mindee.Cli/Program.cs +++ b/src/Mindee.Cli/Program.cs @@ -1,5 +1,4 @@ using System.CommandLine; -using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Mindee.Cli.Commands.V2; using Mindee.Extensions.DependencyInjection; @@ -79,8 +78,6 @@ Mindee.V1.Product.Receipt.ReceiptV5Document, Mindee.V1.Product.Receipt.ReceiptV5Document >; -using V1Client = Mindee.V1.Client; -using V2Client = Mindee.V2.Client; var host = Host.CreateDefaultBuilder(args) .ConfigureLogging((_, logging) => @@ -100,7 +97,7 @@ return await root.Parse(args).InvokeAsync(); -static void BuildV1Commands(Command v1Command, V1Client mindeeClient) +static void BuildV1Commands(Command v1Command, IServiceProvider services) { var apiKeyOption = new Option("--api-key", "-k") { Description = "Mindee V2 API key." }; @@ -131,123 +128,125 @@ static void BuildV1Commands(Command v1Command, V1Client mindeeClient) var barcodeReaderCmd = new PredictBarcodeReaderCommand(new CommandOptions( "barcode-reader", "Barcode Reader", false, false, true, false)); - barcodeReaderCmd.ConfigureAction(mindeeClient); + barcodeReaderCmd.ConfigureAction(services); v1Command.Subcommands.Add(barcodeReaderCmd); var cropperCmd = new PredictCropperCommand(new CommandOptions( "cropper", "Cropper", false, false, true, false)); - cropperCmd.ConfigureAction(mindeeClient); + cropperCmd.ConfigureAction(services); v1Command.Subcommands.Add(cropperCmd); var financialDocumentCmd = new PredictFinancialDocumentCommand(new CommandOptions( "financial-document", "Financial Document", true, false, true, true)); - financialDocumentCmd.ConfigureAction(mindeeClient); + financialDocumentCmd.ConfigureAction(services); v1Command.Subcommands.Add(financialDocumentCmd); var bankAccountDetailsCmd = new PredictBankAccountDetailsCommand(new CommandOptions( "fr-bank-account-details", "FR Bank Account Details", false, false, true, false)); - bankAccountDetailsCmd.ConfigureAction(mindeeClient); + bankAccountDetailsCmd.ConfigureAction(services); v1Command.Subcommands.Add(bankAccountDetailsCmd); var carteGriseCmd = new PredictCarteGriseCommand(new CommandOptions( "fr-carte-grise", "FR Carte Grise", false, false, true, false)); - carteGriseCmd.ConfigureAction(mindeeClient); + carteGriseCmd.ConfigureAction(services); v1Command.Subcommands.Add(carteGriseCmd); var healthCardCmd = new PredictHealthCardCommand(new CommandOptions( "fr-health-card", "FR Health Card", false, false, false, true)); - healthCardCmd.ConfigureAction(mindeeClient); + healthCardCmd.ConfigureAction(services); v1Command.Subcommands.Add(healthCardCmd); var idCardCmd = new PredictIdCardCommand(new CommandOptions( "fr-carte-nationale-d-identite", "FR Carte Nationale d'Identité", false, false, true, false)); - idCardCmd.ConfigureAction(mindeeClient); + idCardCmd.ConfigureAction(services); v1Command.Subcommands.Add(idCardCmd); var payslipCmd = new PredictPayslipCommand(new CommandOptions( "fr-payslip", "FR Payslip", false, false, false, true)); - payslipCmd.ConfigureAction(mindeeClient); + payslipCmd.ConfigureAction(services); v1Command.Subcommands.Add(payslipCmd); var internationalIdCmd = new PredictInternationalIdCommand(new CommandOptions( "international-id", "International ID", false, true, false, true)); - internationalIdCmd.ConfigureAction(mindeeClient); + internationalIdCmd.ConfigureAction(services); v1Command.Subcommands.Add(internationalIdCmd); var invoiceCmd = new PredictInvoiceCommand(new CommandOptions( "invoice", "Invoice", true, false, true, true)); - invoiceCmd.ConfigureAction(mindeeClient); + invoiceCmd.ConfigureAction(services); v1Command.Subcommands.Add(invoiceCmd); var invoiceSplitterCmd = new PredictInvoiceSplitterCommand(new CommandOptions( "invoice-splitter", "Invoice Splitter", false, false, false, true)); - invoiceSplitterCmd.ConfigureAction(mindeeClient); + invoiceSplitterCmd.ConfigureAction(services); v1Command.Subcommands.Add(invoiceSplitterCmd); var multiReceiptsDetectorCmd = new PredictMultiReceiptsDetectorCommand(new CommandOptions( "multi-receipts-detector", "Multi Receipts Detector", false, false, true, false)); - multiReceiptsDetectorCmd.ConfigureAction(mindeeClient); + multiReceiptsDetectorCmd.ConfigureAction(services); v1Command.Subcommands.Add(multiReceiptsDetectorCmd); var passportCmd = new PredictPassportCommand(new CommandOptions( "passport", "Passport", false, false, true, false)); - passportCmd.ConfigureAction(mindeeClient); + passportCmd.ConfigureAction(services); v1Command.Subcommands.Add(passportCmd); var receiptCmd = new PredictReceiptCommand(new CommandOptions( "receipt", "Receipt", true, false, true, true)); - receiptCmd.ConfigureAction(mindeeClient); + receiptCmd.ConfigureAction(services); v1Command.Subcommands.Add(receiptCmd); var bankCheckCmd = new PredictBankCheckCommand(new CommandOptions( "us-bank-check", "US Bank Check", false, false, true, false)); - bankCheckCmd.ConfigureAction(mindeeClient); + bankCheckCmd.ConfigureAction(services); v1Command.Subcommands.Add(bankCheckCmd); } -static void BuildV2Commands(Command v2Command, V2Client mindeeClient) +static void BuildV2Commands(Command v2Command, IServiceProvider services) { + var apiKeyOption = new Option("--api-key", "-k") { Description = "Mindee V2 API key.", }; + v2Command.Add(apiKeyOption); var classificationCmd = new InferenceCommand(new InferenceCommandOptions("classification", "Classification utility.", false, false, false, false, false)); v2Command.Subcommands.Add(classificationCmd); - classificationCmd.ConfigureAction(mindeeClient); + classificationCmd.ConfigureAction(services); var cropCmd = new InferenceCommand(new InferenceCommandOptions("crop", "Crop utility.", false, false, false, false, false)); v2Command.Subcommands.Add(cropCmd); - cropCmd.ConfigureAction(mindeeClient); + cropCmd.ConfigureAction(services); var extractionCmd = new InferenceCommand(new InferenceCommandOptions("extraction", "Generic all-purpose extraction.", true, true, true, true, true)); v2Command.Subcommands.Add(extractionCmd); - extractionCmd.ConfigureAction(mindeeClient); + extractionCmd.ConfigureAction(services); var ocrCmd = new InferenceCommand(new InferenceCommandOptions("ocr", "OCR utility.", false, false, false, false, false)); v2Command.Subcommands.Add(ocrCmd); - ocrCmd.ConfigureAction(mindeeClient); + ocrCmd.ConfigureAction(services); var splitCmd = new InferenceCommand(new InferenceCommandOptions("split", "Split utility.", false, false, false, false, false)); v2Command.Subcommands.Add(splitCmd); - splitCmd.ConfigureAction(mindeeClient); + splitCmd.ConfigureAction(services); } static RootCommand BuildCommandLine(IServiceProvider services) { var root = new RootCommand(); - var v1Command = new Command("v1", "Mindee V1 product commands"); - var mindeeClientV1 = services.GetRequiredService(); - BuildV1Commands(v1Command, mindeeClientV1); - var v2Command = new Command("v2", "Mindee V2 product commands"); - var mindeeClientV2 = services.GetRequiredService(); - BuildV2Commands(v2Command, mindeeClientV2); + var v1Command = new Command("v1", "Mindee V1 product commands."); + BuildV1Commands(v1Command, services); + var v2Command = new Command("v2", "Mindee V2 product commands."); + BuildV2Commands(v2Command, services); + root.Add(v1Command); + root.Add(v2Command); var silentOption = new Option("--silent") { From e33c0818bdc78bb38467665a0b0c5fa3520454e0 Mon Sep 17 00:00:00 2001 From: sebastianMindee <130448732+sebastianMindee@users.noreply.github.com> Date: Wed, 11 Mar 2026 10:16:54 +0100 Subject: [PATCH 16/33] fix rebase + update syntax --- src/Mindee/V2/Client.cs | 2 +- src/Mindee/V2/Parsing/BaseResponse.cs | 10 ++++------ 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/Mindee/V2/Client.cs b/src/Mindee/V2/Client.cs index 4ce074100..f6f2b1cb6 100644 --- a/src/Mindee/V2/Client.cs +++ b/src/Mindee/V2/Client.cs @@ -128,7 +128,7 @@ InputSource inputSource /// /// The URL to poll to retrieve the job. /// - /// + /// /// public async Task GetJobFromUrlAsync(string pollingUrl) { diff --git a/src/Mindee/V2/Parsing/BaseResponse.cs b/src/Mindee/V2/Parsing/BaseResponse.cs index a9057338e..d232c8e23 100644 --- a/src/Mindee/V2/Parsing/BaseResponse.cs +++ b/src/Mindee/V2/Parsing/BaseResponse.cs @@ -1,16 +1,14 @@ -using System; -using Mindee.V2.Product; - namespace Mindee.V2.Parsing { /// /// Base class for all responses from the V2 API. /// - public abstract class CommonResponse : BaseResponse where TProduct : BaseProduct, new() + public abstract class BaseResponse { /// - /// Type of product returned by this response + /// The raw server response. + /// This is not formatted in any way by the library and may contain newline and tab characters. /// - public static Type ReturnType => typeof(TProduct); + public string RawResponse { get; set; } } } From d06a3d9ea57936ce7a710271d0ee4d4e8ad648c5 Mon Sep 17 00:00:00 2001 From: sebastianMindee <130448732+sebastianMindee@users.noreply.github.com> Date: Thu, 12 Mar 2026 17:48:00 +0100 Subject: [PATCH 17/33] finish CLI (no tests) --- src/Mindee.Cli/Commands/V1/PredictCommand.cs | 4 +- .../Commands/V2/InferenceCommand.cs | 23 ++--- src/Mindee.Cli/Program.cs | 86 +++++++++++++------ src/Mindee/V2/Client.cs | 11 +-- src/Mindee/V2/Http/HttpApiV2.cs | 17 +++- src/Mindee/V2/Http/MindeeApiV2.cs | 26 +++++- .../V2/Parsing/Inference/BaseInference.cs | 2 +- src/Mindee/V2/Parsing/LocalResponse.cs | 2 +- src/Mindee/V2/Parsing/Search/SearchModels.cs | 2 +- src/Mindee/V2/Product/Crop/CropResponse.cs | 4 +- .../Product/Extraction/ExtractionResponse.cs | 4 +- .../Mindee.IntegrationTests/V2/ClientTest.cs | 2 +- 12 files changed, 123 insertions(+), 60 deletions(-) diff --git a/src/Mindee.Cli/Commands/V1/PredictCommand.cs b/src/Mindee.Cli/Commands/V1/PredictCommand.cs index 7ffbefd46..061157284 100644 --- a/src/Mindee.Cli/Commands/V1/PredictCommand.cs +++ b/src/Mindee.Cli/Commands/V1/PredictCommand.cs @@ -1,6 +1,5 @@ using System.CommandLine; using System.Text.Json; -using Microsoft.Extensions.DependencyInjection; using Mindee.Input; using Mindee.V1; using Mindee.V1.ClientOptions; @@ -94,11 +93,10 @@ public PredictCommand(CommandOptions options) Arguments.Add(_pathArgument); } - public void ConfigureAction(IServiceProvider services) + public void ConfigureAction(V1Client mindeeClientV1) { this.SetAction(parseResult => { - var mindeeClientV1 = services.GetRequiredService(); var path = parseResult.GetValue(_pathArgument)!; var allWords = _allWordsOption != null && parseResult.GetValue(_allWordsOption); var fullText = _fullTextOption != null && parseResult.GetValue(_fullTextOption); diff --git a/src/Mindee.Cli/Commands/V2/InferenceCommand.cs b/src/Mindee.Cli/Commands/V2/InferenceCommand.cs index abb2aa24a..4297ae419 100644 --- a/src/Mindee.Cli/Commands/V2/InferenceCommand.cs +++ b/src/Mindee.Cli/Commands/V2/InferenceCommand.cs @@ -1,6 +1,5 @@ using System.CommandLine; using System.Text.Json; -using Microsoft.Extensions.DependencyInjection; using Mindee.Input; using Mindee.V2; using Mindee.V2.Parsing; @@ -71,12 +70,18 @@ class InferenceCommand : Command private readonly Option? _confidenceOption; private readonly Option? _polygonsOption; private readonly Option? _textContextOption; - private readonly Argument _modelIdArgument; + private readonly Option _modelIdOption; private readonly Argument _pathArgument; public InferenceCommand(InferenceCommandOptions options) : base(options.Name, options.Description) { + + _modelIdOption = new Option("--model-id", "-m") { Description = "ID of the model to use", Required = true }; + Options.Add(_modelIdOption); + var apiKeyOption = new Option("--api-key", "-k") { Description = "Mindee V2 API key." }; + Options.Add(apiKeyOption);// Will not be used at this step, only here for help display purposes. + _productName = options.Name; _aliasOption = new Option("--alias", "-a") { @@ -95,9 +100,6 @@ public InferenceCommand(InferenceCommandOptions options) Options.Add(_ragOption); } - _modelIdArgument = new Argument("model ID") { Description = "ID of the model to use" }; - Arguments.Add(_modelIdArgument); - _outputOption = new Option("--output", "-o") { Description = "Specify how to output the data. \n" + @@ -155,13 +157,12 @@ public InferenceCommand(InferenceCommandOptions options) Arguments.Add(_pathArgument); } - public void ConfigureAction(IServiceProvider services) + public void ConfigureAction(V2Client mindeeClientV2) { this.SetAction(parseResult => { - var mindeeClientV2 = services.GetRequiredService(); var path = parseResult.GetValue(_pathArgument)!; - var modelId = parseResult.GetValue(_modelIdArgument)!; + var modelId = parseResult.GetValue(_modelIdOption)!; var rag = _ragOption != null && parseResult.GetValue(_ragOption); string? alias = null; if (_aliasOption != null) @@ -187,7 +188,7 @@ public void ConfigureAction(IServiceProvider services) }); } - public class Handler(Client mindeeClient) + public class Handler(V2Client mindeeClient) { private readonly JsonSerializerOptions _jsonSerializerOptions = new() { @@ -206,7 +207,7 @@ public async Task InvokeAsync(string product, string modelId, string path, private async Task EnqueueAndGetResultAsync(InferenceOptions options, string productName) { var inputSource = new LocalInputSource(options.Path); - CommonInferenceResponse response = productName switch + BaseResponse response = productName switch { "classification" => await mindeeClient.EnqueueAndGetResultAsync( inputSource, new ClassificationParameters(options.ModelId, options.Alias)), @@ -231,7 +232,7 @@ private async Task EnqueueAndGetResultAsync(InferenceOptions options, strin private void PrintToConsole( TextWriter console, InferenceOptions options, - CommonInferenceResponse response) + BaseResponse response) { if (options.Output == OutputType.Raw) { diff --git a/src/Mindee.Cli/Program.cs b/src/Mindee.Cli/Program.cs index 45ec3f840..c5c9b280a 100644 --- a/src/Mindee.Cli/Program.cs +++ b/src/Mindee.Cli/Program.cs @@ -1,5 +1,7 @@ using System.CommandLine; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Options; using Mindee.Cli.Commands.V2; using Mindee.Extensions.DependencyInjection; using CommandOptions = Mindee.Cli.Commands.V1.CommandOptions; @@ -78,6 +80,10 @@ Mindee.V1.Product.Receipt.ReceiptV5Document, Mindee.V1.Product.Receipt.ReceiptV5Document >; +using SettingsV1 = Mindee.V1.Http.Settings; +using SettingsV2 = Mindee.V2.Http.Settings; +using V1Client = Mindee.V1.Client; +using V2Client = Mindee.V2.Client; var host = Host.CreateDefaultBuilder(args) .ConfigureLogging((_, logging) => @@ -97,7 +103,7 @@ return await root.Parse(args).InvokeAsync(); -static void BuildV1Commands(Command v1Command, IServiceProvider services) +static void BuildV1Commands(Command v1Command, IServiceProvider services, string[] args) { var apiKeyOption = new Option("--api-key", "-k") { Description = "Mindee V2 API key." }; @@ -117,7 +123,7 @@ static void BuildV1Commands(Command v1Command, IServiceProvider services) var apiKey = parseResult.GetValue(apiKeyOption); V1Client mindeeV1Client; - if (apiKey != null) + if (apiKey == null) { mindeeV1Client = new V1Client(apiKey); } @@ -128,123 +134,149 @@ static void BuildV1Commands(Command v1Command, IServiceProvider services) var barcodeReaderCmd = new PredictBarcodeReaderCommand(new CommandOptions( "barcode-reader", "Barcode Reader", false, false, true, false)); - barcodeReaderCmd.ConfigureAction(services); + barcodeReaderCmd.ConfigureAction(mindeeV1Client); v1Command.Subcommands.Add(barcodeReaderCmd); var cropperCmd = new PredictCropperCommand(new CommandOptions( "cropper", "Cropper", false, false, true, false)); - cropperCmd.ConfigureAction(services); + cropperCmd.ConfigureAction(mindeeV1Client); v1Command.Subcommands.Add(cropperCmd); var financialDocumentCmd = new PredictFinancialDocumentCommand(new CommandOptions( "financial-document", "Financial Document", true, false, true, true)); - financialDocumentCmd.ConfigureAction(services); + financialDocumentCmd.ConfigureAction(mindeeV1Client); v1Command.Subcommands.Add(financialDocumentCmd); var bankAccountDetailsCmd = new PredictBankAccountDetailsCommand(new CommandOptions( "fr-bank-account-details", "FR Bank Account Details", false, false, true, false)); - bankAccountDetailsCmd.ConfigureAction(services); + bankAccountDetailsCmd.ConfigureAction(mindeeV1Client); v1Command.Subcommands.Add(bankAccountDetailsCmd); var carteGriseCmd = new PredictCarteGriseCommand(new CommandOptions( "fr-carte-grise", "FR Carte Grise", false, false, true, false)); - carteGriseCmd.ConfigureAction(services); + carteGriseCmd.ConfigureAction(mindeeV1Client); v1Command.Subcommands.Add(carteGriseCmd); var healthCardCmd = new PredictHealthCardCommand(new CommandOptions( "fr-health-card", "FR Health Card", false, false, false, true)); - healthCardCmd.ConfigureAction(services); + healthCardCmd.ConfigureAction(mindeeV1Client); v1Command.Subcommands.Add(healthCardCmd); var idCardCmd = new PredictIdCardCommand(new CommandOptions( "fr-carte-nationale-d-identite", "FR Carte Nationale d'Identité", false, false, true, false)); - idCardCmd.ConfigureAction(services); + idCardCmd.ConfigureAction(mindeeV1Client); v1Command.Subcommands.Add(idCardCmd); var payslipCmd = new PredictPayslipCommand(new CommandOptions( "fr-payslip", "FR Payslip", false, false, false, true)); - payslipCmd.ConfigureAction(services); + payslipCmd.ConfigureAction(mindeeV1Client); v1Command.Subcommands.Add(payslipCmd); var internationalIdCmd = new PredictInternationalIdCommand(new CommandOptions( "international-id", "International ID", false, true, false, true)); - internationalIdCmd.ConfigureAction(services); + internationalIdCmd.ConfigureAction(mindeeV1Client); v1Command.Subcommands.Add(internationalIdCmd); var invoiceCmd = new PredictInvoiceCommand(new CommandOptions( "invoice", "Invoice", true, false, true, true)); - invoiceCmd.ConfigureAction(services); + invoiceCmd.ConfigureAction(mindeeV1Client); v1Command.Subcommands.Add(invoiceCmd); var invoiceSplitterCmd = new PredictInvoiceSplitterCommand(new CommandOptions( "invoice-splitter", "Invoice Splitter", false, false, false, true)); - invoiceSplitterCmd.ConfigureAction(services); + invoiceSplitterCmd.ConfigureAction(mindeeV1Client); v1Command.Subcommands.Add(invoiceSplitterCmd); var multiReceiptsDetectorCmd = new PredictMultiReceiptsDetectorCommand(new CommandOptions( "multi-receipts-detector", "Multi Receipts Detector", false, false, true, false)); - multiReceiptsDetectorCmd.ConfigureAction(services); + multiReceiptsDetectorCmd.ConfigureAction(mindeeV1Client); v1Command.Subcommands.Add(multiReceiptsDetectorCmd); var passportCmd = new PredictPassportCommand(new CommandOptions( "passport", "Passport", false, false, true, false)); - passportCmd.ConfigureAction(services); + passportCmd.ConfigureAction(mindeeV1Client); v1Command.Subcommands.Add(passportCmd); var receiptCmd = new PredictReceiptCommand(new CommandOptions( "receipt", "Receipt", true, false, true, true)); - receiptCmd.ConfigureAction(services); + receiptCmd.ConfigureAction(mindeeV1Client); v1Command.Subcommands.Add(receiptCmd); var bankCheckCmd = new PredictBankCheckCommand(new CommandOptions( "us-bank-check", "US Bank Check", false, false, true, false)); - bankCheckCmd.ConfigureAction(services); + bankCheckCmd.ConfigureAction(mindeeV1Client); v1Command.Subcommands.Add(bankCheckCmd); } -static void BuildV2Commands(Command v2Command, IServiceProvider services) +static void BuildV2Commands(Command v2Command, IServiceProvider services, string[] args) { - var apiKeyOption = new Option("--api-key", "-k") { Description = "Mindee V2 API key.", }; + var apiKeyOption = new Option("--api-key", "-k") { Description = "Mindee V2 API key." }; + v2Command.Validators.Add(commandResult => + { + try + { + _ = services.GetRequiredService>().Value; + } + catch (OptionsValidationException) + { + commandResult.AddError("Mindee V2 API key is missing. Please provide it via the '--api-key' option or your configured environment variable."); + } + }); v2Command.Add(apiKeyOption); + var parseResult = v2Command.Parse(args); + var apiKey = parseResult.GetValue(apiKeyOption); + V2Client mindeeV2Client; + + if (apiKey == null) + { + mindeeV2Client = new V2Client(apiKey); + } + else + { + mindeeV2Client = services.GetRequiredService(); + } + var searchModelsCmd = new SearchModelsCommand(); + searchModelsCmd.ConfigureAction(mindeeV2Client); + v2Command.Add(searchModelsCmd); var classificationCmd = new InferenceCommand(new InferenceCommandOptions("classification", "Classification utility.", false, false, false, false, false)); v2Command.Subcommands.Add(classificationCmd); - classificationCmd.ConfigureAction(services); + classificationCmd.ConfigureAction(mindeeV2Client); var cropCmd = new InferenceCommand(new InferenceCommandOptions("crop", "Crop utility.", false, false, false, false, false)); v2Command.Subcommands.Add(cropCmd); - cropCmd.ConfigureAction(services); + cropCmd.ConfigureAction(mindeeV2Client); var extractionCmd = new InferenceCommand(new InferenceCommandOptions("extraction", "Generic all-purpose extraction.", true, true, true, true, true)); v2Command.Subcommands.Add(extractionCmd); - extractionCmd.ConfigureAction(services); + extractionCmd.ConfigureAction(mindeeV2Client); var ocrCmd = new InferenceCommand(new InferenceCommandOptions("ocr", "OCR utility.", false, false, false, false, false)); v2Command.Subcommands.Add(ocrCmd); - ocrCmd.ConfigureAction(services); + ocrCmd.ConfigureAction(mindeeV2Client); var splitCmd = new InferenceCommand(new InferenceCommandOptions("split", "Split utility.", false, false, false, false, false)); v2Command.Subcommands.Add(splitCmd); - splitCmd.ConfigureAction(services); + splitCmd.ConfigureAction(mindeeV2Client); } -static RootCommand BuildCommandLine(IServiceProvider services) +static RootCommand BuildCommandLine(IServiceProvider services, string[] args) { var root = new RootCommand(); var v1Command = new Command("v1", "Mindee V1 product commands."); - BuildV1Commands(v1Command, services); + BuildV1Commands(v1Command, services, args); var v2Command = new Command("v2", "Mindee V2 product commands."); - BuildV2Commands(v2Command, services); + BuildV2Commands(v2Command, services, args); root.Add(v1Command); root.Add(v2Command); diff --git a/src/Mindee/V2/Client.cs b/src/Mindee/V2/Client.cs index f6f2b1cb6..ca3b24bcc 100644 --- a/src/Mindee/V2/Client.cs +++ b/src/Mindee/V2/Client.cs @@ -9,6 +9,7 @@ using Mindee.V2.ClientOptions; using Mindee.V2.Http; using Mindee.V2.Parsing; +using Mindee.V2.Parsing.Search; using Mindee.V2.Product.Extraction; using Mindee.V2.Product.Extraction.Params; using SettingsV2 = Mindee.V2.Http.Settings; @@ -151,7 +152,7 @@ public async Task GetJobFromUrlAsync(string pollingUrl) /// /// private async Task GetResultFromUrlAsync(string pollingUrl) - where TResponse : CommonInferenceResponse, new() + where TResponse : BaseResponse, new() { _logger?.LogInformation("Polling: {}", pollingUrl); @@ -171,7 +172,7 @@ private async Task GetResultFromUrlAsync(string pollingUrl /// /// public async Task GetResultAsync(string jobId) - where TResponse : CommonInferenceResponse, new() + where TResponse : BaseResponse, new() { _logger?.LogInformation("Polling: {}", jobId); @@ -218,7 +219,7 @@ public async Task GetJobAsync(string jobId) public async Task EnqueueAndGetResultAsync( InputSource inputSource , BaseParameters parameters) - where TResponse : CommonInferenceResponse, new() + where TResponse : BaseResponse, new() { switch (inputSource) { @@ -246,7 +247,7 @@ InputSource inputSource /// Returns a list of models matching a criteria for the given API key. /// /// - public async Task SearchModels(string name = null, string modelType = null) + public async Task SearchModels(string name=null, string modelType=null) { return await _mindeeApi.SearchModels(name, modelType); } @@ -266,7 +267,7 @@ public async Task SearchModels(string name = null, string modelT /// Thrown when maxRetries is reached and the result isn't ready. private async Task PollForResultsAsync( JobResponse enqueueResponse, - PollingOptions pollingOptions) where TResponse : CommonInferenceResponse, new() + PollingOptions pollingOptions) where TResponse : BaseResponse, new() { var maxRetries = pollingOptions.MaxRetries + 1; var pollingUrl = enqueueResponse.Job.PollingUrl; diff --git a/src/Mindee/V2/Http/HttpApiV2.cs b/src/Mindee/V2/Http/HttpApiV2.cs index 685a42a17..67bac16ea 100644 --- a/src/Mindee/V2/Http/HttpApiV2.cs +++ b/src/Mindee/V2/Http/HttpApiV2.cs @@ -7,6 +7,7 @@ using Mindee.Input; using Mindee.V2.ClientOptions; using Mindee.V2.Parsing; +using Mindee.V2.Parsing.Search; namespace Mindee.V2.Http { @@ -52,13 +53,21 @@ public abstract class HttpApiV2 /// Get a document inference. /// /// Url to poll. - public abstract Task ReqGetResultAsync(string inferenceId) where TResponse : CommonInferenceResponse, new(); + public abstract Task ReqGetResultAsync(string inferenceId) where TResponse : BaseResponse, new(); /// /// Get a document inference. /// /// Url to poll. - public abstract Task ReqGetResultFromUrlAsync(string resultUrl) where TResponse : CommonInferenceResponse, new(); + public abstract Task ReqGetResultFromUrlAsync(string resultUrl) where TResponse : BaseResponse, new(); + + /// + /// Retrieves a list of models available for a given API key. + /// + /// Name of the model to search for. + /// Type of the model to search for. + /// + public abstract Task SearchModels(string? name, string? modelType); /// /// Get the error from the server return. @@ -92,7 +101,7 @@ protected ErrorResponse GetErrorFromContent(int statusCode, string? responseCont /// /// protected TResponse DeserializeResponse(string? responseContent) - where TResponse : CommonInferenceResponse, new() + where TResponse : BaseResponse, new() { Logger?.LogInformation("Parsing HTTP 2xx response ..."); @@ -102,7 +111,7 @@ protected TResponse DeserializeResponse(string? responseContent) } var deserializedResult = JsonSerializer.Deserialize(responseContent); - if (deserializedResult is CommonInferenceResponse model) + if (deserializedResult is BaseResponse model) { model.RawResponse = responseContent; return (TResponse)model; diff --git a/src/Mindee/V2/Http/MindeeApiV2.cs b/src/Mindee/V2/Http/MindeeApiV2.cs index d58a1d9e2..6db263d59 100644 --- a/src/Mindee/V2/Http/MindeeApiV2.cs +++ b/src/Mindee/V2/Http/MindeeApiV2.cs @@ -10,6 +10,8 @@ using Mindee.Input; using Mindee.V2.ClientOptions; using Mindee.V2.Parsing; +using Mindee.V2.Parsing.Search; +using Mindee.V2.Product; using Mindee.V2.Product.Extraction.Params; using RestSharp; #if NET6_0_OR_GREATER @@ -62,6 +64,26 @@ BaseParameters parameters return HandleJobResponse(response); } + public override async Task SearchModels(string name, string modelType) + { + var request = new RestRequest("v2/search/models"); + Logger?.LogInformation("Fetching models..."); + if (!string.IsNullOrWhiteSpace(name)) + { + Logger?.LogInformation("Models matching name like {Name}", name); + request.AddParameter("name", name); + } + + if (!string.IsNullOrWhiteSpace(modelType)) + { + Logger?.LogInformation("Models matching model_type={ModelType}", modelType); + request.AddParameter("model_type", modelType); + } + + var response = await _httpClient.ExecuteGetAsync(request); + return handleSearchResponse(response); + } + public override async Task ReqGetJobAsync(string jobId) { var request = new RestRequest($"v2/jobs/{jobId}"); @@ -85,7 +107,7 @@ public override async Task ReqGetJobFromUrlAsync(string pollingUrl) public override async Task ReqGetResultAsync(string inferenceId) { - var slug = typeof(TResponse).GetCustomAttribute(); + var slug = typeof(TResponse).GetCustomAttribute(); var request = new RestRequest($"v2/products/{slug}/results/{inferenceId}"); Logger?.LogInformation("HTTP GET to {RequestResource}...", request.Resource); var queueResponse = await _httpClient.ExecuteGetAsync(request); @@ -209,7 +231,7 @@ private JobResponse HandleJobResponse(RestResponse restResponse) } private TResponse HandleProductResponse(RestResponse restResponse) - where TResponse : CommonInferenceResponse, new() + where TResponse : BaseResponse, new() { Logger?.LogDebug("HTTP response: {RestResponseContent}", restResponse.Content); diff --git a/src/Mindee/V2/Parsing/Inference/BaseInference.cs b/src/Mindee/V2/Parsing/Inference/BaseInference.cs index 52f1155f0..a27dc9701 100644 --- a/src/Mindee/V2/Parsing/Inference/BaseInference.cs +++ b/src/Mindee/V2/Parsing/Inference/BaseInference.cs @@ -3,7 +3,7 @@ using System.Text.Json.Serialization; using Mindee.Parsing; -namespace Mindee.V2.Parsing +namespace Mindee.V2.Parsing.Inference { /// /// Base for all inference-based V2 products. diff --git a/src/Mindee/V2/Parsing/LocalResponse.cs b/src/Mindee/V2/Parsing/LocalResponse.cs index b0071cf10..fde34ca66 100644 --- a/src/Mindee/V2/Parsing/LocalResponse.cs +++ b/src/Mindee/V2/Parsing/LocalResponse.cs @@ -26,7 +26,7 @@ public LocalResponse(FileInfo input) : base(input) /// /// public TResponse DeserializeResponse() - where TResponse : CommonInferenceResponse, new() + where TResponse : BaseResponse, new() { var model = JsonSerializer.Deserialize(FileBytes); diff --git a/src/Mindee/V2/Parsing/Search/SearchModels.cs b/src/Mindee/V2/Parsing/Search/SearchModels.cs index b1fd3abe4..2c9e8c190 100644 --- a/src/Mindee/V2/Parsing/Search/SearchModels.cs +++ b/src/Mindee/V2/Parsing/Search/SearchModels.cs @@ -18,7 +18,7 @@ public override string ToString() return "\n"; } StringBuilder stringBuilder = new StringBuilder(); - foreach (SearchModel model in this) + foreach(SearchModel model in this) { stringBuilder.Append($"* :Name: {model.Name}"); stringBuilder.Append('\n'); diff --git a/src/Mindee/V2/Product/Crop/CropResponse.cs b/src/Mindee/V2/Product/Crop/CropResponse.cs index ef4ccf76d..4f422efa7 100644 --- a/src/Mindee/V2/Product/Crop/CropResponse.cs +++ b/src/Mindee/V2/Product/Crop/CropResponse.cs @@ -6,8 +6,8 @@ namespace Mindee.V2.Product.Crop /// /// Represent a crop response from Mindee V2 API. /// - [EndpointSlug("crop")] - public class CropResponse : CommonInferenceResponse + [ProductSlug("crop")] + public class CropResponse : BaseResponse { /// /// Contents of the inference. diff --git a/src/Mindee/V2/Product/Extraction/ExtractionResponse.cs b/src/Mindee/V2/Product/Extraction/ExtractionResponse.cs index 071fab776..4d1caa290 100644 --- a/src/Mindee/V2/Product/Extraction/ExtractionResponse.cs +++ b/src/Mindee/V2/Product/Extraction/ExtractionResponse.cs @@ -6,8 +6,8 @@ namespace Mindee.V2.Product.Extraction /// /// Response for an extraction inference. /// - [EndpointSlug("extraction")] - public class ExtractionResponse : CommonInferenceResponse + [ProductSlug("extraction")] + public class ExtractionResponse : BaseResponse { /// /// Contents of the inference. diff --git a/tests/Mindee.IntegrationTests/V2/ClientTest.cs b/tests/Mindee.IntegrationTests/V2/ClientTest.cs index fdddc0e37..b56f1096b 100644 --- a/tests/Mindee.IntegrationTests/V2/ClientTest.cs +++ b/tests/Mindee.IntegrationTests/V2/ClientTest.cs @@ -1,7 +1,7 @@ using Mindee.Exceptions; using Mindee.Input; using Mindee.V2; -using Mindee.V2.Parsing; +using Mindee.V2.Parsing.Inference; using Mindee.V2.Product.Extraction; using Mindee.V2.Product.Extraction.Params; From 6b89d15281c1b00af1fd5df669d811bf90ad2738 Mon Sep 17 00:00:00 2001 From: sebastianMindee <130448732+sebastianMindee@users.noreply.github.com> Date: Thu, 12 Mar 2026 17:50:46 +0100 Subject: [PATCH 18/33] fix lint --- src/Mindee/V2/Client.cs | 2 +- src/Mindee/V2/Parsing/Search/SearchModels.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Mindee/V2/Client.cs b/src/Mindee/V2/Client.cs index ca3b24bcc..d103cdb6b 100644 --- a/src/Mindee/V2/Client.cs +++ b/src/Mindee/V2/Client.cs @@ -247,7 +247,7 @@ InputSource inputSource /// Returns a list of models matching a criteria for the given API key. /// /// - public async Task SearchModels(string name=null, string modelType=null) + public async Task SearchModels(string name = null, string modelType = null) { return await _mindeeApi.SearchModels(name, modelType); } diff --git a/src/Mindee/V2/Parsing/Search/SearchModels.cs b/src/Mindee/V2/Parsing/Search/SearchModels.cs index 2c9e8c190..b1fd3abe4 100644 --- a/src/Mindee/V2/Parsing/Search/SearchModels.cs +++ b/src/Mindee/V2/Parsing/Search/SearchModels.cs @@ -18,7 +18,7 @@ public override string ToString() return "\n"; } StringBuilder stringBuilder = new StringBuilder(); - foreach(SearchModel model in this) + foreach (SearchModel model in this) { stringBuilder.Append($"* :Name: {model.Name}"); stringBuilder.Append('\n'); From 1a2f62868c9bc635263cdbbc81c5fcf68faa1cf5 Mon Sep 17 00:00:00 2001 From: sebastianMindee <130448732+sebastianMindee@users.noreply.github.com> Date: Fri, 13 Mar 2026 11:46:03 +0100 Subject: [PATCH 19/33] tidy up --- src/Mindee.Cli/Commands/V1/PredictCommand.cs | 55 ++++++------ .../Commands/V2/InferenceCommand.cs | 83 +++++++++---------- 2 files changed, 66 insertions(+), 72 deletions(-) diff --git a/src/Mindee.Cli/Commands/V1/PredictCommand.cs b/src/Mindee.Cli/Commands/V1/PredictCommand.cs index 061157284..790b5831a 100644 --- a/src/Mindee.Cli/Commands/V1/PredictCommand.cs +++ b/src/Mindee.Cli/Commands/V1/PredictCommand.cs @@ -163,35 +163,32 @@ private void PrintToConsole( { switch (options.Output) { - console.Write(JsonSerializer.Serialize(response, _jsonSerializerOptions)); - } - else - { - if (options.AllWords && response.Document.Ocr != null) - { - console.Write("#############\nDocument Text\n#############\n::\n"); - var ocr = response.Document.Ocr.ToString().Replace("\n", "\n "); - console.Write(" " + ocr + "\n\n"); - } - else if (options.FullText && response.Document.Inference.Extras.FullTextOcr != null) - { - console.Write("#############\nDocument Text\n#############\n::\n"); - var ocr = response.Document.Inference.Extras.FullTextOcr.Replace("\n", "\n "); - console.Write(" " + ocr + "\n\n"); - } - - switch (options.Output) - { - case OutputType.Full: - console.Write(response.Document.ToString()); - break; - case OutputType.Summary: - console.Write(response.Document.Inference.Prediction.ToString()); - break; - case OutputType.Raw: - console.Write(response.RawResponse); - break; - } + case OutputType.Full: + if (options.AllWords && response.Document.Ocr != null) + { + console.Write("#############\nDocument Text\n#############\n::\n"); + var ocr = response.Document.Ocr.ToString().Replace("\n", "\n "); + console.Write(" " + ocr + "\n\n"); + } + else if (options.FullText && response.Document.Inference.Extras.FullTextOcr != null) + { + console.Write("#############\nDocument Text\n#############\n::\n"); + var ocr = response.Document.Inference.Extras.FullTextOcr.Replace("\n", "\n "); + console.Write(" " + ocr + "\n\n"); + } + console.Write(response.Document.ToString()); + break; + case OutputType.Summary: + console.Write(response.Document.Inference.Prediction.ToString()); + break; + case OutputType.Raw: + using (var jsonDocument = JsonDocument.Parse(response.RawResponse)) + { + console.WriteLine(JsonSerializer.Serialize(jsonDocument, _jsonSerializerOptions)); + } + break; + default: + throw new ArgumentOutOfRangeException($"Unknown output type: {options.Output}."); } } } diff --git a/src/Mindee.Cli/Commands/V2/InferenceCommand.cs b/src/Mindee.Cli/Commands/V2/InferenceCommand.cs index 4297ae419..80db73d5c 100644 --- a/src/Mindee.Cli/Commands/V2/InferenceCommand.cs +++ b/src/Mindee.Cli/Commands/V2/InferenceCommand.cs @@ -1,7 +1,6 @@ using System.CommandLine; using System.Text.Json; using Mindee.Input; -using Mindee.V2; using Mindee.V2.Parsing; using Mindee.V2.Product.Classification; using Mindee.V2.Product.Classification.Params; @@ -76,11 +75,11 @@ class InferenceCommand : Command public InferenceCommand(InferenceCommandOptions options) : base(options.Name, options.Description) { - - _modelIdOption = new Option("--model-id", "-m") { Description = "ID of the model to use", Required = true }; + _modelIdOption = + new Option("--model-id", "-m") { Description = "ID of the model to use", Required = true }; Options.Add(_modelIdOption); var apiKeyOption = new Option("--api-key", "-k") { Description = "Mindee V2 API key." }; - Options.Add(apiKeyOption);// Will not be used at this step, only here for help display purposes. + Options.Add(apiKeyOption); // Will not be used at this step, only here for help display purposes. _productName = options.Name; _aliasOption = new Option("--alias", "-a") @@ -104,6 +103,7 @@ public InferenceCommand(InferenceCommandOptions options) { Description = "Specify how to output the data. \n" + "- summary: a basic summary (default)\n" + + "- full: detail extraction results, including options\n" + "- raw: full JSON object\n", DefaultValueFactory = _ => OutputType.Summary }; @@ -183,7 +183,8 @@ public void ConfigureAction(V2Client mindeeClientV2) var handler = new Handler(mindeeClientV2); return handler - .InvokeAsync(_productName, modelId, path, alias, rag, rawText, confidence, polygon, textContext, output) + .InvokeAsync(_productName, modelId, path, alias, rag, rawText, confidence, polygon, textContext, + output) .GetAwaiter().GetResult(); }); } @@ -234,51 +235,47 @@ private void PrintToConsole( InferenceOptions options, BaseResponse response) { - if (options.Output == OutputType.Raw) + var validTypes = new[] { - console.Write(JsonSerializer.Serialize(response, _jsonSerializerOptions)); - } - else + typeof(ClassificationResponse), typeof(CropResponse), typeof(OcrResponse), + typeof(SplitResponse), typeof(ExtractionResponse) + }; + + if (!validTypes.Contains(response.GetType())) { - var validTypes = new[] - { - typeof(ClassificationResponse), typeof(CropResponse), typeof(OcrResponse), - typeof(SplitResponse), typeof(ExtractionResponse) - }; + return; + } - if (validTypes.Contains(response.GetType())) - { - dynamic dynResponse = response; + dynamic dynResponse = response; + switch (options.Output) + { + case OutputType.Full: if (options.RawText && dynResponse.Inference.ActiveOptions.RawText) { - if (options.RawText && dynResponse.Inference.ActiveOptions.RawText) - { - console.Write("#############\nDocument Text\n#############\n::\n"); - var rawText = dynResponse.Inference.Result.RawText.ToString().Replace("\n", "\n "); - console.Write(" " + rawText + "\n\n"); - } - else if (options.Rag && dynResponse.Inference.ActiveOptions.Rag) - { - console.Write("#############\nDocument Text\n#############\n::\n"); - var rawText = dynResponse.Inference.Result.Rag.ToString().Replace("\n", "\n "); - console.Write(" " + rawText + "\n\n"); - } - - switch (options.Output) - { - case OutputType.Full: - console.Write(dynResponse.Inference.ToString()); - break; - case OutputType.Summary: - console.Write(dynResponse.Inference.Result.ToString()); - break; - case OutputType.Raw: - console.Write(response.RawResponse); - break; - } + console.Write("#############\nRaw Text\n#############\n::\n"); + var rawText = dynResponse.Inference.Result.RawText.ToString().Replace("\n", "\n "); + console.Write(" " + rawText + "\n\n"); + } + if (options.Rag && dynResponse.Inference.ActiveOptions.Rag) + { + console.Write("#############\nRetrieval-Augmented Generation\n#############\n::\n"); + var rawText = dynResponse.Inference.Result.Rag.ToString().Replace("\n", "\n "); + console.Write(" " + rawText + "\n\n"); + } + console.Write(dynResponse.Inference.ToString()); + break; + case OutputType.Summary: + console.Write(dynResponse.Inference.Result.ToString()); + break; + case OutputType.Raw: + using (var jsonDocument = JsonDocument.Parse(response.RawResponse)) + { + console.WriteLine(JsonSerializer.Serialize(jsonDocument, _jsonSerializerOptions)); } - } + break; + default: + throw new ArgumentOutOfRangeException($"Unknown output type: {options.Output}."); } } } From 770dada583407ef8c7688480cc39fbed5d05e5f9 Mon Sep 17 00:00:00 2001 From: sebastianMindee <130448732+sebastianMindee@users.noreply.github.com> Date: Fri, 13 Mar 2026 14:30:49 +0100 Subject: [PATCH 20/33] add tests --- .github/workflows/_test-cli.yml | 23 +++++++++-------------- .github/workflows/pull-request.yml | 2 ++ src/Mindee.Cli/Program.cs | 4 ++-- 3 files changed, 13 insertions(+), 16 deletions(-) diff --git a/.github/workflows/_test-cli.yml b/.github/workflows/_test-cli.yml index 37c59029d..3356cbc71 100644 --- a/.github/workflows/_test-cli.yml +++ b/.github/workflows/_test-cli.yml @@ -5,8 +5,8 @@ on: workflow_dispatch: env: - Mindee__ApiKey: ${{ secrets.MINDEE_API_KEY_SE_TESTS }} - MindeeV2__ApiKey: ${{ secrets.MINDEE_V2_SE_TESTS_API_KEY }} + MINDEE_API_KEY: ${{ secrets.MINDEE_API_KEY_SE_TESTS }} + MINDEE_V2_API_KEY: ${{ secrets.MINDEE_V2_SE_TESTS_API_KEY }} MINDEE_V2_SE_TESTS_FINDOC_MODEL_ID: ${{ secrets.MINDEE_V2_SE_TESTS_FINDOC_MODEL_ID }} MINDEE_V2_SE_TESTS_CLASSIFICATION_MODEL_ID: ${{ secrets.MINDEE_V2_SE_TESTS_CLASSIFICATION_MODEL_ID }} MINDEE_V2_SE_TESTS_CROP_MODEL_ID: ${{ secrets.MINDEE_V2_SE_TESTS_CROP_MODEL_ID }} @@ -18,7 +18,7 @@ jobs: name: Run CLI tests timeout-minutes: 30 strategy: - max-parallel: 4 + max-parallel: 3 matrix: os_config: - os: "ubuntu-22.04" @@ -28,6 +28,7 @@ jobs: - os: "windows-latest" rid: "win-x64" dotnet: + - "net6.0" - "net8.0" - "net10.0" include: @@ -64,24 +65,18 @@ jobs: run: | dotnet tool install -g dotnet-script - - name: Publish Locally (.NET Framework) - if: startsWith(matrix.dotnet, 'net4') + - name: Publish Locally run: | cd src/Mindee.Cli - dotnet publish -f ${{ matrix.dotnet }} -c Release -r ${{ matrix.os_config.rid }} -o ./bin/Release/${{ matrix.dotnet }}/${{ matrix.os_config.rid }} - - - name: Publish Locally (.NET 6+) - if: ${{ !startsWith(matrix.dotnet, 'net4') }} - run: | - cd src/Mindee.Cli - dotnet publish -f ${{ matrix.dotnet }} -c Release -r ${{ matrix.os_config.rid }} --self-contained true -p:PublishSingleFile=true -o ./bin/Release/${{ matrix.dotnet }}/${{ matrix.os_config.rid }} + dotnet publish -f ${{ matrix.dotnet }} -c Release -r ${{ matrix.os_config.rid }} --self-contained true -p:PublishSingleFile=true - name: Test V1 CLI shell: bash run: | - ./tests/test_v1_cli.sh ./tests/resources/file_types/pdf/blank_1.pdf ${{ matrix.dotnet }} ${{ matrix.os_config.rid }} + ./src/Mindee.Cli/tests/test_v1_cli.sh ./tests/resources/file_types/pdf/blank_1.pdf ${{ matrix.dotnet }} ${{ matrix.os_config.rid }} - name: Test V2 CLI shell: bash run: | - ./tests/test_v2_cli.sh ./tests/resources/file_types/pdf/blank_1.pdf ${{ matrix.dotnet }} ${{ matrix.os_config.rid }} + ./src/Mindee.Cli/tests/test_v2_cli.sh ./tests/resources/file_types/pdf/blank_1.pdf ${{ matrix.dotnet }} ${{ matrix.os_config.rid }} + diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index 62497a451..e44e3cc0a 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -29,6 +29,8 @@ jobs: actions: read security-events: write contents: read + test-cli: + uses: ./.github/workflows/_test-cli.yml test-units: uses: ./.github/workflows/_test-units.yml needs: diff --git a/src/Mindee.Cli/Program.cs b/src/Mindee.Cli/Program.cs index c5c9b280a..3b01674ba 100644 --- a/src/Mindee.Cli/Program.cs +++ b/src/Mindee.Cli/Program.cs @@ -123,7 +123,7 @@ static void BuildV1Commands(Command v1Command, IServiceProvider services, string var apiKey = parseResult.GetValue(apiKeyOption); V1Client mindeeV1Client; - if (apiKey == null) + if (apiKey != null) { mindeeV1Client = new V1Client(apiKey); } @@ -241,7 +241,7 @@ static void BuildV2Commands(Command v2Command, IServiceProvider services, string var apiKey = parseResult.GetValue(apiKeyOption); V2Client mindeeV2Client; - if (apiKey == null) + if (apiKey != null) { mindeeV2Client = new V2Client(apiKey); } From 0c72daef02351939cd4b61f2e08a51cb6392977b Mon Sep 17 00:00:00 2001 From: sebastianMindee <130448732+sebastianMindee@users.noreply.github.com> Date: Fri, 13 Mar 2026 14:34:30 +0100 Subject: [PATCH 21/33] add search models test --- tests/test_v2_cli.sh | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/test_v2_cli.sh b/tests/test_v2_cli.sh index f8dc406ce..de1860f0e 100755 --- a/tests/test_v2_cli.sh +++ b/tests/test_v2_cli.sh @@ -38,6 +38,17 @@ else CLI_PATH="./src/Mindee.Cli/bin/Release/$NET_VERSION/$RID/Mindee.Cli" fi +echo "--- Test model list retrieval" +MODELS=$("$CLI_PATH" v2 search-models) +if [[ -z "${MODELS}" ]]; then + echo "Error: no models found" + exit 1 +else + echo "Models retrieval OK" +fi + +declare -A MODEL_MAP + if [ "$RID" = "win-x64" ]; then CLI_PATH="${CLI_PATH}.exe" fi From fdecbbdea74a80a5c8e2058c122b6073b781bdba Mon Sep 17 00:00:00 2001 From: sebastianMindee <130448732+sebastianMindee@users.noreply.github.com> Date: Fri, 13 Mar 2026 14:47:08 +0100 Subject: [PATCH 22/33] fix test --- .github/workflows/_test-cli.yml | 4 ++-- .github/workflows/pull-request.yml | 6 ++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/.github/workflows/_test-cli.yml b/.github/workflows/_test-cli.yml index 3356cbc71..5cfa01e81 100644 --- a/.github/workflows/_test-cli.yml +++ b/.github/workflows/_test-cli.yml @@ -73,10 +73,10 @@ jobs: - name: Test V1 CLI shell: bash run: | - ./src/Mindee.Cli/tests/test_v1_cli.sh ./tests/resources/file_types/pdf/blank_1.pdf ${{ matrix.dotnet }} ${{ matrix.os_config.rid }} + ./tests/test_v1_cli.sh ./tests/resources/file_types/pdf/blank_1.pdf ${{ matrix.dotnet }} ${{ matrix.os_config.rid }} - name: Test V2 CLI shell: bash run: | - ./src/Mindee.Cli/tests/test_v2_cli.sh ./tests/resources/file_types/pdf/blank_1.pdf ${{ matrix.dotnet }} ${{ matrix.os_config.rid }} + ./tests/test_v2_cli.sh ./tests/resources/file_types/pdf/blank_1.pdf ${{ matrix.dotnet }} ${{ matrix.os_config.rid }} diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index e44e3cc0a..33dcb6ecb 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -29,8 +29,6 @@ jobs: actions: read security-events: write contents: read - test-cli: - uses: ./.github/workflows/_test-cli.yml test-units: uses: ./.github/workflows/_test-units.yml needs: @@ -50,3 +48,7 @@ jobs: uses: ./.github/workflows/_test-cli.yml needs: test-units secrets: inherit + test-cli: + uses: ./.github/workflows/_test-cli.yml + needs: test-smoke + secrets: inherit From eb0c177d4da7eed4992cd45436a3f22339fb0bd7 Mon Sep 17 00:00:00 2001 From: sebastianMindee <130448732+sebastianMindee@users.noreply.github.com> Date: Fri, 13 Mar 2026 15:59:36 +0100 Subject: [PATCH 23/33] make tests go a bit faster --- .github/workflows/_test-cli.yml | 2 +- .github/workflows/pull-request.yml | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/.github/workflows/_test-cli.yml b/.github/workflows/_test-cli.yml index 5cfa01e81..b7eef03df 100644 --- a/.github/workflows/_test-cli.yml +++ b/.github/workflows/_test-cli.yml @@ -18,7 +18,7 @@ jobs: name: Run CLI tests timeout-minutes: 30 strategy: - max-parallel: 3 + max-parallel: 4 matrix: os_config: - os: "ubuntu-22.04" diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index 33dcb6ecb..62497a451 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -48,7 +48,3 @@ jobs: uses: ./.github/workflows/_test-cli.yml needs: test-units secrets: inherit - test-cli: - uses: ./.github/workflows/_test-cli.yml - needs: test-smoke - secrets: inherit From 3a8c13e63d01665689d8d63f60b07d6c9f99e81a Mon Sep 17 00:00:00 2001 From: sebastianMindee <130448732+sebastianMindee@users.noreply.github.com> Date: Fri, 13 Mar 2026 16:12:37 +0100 Subject: [PATCH 24/33] fix env vars --- .github/workflows/_test-cli.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/_test-cli.yml b/.github/workflows/_test-cli.yml index b7eef03df..eae4756af 100644 --- a/.github/workflows/_test-cli.yml +++ b/.github/workflows/_test-cli.yml @@ -5,8 +5,8 @@ on: workflow_dispatch: env: - MINDEE_API_KEY: ${{ secrets.MINDEE_API_KEY_SE_TESTS }} - MINDEE_V2_API_KEY: ${{ secrets.MINDEE_V2_SE_TESTS_API_KEY }} + Mindee__ApiKey: ${{ secrets.MINDEE_API_KEY_SE_TESTS }} + MindeeV2__ApiKey: ${{ secrets.MINDEE_V2_SE_TESTS_API_KEY }} MINDEE_V2_SE_TESTS_FINDOC_MODEL_ID: ${{ secrets.MINDEE_V2_SE_TESTS_FINDOC_MODEL_ID }} MINDEE_V2_SE_TESTS_CLASSIFICATION_MODEL_ID: ${{ secrets.MINDEE_V2_SE_TESTS_CLASSIFICATION_MODEL_ID }} MINDEE_V2_SE_TESTS_CROP_MODEL_ID: ${{ secrets.MINDEE_V2_SE_TESTS_CROP_MODEL_ID }} From b643b6ca49d3dde30b7f0c07d57854335c0edc40 Mon Sep 17 00:00:00 2001 From: sebastianMindee <130448732+sebastianMindee@users.noreply.github.com> Date: Fri, 13 Mar 2026 16:39:30 +0100 Subject: [PATCH 25/33] disable event logging for windows --- .github/workflows/_test-cli.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/_test-cli.yml b/.github/workflows/_test-cli.yml index eae4756af..9f00ca084 100644 --- a/.github/workflows/_test-cli.yml +++ b/.github/workflows/_test-cli.yml @@ -12,6 +12,7 @@ env: MINDEE_V2_SE_TESTS_CROP_MODEL_ID: ${{ secrets.MINDEE_V2_SE_TESTS_CROP_MODEL_ID }} MINDEE_V2_SE_TESTS_SPLIT_MODEL_ID: ${{ secrets.MINDEE_V2_SE_TESTS_SPLIT_MODEL_ID }} MINDEE_V2_SE_TESTS_OCR_MODEL_ID: ${{ secrets.MINDEE_V2_SE_TESTS_OCR_MODEL_ID }} + Logging__EventLog__LogLevel__Default: "None" jobs: test: From 22dc7759e20d21d6be0d591cf114f0aff7df5ac8 Mon Sep 17 00:00:00 2001 From: sebastianMindee <130448732+sebastianMindee@users.noreply.github.com> Date: Fri, 13 Mar 2026 17:17:06 +0100 Subject: [PATCH 26/33] fix windows logging --- .github/workflows/_test-cli.yml | 1 - src/Mindee.Cli/Program.cs | 10 ++++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/.github/workflows/_test-cli.yml b/.github/workflows/_test-cli.yml index 9f00ca084..eae4756af 100644 --- a/.github/workflows/_test-cli.yml +++ b/.github/workflows/_test-cli.yml @@ -12,7 +12,6 @@ env: MINDEE_V2_SE_TESTS_CROP_MODEL_ID: ${{ secrets.MINDEE_V2_SE_TESTS_CROP_MODEL_ID }} MINDEE_V2_SE_TESTS_SPLIT_MODEL_ID: ${{ secrets.MINDEE_V2_SE_TESTS_SPLIT_MODEL_ID }} MINDEE_V2_SE_TESTS_OCR_MODEL_ID: ${{ secrets.MINDEE_V2_SE_TESTS_OCR_MODEL_ID }} - Logging__EventLog__LogLevel__Default: "None" jobs: test: diff --git a/src/Mindee.Cli/Program.cs b/src/Mindee.Cli/Program.cs index 3b01674ba..b9ec28666 100644 --- a/src/Mindee.Cli/Program.cs +++ b/src/Mindee.Cli/Program.cs @@ -1,6 +1,7 @@ using System.CommandLine; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Mindee.Cli.Commands.V2; using Mindee.Extensions.DependencyInjection; @@ -86,11 +87,12 @@ using V2Client = Mindee.V2.Client; var host = Host.CreateDefaultBuilder(args) - .ConfigureLogging((_, logging) => + .ConfigureLogging(logging => { - logging.ClearProviders(); - logging.AddConsole(); - logging.AddDebug(); + if (Environment.OSVersion.Platform != PlatformID.Win32NT) + { + logging.AddFilter("Microsoft.Extensions.Logging.EventLog", LogLevel.None); + } }) .ConfigureServices((_, services) => { From 9f0cc2cb2e8e9d985fa1dc429b0403d5e805ed41 Mon Sep 17 00:00:00 2001 From: sebastianMindee <130448732+sebastianMindee@users.noreply.github.com> Date: Fri, 13 Mar 2026 17:42:21 +0100 Subject: [PATCH 27/33] fix? --- src/Mindee.Cli/Program.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Mindee.Cli/Program.cs b/src/Mindee.Cli/Program.cs index b9ec28666..11a02cab4 100644 --- a/src/Mindee.Cli/Program.cs +++ b/src/Mindee.Cli/Program.cs @@ -87,11 +87,13 @@ using V2Client = Mindee.V2.Client; var host = Host.CreateDefaultBuilder(args) - .ConfigureLogging(logging => + .ConfigureLogging((_, logging) => { if (Environment.OSVersion.Platform != PlatformID.Win32NT) { - logging.AddFilter("Microsoft.Extensions.Logging.EventLog", LogLevel.None); + logging.ClearProviders(); + logging.AddConsole(); + logging.AddDebug(); } }) .ConfigureServices((_, services) => From 2b27979e1a7a73c89083dceb0ee0cc2098223e46 Mon Sep 17 00:00:00 2001 From: sebastianMindee <130448732+sebastianMindee@users.noreply.github.com> Date: Fri, 13 Mar 2026 18:14:32 +0100 Subject: [PATCH 28/33] fix windows CI --- tests/test_v1_cli.sh | 3 +++ tests/test_v2_cli.sh | 3 +++ 2 files changed, 6 insertions(+) diff --git a/tests/test_v1_cli.sh b/tests/test_v1_cli.sh index f40d10c81..b48888889 100755 --- a/tests/test_v1_cli.sh +++ b/tests/test_v1_cli.sh @@ -37,6 +37,9 @@ if [ "$WD" = "tests" ]; then else CLI_PATH="./src/Mindee.Cli/bin/Release/$NET_VERSION/$RID/Mindee.Cli" fi +if [[ "$RID" == "win-x64" ]]; then + CLI_PATH="${CLI_PATH}.exe" +fi if [ "$RID" = "win-x64" ]; then CLI_PATH="${CLI_PATH}.exe" diff --git a/tests/test_v2_cli.sh b/tests/test_v2_cli.sh index de1860f0e..4dffa010a 100755 --- a/tests/test_v2_cli.sh +++ b/tests/test_v2_cli.sh @@ -37,6 +37,9 @@ if [ "$WD" = "tests" ]; then else CLI_PATH="./src/Mindee.Cli/bin/Release/$NET_VERSION/$RID/Mindee.Cli" fi +if [[ "$RID" == "win-x64" ]]; then + CLI_PATH="${CLI_PATH}.exe" +fi echo "--- Test model list retrieval" MODELS=$("$CLI_PATH" v2 search-models) From 849db694879a1c42670ac2733e3c1943bf54635d Mon Sep 17 00:00:00 2001 From: sebastianMindee <130448732+sebastianMindee@users.noreply.github.com> Date: Sun, 15 Mar 2026 20:20:26 +0100 Subject: [PATCH 29/33] fix again? --- src/Mindee.Cli/Program.cs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/Mindee.Cli/Program.cs b/src/Mindee.Cli/Program.cs index 11a02cab4..d78585c6c 100644 --- a/src/Mindee.Cli/Program.cs +++ b/src/Mindee.Cli/Program.cs @@ -89,12 +89,9 @@ var host = Host.CreateDefaultBuilder(args) .ConfigureLogging((_, logging) => { - if (Environment.OSVersion.Platform != PlatformID.Win32NT) - { - logging.ClearProviders(); - logging.AddConsole(); - logging.AddDebug(); - } + logging.ClearProviders(); + logging.AddConsole(); + logging.AddDebug(); }) .ConfigureServices((_, services) => { From 4db750ab2ef8358059b7f06e63f5e808b9786f62 Mon Sep 17 00:00:00 2001 From: sebastianMindee <130448732+sebastianMindee@users.noreply.github.com> Date: Sun, 15 Mar 2026 20:58:44 +0100 Subject: [PATCH 30/33] fix 472/48 --- .github/workflows/_test-cli.yml | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/.github/workflows/_test-cli.yml b/.github/workflows/_test-cli.yml index eae4756af..8298e3691 100644 --- a/.github/workflows/_test-cli.yml +++ b/.github/workflows/_test-cli.yml @@ -65,10 +65,17 @@ jobs: run: | dotnet tool install -g dotnet-script - - name: Publish Locally + - name: Publish Locally (.NET Framework) + if: startsWith(matrix.dotnet, 'net4') run: | cd src/Mindee.Cli - dotnet publish -f ${{ matrix.dotnet }} -c Release -r ${{ matrix.os_config.rid }} --self-contained true -p:PublishSingleFile=true + dotnet publish -f ${{ matrix.dotnet }} -c Release -r ${{ matrix.os_config.rid }} -o ./bin/Release/${{ matrix.dotnet }}/${{ matrix.os_config.rid }} + + - name: Publish Locally (.NET 6+) + if: ${{ !startsWith(matrix.dotnet, 'net4') }} + run: | + cd src/Mindee.Cli + dotnet publish -f ${{ matrix.dotnet }} -c Release -r ${{ matrix.os_config.rid }} --self-contained true -p:PublishSingleFile=true -o ./bin/Release/${{ matrix.dotnet }}/${{ matrix.os_config.rid }} - name: Test V1 CLI shell: bash @@ -79,4 +86,3 @@ jobs: shell: bash run: | ./tests/test_v2_cli.sh ./tests/resources/file_types/pdf/blank_1.pdf ${{ matrix.dotnet }} ${{ matrix.os_config.rid }} - From 1bc43b72fb9f6aa311fd32fbad244c1bc21765c2 Mon Sep 17 00:00:00 2001 From: sebastianMindee <130448732+sebastianMindee@users.noreply.github.com> Date: Mon, 16 Mar 2026 11:02:14 +0100 Subject: [PATCH 31/33] address suggestions --- .github/workflows/_test-cli.yml | 1 - src/Mindee.Cli/Commands/V2/InferenceCommand.cs | 8 ++++---- tests/test_v1_cli.sh | 3 --- tests/test_v2_cli.sh | 14 -------------- 4 files changed, 4 insertions(+), 22 deletions(-) diff --git a/.github/workflows/_test-cli.yml b/.github/workflows/_test-cli.yml index 8298e3691..37c59029d 100644 --- a/.github/workflows/_test-cli.yml +++ b/.github/workflows/_test-cli.yml @@ -28,7 +28,6 @@ jobs: - os: "windows-latest" rid: "win-x64" dotnet: - - "net6.0" - "net8.0" - "net10.0" include: diff --git a/src/Mindee.Cli/Commands/V2/InferenceCommand.cs b/src/Mindee.Cli/Commands/V2/InferenceCommand.cs index 80db73d5c..cfb2901b0 100644 --- a/src/Mindee.Cli/Commands/V2/InferenceCommand.cs +++ b/src/Mindee.Cli/Commands/V2/InferenceCommand.cs @@ -114,7 +114,7 @@ public InferenceCommand(InferenceCommandOptions options) _rawTextOption = new Option("--raw-text", "-r") { Description = - "To get all the words in the current document. Only supported in some plans. False by default.", + "To get all the words in the current document. False by default.", DefaultValueFactory = _ => false }; Options.Add(_rawTextOption); @@ -125,7 +125,7 @@ public InferenceCommand(InferenceCommandOptions options) _confidenceOption = new Option("--confidence", "-c") { Description = - "To retrieve confidence scores from the extraction. Only supported in some plans. False by default.", + "To retrieve confidence scores from the extraction. False by default.", DefaultValueFactory = _ => false }; Options.Add(_confidenceOption); @@ -136,7 +136,7 @@ public InferenceCommand(InferenceCommandOptions options) _polygonsOption = new Option("--polygon", "-p") { Description = - "To retrieve bounding boxes from the extraction. Only supported in some plans. False by default.", + "To retrieve bounding boxes from the extraction. False by default.", DefaultValueFactory = _ => false }; Options.Add(_polygonsOption); @@ -147,7 +147,7 @@ public InferenceCommand(InferenceCommandOptions options) _textContextOption = new Option("--text-context", "-t") { Description = - "To add text context to your API call. Only supported in some plans. False by default.", + "To add text context to your API call. False by default.", DefaultValueFactory = _ => null }; Options.Add(_textContextOption); diff --git a/tests/test_v1_cli.sh b/tests/test_v1_cli.sh index b48888889..f40d10c81 100755 --- a/tests/test_v1_cli.sh +++ b/tests/test_v1_cli.sh @@ -37,9 +37,6 @@ if [ "$WD" = "tests" ]; then else CLI_PATH="./src/Mindee.Cli/bin/Release/$NET_VERSION/$RID/Mindee.Cli" fi -if [[ "$RID" == "win-x64" ]]; then - CLI_PATH="${CLI_PATH}.exe" -fi if [ "$RID" = "win-x64" ]; then CLI_PATH="${CLI_PATH}.exe" diff --git a/tests/test_v2_cli.sh b/tests/test_v2_cli.sh index 4dffa010a..f8dc406ce 100755 --- a/tests/test_v2_cli.sh +++ b/tests/test_v2_cli.sh @@ -37,20 +37,6 @@ if [ "$WD" = "tests" ]; then else CLI_PATH="./src/Mindee.Cli/bin/Release/$NET_VERSION/$RID/Mindee.Cli" fi -if [[ "$RID" == "win-x64" ]]; then - CLI_PATH="${CLI_PATH}.exe" -fi - -echo "--- Test model list retrieval" -MODELS=$("$CLI_PATH" v2 search-models) -if [[ -z "${MODELS}" ]]; then - echo "Error: no models found" - exit 1 -else - echo "Models retrieval OK" -fi - -declare -A MODEL_MAP if [ "$RID" = "win-x64" ]; then CLI_PATH="${CLI_PATH}.exe" From e67a925ab940003f0b45de5a0a56deb40fd6ff5e Mon Sep 17 00:00:00 2001 From: sebastianMindee <130448732+sebastianMindee@users.noreply.github.com> Date: Mon, 16 Mar 2026 11:08:44 +0100 Subject: [PATCH 32/33] :recycle: update CI --- .github/workflows/_publish-code.yml | 2 +- .github/workflows/_publish-docs.yml | 4 ++-- .github/workflows/_static-analysis.yml | 2 +- .github/workflows/_test-cli.yml | 11 +++++------ .github/workflows/_test-integrations.yml | 9 +++------ .github/workflows/_test-smoke.yml | 5 ++--- .github/workflows/_test-units.yml | 5 ++--- 7 files changed, 16 insertions(+), 22 deletions(-) diff --git a/.github/workflows/_publish-code.yml b/.github/workflows/_publish-code.yml index 10390d96d..3a4cc4ef2 100644 --- a/.github/workflows/_publish-code.yml +++ b/.github/workflows/_publish-code.yml @@ -16,7 +16,7 @@ jobs: - name: Setup .NET uses: actions/setup-dotnet@v4 with: - dotnet-version: '9.0.x' + dotnet-version: '10.0.x' - name: Restore strong-name key from secret run: | diff --git a/.github/workflows/_publish-docs.yml b/.github/workflows/_publish-docs.yml index e4d437ff3..5fae2486d 100644 --- a/.github/workflows/_publish-docs.yml +++ b/.github/workflows/_publish-docs.yml @@ -17,7 +17,7 @@ concurrency: jobs: build: - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 steps: - name: Checkout uses: actions/checkout@v4 @@ -25,7 +25,7 @@ jobs: - name: Setup .NET uses: actions/setup-dotnet@v4 with: - dotnet-version: '9.0.x' + dotnet-version: '10.0.x' - name: Build run: dotnet build "src" --configuration Release diff --git a/.github/workflows/_static-analysis.yml b/.github/workflows/_static-analysis.yml index df2ca2a5b..1e41a53c1 100644 --- a/.github/workflows/_static-analysis.yml +++ b/.github/workflows/_static-analysis.yml @@ -14,7 +14,7 @@ jobs: - name: Setup .NET uses: actions/setup-dotnet@v4 with: - dotnet-version: '9.0.x' + dotnet-version: '10.0.x' - name: Install dotnet-format tool run: dotnet tool install -g dotnet-format diff --git a/.github/workflows/_test-cli.yml b/.github/workflows/_test-cli.yml index 37c59029d..d3fb29e5c 100644 --- a/.github/workflows/_test-cli.yml +++ b/.github/workflows/_test-cli.yml @@ -21,10 +21,10 @@ jobs: max-parallel: 4 matrix: os_config: - - os: "ubuntu-22.04" + - os: "ubuntu-24.04" rid: "linux-x64" -# - os: "macos-latest" -# rid: "osx-x64" + - os: "macos-latest" + rid: "osx-x64" - os: "windows-latest" rid: "win-x64" dotnet: @@ -49,7 +49,6 @@ jobs: uses: actions/setup-dotnet@v4 with: dotnet-version: | - 6.0.x 8.0.x 10.0.x @@ -77,11 +76,11 @@ jobs: dotnet publish -f ${{ matrix.dotnet }} -c Release -r ${{ matrix.os_config.rid }} --self-contained true -p:PublishSingleFile=true -o ./bin/Release/${{ matrix.dotnet }}/${{ matrix.os_config.rid }} - name: Test V1 CLI - shell: bash + shell: sh run: | ./tests/test_v1_cli.sh ./tests/resources/file_types/pdf/blank_1.pdf ${{ matrix.dotnet }} ${{ matrix.os_config.rid }} - name: Test V2 CLI - shell: bash + shell: sh run: | ./tests/test_v2_cli.sh ./tests/resources/file_types/pdf/blank_1.pdf ${{ matrix.dotnet }} ${{ matrix.os_config.rid }} diff --git a/.github/workflows/_test-integrations.yml b/.github/workflows/_test-integrations.yml index 49a40f21e..e27678e40 100644 --- a/.github/workflows/_test-integrations.yml +++ b/.github/workflows/_test-integrations.yml @@ -24,9 +24,8 @@ jobs: max-parallel: 4 matrix: os: - - "ubuntu-22.04" - # needs looking into - # - "macos-14" + - "ubuntu-24.04" + - "macos-15" dotnet-version: - "net6.0" - "net8.0" @@ -40,7 +39,6 @@ jobs: uses: actions/setup-dotnet@v4 with: dotnet-version: | - 6.0.x 8.0.x 10.0.x @@ -68,7 +66,7 @@ jobs: dotnet-version: - "net472" - "net48" - - "net6.0" + - "net8.0" - "net10.0" runs-on: ${{ matrix.os }} steps: @@ -80,7 +78,6 @@ jobs: uses: actions/setup-dotnet@v4 with: dotnet-version: | - 6.0.x 8.0.x 10.0.x diff --git a/.github/workflows/_test-smoke.yml b/.github/workflows/_test-smoke.yml index 75d028e44..5bfd3e568 100644 --- a/.github/workflows/_test-smoke.yml +++ b/.github/workflows/_test-smoke.yml @@ -22,10 +22,10 @@ jobs: max-parallel: 3 matrix: os: - - "ubuntu-22.04" + - "ubuntu-24.04" dotnet: - - "net6.0" - "net8.0" + - "net10.0" runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v4 @@ -36,7 +36,6 @@ jobs: uses: actions/setup-dotnet@v4 with: dotnet-version: | - 6.0.x 8.0.x 10.0.x diff --git a/.github/workflows/_test-units.yml b/.github/workflows/_test-units.yml index 9475991df..1177fc142 100644 --- a/.github/workflows/_test-units.yml +++ b/.github/workflows/_test-units.yml @@ -10,9 +10,9 @@ jobs: strategy: matrix: os: - - "ubuntu-22.04" + - "ubuntu-24.04" # needs looking into - # - "macos-14" + - "macos-15" dotnet: - "net6.0" - "net8.0" @@ -65,7 +65,6 @@ jobs: id: setup-step with: dotnet-version: | - 6.0.x 8.0.x 10.0.x From fd0bff29876f7b7372a150622132905d64486058 Mon Sep 17 00:00:00 2001 From: sebastianMindee <130448732+sebastianMindee@users.noreply.github.com> Date: Mon, 16 Mar 2026 11:30:25 +0100 Subject: [PATCH 33/33] fix version for integration tests --- .github/workflows/_test-integrations.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/_test-integrations.yml b/.github/workflows/_test-integrations.yml index e27678e40..a1c21cfe0 100644 --- a/.github/workflows/_test-integrations.yml +++ b/.github/workflows/_test-integrations.yml @@ -27,8 +27,8 @@ jobs: - "ubuntu-24.04" - "macos-15" dotnet-version: - - "net6.0" - "net8.0" + - "net10.0" runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v4