### Install ReductoAi Ruby Gem Source: https://github.com/dpaluy/reducto_ai/blob/master/README.md Installs the ReductoAi Ruby gem using Bundler. Ensure you have a Gemfile in your project. ```ruby bundle add reducto_ai ``` -------------------------------- ### Use Async for Large Documents (Ruby) Source: https://github.com/dpaluy/reducto_ai/blob/master/README.md Provides an example of using asynchronous parsing for large documents to prevent timeouts. It shows how to initiate an async job and then poll for its completion before proceeding with other operations. ```ruby # Parse async for large files job = client.parse.async(input: large_pdf_url) job_id = job["job_id"] # Poll or use webhooks loop do result = client.jobs.retrieve(job_id: job_id) break if result["status"] == "complete" sleep 2 end # Then reuse the job_id for split/extract split = client.split.sync(input: job_id, split_description: [...]) ``` -------------------------------- ### ReductoAI Multi-invoice Processing Example (Ruby) Source: https://github.com/dpaluy/reducto_ai/blob/master/README.md A multi-step process to parse a document containing multiple invoices and then split it into individual invoice segments. This is the first step in a more complex workflow. ```ruby client = ReductoAI::Client.new # 1. Parse the document # API Reference: https://docs.reducto.ai/api-reference/parse parse = client.parse.sync(input: "https://example.com/invoices.pdf") # Response: # { # "job_id" => "parse-123", # "status" => "complete", # "result" => {...} # } # 2. Split into individual invoices ``` -------------------------------- ### Asynchronous Processing for Large Documents (Ruby) Source: https://context7.com/dpaluy/reducto_ai/llms.txt This example shows how to handle large documents (over 10 pages) asynchronously to prevent timeouts. It includes a helper method `poll_until_complete` to check job status with exponential backoff, and demonstrates reusing the job ID for subsequent split operations. ```ruby # For documents > 10 pages, use async to avoid timeouts job = client.parse.async(input: "large-document.pdf") job_id = job["job_id"] # Poll with exponential backoff def poll_until_complete(client, job_id) wait_time = 2 max_wait = 60 loop do result = client.jobs.retrieve(job_id: job_id) case result["status"] when "succeeded" return result["result"] when "failed" raise "Job failed: #{result['error']}" end sleep wait_time wait_time = [wait_time * 1.5, max_wait].min end end result = poll_until_complete(client, job_id) # Then reuse job_id for split/extract split = client.split.sync(input: job_id, split_description: [...]) ``` -------------------------------- ### Start Async Edit for Large Documents (Ruby) Source: https://context7.com/dpaluy/reducto_ai/llms.txt Initiates an asynchronous editing job for large documents. It takes a document URL and instructions, returning a job ID that can be used to track the operation's progress and retrieve results. ```ruby job = client.edit.async( input: "https://example.com/large-contract.pdf", instructions: "Redact all personal information" ) edit_job_id = job["job_id"] result = client.jobs.retrieve(job_id: edit_job_id) ``` -------------------------------- ### Classify and Extract Documents in Ruby Source: https://context7.com/dpaluy/reducto_ai/llms.txt Shows a complete workflow for parsing a document, extracting structured data based on a provided schema, and then routing the processed data based on its classified document type. This example utilizes the `parse` and `extract` methods of the Reducto AI client. ```ruby client = ReductoAI::Client.new # Parse document parse = client.parse.sync(input: "https://example.com/document.pdf") job_id = parse["job_id"] # Extract with classification extraction = client.extract.sync( input: job_id, instructions: { schema: { type: "object", properties: { document_type: { type: "string", enum: ["invoice", "credit_note", "debit_note", "receipt"], description: "Type of financial document" }, document_number: { type: "string", description: "Document identifier number" }, vendor_name: { type: "string" }, total_amount: { type: "string" } }, required: ["document_type", "document_number"] } }, settings: { citations: { enabled: false } } ) # Response: # { # "job_id" => "class-123", # "status" => "succeeded", # "result" => [ # { # "document_type" => "invoice", # "document_number" => "INV-2024-001", # "vendor_name" => "Acme Corp", # "total_amount" => "$1,234.56" # } # ], # "usage" => { "credits" => 2.0 }, # "studio_link" => "https://studio.reducto.ai/job/class-123" # } data = extraction.dig("result", 0) doc_type = data["document_type"] # Route based on classification case doc_type when "invoice" process_invoice(data) when "credit_note" process_credit_note(data) when "receipt" process_receipt(data) end ``` -------------------------------- ### Jobs API - Check API Version Source: https://context7.com/dpaluy/reducto_ai/llms.txt Get the current version of the Reducto AI API. This is useful for compatibility checks and understanding API level. ```APIDOC ## GET /api/version ### Description Retrieves the current version of the Reducto API. ### Method GET ### Endpoint `/api/version` ### Response #### Success Response (200) - **version** (string) - The current API version. #### Response Example ```json { "version": "1.2.3" } ``` ``` -------------------------------- ### Configure ReductoAI Ruby Client Globally Source: https://context7.com/dpaluy/reducto_ai/llms.txt Sets up global configuration for the ReductoAI client, including API key, base URL, and timeouts. This is typically done once at the application's startup. ```ruby require 'reducto_ai' ReductoAI.configure do |config| config.api_key = ENV.fetch("REDUCTO_API_KEY") config.base_url = "https://platform.reducto.ai" # optional, defaults to this config.open_timeout = 5 # optional, defaults to 5 seconds config.read_timeout = 30 # optional, defaults to 30 seconds end ``` -------------------------------- ### Configure ReductoAI Client Per-Instance Source: https://context7.com/dpaluy/reducto_ai/llms.txt Allows for per-client configuration, overriding global settings. This is useful for multi-tenant applications or when specific clients require different timeouts or loggers. A new ReductoAI::Client instance is created with custom parameters. ```ruby # Override global config for specific clients (multi-tenant scenarios) client = ReductoAI::Client.new( api_key: "tenant_specific_key", base_url: "https://platform.reducto.ai", open_timeout: 10, read_timeout: 60, logger: Logger.new($stdout) ) ``` -------------------------------- ### Configure ReductoAI API Key in Rails Source: https://github.com/dpaluy/reducto_ai/blob/master/README.md Sets up the ReductoAI client configuration within a Rails application's initializer. It retrieves the API key from Rails credentials. ```ruby ReductoAI.configure do |c| c.api_key = Rails.application.credentials.dig(:reducto, :api_key) # c.base_url = "https://platform.reducto.ai" # c.open_timeout = 5; c.read_timeout = 30 end # Optional: override shared client (multi-tenant or custom timeouts) # ReductoAI.client = ReductoAI::Client.new(api_key: ..., read_timeout: 10) ``` -------------------------------- ### Split Before Extract for Multi-Document Files (Ruby) Source: https://github.com/dpaluy/reducto_ai/blob/master/README.md Illustrates a best practice for multi-page or multi-document files where splitting the document into partitions is done first, followed by targeted extraction from specific partitions to save credits. ```ruby # 1. Parse the document once parse = client.parse.sync(input: "multi-invoice.pdf") # 1 credit × 10 pages = 10 credits job_id = parse["job_id"] # 2. Split into partitions split = client.split.sync( input: job_id, split_description: [{ name: "Invoice", description: "..." }] ) # 2 credits × 10 pages = 20 credits # 3. Extract only from specific partitions partitions = split.dig("result", "splits").first["partitions"] invoices = partitions.map do |partition| client.extract.sync( input: job_id, instructions: { schema: invoice_schema }, settings: { page_range: partition["pages"] } # Extract only relevant pages ) end # 1 credit × 10 pages = 10 credits # Total: 40 credits for 10-page document with 5 invoices ``` -------------------------------- ### Generate Marked-up PDFs (Ruby) Source: https://context7.com/dpaluy/reducto_ai/llms.txt Creates an annotated PDF document with specified edits, such as highlights and comments. The `client.edit.sync` method takes a document URL and instructions for the edits. The response includes a URL to the edited document and a list of changes made. ```ruby client = ReductoAI::Client.new # Create annotated PDF with highlights and comments response = client.edit.sync( input: "https://example.com/contract.pdf", instructions: "Highlight all monetary amounts in yellow and add a comment with the total sum" ) # Response structure: # { # "job_id" => "edit-123", # "status" => "succeeded", # "result" => { # "edited_document_url" => "https://reducto-storage.s3.amazonaws.com/edited-abc123.pdf", # "changes" => [ # { "page" => 0, "type" => "highlight", "text" => "$1,234.56" } # ] # }, # "usage" => { "num_pages" => 1, "credits" => 4.0 } # } edited_url = response.dig("result", "edited_document_url") ``` -------------------------------- ### Cost Optimization: Parse Once, Extract Multiple Times (Ruby) Source: https://github.com/dpaluy/reducto_ai/blob/master/README.md Explains and demonstrates how parsing a document once and then performing multiple extractions using the same job ID is more cost-effective than parsing for each extraction. ```ruby # Parse once (1 credit) parse = client.parse.sync(input: "https://example.com/doc.pdf") job_id = parse["job_id"] # Extract multiple schemas (1 credit each) schema_a = client.extract.sync(input: job_id, instructions: schema_a) schema_b = client.extract.sync(input: job_id, instructions: schema_b) # Total: 3 credits instead of 4 ``` -------------------------------- ### Generate Marked-up PDFs Source: https://context7.com/dpaluy/reducto_ai/llms.txt Creates an annotated PDF by applying instructions for highlighting and adding comments. ```APIDOC ## Edit API - Generate Marked-up PDFs ### Description Edits a PDF document by applying specified instructions, such as highlighting text or adding comments. ### Method POST ### Endpoint `/api/v1/edit/sync` ### Parameters #### Request Body - **input** (string) - Required - URL of the PDF document to edit. - **instructions** (string) - Required - Natural language instructions for editing (e.g., "Highlight all monetary amounts in yellow and add a comment with the total sum"). ### Request Example ```ruby client = ReductoAI::Client.new # Create annotated PDF with highlights and comments response = client.edit.sync( input: "https://example.com/contract.pdf", instructions: "Highlight all monetary amounts in yellow and add a comment with the total sum" ) ``` ### Response #### Success Response (200) - **job_id** (string) - The ID for the edit job. - **status** (string) - The status of the edit job (e.g., "succeeded"). - **result** (object) - Contains details about the edited document. - **edited_document_url** (string) - URL to the generated marked-up PDF. - **changes** (array of objects) - A log of the changes applied. - **page** (integer) - The page number where the change occurred. - **type** (string) - The type of change (e.g., "highlight", "comment"). - **text** (string) - The text content affected or added. - **usage** (object) - Usage metrics. #### Response Example ```json { "job_id": "edit-123", "status": "succeeded", "result": { "edited_document_url": "https://reducto-storage.s3.amazonaws.com/edited-abc123.pdf", "changes": [ { "page": 0, "type": "highlight", "text": "$1,234.56" }, { "page": 1, "type": "comment", "text": "Total sum: $5,678.90" } ] }, "usage": { "num_pages": 1, "credits": 4.0 } } ``` ``` -------------------------------- ### Parse Document with Options using ReductoAI Client Source: https://context7.com/dpaluy/reducto_ai/llms.txt Demonstrates parsing a document with custom options, such as specifying output formats (e.g., markdown) and setting the processing mode to OCR. This allows for more tailored document processing. ```ruby # Parse with custom settings response = client.parse.sync( input: "https://example.com/document.pdf", output_formats: { markdown: true }, mode: "ocr" ) ``` -------------------------------- ### Extracting Data from Relevant Partitions (Ruby) Source: https://context7.com/dpaluy/reducto_ai/llms.txt This snippet demonstrates how to extract data from specific partitions of a document. It utilizes the `extract.sync` method with a provided schema and page range. This approach is more cost-effective than extracting all pages. ```ruby partitions = split.dig("result", "splits", 0, "partitions") results = partitions.map do |partition| client.extract.sync( input: job_id, instructions: { schema: invoice_schema }, settings: { page_range: partition["pages"] } ) end ``` -------------------------------- ### Development Commands (Ruby) Source: https://github.com/dpaluy/reducto_ai/blob/master/README.md Common development commands for the project, including running tests and code linting using Rake and RuboCop. ```ruby bundle exec rake test bundle exec rubocop ``` -------------------------------- ### Handle Validation Errors in Ruby Source: https://context7.com/dpaluy/reducto_ai/llms.txt Illustrates how to handle `ArgumentError` exceptions that occur due to missing or invalid parameters, such as `input` or `instructions`, when using the Reducto AI client. This ensures that the application correctly identifies and reports validation issues. ```ruby begin # Missing required parameter client.extract.sync(input: nil, instructions: schema) rescue ArgumentError => e puts "Validation error: #{e.message}" # => "input is required" end begin # Empty instructions client.extract.sync(input: job_id, instructions: {}) rescue ArgumentError => e puts "Validation error: #{e.message}" # => "instructions are required" end ``` -------------------------------- ### Configure ReductoAI API Key (Ruby) Source: https://github.com/dpaluy/reducto_ai/blob/master/README.md Configures the ReductoAI client with your API key. The API key should be set as an environment variable `REDUCTO_API_KEY`. ```ruby ReductoAI.configure do |config| config.api_key = ENV.fetch("REDUCTO_API_KEY") end ``` -------------------------------- ### Split Document into Logical Sections (Ruby) Source: https://context7.com/dpaluy/reducto_ai/llms.txt Splits a parsed document into logical sections based on defined descriptions and rules. It first parses the document using `client.parse.sync` and then uses `client.split.sync` with custom `split_description` and `split_rules` to partition the document. The response includes details about the splits and partitions, including page ranges. ```ruby client = ReductoAI::Client.new # Parse document first parse = client.parse.sync(input: "https://example.com/multi-invoice.pdf") job_id = parse["job_id"] # Split into individual invoices split = client.split.sync( input: job_id, split_description: [ { name: "Invoice", description: "All pages that belong to a single invoice", partition_key: "invoice_number" } ], split_rules: <<~RULES The document contains multiple invoices one after another. Each invoice has a unique invoice number formatted like "Invoice #12345" near the top. Segment the document into one partition per invoice. Keep pages contiguous per invoice and include any following appendices. RULES ) # Response structure: # { # "job_id" => "split-123", # "status" => "succeeded", # "result" => { # "splits" => [ # { # "name" => "Invoice", # "pages" => [0, 1, 2, 3, 4], # "conf" => "high", # "partitions" => [ # { "name" => "Invoice #12345", "pages" => [0, 1], "conf" => "high" }, # { "name" => "Invoice #12346", "pages" => [2, 3], "conf" => "high" }, # { "name" => "Invoice #12347", "pages" => [4], "conf" => "high" } # ] # } # ] # }, # "usage" => { "num_pages" => 5, "credits" => 0.0 } # Free when using job_id # } partitions = split.dig("result", "splits", 0, "partitions") # => [ # {"name" => "Invoice #12345", "pages" => [0, 1], "conf" => "high"}, # {"name" => "Invoice #12346", "pages" => [2, 3], "conf" => "high"} # ] ``` -------------------------------- ### Handle Reducto AI Exceptions in Ruby Source: https://context7.com/dpaluy/reducto_ai/llms.txt Demonstrates how to catch and handle various ReductoAI specific exceptions, such as authentication errors, client errors, and server errors. It also includes generic error handling for unexpected issues. This pattern helps in gracefully managing API interactions and providing informative feedback. ```ruby client = ReductoAI::Client.new begin response = client.parse.sync(input: "https://example.com/doc.pdf") rescue ReductoAI::AuthenticationError => e # 401 - Invalid API key puts "Authentication failed: #{e.message}" puts "Status: #{e.status}" puts "Body: #{e.body}" rescue ReductoAI::ClientError => e # 400, 404, 422 - Invalid request puts "Client error: #{e.message}" puts "Status: #{e.status}" if e.status == 400 puts "Bad request - check your parameters" elsif e.status == 404 puts "Resource not found" elsif e.status == 422 puts "Validation error: #{e.body}" end rescue ReductoAI::ServerError => e # 500-599 - Reducto server error puts "Server error: #{e.message}" puts "Status: #{e.status}" # Retry with exponential backoff rescue ReductoAI::NetworkError => e # Timeout or connection failure puts "Network error: #{e.message}" # Retry or use async endpoint rescue ReductoAI::Error => e # Generic error catch-all puts "Reducto error: #{e.message}" puts "Status: #{e.status}" puts "Response body: #{e.body}" end ``` -------------------------------- ### Configure Webhook Endpoints (Ruby) Source: https://context7.com/dpaluy/reducto_ai/llms.txt Generates a URL to a portal where users can configure webhook endpoints for receiving real-time notifications about job statuses and results. This facilitates automated workflows. ```ruby # Get webhook configuration portal URL response = client.jobs.configure_webhook # Response structure: # { # "webhook_url" => "https://platform.reducto.ai/webhooks/configure?token=abc123" # } webhook_config_url = response["webhook_url"] # Direct user to this URL to configure webhook endpoints ``` -------------------------------- ### Direct Document Split from URL (Ruby) Source: https://context7.com/dpaluy/reducto_ai/llms.txt Splits a document directly from a URL without requiring a prior parsing step. The API handles the internal parsing. It uses `client.split.sync` with a URL as input and a `split_description` to define how the document should be partitioned. The resulting partitions can be accessed via the response. ```ruby # Split directly from URL (will parse internally) response = client.split.sync( input: { url: "https://example.com/invoices.pdf" }, split_description: [ { name: "Invoice", description: "Individual invoices within the document", partition_key: "invoice_number" } ] ) # Access partitions partitions = response.dig("result", "splits", 0, "partitions") partitions.each do |partition| puts "Invoice: #{partition['name']} - Pages: #{partition['pages'].join(', ')}" end ``` -------------------------------- ### Split Multi-Invoice PDF into Partitions (Ruby) Source: https://github.com/dpaluy/reducto_ai/blob/master/README.md Splits a document containing multiple invoices into separate partitions, one for each invoice. It uses a prompt to identify and name each invoice partition based on its unique invoice number. The output includes the job ID and a structured result mapping invoices to page ranges. ```ruby split = client.split.sync( input: parse["job_id"], split_description: [ { name: "Invoice", description: "All pages that belong to a single invoice", partition_key: "invoice_number" } ], split_rules: <<~PROMPT The document contains multiple invoices one after another. Each invoice has a unique invoice number formatted like "Invoice #12345" near the top of the first page. Segment the document into one partition per invoice. Keep pages contiguous per invoice and include any following appendices until the next invoice number. Name each partition using the exact invoice number you detect (e.g., "Invoice #12345"). PROMPT ) # Response: # { # "job_id" => "split-456", # "result" => { # "splits" => [{ # "name" => "Invoice", # "partitions" => [ # {"name" => "Invoice #12345", "pages" => [0, 1, 2]}, # {"name" => "Invoice #12346", "pages" => [3, 4]} # ] # }] # } # } ``` -------------------------------- ### Complex Pipeline with Split and Extract (Ruby) Source: https://context7.com/dpaluy/reducto_ai/llms.txt Demonstrates a complex pipeline involving parsing, splitting a document into logical parts (e.g., individual invoices), and then extracting data from each of those parts. This is ideal for multi-page documents with distinct sections. ```ruby # Parse → Split → Extract each partition response = client.pipeline.sync( input: "https://example.com/multi-invoice.pdf", steps: [ { type: "parse" }, { type: "split", split_description: [ { name: "Invoice", description: "Individual invoices" } ] }, { type: "extract", instructions: { schema: invoice_schema }, apply_to_partitions: true # Extract from each partition } ] ) ``` -------------------------------- ### POST /split Source: https://github.com/dpaluy/reducto_ai/blob/master/README.md Splits a document into multiple partitions based on defined criteria. This is useful for separating invoices, receipts, or any other multi-part documents into logical units. ```APIDOC ## POST /split ### Description Splits a document into multiple partitions based on defined criteria. This is useful for separating invoices, receipts, or any other multi-part documents into logical units. ### Method POST ### Endpoint /split ### Parameters #### Query Parameters - **input** (object | string) - Required - The input document, either as a URL (string) or an object with a `url` or `file` key. - **split_description** (array) - Required - An array of objects defining the splits. Each object should have `name`, `description`, and `partition_key`. - **split_rules** (string) - Optional - A prompt detailing how to split the document when automatic detection is insufficient. ### Request Example ```json { "input": {"url": "https://example.com/invoices.pdf"}, "split_description": [ { "name": "Invoice", "description": "Individual invoices within the document", "partition_key": "invoice_number" } ] } ``` ### Response #### Success Response (200) - **usage** (object) - Information about the usage of the API call. - **result** (object) - Contains the splitting results, including `splits` and `section_mapping`. - **splits** (array) - An array of identified splits, each containing `name`, `pages`, `conf`, and `partitions`. - **partitions** (array) - An array of partitions within a split, each with `name`, `pages`, and `conf`. #### Response Example ```json { "usage": {"num_pages": 2, "credits": null}, "result": { "section_mapping": null, "splits": [ { "name": "Invoice", "pages": [1, 2], "conf": "high", "partitions": [ {"name": "0000569050-001", "pages": [1], "conf": "high"}, {"name": "0000569050-002", "pages": [2], "conf": "high"} ] } ] } } ``` ``` -------------------------------- ### Split Multi-Document Files Before Extract in Ruby Source: https://context7.com/dpaluy/reducto_ai/llms.txt Explains how to efficiently process multi-document files (like a PDF containing multiple invoices) by first parsing the file and then using the `split` method with `job_id`. This avoids redundant parsing costs and allows for targeted extraction from individual document segments. ```ruby # Process 10-page PDF with 5 invoices parse = client.parse.sync(input: "multi-invoice.pdf") # 10 credits job_id = parse["job_id"] # Split into partitions (free with job_id) split = client.split.sync( input: job_id, split_description: [{ name: "Invoice", description: "..." }] ) # 0 credits (free when using job_id from parse) ``` -------------------------------- ### POST /parse Source: https://github.com/dpaluy/reducto_ai/blob/master/README.md Parses a document to prepare it for subsequent operations like extraction or splitting. This step is crucial for efficient processing, as it allows reusing the obtained job ID. ```APIDOC ## POST /parse ### Description Parses a document to prepare it for subsequent operations like extraction or splitting. This step is crucial for efficient processing, as it allows reusing the obtained job ID. ### Method POST ### Endpoint /parse ### Parameters #### Query Parameters - **input** (string) - Required - The URL of the document to parse. ### Request Example ```json { "input": "https://example.com/document.pdf" } ``` ### Response #### Success Response (200) - **job_id** (string) - The ID generated after parsing the document. This ID can be reused for subsequent `extract` or `split` calls. #### Response Example ```json { "job_id": "parse-job-id-123" } ``` ``` -------------------------------- ### Parse Once, Reuse Job ID for Extraction (Ruby) Source: https://github.com/dpaluy/reducto_ai/blob/master/README.md Demonstrates parsing a document and then reusing the obtained job_id for multiple extraction tasks, significantly reducing credit costs compared to parsing for each extraction. ```ruby parse = client.parse.sync(input: url) # 1 credit job_id = parse["job_id"] extract1 = client.extract.sync(input: job_id, instructions: schema_a) # 1 credit extract2 = client.extract.sync(input: job_id, instructions: schema_b) # 1 credit split = client.split.sync(input: job_id, split_description: [...]) # 2 credits # Total: 5 credits for a 1-page document (saved 2 credits) ``` -------------------------------- ### Cost-Efficient Document Processing: Parse Once (Ruby) Source: https://github.com/dpaluy/reducto_ai/blob/master/README.md Demonstrates a cost-efficient approach to document processing by parsing a document once and reusing its job ID for multiple subsequent operations like extraction or splitting. This avoids redundant parsing costs, significantly reducing credit usage compared to calling APIs with URLs directly for each operation. ```ruby # Parse once parsed_doc = client.parse.sync(input: url) # Reuse job_id for multiple operations extract1 = client.extract.sync(input: parsed_doc["job_id"], instructions: schema_a) # 1 credit extract2 = client.extract.sync(input: parsed_doc["job_id"], instructions: schema_b) # 1 credit split = client.split.sync(input: parsed_doc["job_id"], split_description: [...]) # 2 credits # Total: 4 credits for a 1-page document ``` -------------------------------- ### Split Document into Logical Sections Source: https://context7.com/dpaluy/reducto_ai/llms.txt Splits a pre-parsed document into logical sections based on defined rules and descriptions. ```APIDOC ## Split API - Split Document into Logical Sections ### Description Splits a document into logical sections based on provided descriptions and rules. This typically follows a parsing step. ### Method POST ### Endpoint `/api/v1/split/sync` ### Parameters #### Request Body - **input** (string) - Required - The job ID of the parsed document. - **split_description** (array of objects) - Required - Defines the types of sections to split into. - **name** (string) - Required - The name of the split section (e.g., "Invoice"). - **description** (string) - Optional - A description of the section. - **partition_key** (string) - Optional - A key to identify partitions within the section (e.g., "invoice_number"). - **split_rules** (string) - Optional - Natural language rules to guide the splitting process. ### Request Example ```ruby client = ReductoAI::Client.new # Parse document first parse = client.parse.sync(input: "https://example.com/multi-invoice.pdf") job_id = parse["job_id"] # Split into individual invoices split = client.split.sync( input: job_id, split_description: [ { name: "Invoice", description: "All pages that belong to a single invoice", partition_key: "invoice_number" } ], split_rules: <<~RULES The document contains multiple invoices one after another. Each invoice has a unique invoice number formatted like "Invoice #12345" near the top. Segment the document into one partition per invoice. Keep pages contiguous per invoice and include any following appendices. RULES ) ``` ### Response #### Success Response (200) - **job_id** (string) - The ID for the split job. - **status** (string) - The status of the split job (e.g., "succeeded"). - **result** (object) - Contains the details of the splits. - **splits** (array of objects) - Information about each identified split section. - **name** (string) - The name of the split section. - **pages** (array of integers) - The page numbers belonging to this section. - **conf** (string) - Confidence level of the split. - **partitions** (array of objects) - Details about individual partitions within a split. - **name** (string) - The name or identifier of the partition. - **pages** (array of integers) - The page numbers belonging to this partition. - **conf** (string) - Confidence level of the partition. - **usage** (object) - Usage metrics. #### Response Example ```json { "job_id": "split-123", "status": "succeeded", "result": { "splits": [ { "name": "Invoice", "pages": [0, 1, 2, 3, 4], "conf": "high", "partitions": [ { "name": "Invoice #12345", "pages": [0, 1], "conf": "high" }, { "name": "Invoice #12346", "pages": [2, 3], "conf": "high" }, { "name": "Invoice #12347", "pages": [4], "conf": "high" } ] } ] }, "usage": { "num_pages": 5, "credits": 0.0 } } ``` ``` -------------------------------- ### Split with Extract Pipeline (Ruby) Source: https://context7.com/dpaluy/reducto_ai/llms.txt Combines parsing, splitting, and extraction into a single workflow. The document is first parsed, then split into partitions. Finally, data is extracted from each partition using a defined schema. This allows for processing individual sections of a document independently. ```ruby # Combined workflow: Parse → Split → Extract each partition parse = client.parse.sync(input: "https://example.com/documents.pdf") job_id = parse["job_id"] split = client.split.sync( input: job_id, split_description: [{ name: "Document", description: "Individual documents" }] ) # Extract data from each partition invoice_schema = { type: "object", properties: { invoice_number: { type: "string" }, total_due: { type: "string" } } } partitions = split.dig("result", "splits", 0, "partitions") results = partitions.map do |partition| client.extract.sync( input: job_id, instructions: { schema: invoice_schema }, settings: { page_range: partition["pages"] } ) end # Process extracted data results.each_with_index do |result, index| data = result.dig("result", 0) puts "Partition #{index}: #{data['invoice_number']} - #{data['total_due']}" end ``` -------------------------------- ### Configure ReductoAI Ruby Client for Rails Source: https://context7.com/dpaluy/reducto_ai/llms.txt Configures the ReductoAI client specifically for a Rails application, utilizing Rails credentials for the API key and Rails logger. This ensures secure API key management within the Rails environment. ```ruby # config/initializers/reducto_ai.rb ReductoAI.configure do |c| c.api_key = Rails.application.credentials.dig(:reducto, :api_key) c.base_url = "https://platform.reducto.ai" c.open_timeout = 5 c.read_timeout = 30 c.logger = Rails.logger # optional, uses Rails.logger by default end ``` -------------------------------- ### Directly Split PDF from URL (Ruby) Source: https://github.com/dpaluy/reducto_ai/blob/master/README.md Splits a multi-invoice PDF directly from a URL without requiring pre-parsing. This method is convenient for immediate processing but may be less cost-efficient for repeated operations on the same document compared to parsing once. The output details the splits and their corresponding page ranges. ```ruby client = ReductoAI::Client.new # Split document directly from URL # API Reference: https://docs.reducto.ai/api-reference/split response = client.split.sync( input: { url: "https://example.com/invoices.pdf" }, split_description: [ { name: "Invoice", description: "Individual invoices within the document", partition_key: "invoice_number" } ] ) # Response: # { # "usage" => {"num_pages" => 2, "credits" => nil}, # "result" => { # "section_mapping" => nil, # "splits" => [{ # "name" => "Invoice", # "pages" => [1, 2], # "conf" => "high", # "partitions" => [ # {"name" => "0000569050-001", "pages" => [1], "conf" => "high"}, # {"name" => "0000569050-002", "pages" => [2], "conf" => "high"} # ] # }] # } # } # Access partitions partitions = response.dig("result", "splits").first["partitions"] # => [{"name"=>"0000569050-001", "pages"=>[1], "conf"=>"high"}, ...] ``` -------------------------------- ### Store and Reuse Parse Results (Ruby) Source: https://github.com/dpaluy/reducto_ai/blob/master/README.md Demonstrates the practice of storing the `job_id` obtained from an initial parse operation. This allows for subsequent extractions of different schemas without needing to re-parse the document, saving credits. ```ruby # Store the job_id with your document record document.update(reducto_job_id: parse["job_id"]) # Later: Extract different schemas without re-parsing schema_v1 = client.extract.sync(input: document.reducto_job_id, instructions: schema_v1) schema_v2 = client.extract.sync(input: document.reducto_job_id, instructions: schema_v2) # Only 2 credits instead of 4 ``` -------------------------------- ### Check Reducto API Version (Ruby) Source: https://context7.com/dpaluy/reducto_ai/llms.txt Retrieves the current version of the Reducto API. This is helpful for ensuring compatibility and staying updated with the latest features or changes. ```ruby # Get Reducto API version version = client.jobs.version # Response: { "version" => "1.2.3" } ``` -------------------------------- ### Direct Split Without Pre-parsing Source: https://context7.com/dpaluy/reducto_ai/llms.txt Splits a document directly from a URL, performing internal parsing. ```APIDOC ## Split API - Direct Split Without Pre-parsing ### Description Initiates a split operation directly from a document URL. The API handles the parsing internally before splitting. ### Method POST ### Endpoint `/api/v1/split/sync` ### Parameters #### Request Body - **input** (object) - Required - Input specifies the document source. - **url** (string) - Required - The URL of the document to split. - **split_description** (array of objects) - Required - Defines the types of sections to split into. - **name** (string) - Required - The name of the split section (e.g., "Invoice"). - **description** (string) - Optional - A description of the section. - **partition_key** (string) - Optional - A key to identify partitions within the section (e.g., "invoice_number"). ### Request Example ```ruby # Split directly from URL (will parse internally) response = client.split.sync( input: { url: "https://example.com/invoices.pdf" }, split_description: [ { name: "Invoice", description: "Individual invoices within the document", partition_key: "invoice_number" } ] ) ``` ### Response #### Success Response (200) - **job_id** (string) - The ID for the split job. - **status** (string) - The status of the split job (e.g., "succeeded"). - **result** (object) - Contains the details of the splits. - **splits** (array of objects) - Information about each identified split section. - **name** (string) - The name of the split section. - **pages** (array of integers) - The page numbers belonging to this section. - **conf** (string) - Confidence level of the split. - **partitions** (array of objects) - Details about individual partitions within a split. - **name** (string) - The name or identifier of the partition. - **pages** (array of integers) - The page numbers belonging to this partition. - **conf** (string) - Confidence level of the partition. - **usage** (object) - Usage metrics. #### Response Example ```json { "job_id": "split-direct-456", "status": "succeeded", "result": { "splits": [ { "name": "Invoice", "pages": [0, 1, 2, 3], "conf": "high", "partitions": [ { "name": "Invoice #ABC", "pages": [0, 1], "conf": "high" }, { "name": "Invoice #DEF", "pages": [2, 3], "conf": "high" } ] } ] }, "usage": { "num_pages": 4, "credits": 1.0 } } ``` ``` -------------------------------- ### Jobs API - Configure Webhooks Source: https://context7.com/dpaluy/reducto_ai/llms.txt Obtain a URL to configure webhook endpoints. This allows the API to send notifications about job status changes to your specified URL. ```APIDOC ## GET /api/jobs/configure_webhook ### Description Retrieves a URL that directs to the webhook configuration portal. Users can configure their webhook endpoints through this portal. ### Method GET ### Endpoint `/api/jobs/configure_webhook` ### Response #### Success Response (200) - **webhook_url** (string) - The URL for configuring webhook endpoints. #### Response Example ```json { "webhook_url": "https://platform.reducto.ai/webhooks/configure?token=abc123" } ``` ``` -------------------------------- ### Asynchronous Edit Source: https://context7.com/dpaluy/reducto_ai/llms.txt Initiates an asynchronous job for editing PDF documents. ```APIDOC ## Edit API - Asynchronous Edit ### Description Starts an asynchronous job for editing PDF documents, allowing for background processing of complex edits or large files. ### Method POST ### Endpoint `/api/v1/edit/async` ### Parameters #### Request Body - **input** (string) - Required - URL of the PDF document to edit. - **instructions** (string) - Required - Natural language instructions for editing. - **form_schema** (object) - Optional - Key-value map for filling form fields. ### Request Example ```ruby # Start an asynchronous edit job response = client.edit.async( input: "https://example.com/large_document.pdf", instructions: "Summarize the key findings on the last page.", form_schema: { field1: "value1" } # Optional: if filling forms ) async_job_id = response["job_id"] # Poll for completion using client.jobs.retrieve(job_id: async_job_id) ``` ### Response #### Success Response (200) - **job_id** (string) - The ID of the asynchronous edit job. - **status** (string) - The initial status of the job (e.g., "processing"). #### Response Example ```json { "job_id": "async-edit-901", "status": "processing" } ``` ``` -------------------------------- ### ReductoAI Sync Parse and Extract Operations (Ruby) Source: https://github.com/dpaluy/reducto_ai/blob/master/README.md Demonstrates synchronous parsing of a document followed by extracting structured data based on a provided schema. The parse operation returns a job_id, which is then used as input for the extract operation. ```ruby client = ReductoAI::Client.new # Parse a document # API Reference: https://docs.reducto.ai/api-reference/parse parse = client.parse.sync(input: "https://example.com/invoice.pdf") job_id = parse["job_id"] # Response: # { # "job_id" => "abc-123", # "status" => "complete", # "result" => {...} # } # Extract structured data # API Reference: https://docs.reducto.ai/api-reference/extract extraction = client.extract.sync( input: job_id, instructions: { schema: { type: "object", properties: { invoice_number: { type: "string" }, total_due: { type: "string" } }, required: ["invoice_number", "total_due"] } } ) # Response: # { # "job_id" => "820dca1b-3215-4d24-be09-6494d4c3cd88", # "usage" => {"num_pages" => 1, "num_fields" => 2, "credits" => 2.0}, # "studio_link" => "https://studio.reducto.ai/job/820dca1b-3115-4d24-be09-6494d4c3cd88", # "result" => [{"invoice_number" => "INV-2024-001", "total_due" => "$1,234.56"}], # "citations" => nil # } ``` -------------------------------- ### Upload File from IO Object (Ruby) Source: https://context7.com/dpaluy/reducto_ai/llms.txt Provides methods to upload files to the Reducto AI API directly from IO objects, such as File or StringIO. This is useful for handling binary data or in-memory file content without saving it to disk first. ```ruby # Upload from File object File.open("/path/to/document.pdf", "rb") do |file| response = client.jobs.upload(file: file, extension: "pdf") file_url = response["url"] end # Upload from StringIO (for in-memory content) require 'stringio' content = StringIO.new(pdf_binary_data) response = client.jobs.upload(file: content, extension: "pdf") ```