From 41933e17f71bf89f5f8a8537f5e3fc99b6cb10f2 Mon Sep 17 00:00:00 2001 From: sebastianMindee <130448732+sebastianMindee@users.noreply.github.com> Date: Tue, 21 Apr 2026 17:27:03 +0200 Subject: [PATCH 1/3] :sparkles: add nuGet support for CLI --- .github/workflows/_publish-cli-code.yml | 49 +++++++++++++++++++++++++ .github/workflows/publish-release.yml | 3 ++ src/Mindee.Cli/Mindee.Cli.csproj | 3 ++ 3 files changed, 55 insertions(+) create mode 100644 .github/workflows/_publish-cli-code.yml diff --git a/.github/workflows/_publish-cli-code.yml b/.github/workflows/_publish-cli-code.yml new file mode 100644 index 000000000..bc38c5476 --- /dev/null +++ b/.github/workflows/_publish-cli-code.yml @@ -0,0 +1,49 @@ +name: Publish CLI to NuGet + +on: + workflow_call: + workflow_dispatch: + +jobs: + publish: + name: Publish CLI release to NuGet + runs-on: ubuntu-latest + + steps: + - name: Check out Git repository + uses: actions/checkout@v5 + + - name: Setup .NET + uses: actions/setup-dotnet@v4 + with: + dotnet-version: '10.0.x' + + - name: Restore strong-name key from secret + run: | + echo "${{ secrets.MINDEE_SNK_B64 }}" | base64 -d > /tmp/Mindee.snk + chmod 600 /tmp/Mindee.snk + + - name: Install dependencies + run: dotnet restore "src/Mindee.Cli" -p:TargetFrameworks=net8.0 + + - name: Build (strong-name signed) + run: dotnet build "src/Mindee.Cli" --configuration Release --no-restore -p:TargetFrameworks=net8.0 -p:MindeeStrongNameKeyFile=/tmp/Mindee.snk + + - name: Pack + run: dotnet pack "src/Mindee.Cli" -c Release -p:PackAsTool=true -p:TargetFrameworks=net8.0 -p:IncludeSymbols=true -p:SymbolPackageFormat=snupkg --no-build --no-restore --output nuget + + - name: Verify strong-name (PublicKeyToken) + run: | + sudo apt-get update + sudo apt-get install -y mono-devel unzip + DLL_PATH=$(unzip -Z -1 nuget/*.nupkg | grep -m1 '/Mindee.dll$') + if [ -z "$DLL_PATH" ]; then + echo "Mindee.dll not found in packaged CLI tool." + exit 1 + fi + unzip -p nuget/*.nupkg "$DLL_PATH" > /tmp/Mindee.dll + sn -T /tmp/Mindee.dll + sn -vf /tmp/Mindee.dll + + - name: Publish NuGet packages to NuGet + run: dotnet nuget push nuget/*.nupkg --api-key ${{ secrets.NUGET_KEY }} --source "nuget.org" --skip-duplicate diff --git a/.github/workflows/publish-release.yml b/.github/workflows/publish-release.yml index 5a369a4f3..0053387db 100644 --- a/.github/workflows/publish-release.yml +++ b/.github/workflows/publish-release.yml @@ -15,3 +15,6 @@ jobs: publish_code: uses: mindee/mindee-api-dotnet/.github/workflows/_publish-code.yml@main secrets: inherit + publish_cli_code: + uses: mindee/mindee-api-dotnet/.github/workflows/_publish-cli-code.yml@main + secrets: inherit diff --git a/src/Mindee.Cli/Mindee.Cli.csproj b/src/Mindee.Cli/Mindee.Cli.csproj index 9c1119201..fc70dbdf4 100644 --- a/src/Mindee.Cli/Mindee.Cli.csproj +++ b/src/Mindee.Cli/Mindee.Cli.csproj @@ -4,6 +4,8 @@ Exe enable enable + true + mindee @@ -43,6 +45,7 @@ + From 056ff2088ee4397a555ed98cd92550a8bc0bfaee Mon Sep 17 00:00:00 2001 From: sebastianMindee <130448732+sebastianMindee@users.noreply.github.com> Date: Tue, 21 Apr 2026 17:44:11 +0200 Subject: [PATCH 2/3] fix thresholds for test --- tests/Mindee.IntegrationTests/V2/FileOperations/CropTest.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/Mindee.IntegrationTests/V2/FileOperations/CropTest.cs b/tests/Mindee.IntegrationTests/V2/FileOperations/CropTest.cs index e851e459e..70778c0a1 100644 --- a/tests/Mindee.IntegrationTests/V2/FileOperations/CropTest.cs +++ b/tests/Mindee.IntegrationTests/V2/FileOperations/CropTest.cs @@ -80,10 +80,10 @@ public async Task Extract_Crops_From_Image_Correctly() extractedImages.SaveAllToDisk(_outputDir, 50); var file1Info = new FileInfo(Path.Combine(_outputDir, "crop_001.jpg")); - Assert.InRange(file1Info.Length, 99000, 110000); + Assert.InRange(file1Info.Length, 98000, 110000); var file2Info = new FileInfo(Path.Combine(_outputDir, "crop_002.jpg")); - Assert.InRange(file2Info.Length, 99000, 110000); + Assert.InRange(file2Info.Length, 98000, 110000); } [Fact(Timeout = 180000)] From dcb79f09bacfd3322e0fcbd21b356a8d716635e6 Mon Sep 17 00:00:00 2001 From: sebastianMindee <130448732+sebastianMindee@users.noreply.github.com> Date: Wed, 22 Apr 2026 13:08:14 +0200 Subject: [PATCH 3/3] fix CLI for nuget publish --- .gitignore | 2 + src/Mindee.Cli/Commands/V1/PredictCommand.cs | 15 ++- .../Commands/V2/InferenceCommand.cs | 45 ++++++- .../Commands/V2/SearchModelsCommand.cs | 46 ++++++- src/Mindee.Cli/Mindee.Cli.csproj | 2 +- src/Mindee.Cli/Program.cs | 94 +++++--------- src/Mindee.Cli/README.md | 116 ++++++++++++++++++ 7 files changed, 251 insertions(+), 69 deletions(-) create mode 100644 src/Mindee.Cli/README.md diff --git a/.gitignore b/.gitignore index d1cbd4e00..30a04578b 100644 --- a/.gitignore +++ b/.gitignore @@ -370,3 +370,5 @@ _site # StrongName files *.snk *.snk.b64 +# Local CLI publish. +dotnet-tools.json diff --git a/src/Mindee.Cli/Commands/V1/PredictCommand.cs b/src/Mindee.Cli/Commands/V1/PredictCommand.cs index 790b5831a..b1e7bddb9 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.Options; using Mindee.Input; using Mindee.V1; using Mindee.V1.ClientOptions; @@ -93,7 +94,7 @@ public PredictCommand(CommandOptions options) Arguments.Add(_pathArgument); } - public void ConfigureAction(V1Client mindeeClientV1) + public void ConfigureAction(Func clientFactory) { this.SetAction(parseResult => { @@ -102,6 +103,18 @@ public void ConfigureAction(V1Client mindeeClientV1) var fullText = _fullTextOption != null && parseResult.GetValue(_fullTextOption); var output = parseResult.GetValue(_outputOption); var isAsync = _asyncOption != null && parseResult.GetValue(_asyncOption); + V1Client mindeeClientV1; + try + { + mindeeClientV1 = clientFactory(); + } + catch (OptionsValidationException) + { + Console.Error.WriteLine( + "The Mindee V1 API key is missing. " + + "Please provide it via the '--api-key' option or your configured environment variable."); + return 1; + } var handler = new Handler(mindeeClientV1); return handler.InvokeAsync(path, allWords, fullText, output, isAsync).GetAwaiter().GetResult(); diff --git a/src/Mindee.Cli/Commands/V2/InferenceCommand.cs b/src/Mindee.Cli/Commands/V2/InferenceCommand.cs index cfb2901b0..f86099097 100644 --- a/src/Mindee.Cli/Commands/V2/InferenceCommand.cs +++ b/src/Mindee.Cli/Commands/V2/InferenceCommand.cs @@ -1,5 +1,7 @@ using System.CommandLine; using System.Text.Json; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; using Mindee.Input; using Mindee.V2.Parsing; using Mindee.V2.Product.Classification; @@ -12,6 +14,7 @@ using Mindee.V2.Product.Ocr.Params; using Mindee.V2.Product.Split; using Mindee.V2.Product.Split.Params; +using SettingsV2 = Mindee.V2.Http.Settings; using V2Client = Mindee.V2.Client; namespace Mindee.Cli.Commands.V2 @@ -71,6 +74,7 @@ class InferenceCommand : Command private readonly Option? _textContextOption; private readonly Option _modelIdOption; private readonly Argument _pathArgument; + private readonly Option _apiKeyOption; public InferenceCommand(InferenceCommandOptions options) : base(options.Name, options.Description) @@ -78,8 +82,8 @@ public InferenceCommand(InferenceCommandOptions options) _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. + _apiKeyOption = new Option("--api-key", "-k") { Description = "Mindee V2 API key." }; + Options.Add(_apiKeyOption); _productName = options.Name; _aliasOption = new Option("--alias", "-a") @@ -157,8 +161,28 @@ public InferenceCommand(InferenceCommandOptions options) Arguments.Add(_pathArgument); } - public void ConfigureAction(V2Client mindeeClientV2) + public void ConfigureAction(IServiceProvider services) { + Validators.Add(commandResult => + { + var apiKey = commandResult.GetValue(_apiKeyOption); + if (!string.IsNullOrWhiteSpace(apiKey)) + { + return; + } + + try + { + _ = services.GetRequiredService>().Value; + } + catch (OptionsValidationException) + { + commandResult.AddError( + "The Mindee V2 API key is missing. " + + "Please provide it via the '--api-key' option or your configured environment variable."); + } + }); + this.SetAction(parseResult => { var path = parseResult.GetValue(_pathArgument)!; @@ -180,6 +204,21 @@ public void ConfigureAction(V2Client mindeeClientV2) } var output = parseResult.GetValue(_outputOption); + var apiKey = parseResult.GetValue(_apiKeyOption); + V2Client mindeeClientV2; + try + { + mindeeClientV2 = !string.IsNullOrWhiteSpace(apiKey) + ? new V2Client(apiKey) + : services.GetRequiredService(); + } + catch (OptionsValidationException) + { + Console.Error.WriteLine( + "The Mindee V2 API key is missing. " + + "Please provide it via the '--api-key' option or your configured environment variable."); + return 1; + } var handler = new Handler(mindeeClientV2); return handler diff --git a/src/Mindee.Cli/Commands/V2/SearchModelsCommand.cs b/src/Mindee.Cli/Commands/V2/SearchModelsCommand.cs index d49304d57..63a7bac12 100644 --- a/src/Mindee.Cli/Commands/V2/SearchModelsCommand.cs +++ b/src/Mindee.Cli/Commands/V2/SearchModelsCommand.cs @@ -1,6 +1,9 @@ using System.CommandLine; using System.Text.Json; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; using Mindee.V2.Parsing.Search; +using SettingsV2 = Mindee.V2.Http.Settings; using V2Client = Mindee.V2.Client; namespace Mindee.Cli.Commands.V2 @@ -10,6 +13,7 @@ namespace Mindee.Cli.Commands.V2 /// public class SearchModelsCommand : Command { + private readonly Option _apiKeyOption; private readonly Option? _nameOption; private readonly Option? _modelTypeOption; private readonly Option? _rawOption; @@ -19,6 +23,9 @@ public class SearchModelsCommand : Command /// public SearchModelsCommand() : base("search-models", "Search available models.") { + _apiKeyOption = new Option("--api-key", "-k") { Description = "Mindee V2 API key." }; + Options.Add(_apiKeyOption); + _nameOption = new Option("--name", "-n") { Description = "Filter by model name partial match (case insensitive).", @@ -50,14 +57,49 @@ Filter by exact model type (case sensitive). /// /// /// - /// V2 Client instance - public void ConfigureAction(V2Client mindeeClientV2) + /// Service provider for dependency resolution + public void ConfigureAction(IServiceProvider services) { + Validators.Add(commandResult => + { + var apiKey = commandResult.GetValue(_apiKeyOption); + if (!string.IsNullOrWhiteSpace(apiKey)) + { + return; + } + + try + { + _ = services.GetRequiredService>().Value; + } + catch (OptionsValidationException) + { + commandResult.AddError( + "The Mindee V2 API key is missing. " + + "Please provide it via the '--api-key' option or your configured environment variable."); + } + }); + this.SetAction(parseResult => { var name = _nameOption != null ? parseResult.GetValue(_nameOption) : null; var modelType = _modelTypeOption != null ? parseResult.GetValue(_modelTypeOption) : null; var raw = _rawOption != null && parseResult.GetValue(_rawOption); + var apiKey = parseResult.GetValue(_apiKeyOption); + V2Client mindeeClientV2; + try + { + mindeeClientV2 = !string.IsNullOrWhiteSpace(apiKey) + ? new V2Client(apiKey) + : services.GetRequiredService(); + } + catch (OptionsValidationException) + { + Console.Error.WriteLine( + "The Mindee V2 API key is missing. " + + "Please provide it via the '--api-key' option or your configured environment variable."); + return 1; + } var handler = new Handler(mindeeClientV2); return handler diff --git a/src/Mindee.Cli/Mindee.Cli.csproj b/src/Mindee.Cli/Mindee.Cli.csproj index fc70dbdf4..f2fe4833e 100644 --- a/src/Mindee.Cli/Mindee.Cli.csproj +++ b/src/Mindee.Cli/Mindee.Cli.csproj @@ -45,7 +45,7 @@ - + diff --git a/src/Mindee.Cli/Program.cs b/src/Mindee.Cli/Program.cs index 359ab3764..8108d1ca7 100644 --- a/src/Mindee.Cli/Program.cs +++ b/src/Mindee.Cli/Program.cs @@ -82,9 +82,7 @@ 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) => @@ -109,6 +107,12 @@ static void BuildV1Commands(Command v1Command, IServiceProvider services, string var apiKeyOption = new Option("--api-key", "-k") { Description = "Mindee V1 API key." }; v1Command.Validators.Add(commandResult => { + var apiKey = commandResult.GetValue(apiKeyOption); + if (!string.IsNullOrWhiteSpace(apiKey)) + { + return; + } + try { _ = services.GetRequiredService>().Value; @@ -123,138 +127,104 @@ static void BuildV1Commands(Command v1Command, IServiceProvider services, string v1Command.Add(apiKeyOption); var parseResult = v1Command.Parse(args); var apiKey = parseResult.GetValue(apiKeyOption); - V1Client mindeeV1Client; - - if (apiKey != null) - { - mindeeV1Client = new V1Client(apiKey); - } - else - { - mindeeV1Client = services.GetRequiredService(); - } + Func mindeeV1ClientFactory = !string.IsNullOrWhiteSpace(apiKey) + ? () => new V1Client(apiKey) + : services.GetRequiredService; var barcodeReaderCmd = new PredictBarcodeReaderCommand(new CommandOptions( "barcode-reader", "Barcode Reader", false, false, true, false)); - barcodeReaderCmd.ConfigureAction(mindeeV1Client); + barcodeReaderCmd.ConfigureAction(mindeeV1ClientFactory); v1Command.Subcommands.Add(barcodeReaderCmd); var cropperCmd = new PredictCropperCommand(new CommandOptions( "cropper", "Cropper", false, false, true, false)); - cropperCmd.ConfigureAction(mindeeV1Client); + cropperCmd.ConfigureAction(mindeeV1ClientFactory); v1Command.Subcommands.Add(cropperCmd); var financialDocumentCmd = new PredictFinancialDocumentCommand(new CommandOptions( "financial-document", "Financial Document", true, false, true, true)); - financialDocumentCmd.ConfigureAction(mindeeV1Client); + financialDocumentCmd.ConfigureAction(mindeeV1ClientFactory); 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(mindeeV1ClientFactory); 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(mindeeV1ClientFactory); 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(mindeeV1ClientFactory); 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(mindeeV1ClientFactory); v1Command.Subcommands.Add(idCardCmd); var payslipCmd = new PredictPayslipCommand(new CommandOptions( "fr-payslip", "FR Payslip", false, false, false, true)); - payslipCmd.ConfigureAction(mindeeV1Client); + payslipCmd.ConfigureAction(mindeeV1ClientFactory); v1Command.Subcommands.Add(payslipCmd); var internationalIdCmd = new PredictInternationalIdCommand(new CommandOptions( "international-id", "International ID", false, true, false, true)); - internationalIdCmd.ConfigureAction(mindeeV1Client); + internationalIdCmd.ConfigureAction(mindeeV1ClientFactory); v1Command.Subcommands.Add(internationalIdCmd); var invoiceCmd = new PredictInvoiceCommand(new CommandOptions( "invoice", "Invoice", true, false, true, true)); - invoiceCmd.ConfigureAction(mindeeV1Client); + invoiceCmd.ConfigureAction(mindeeV1ClientFactory); v1Command.Subcommands.Add(invoiceCmd); var invoiceSplitterCmd = new PredictInvoiceSplitterCommand(new CommandOptions( "invoice-splitter", "Invoice Splitter", false, false, false, true)); - invoiceSplitterCmd.ConfigureAction(mindeeV1Client); + invoiceSplitterCmd.ConfigureAction(mindeeV1ClientFactory); 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(mindeeV1ClientFactory); v1Command.Subcommands.Add(multiReceiptsDetectorCmd); var passportCmd = new PredictPassportCommand(new CommandOptions( "passport", "Passport", false, false, true, false)); - passportCmd.ConfigureAction(mindeeV1Client); + passportCmd.ConfigureAction(mindeeV1ClientFactory); v1Command.Subcommands.Add(passportCmd); var receiptCmd = new PredictReceiptCommand(new CommandOptions( "receipt", "Receipt", true, false, true, true)); - receiptCmd.ConfigureAction(mindeeV1Client); + receiptCmd.ConfigureAction(mindeeV1ClientFactory); 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(mindeeV1ClientFactory); v1Command.Subcommands.Add(bankCheckCmd); } -static void BuildV2Commands(Command v2Command, IServiceProvider services, string[] args) +static void BuildV2Commands(Command v2Command, IServiceProvider services) { - var apiKeyOption = new Option("--api-key", "-k") { Description = "Mindee V2 API key." }; - v2Command.Validators.Add(commandResult => - { - try - { - _ = services.GetRequiredService>().Value; - } - catch (OptionsValidationException) - { - commandResult.AddError( - "The 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); + searchModelsCmd.ConfigureAction(services); v2Command.Add(searchModelsCmd); var classificationCmd = new InferenceCommand( new InferenceCommandOptions( @@ -266,7 +236,7 @@ static void BuildV2Commands(Command v2Command, IServiceProvider services, string false, false)); v2Command.Subcommands.Add(classificationCmd); - classificationCmd.ConfigureAction(mindeeV2Client); + classificationCmd.ConfigureAction(services); var cropCmd = new InferenceCommand( new InferenceCommandOptions( "crop", @@ -277,7 +247,7 @@ static void BuildV2Commands(Command v2Command, IServiceProvider services, string false, false)); v2Command.Subcommands.Add(cropCmd); - cropCmd.ConfigureAction(mindeeV2Client); + cropCmd.ConfigureAction(services); var extractionCmd = new InferenceCommand( new InferenceCommandOptions("extraction", "Generic all-purpose extraction.", @@ -287,7 +257,7 @@ static void BuildV2Commands(Command v2Command, IServiceProvider services, string true, true)); v2Command.Subcommands.Add(extractionCmd); - extractionCmd.ConfigureAction(mindeeV2Client); + extractionCmd.ConfigureAction(services); var ocrCmd = new InferenceCommand( new InferenceCommandOptions( "ocr", "OCR utility.", @@ -297,7 +267,7 @@ static void BuildV2Commands(Command v2Command, IServiceProvider services, string false, false)); v2Command.Subcommands.Add(ocrCmd); - ocrCmd.ConfigureAction(mindeeV2Client); + ocrCmd.ConfigureAction(services); var splitCmd = new InferenceCommand( new InferenceCommandOptions( "split", @@ -308,14 +278,14 @@ static void BuildV2Commands(Command v2Command, IServiceProvider services, string false, false)); v2Command.Subcommands.Add(splitCmd); - splitCmd.ConfigureAction(mindeeV2Client); + splitCmd.ConfigureAction(services); } static RootCommand BuildCommandLine(IServiceProvider services, string[] args) { var root = new RootCommand(); var v1Command = new Command("v1", "Mindee V1 product commands."); - BuildV2Commands(root, services, args); + BuildV2Commands(root, services); BuildV1Commands(v1Command, services, args); root.Add(v1Command); diff --git a/src/Mindee.Cli/README.md b/src/Mindee.Cli/README.md new file mode 100644 index 000000000..17b0c13c2 --- /dev/null +++ b/src/Mindee.Cli/README.md @@ -0,0 +1,116 @@ +# Mindee CLI for .NET + +Simple command-line interface for the Mindee APIs. + +## Install + +```bash +dotnet tool install --global Mindee.Cli +mindee -h +``` + +## Authentication + +Pass your API key with `--api-key`: + +- V2: `mindee --api-key ...` +- V1: `mindee v1 --api-key ...` + +You can also configure keys via environment variables: + +- V2: `MindeeV2__ApiKey` +- V1: `Mindee__ApiKey` + +## V2 Usage (Latest) + +V2 commands are top-level commands: + +### Products +- `classification` : Classify tool +- `crop` : Crop tool +- `extraction` : Extraction tool (most common models) +- `ocr` : OCR tool +- `split` : Split tool + +### Tools +- `search-models` + +### Inference syntax + +```bash +mindee --api-key --model-id [options] +``` + +### Search-models syntax + +```bash +mindee --api-key search-models [--name ] [--model-type ] [--raw-json] +``` + +### V2 examples + +```bash +# List available extraction models +mindee --api-key search-models --model-type extraction + +# Run an extraction model +mindee --api-key extraction --model-id ./invoice.pdf --output full --raw-text +``` + +## V1 (Legacy) + +V1 commands are under the `v1` namespace: + +- `barcode-reader` +- `cropper` +- `financial-document` +- `fr-bank-account-details` +- `fr-carte-grise` +- `fr-health-card` +- `fr-carte-nationale-d-identite` +- `fr-payslip` +- `international-id` +- `invoice` +- `invoice-splitter` +- `multi-receipts-detector` +- `passport` +- `receipt` +- `us-bank-check` + +### General syntax + +```bash +mindee v1 --api-key [options] +``` + +### V1 examples + +```bash +# Run invoice parsing +mindee v1 --api-key invoice ./invoice.pdf --output summary + +# Run async receipt parsing and print raw JSON +mindee v1 --api-key receipt ./receipt.jpg --async --output raw +``` + +## Output Modes + +For commands that support `--output`: + +- `summary`: basic summary (default) +- `full`: detailed result +- `raw`: full JSON response + +## Help + +```bash +mindee -h +mindee -h +mindee v1 -h +mindee v1 -h +``` + +## References + +- V2 docs: https://docs.mindee.com/integrations/client-libraries-sdk +- V1 docs: https://docs.mindee.com/v1/libraries/dotnet-ocr-sdk