diff --git a/bin/mindee.rb b/bin/mindee.rb index f0abeaf5d..4f356d14c 100755 --- a/bin/mindee.rb +++ b/bin/mindee.rb @@ -9,7 +9,10 @@ def root_help help = "Usage: mindee command [options]\n\nAvailable commands:\n" help += " #{'v1'.ljust(50)}Use Version 1 of the Mindee API\n" - help += " #{'search-models'.ljust(50)}Search for available models for this API key\n" + + MindeeCLI::V2SearchCommands::V2_SEARCH_COMMANDS.each do |search_command, search_values| + help += " #{search_command.ljust(50)}#{search_values[:description]}\n" + end V2_PRODUCTS.each do |product_key, product_values| help += " #{product_key.ljust(50)}#{product_values[:description]}\n" diff --git a/bin/v2/parser.rb b/bin/v2/parser.rb index 3b16d3ff9..c1ca30e71 100644 --- a/bin/v2/parser.rb +++ b/bin/v2/parser.rb @@ -2,11 +2,14 @@ require 'mindee' require_relative 'products' +require_relative 'search_commands' module MindeeCLI # Mindee Command Line Interface # V2 CLI class. class V2Parser + include V2SearchCommands + # @return [Array] attr_reader :arguments @@ -17,7 +20,10 @@ class V2Parser attr_reader :product_parser # @return [Parser] - attr_reader :search_parser + attr_reader :search_models_parser + + # @return [Parser] + attr_reader :search_rag_docs_parser def initialize(arguments, command_prefix: 'mindee v2') @arguments = arguments @@ -26,26 +32,18 @@ def initialize(arguments, command_prefix: 'mindee v2') opts.banner = "Usage: #{@command_prefix} command [options]" end @product_parser = init_product_parser - @search_parser = init_search_parser + @search_models_parser = init_search_models_parser + @search_rag_docs_parser = init_search_rag_docs_parser end # Summarize and print the result of the command. # @param command [String] def print_result(command) - if command == 'search-models' - @search_parser.parse!(@arguments) - result = search(@options) - summarized_result = output_format == :full ? result.to_s : result.models.to_s - else - @product_parser[command].parse!(@arguments) - @options[:file_path] = @arguments.shift - if @options[:file_path].nil? - warn 'file missing' - abort(@product_parser[command].help) - end - result = send(command, @options) - summarized_result = output_format == :full ? result.inference.to_s : result.inference.result.to_s - end + result, summarized_result = if V2_SEARCH_COMMANDS.key?(command) + run_search(command) + else + run_product(command) + end if output_format == :raw puts JSON.pretty_generate(raw_payload(result.raw_http)) @@ -63,22 +61,41 @@ def execute validate_command!(command) print_result(command) rescue OptionParser::InvalidOption, OptionParser::MissingArgument => e - if command == 'search-models' - abort("#{e.message}\n\n#{@search_parser.help}") - else - abort("#{e.message}\n\n#{@product_parser[command].help}") - end + abort("#{e.message}\n\n#{command_parser(command).help}") rescue Mindee::Error::MindeeError => e abort(format_cli_error(e)) end private + # Parse the arguments and run the given product command. + # @param command [String] + # @return [Array(Mindee::V2::Parsing::BaseResponse, String)] Response and its summary. + def run_product(command) + @product_parser[command].parse!(@arguments) + @options[:file_path] = @arguments.shift + if @options[:file_path].nil? + warn 'file missing' + abort(@product_parser[command].help) + end + result = send(command, @options) + summarized_result = output_format == :full ? result.inference.to_s : result.inference.result.to_s + [result, summarized_result] + end + + # @param command [String] + # @return [OptionParser] + def command_parser(command) + V2_SEARCH_COMMANDS.key?(command) ? search_parser_for(command) : @product_parser[command] + end + def validate_command!(command) - return if V2_PRODUCTS.include?(command) || command == 'search-models' + return if V2_PRODUCTS.include?(command) || V2_SEARCH_COMMANDS.key?(command) error_msg = "#{@options_parser.help}\nAvailable commands:\n" - error_msg += " #{'search-models'.ljust(50)}Search for available models for this API key\n" + V2_SEARCH_COMMANDS.each do |search_command, search_values| + error_msg += " #{search_command.ljust(50)}#{search_values[:description]}\n" + end V2_PRODUCTS.each do |product_key, product_values| error_msg += " #{product_key.to_s.ljust(50)}#{product_values[:description]}\n" @@ -98,21 +115,6 @@ def format_cli_error(error) end end - def init_search_parser - OptionParser.new do |options_parser| - options_parser.banner = "Usage: #{@command_prefix} search-models [options]" - init_common_options(options_parser) - options_parser.on('-n [NAME]', '--name [NAME]', - 'Search for partial matches in model name. Note: case insensitive') do |v| - @options[:model_name] = v - end - options_parser.on('-t [NAME]', '--type [NAME]', - 'Search for EXACT matches in model type. Note: case sensitive') do |v| - @options[:model_type] = v - end - end - end - def setup_specific_options(options_parser, doc_value) options_parser.on('-r', '--rag', 'Enable RAG') { @options[:rag] = true } if doc_value.key?(:rag) if doc_value.key?(:raw_text) @@ -218,13 +220,6 @@ def send(product_command, options) ) end - # @param options [Hash] - # @return [Mindee::V2::Parsing::Search::SearchResponse] - def search(options) - mindee_client = Mindee::V2::Client.new(api_key: options[:api_key]) - mindee_client.search_models(options[:model_name], options[:model_type]) - end - # @param options [Hash] # @return [Mindee::Input::InputSource] def setup_input_source(options) diff --git a/bin/v2/search_commands.rb b/bin/v2/search_commands.rb new file mode 100644 index 000000000..6b0308371 --- /dev/null +++ b/bin/v2/search_commands.rb @@ -0,0 +1,100 @@ +# frozen_string_literal: true + +require 'mindee' +require_relative 'products' + +module MindeeCLI + # Search-related commands for the V2 CLI. + module V2SearchCommands + # NOTE: keep command names as string instead of symbols due to kebab-case. + V2_SEARCH_COMMANDS = { + 'search-models' => { + description: 'Search available models.', + parser: :search_models_parser, + runner: :search_models, + summary: :models, + }, + 'search-rag-docs' => { + description: 'Search available RAG documents for a given model.', + parser: :search_rag_docs_parser, + runner: :search_rag_documents, + summary: :rag_documents, + }, + }.freeze + + private + + # Parse the arguments and run the given search command. + # @param command [String] + # @return [Array(Mindee::V2::Parsing::Search::BaseSearchResponse, String)] Response and its summary. + def run_search(command) + search_command = V2_SEARCH_COMMANDS[command] + search_parser_for(command).parse!(@arguments) + result = __send__(search_command[:runner], @options) + summarized_result = output_format == :full ? result.to_s : result.public_send(search_command[:summary]).to_s + [result, summarized_result] + end + + # @param command [String] + # @return [OptionParser] + def search_parser_for(command) + __send__(V2_SEARCH_COMMANDS[command][:parser]) + end + + # @return [OptionParser] + def init_search_models_parser + OptionParser.new do |options_parser| + options_parser.banner = "Usage: #{@command_prefix} search-models [options]" + init_common_options(options_parser) + options_parser.on('-n [NAME]', '--name [NAME]', + 'Filter by model name partial match (case insensitive).') do |v| + @options[:model_name] = v + end + options_parser.on('-m [MODEL_TYPE]', '--model-type [MODEL_TYPE]', + 'Filter by exact model type (case sensitive).', + "Available options: #{V2_PRODUCTS.keys.join(', ')}") do |v| + @options[:model_type] = v + end + end + end + + # @return [OptionParser] + def init_search_rag_docs_parser + OptionParser.new do |options_parser| + options_parser.banner = "Usage: #{@command_prefix} search-rag-docs [options]" + init_common_options(options_parser) + options_parser.on('-m MODEL_ID', '--model-id MODEL_ID', 'Filter by model ID') do |v| + @options[:model_id] = v + end + options_parser.on('-f [FILENAME]', '--filename [FILENAME]', + 'Filter by file name partial match (case insensitive).') do |v| + @options[:filename] = v + end + end + end + + # @param options [Hash] + # @return [Mindee::V2::Search::Models::ModelSearchResponse] + def search_models(options) + mindee_client = Mindee::V2::Client.new(api_key: options[:api_key]) + mindee_client.search( + Mindee::V2::Search::Models::ModelSearchParameters.new( + name: options[:model_name], + model_type: options[:model_type] + ) + ) + end + + # @param options [Hash] + # @return [Mindee::V2::Search::RAGDocuments::RAGDocumentSearchResponse] + def search_rag_documents(options) + mindee_client = Mindee::V2::Client.new(api_key: options[:api_key]) + mindee_client.search( + Mindee::V2::Search::RAGDocuments::RAGDocumentSearchParameters.new( + model_id: options[:model_id], + filename: options[:filename] + ) + ) + end + end +end diff --git a/lib/mindee/input/base_parameters.rb b/lib/mindee/input/base_parameters.rb deleted file mode 100644 index a9ce79183..000000000 --- a/lib/mindee/input/base_parameters.rb +++ /dev/null @@ -1,156 +0,0 @@ -# frozen_string_literal: true - -module Mindee - module Input - # Base class for parameters accepted by all V2 endpoints. - class BaseParameters - # @return [String] ID of the model (required). - attr_reader :model_id - - # @return [String, nil] Optional alias for the file. - attr_reader :file_alias - - # @return [Array, nil] Optional list of Webhooks IDs to propagate the API response to. - attr_reader :webhook_ids - - # @return [PollingOptions] Options for polling. Set only if having timeout issues. - attr_reader :polling_options - - # @return [Boolean, nil] Whether to close the file after parsing. - attr_reader :close_file - - # @param [String] model_id ID of the model - # @param [String, nil] file_alias File alias, if applicable. - # @param [Array, nil] webhook_ids List of webhook IDs to propagate the API response to. - # @param [Hash, PollingOptions, nil] polling_options Options for polling. Set only if having timeout issues. - # @param [Boolean, nil] close_file Whether to close the file after parsing. - def initialize( - model_id, - file_alias: nil, - webhook_ids: nil, - polling_options: nil, - close_file: true - ) - raise Error::MindeeInputError, 'Model ID is required.' if model_id.empty? || model_id.nil? - - @model_id = model_id - @file_alias = file_alias - @webhook_ids = webhook_ids || [] - @polling_options = get_clean_polling_options(polling_options) - @close_file = close_file.nil? || close_file - end - - # Sets polling options after normalizing hash inputs. - # @param [Hash, PollingOptions, nil] polling_options - # @return [PollingOptions] - def polling_options=(polling_options) - @polling_options = get_clean_polling_options(polling_options) - end - - # @return [String] Slug for the endpoint. - def self.slug - if self == BaseParameters - raise NotImplementedError, 'Cannot access `slug` directly on the BaseParameters class.' - end - - '' - end - - # @return [String] Slug for the endpoint. - def slug - self.class.slug - end - - # Load from a hash - # @param [Hash] params Parameters to provide as a hash. - # @return [BaseParameters] - def self.from_hash(params: {}) - load_from_hash(params: params) - new( - params[:model_id], - file_alias: params[:file_alias], - webhook_ids: params[:webhook_ids], - polling_options: params[:polling_options], - close_file: params[:close_file] - ) - end - - # Loads a prediction from a Hash. - # @param [Hash] params Parameters to provide as a hash. - # @return [Hash] - def self.load_from_hash(params: {}) - params.transform_keys!(&:to_sym) - - if params.empty? || params[:model_id].nil? || params[:model_id].empty? - raise Error::MindeeInputError, 'Model ID is required.' - end - - polling_options_input = params.fetch(:page_options, PollingOptions.new) - if polling_options_input.is_a?(Hash) - polling_options_input = polling_options_input.transform_keys(&:to_sym) - PollingOptions.new( - initial_delay_sec: polling_options_input.fetch(:initial_delay_sec, 2.0), - delay_sec: polling_options_input.fetch(:delay_sec, 1.5), - max_retries: polling_options_input.fetch(:max_retries, 80) - ) - end - params - end - - # Appends base form data to the provided array. - # @param [Array] form_data Array of form fields - # @return [Array] - def append_form_data(form_data) - form_data.push(['alias', @file_alias]) if @file_alias - webhook_ids = @webhook_ids || [] - form_data.push(['webhook_ids', webhook_ids.join(',')]) unless @webhook_ids.nil? || webhook_ids.empty? - form_data - end - - # Validates the parameters for async auto-polling - def validate_async_params - min_delay_sec = 1 - min_initial_delay_sec = 1 - min_retries = 2 - - if @polling_options.delay_sec < min_delay_sec - raise ArgumentError, - "Cannot set auto-poll delay to less than #{min_delay_sec} second(s)" - end - if @polling_options.initial_delay_sec < min_initial_delay_sec - raise ArgumentError, - "Cannot set initial parsing delay to less than #{min_initial_delay_sec} second(s)" - end - return unless @polling_options.max_retries < min_retries - - raise ArgumentError, - "Cannot set auto-poll retries to less than #{min_retries}" - end - - private - - # Cleans a proper polling options object potentially from a hash. - # @param [Hash, PollingOptions, nil] polling_options Polling options. - # @return [PollingOptions] Valid polling options object. - def get_clean_polling_options(polling_options) - return PollingOptions.new if polling_options.is_a?(PollingOptions) - - if polling_options.is_a?(Hash) - polling_options = polling_options.transform_keys(&:to_sym) - output_polling_options = PollingOptions.new( - initial_delay_sec: polling_options.fetch(:initial_delay_sec, 2.0), - delay_sec: polling_options.fetch(:delay_sec, 1.5), - max_retries: polling_options.fetch(:max_retries, 80) - ) - else - output_polling_options = if polling_options.is_a?(PollingOptions) - polling_options || PollingOptions.new - else - PollingOptions.new - end - end - output_polling_options - end - end - end -end diff --git a/lib/mindee/v1/client.rb b/lib/mindee/v1/client.rb index e0e4589ee..3a22b536b 100644 --- a/lib/mindee/v1/client.rb +++ b/lib/mindee/v1/client.rb @@ -250,7 +250,7 @@ def parse_queued(job_id, product_class, endpoint: nil) # @param endpoint [Mindee::V1::HTTP::Endpoint] Endpoint of the API. # @param cancellation_token [Mindee::HTTP::CancellationToken, nil] Token for cancellation. # @return [Mindee::V1::Parsing::Common::ApiResponse] - # rubocop:disable Metrics/PerceivedComplexity + # rubocop:disable-next Metrics/PerceivedComplexity def enqueue_and_parse( input_source, product_class, @@ -293,7 +293,6 @@ def enqueue_and_parse( queue_res end - # rubocop:enable Metrics/PerceivedComplexity # rubocop:enable Metrics/CyclomaticComplexity # Sends a document to a workflow. diff --git a/lib/mindee/v2.rb b/lib/mindee/v2.rb index 4274e91f3..071c38f9f 100644 --- a/lib/mindee/v2.rb +++ b/lib/mindee/v2.rb @@ -1,7 +1,9 @@ # frozen_string_literal: true +require_relative 'v2/client_options' require_relative 'v2/client' require_relative 'v2/http' require_relative 'v2/file_operations' if Mindee::Dependencies.all_deps_available? require_relative 'v2/parsing' +require_relative 'v2/search' require_relative 'v2/product' diff --git a/lib/mindee/v2/client.rb b/lib/mindee/v2/client.rb index bc4fad7ab..0b06d82ac 100644 --- a/lib/mindee/v2/client.rb +++ b/lib/mindee/v2/client.rb @@ -37,7 +37,7 @@ def get_job(job_id) # @param product [Class] The return class. # @param input_source [Mindee::Input::Source::LocalInputSource, Mindee::Input::Source::URLInputSource] # The source of the input document (local file or URL). - # @param params [Hash, Input::BaseParameters] Parameters for the inference. + # @param params [Hash, ClientOptions::BaseProductParameters] Parameters for the inference. # @return [Mindee::V2::Parsing::JobResponse] def enqueue( product, @@ -48,7 +48,7 @@ def enqueue( normalized_params.validate_async_params logger.debug("Enqueueing document to model '#{normalized_params.model_id}'.") - @mindee_api.req_post_enqueue(input_source, normalized_params) + @mindee_api.req_post_product_enqueue(input_source, normalized_params) end # Enqueues to an asynchronous endpoint and automatically polls for a response. @@ -56,11 +56,11 @@ def enqueue( # @param product [Class] The return class. # @param input_source [Mindee::Input::Source::LocalInputSource, Mindee::Input::Source::URLInputSource] # The source of the input document (local file or URL). - # @param params [Hash, Input::BaseParameters] Parameters for the inference. + # @param params [Hash, ClientOptions::BaseProductParameters] Parameters for the inference. # @param polling_options [Hash, PollingOptions, nil] Parameters for polling. # @param cancellation_token [Mindee::HTTP::CancellationToken, nil] Token for cancellation. # @return [Parsing::BaseResponse] - # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity + # rubocop:disable-next Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity def enqueue_and_get_result( product, input_source, @@ -117,14 +117,21 @@ def enqueue_and_get_result( raise Mindee::Error::MindeeError, "Asynchronous parsing request timed out after #{sec_count} seconds" end - # rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity - # Searches for a list of available models for the given API key. - # @param model_name [String] - # @param model_type [String] - # @return [Mindee::V2::Parsing::Search::SearchResponse] + # Search for resources matching the given criteria. + # @param params [ClientOptions::BaseSearchParameters] Search parameters. + # @return [Mindee::V2::Parsing::Search::BaseSearchResponse] A search response containing the matching resources. + def search(params) + @mindee_api.req_get_search(params) + end + + # Returns a list of models matching a criteria for the given API key. + # @deprecated Use {#search} instead. + # @param model_name [String, nil] Name filter. + # @param model_type [String, nil] Model type filter. + # @return [Mindee::V2::Search::Models::ModelSearchResponse] def search_models(model_name, model_type) - @mindee_api.search_models(model_name, model_type) + search(Search::Models::ModelSearchParameters.new(name: model_name, model_type: model_type)) end private @@ -136,7 +143,7 @@ def search_models(model_name, model_type) def normalize_parameters(param_class, params, polling_options: nil) if params.is_a?(Hash) params[:polling_options] = polling_options if polling_options - elsif params.is_a?(Mindee::Input::BaseParameters) && !polling_options.nil? + elsif params.is_a?(Mindee::V2::ClientOptions::BaseProductParameters) && !polling_options.nil? params.polling_options = polling_options end return param_class.from_hash(params: params) if params.is_a?(Hash) diff --git a/lib/mindee/v2/client_options.rb b/lib/mindee/v2/client_options.rb new file mode 100644 index 000000000..3eaae98b6 --- /dev/null +++ b/lib/mindee/v2/client_options.rb @@ -0,0 +1,4 @@ +# frozen_string_literal: true + +require_relative 'client_options/base_product_parameters' +require_relative 'client_options/base_search_parameters' diff --git a/lib/mindee/v2/client_options/base_product_parameters.rb b/lib/mindee/v2/client_options/base_product_parameters.rb new file mode 100644 index 000000000..14956503e --- /dev/null +++ b/lib/mindee/v2/client_options/base_product_parameters.rb @@ -0,0 +1,162 @@ +# frozen_string_literal: true + +module Mindee + module V2 + module ClientOptions + # Base class for parameters accepted by all V2 endpoints. + class BaseProductParameters + # @return [String] Model ID to use for the inference. Required. + attr_reader :model_id + + # @return [String, nil] Optional: a free-form string to tag the request with your own identifier. + # For example, an internal document ID, reference number, or database key. + # If set, it will be included in the job and result responses. + attr_reader :file_alias + + # @return [Array, nil] Webhook IDs to call after all processing is finished. + # If empty, no webhooks will be used. + attr_reader :webhook_ids + + # @return [Input::PollingOptions] Options for polling. Set only if having timeout issues. + attr_reader :polling_options + + # @return [Boolean, nil] Whether to close the file after parsing. + attr_reader :close_file + + # @param [String] model_id ID of the model + # @param [String, nil] file_alias File alias, if applicable. + # @param [Array, nil] webhook_ids List of webhook IDs to propagate the API response to. + # @param [Hash, Input::PollingOptions, nil] polling_options Options for polling. Set only if having timeout + # issues. + # @param [Boolean, nil] close_file Whether to close the file after parsing. + def initialize( + model_id, + file_alias: nil, + webhook_ids: nil, + polling_options: nil, + close_file: true + ) + raise Error::MindeeInputError, 'Model ID is required.' if model_id.nil? || model_id.empty? + + @model_id = model_id + @file_alias = file_alias + @webhook_ids = webhook_ids || [] + @polling_options = get_clean_polling_options(polling_options) + @close_file = close_file.nil? || close_file + end + + # Sets polling options after normalizing hash inputs. + # @param [Hash, Input::PollingOptions, nil] polling_options + # @return [Input::PollingOptions] + def polling_options=(polling_options) + @polling_options = get_clean_polling_options(polling_options) + end + + # @return [String] Slug for the endpoint. + def self.slug + if self == BaseProductParameters + raise NotImplementedError, 'Cannot access `slug` directly on the BaseProductParameters class.' + end + + '' + end + + # @return [String] Slug for the endpoint. + def slug + self.class.slug + end + + # Load from a hash + # @param [Hash] params Parameters to provide as a hash. + # @return [BaseProductParameters] + def self.from_hash(params: {}) + load_from_hash(params: params) + new( + params[:model_id], + file_alias: params[:file_alias], + webhook_ids: params[:webhook_ids], + polling_options: params[:polling_options], + close_file: params[:close_file] + ) + end + + # Loads a prediction from a Hash. + # @param [Hash] params Parameters to provide as a hash. + # @return [Hash] + def self.load_from_hash(params: {}) + params.transform_keys!(&:to_sym) + + if params.empty? || params[:model_id].nil? || params[:model_id].empty? + raise Error::MindeeInputError, 'Model ID is required.' + end + + polling_options_input = params.fetch(:page_options, Input::PollingOptions.new) + if polling_options_input.is_a?(Hash) + polling_options_input = polling_options_input.transform_keys(&:to_sym) + Input::PollingOptions.new( + initial_delay_sec: polling_options_input.fetch(:initial_delay_sec, 2.0), + delay_sec: polling_options_input.fetch(:delay_sec, 1.5), + max_retries: polling_options_input.fetch(:max_retries, 80) + ) + end + params + end + + # Appends base form data to the provided array. + # @param [Array] form_data Array of form fields + # @return [Array] + def append_form_data(form_data) + form_data.push(['alias', @file_alias]) if @file_alias + webhook_ids = @webhook_ids || [] + form_data.push(['webhook_ids', webhook_ids.join(',')]) unless @webhook_ids.nil? || webhook_ids.empty? + form_data + end + + # Validates the parameters for async auto-polling + def validate_async_params + min_delay_sec = 1 + min_initial_delay_sec = 1 + min_retries = 2 + + if @polling_options.delay_sec < min_delay_sec + raise ArgumentError, + "Cannot set auto-poll delay to less than #{min_delay_sec} second(s)" + end + if @polling_options.initial_delay_sec < min_initial_delay_sec + raise ArgumentError, + "Cannot set initial parsing delay to less than #{min_initial_delay_sec} second(s)" + end + return unless @polling_options.max_retries < min_retries + + raise ArgumentError, + "Cannot set auto-poll retries to less than #{min_retries}" + end + + private + + # Cleans a proper polling options object potentially from a hash. + # @param [Hash, Input::PollingOptions, nil] polling_options Polling options. + # @return [Input::PollingOptions] Valid polling options object. + def get_clean_polling_options(polling_options) + return Input::PollingOptions.new if polling_options.is_a?(Input::PollingOptions) + + if polling_options.is_a?(Hash) + polling_options = polling_options.transform_keys(&:to_sym) + output_polling_options = Input::PollingOptions.new( + initial_delay_sec: polling_options.fetch(:initial_delay_sec, 2.0), + delay_sec: polling_options.fetch(:delay_sec, 1.5), + max_retries: polling_options.fetch(:max_retries, 80) + ) + else + output_polling_options = if polling_options.is_a?(Input::PollingOptions) + polling_options || Input::PollingOptions.new + else + Input::PollingOptions.new + end + end + output_polling_options + end + end + end + end +end diff --git a/lib/mindee/v2/client_options/base_search_parameters.rb b/lib/mindee/v2/client_options/base_search_parameters.rb new file mode 100644 index 000000000..89d1ed815 --- /dev/null +++ b/lib/mindee/v2/client_options/base_search_parameters.rb @@ -0,0 +1,51 @@ +# frozen_string_literal: true + +module Mindee + module V2 + module ClientOptions + # Base parameters for searches. + class BaseSearchParameters + # @return [Integer, nil] 1-based page index. + attr_reader :page + # @return [Integer, nil] Number of items per page. + attr_reader :per_page + + # @param page [Integer, nil] 1-based page index. + # @param per_page [Integer, nil] Number of items per page. + def initialize(page: nil, per_page: nil) + @page = page + @per_page = per_page + end + + # Gets the request parameters for the search request. + # @return [Hash{String => String, Array}] + def request_parameters + params = {} # : Hash[String, String | Array[String]] + params['page'] = @page.to_s unless @page.nil? + params['per_page'] = @per_page.to_s unless @per_page.nil? + params + end + + # @return [String] Slug of searchable resources. + def self.slug + raise NotImplementedError, 'Subclasses must implement the `slug` class method' + end + + # @return [String] Slug of searchable resources. + def slug + self.class.slug + end + + # @return [Class] Response class for the search. + def self.response_class + raise NotImplementedError, 'Subclasses must implement the `response_class` class method' + end + + # @return [Class] Response class for the search. + def response_class + self.class.response_class + end + end + end + end +end diff --git a/lib/mindee/v2/http/mindee_api_v2.rb b/lib/mindee/v2/http/mindee_api_v2.rb index 436ee0885..18c0539dc 100644 --- a/lib/mindee/v2/http/mindee_api_v2.rb +++ b/lib/mindee/v2/http/mindee_api_v2.rb @@ -17,13 +17,13 @@ def initialize(api_key: nil) @settings = ApiV2Settings.new(api_key: api_key) end - # Sends a file to the queue. + # Send a file to the asynchronous processing queue for inference processing. # # @param input_source [Input::Source::LocalInputSource, Input::Source::URLInputSource] - # @param params [Input::BaseParameters] + # @param params [ClientOptions::BaseProductParameters] # @return [Mindee::V2::Parsing::JobResponse] # @raise [Mindee::Error::MindeeHttpErrorV2] - def req_post_enqueue(input_source, params) + def req_post_product_enqueue(input_source, params) @settings.check_api_key response = enqueue( input_source, @@ -57,28 +57,15 @@ def req_get_job(job_id) Mindee::V2::Parsing::JobResponse.new(process_response(response)) end - # Retrieves a list of models. - # @param model_name [String, nil] - # @param model_type [String, nil] - # @return [Mindee::V2::Parsing::Search::SearchResponse] - def search_models(model_name, model_type) - Mindee::V2::Parsing::Search::SearchResponse.new(process_response(req_get_search_models(model_name, - model_type))) - end - - private - - # Retrieves a list of models. - # @param model_name [String, nil] - # @param model_type [String, nil] - # @return [Net::HTTPResponse] - def req_get_search_models(model_name, model_type) - url = "#{@settings.base_url}/v2/search/models" - uri = URI(url) + # Retrieves a list of resources with the given criteria. + # @param params [ClientOptions::BaseSearchParameters] Search parameters. + # @return [Mindee::V2::Parsing::Search::BaseSearchResponse] A search response containing the matching + # resources. + def req_get_search(params) + @settings.check_api_key + uri = URI("#{@settings.base_url}/v2/search/#{params.slug}") - query_params = {} # @type var query_params: Hash[Symbol, String | nil] - query_params[:name] = model_name if model_name - query_params[:model_type] = model_type if model_type + query_params = params.request_parameters uri.query = URI.encode_www_form(query_params) unless query_params.empty? headers = { @@ -88,12 +75,15 @@ def req_get_search_models(model_name, model_type) req = Net::HTTP::Get.new(uri, headers) req['Transfer-Encoding'] = 'chunked' - Net::HTTP.start(uri.hostname, uri.port, use_ssl: true, read_timeout: @settings.request_timeout) do |http| - return http.request(req) + response = Net::HTTP.start(uri.hostname, uri.port, + use_ssl: true, read_timeout: @settings.request_timeout) do |http| + http.request(req) end - raise Mindee::Error::MindeeError, 'Could not resolve server response.' + params.response_class.new(process_response(response)) end + private + # @param resource [String] Resource to check. # @return [Boolean] def uri?(resource) @@ -191,7 +181,7 @@ def enqueue_form_options(form_data, params) end # @param input_source [Mindee::Input::Source::LocalInputSource, Mindee::Input::Source::URLInputSource] - # @param params [Input::BaseParameters] Inference options. + # @param params [ClientOptions::BaseProductParameters] Inference options. # @return [Net::HTTPResponse, nil] def enqueue(input_source, params) uri = URI("#{@settings.base_url}/v2/products/#{params.slug}/enqueue") diff --git a/lib/mindee/v2/parsing/search.rb b/lib/mindee/v2/parsing/search.rb index 19050b2bc..4f45ceaf2 100644 --- a/lib/mindee/v2/parsing/search.rb +++ b/lib/mindee/v2/parsing/search.rb @@ -1,7 +1,11 @@ # frozen_string_literal: true require_relative 'search/pagination_metadata' +require_relative 'search/model_webhook' require_relative 'search/search_model' require_relative 'search/search_models' +require_relative 'search/search_rag_document' +require_relative 'search/search_rag_documents' +require_relative 'search/base_search_response' +require_relative '../search/models/model_search_response' require_relative 'search/search_response' -require_relative 'search/model_webhook' diff --git a/lib/mindee/v2/parsing/search/base_search_response.rb b/lib/mindee/v2/parsing/search/base_search_response.rb new file mode 100644 index 000000000..9fa1be459 --- /dev/null +++ b/lib/mindee/v2/parsing/search/base_search_response.rb @@ -0,0 +1,47 @@ +# frozen_string_literal: true + +module Mindee + module V2 + module Parsing + module Search + # Base class for search responses. + class BaseSearchResponse < CommonResponse + # Pagination metadata. + # @return [Mindee::V2::Parsing::Search::PaginationMetadata] + attr_reader :pagination + + # @param http_response [Hash] The parsed JSON payload from the API. + def initialize(http_response) + super + + @pagination = PaginationMetadata.new(http_response['pagination']) + end + + # Lines composing the response-specific body (header + items). + # @return [Array] + def body_lines + raise NotImplementedError, 'body_lines must be implemented in subclasses' + end + + # Pagination metadata (Obsolete). + # @deprecated Use {#pagination} instead. + # @return [Mindee::V2::Parsing::Search::PaginationMetadata] + def pagination_metadata + pagination + end + + # String representation of the search response. + # @return [String] + def to_s + lines = body_lines + lines.push('Pagination Metadata') + lines.push('###################') + lines.push(@pagination.to_s) + + lines.join("\n") + end + end + end + end + end +end diff --git a/lib/mindee/v2/parsing/search/model_webhook.rb b/lib/mindee/v2/parsing/search/model_webhook.rb index 4e2d7df8b..629497a47 100644 --- a/lib/mindee/v2/parsing/search/model_webhook.rb +++ b/lib/mindee/v2/parsing/search/model_webhook.rb @@ -4,7 +4,7 @@ module Mindee module V2 module Parsing module Search - # Individual webhook information. + # Information about a model's webhook. class ModelWebhook # @return [String] ID of the webhook. attr_reader :id @@ -15,14 +15,14 @@ class ModelWebhook # @return [String] URL of the webhook. attr_reader :url - # @param payload [Hash] The parsed JSON payload mapping to the search model. + # @param payload [Hash] The parsed JSON payload mapping to the webhook. def initialize(payload) @id = payload['id'] @name = payload['name'] @url = payload['url'] end - # String representation of the model. + # String representation of the webhook. # @return [String] def to_s [ diff --git a/lib/mindee/v2/parsing/search/pagination_metadata.rb b/lib/mindee/v2/parsing/search/pagination_metadata.rb index 207a068a4..f85162a57 100644 --- a/lib/mindee/v2/parsing/search/pagination_metadata.rb +++ b/lib/mindee/v2/parsing/search/pagination_metadata.rb @@ -4,7 +4,7 @@ module Mindee module V2 module Parsing module Search - # Pagination Metadata data associated with model search. + # Pagination metadata associated with searches. class PaginationMetadata # @return [Integer] Number of items per page. attr_reader :per_page diff --git a/lib/mindee/v2/parsing/search/search_models.rb b/lib/mindee/v2/parsing/search/search_models.rb index a49a63dff..751e494c0 100644 --- a/lib/mindee/v2/parsing/search/search_models.rb +++ b/lib/mindee/v2/parsing/search/search_models.rb @@ -4,8 +4,9 @@ module Mindee module V2 module Parsing module Search - # Array of search models. + # List of search models. class SearchModels < Array + # @param prediction [Array] The parsed JSON payload mapping to the search models. def initialize(prediction) super(prediction.map { |entry| SearchModel.new(entry) }) end diff --git a/lib/mindee/v2/parsing/search/search_rag_document.rb b/lib/mindee/v2/parsing/search/search_rag_document.rb new file mode 100644 index 000000000..7e672b7af --- /dev/null +++ b/lib/mindee/v2/parsing/search/search_rag_document.rb @@ -0,0 +1,60 @@ +# frozen_string_literal: true + +require 'time' + +module Mindee + module V2 + module Parsing + module Search + # Individual RAG document information. + class SearchRAGDocument + # @return [String] Unique identifier of the RAG document. + attr_reader :id + + # @return [String] Model identifier linked to the RAG document. + attr_reader :model_id + + # @return [String] Original filename of the uploaded document. + attr_reader :filename + + # @return [Time] Date and time of the document creation. + attr_reader :created_at + + # @return [Integer] Number of times this document was used in an inference. + attr_reader :total_matches + + # @return [Time, nil] Date and time of the latest matching inference, if any. + attr_reader :last_match_at + + # @return [String] Current status of the RAG document. + attr_reader :status + + # @param server_response [Hash] The parsed JSON payload mapping to the RAG document. + def initialize(server_response) + @id = server_response['id'] + @model_id = server_response['model_id'] + @filename = server_response['filename'] + @created_at = Time.iso8601(server_response['created_at']) + @total_matches = server_response['total_matches'] + @last_match_at = (Time.iso8601(server_response['last_match_at']) if server_response['last_match_at']) + @status = server_response['status'] + end + + # String representation of the RAG document. + # @return [String] + def to_s + [ + ":ID: #{@id}", + ":Model ID: #{@model_id}", + ":Filename: #{@filename}", + ":Created At: #{@created_at}", + ":Total Matches: #{@total_matches}", + ":Last Match At: #{@last_match_at}", + ":Status: #{@status}", + ].join("\n") + end + end + end + end + end +end diff --git a/lib/mindee/v2/parsing/search/search_rag_documents.rb b/lib/mindee/v2/parsing/search/search_rag_documents.rb new file mode 100644 index 000000000..0e8964d4b --- /dev/null +++ b/lib/mindee/v2/parsing/search/search_rag_documents.rb @@ -0,0 +1,39 @@ +# frozen_string_literal: true + +require_relative 'search_rag_document' + +module Mindee + module V2 + module Parsing + module Search + # List of RAG documents. + class SearchRAGDocuments < Array + # @param raw_response [Array] The parsed JSON payload mapping to the RAG documents. + def initialize(raw_response) + super(raw_response.map { |entry| SearchRAGDocument.new(entry) }) + end + + # Default string representation. + # @return [String] + def to_s + return "\n" if empty? + + lines = flat_map do |rag_document| + [ + "* :ID: #{rag_document.id}", + " :Model ID: #{rag_document.model_id}", + " :Filename: #{rag_document.filename}", + " :Created At: #{rag_document.created_at}", + " :Total Matches: #{rag_document.total_matches}", + " :Last Match At: #{rag_document.last_match_at}", + " :Status: #{rag_document.status}", + ] + end + + "#{lines.join("\n")}\n" + end + end + end + end + end +end diff --git a/lib/mindee/v2/parsing/search/search_response.rb b/lib/mindee/v2/parsing/search/search_response.rb index 3b7ee41ff..7cba74b34 100644 --- a/lib/mindee/v2/parsing/search/search_response.rb +++ b/lib/mindee/v2/parsing/search/search_response.rb @@ -5,35 +5,8 @@ module V2 module Parsing module Search # Models search response. - class SearchResponse < CommonResponse - # @return [Search::SearchModels] Parsed search payload. - attr_reader :models - # @return [Search::PaginationMetadata] Pagination metadata. - attr_reader :pagination - # @return [Search::PaginationMetadata] Pagination metadata. - attr_reader :pagination_metadata - - def initialize(server_response) - super - - @models = SearchModels.new(server_response['models']) - @pagination = PaginationMetadata.new(server_response['pagination']) - @pagination_metadata = @pagination - end - - # String representation. - # @return [String] - def to_s - [ - 'Models', - '######', - @models.to_s, - 'Pagination Metadata', - '###################', - @pagination.to_s, - '', - ].join("\n") - end + # @deprecated Use {Mindee::V2::Search::Models::ModelSearchResponse} instead. + class SearchResponse < Mindee::V2::Search::Models::ModelSearchResponse end end end diff --git a/lib/mindee/v2/product/base_product.rb b/lib/mindee/v2/product/base_product.rb index d6633a707..f22668670 100644 --- a/lib/mindee/v2/product/base_product.rb +++ b/lib/mindee/v2/product/base_product.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require_relative '../parsing/base_response' -require_relative '../../input/base_parameters' +require_relative '../client_options/base_product_parameters' module Mindee module V2 @@ -11,7 +11,7 @@ class BaseProduct # @return [String] The slug of the endpoint used for this response @slug = '' # @return [Class] The class of the parameters used for this response - @params_type = Mindee::Input::BaseParameters + @params_type = Mindee::V2::ClientOptions::BaseProductParameters # @return [Class] The class of the response used for this product @response_type = Mindee::V2::Parsing::BaseResponse diff --git a/lib/mindee/v2/product/classification/classification_classifier.rb b/lib/mindee/v2/product/classification/classification_classifier.rb index f5c37e940..bfd399947 100644 --- a/lib/mindee/v2/product/classification/classification_classifier.rb +++ b/lib/mindee/v2/product/classification/classification_classifier.rb @@ -13,11 +13,10 @@ class ClassificationClassifier # @param server_response [Hash] Hash representation of the JSON returned by the service. def initialize(server_response) @document_type = server_response['document_type'] - # rubocop:disable Style/GuardClause + # rubocop:disable-next Style/GuardClause unless server_response['extraction_response'].nil? @extraction_response = V2::Product::Extraction::ExtractionResponse.new(server_response['extraction_response']) end - # rubocop:enable Style/GuardClause end # @return [String] String representation. diff --git a/lib/mindee/v2/product/classification/params/classification_parameters.rb b/lib/mindee/v2/product/classification/params/classification_parameters.rb index 0a037e9f7..786d27327 100644 --- a/lib/mindee/v2/product/classification/params/classification_parameters.rb +++ b/lib/mindee/v2/product/classification/params/classification_parameters.rb @@ -7,7 +7,7 @@ module Classification # Classification parameters. module Params # Parameters accepted by the classification utility v2 endpoint. - class ClassificationParameters < Mindee::Input::BaseParameters + class ClassificationParameters < Mindee::V2::ClientOptions::BaseProductParameters # @return [String] Slug for the endpoint. def self.slug 'classification' diff --git a/lib/mindee/v2/product/crop/crop_item.rb b/lib/mindee/v2/product/crop/crop_item.rb index a1b8dd7e6..dbedb2e39 100644 --- a/lib/mindee/v2/product/crop/crop_item.rb +++ b/lib/mindee/v2/product/crop/crop_item.rb @@ -16,11 +16,10 @@ class CropItem def initialize(server_response) @object_type = server_response['object_type'] @location = Mindee::V2::Parsing::Field::FieldLocation.new(server_response['location']) - # rubocop:disable Style/GuardClause + # rubocop:disable-next Style/GuardClause unless server_response['extraction_response'].nil? @extraction_response = V2::Product::Extraction::ExtractionResponse.new(server_response['extraction_response']) end - # rubocop:enable Style/GuardClause end # String representation. diff --git a/lib/mindee/v2/product/crop/params/crop_parameters.rb b/lib/mindee/v2/product/crop/params/crop_parameters.rb index 4113f7d88..43958b027 100644 --- a/lib/mindee/v2/product/crop/params/crop_parameters.rb +++ b/lib/mindee/v2/product/crop/params/crop_parameters.rb @@ -7,7 +7,7 @@ module Crop # Crop parameters. module Params # Parameters accepted by the crop utility v2 endpoint. - class CropParameters < Mindee::Input::BaseParameters + class CropParameters < Mindee::V2::ClientOptions::BaseProductParameters # @return [String] Slug for the endpoint. def self.slug 'crop' diff --git a/lib/mindee/v2/product/extraction/params/extraction_parameters.rb b/lib/mindee/v2/product/extraction/params/extraction_parameters.rb index 00886e85a..7b9b8c263 100644 --- a/lib/mindee/v2/product/extraction/params/extraction_parameters.rb +++ b/lib/mindee/v2/product/extraction/params/extraction_parameters.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -require_relative '../../../../input/base_parameters' +require_relative '../../../client_options/base_product_parameters' require_relative 'data_schema' module Mindee @@ -9,7 +9,7 @@ module Product module Extraction module Params # Parameters accepted by the extraction v2 endpoint. - class ExtractionParameters < Mindee::Input::BaseParameters + class ExtractionParameters < Mindee::V2::ClientOptions::BaseProductParameters # @return [Boolean, nil] Enhance extraction accuracy with Retrieval-Augmented Generation. attr_reader :rag diff --git a/lib/mindee/v2/product/ocr/params/ocr_parameters.rb b/lib/mindee/v2/product/ocr/params/ocr_parameters.rb index 7774c0684..92b86cc22 100644 --- a/lib/mindee/v2/product/ocr/params/ocr_parameters.rb +++ b/lib/mindee/v2/product/ocr/params/ocr_parameters.rb @@ -7,7 +7,7 @@ module OCR # OCR Parameters. module Params # Parameters accepted by the ocr utility v2 endpoint. - class OCRParameters < Mindee::Input::BaseParameters + class OCRParameters < Mindee::V2::ClientOptions::BaseProductParameters # @return [String] Slug for the endpoint. def self.slug 'ocr' diff --git a/lib/mindee/v2/product/split/params/split_parameters.rb b/lib/mindee/v2/product/split/params/split_parameters.rb index 2c30a0de3..08fd39d36 100644 --- a/lib/mindee/v2/product/split/params/split_parameters.rb +++ b/lib/mindee/v2/product/split/params/split_parameters.rb @@ -8,7 +8,7 @@ module Split # Split parameters. module Params # Parameters accepted by the split utility v2 endpoint. - class SplitParameters < Mindee::Input::BaseParameters + class SplitParameters < Mindee::V2::ClientOptions::BaseProductParameters # @return [String] Slug for the endpoint. def self.slug 'split' diff --git a/lib/mindee/v2/product/split/split_range.rb b/lib/mindee/v2/product/split/split_range.rb index 2752334f4..8ae7ee8db 100644 --- a/lib/mindee/v2/product/split/split_range.rb +++ b/lib/mindee/v2/product/split/split_range.rb @@ -17,11 +17,10 @@ class SplitRange def initialize(server_response) @page_range = server_response['page_range'] @document_type = server_response['document_type'] - # rubocop:disable Style/GuardClause + # rubocop:disable-next Style/GuardClause unless server_response['extraction_response'].nil? @extraction_response = V2::Product::Extraction::ExtractionResponse.new(server_response['extraction_response']) end - # rubocop:enable Style/GuardClause end # String representation. diff --git a/lib/mindee/v2/search.rb b/lib/mindee/v2/search.rb new file mode 100644 index 000000000..1204cb481 --- /dev/null +++ b/lib/mindee/v2/search.rb @@ -0,0 +1,6 @@ +# frozen_string_literal: true + +require_relative 'search/models/model_search_response' +require_relative 'search/models/model_search_parameters' +require_relative 'search/rag_documents/rag_document_search_response' +require_relative 'search/rag_documents/rag_document_search_parameters' diff --git a/lib/mindee/v2/search/models/model_search_parameters.rb b/lib/mindee/v2/search/models/model_search_parameters.rb new file mode 100644 index 000000000..403a6cacc --- /dev/null +++ b/lib/mindee/v2/search/models/model_search_parameters.rb @@ -0,0 +1,51 @@ +# frozen_string_literal: true + +module Mindee + module V2 + module Search + module Models + # Search parameters for models. + class ModelSearchParameters < Mindee::V2::ClientOptions::BaseSearchParameters + # @return [String, nil] Case-insensitive search term for the model name. + attr_reader :name + + # @return [String, nil] Case-insensitive search term for the model type. + attr_reader :model_type + + # @param name [String, nil] Case-insensitive search term for the model name. + # @param model_type [String, nil] Case-insensitive search term for the model type. + # @param page [Integer, nil] 1-based page index. + # @param per_page [Integer, nil] Number of items per page. + def initialize(name: nil, model_type: nil, page: nil, per_page: nil) + super(page: page, per_page: per_page) + @name = name + @model_type = model_type + end + + # @return [String] Slug of searchable resources. + def self.slug + 'models' + end + + # @return [Class] Response class for the search. + def self.response_class + ModelSearchResponse + end + + # Gets the request parameters for the search request. + # @return [Hash{String => String, Array}] + def request_parameters + params = super + + name = @name + model_type = @model_type + params['name'] = name unless name.nil? + params['model_type'] = model_type unless model_type.nil? + + params + end + end + end + end + end +end diff --git a/lib/mindee/v2/search/models/model_search_response.rb b/lib/mindee/v2/search/models/model_search_response.rb new file mode 100644 index 000000000..4300a2e49 --- /dev/null +++ b/lib/mindee/v2/search/models/model_search_response.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +module Mindee + module V2 + module Search + module Models + # Models search response. + class ModelSearchResponse < Mindee::V2::Parsing::Search::BaseSearchResponse + # @return [Mindee::V2::Parsing::Search::SearchModels] Paginated list of matching models. + attr_reader :models + + # @param raw_response [Hash] The parsed JSON payload from the API. + def initialize(raw_response) + super + + @models = Mindee::V2::Parsing::Search::SearchModels.new(raw_response['models']) + end + + # Lines composing the response-specific body (header + items). + # @return [Array] + def body_lines + ['Models', '######', @models.to_s] + end + end + end + end + end +end diff --git a/lib/mindee/v2/search/rag_documents/rag_document_search_parameters.rb b/lib/mindee/v2/search/rag_documents/rag_document_search_parameters.rb new file mode 100644 index 000000000..7ee67f7cf --- /dev/null +++ b/lib/mindee/v2/search/rag_documents/rag_document_search_parameters.rb @@ -0,0 +1,52 @@ +# frozen_string_literal: true + +module Mindee + module V2 + module Search + module RAGDocuments + # Search parameters for RAG Documents. + class RAGDocumentSearchParameters < Mindee::V2::ClientOptions::BaseSearchParameters + # @return [String] Model identifier to search in. + attr_reader :model_id + + # @return [String, nil] Case-insensitive substring search on filename. + attr_reader :filename + + # @param model_id [String] Model identifier to search in. + # @param filename [String, nil] Case-insensitive substring search on filename. + # @param page [Integer, nil] 1-based page index. + # @param per_page [Integer, nil] Number of items per page. + def initialize(model_id:, filename: nil, page: nil, per_page: nil) + super(page: page, per_page: per_page) + raise Error::MindeeInputError, 'Model ID is required.' if model_id.nil? || model_id.empty? + + @model_id = model_id + @filename = filename + end + + # @return [String] Slug of searchable resources. + def self.slug + 'rag-documents' + end + + # @return [Class] Response class for the search. + def self.response_class + RAGDocumentSearchResponse + end + + # Gets the request parameters for the search request. + # @return [Hash{String => String, Array}] + def request_parameters + params = super + + params['model_id'] = @model_id + filename = @filename + params['filename'] = filename unless filename.nil? + + params + end + end + end + end + end +end diff --git a/lib/mindee/v2/search/rag_documents/rag_document_search_response.rb b/lib/mindee/v2/search/rag_documents/rag_document_search_response.rb new file mode 100644 index 000000000..e549cbdce --- /dev/null +++ b/lib/mindee/v2/search/rag_documents/rag_document_search_response.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +module Mindee + module V2 + module Search + module RAGDocuments + # RAG Documents search response. + class RAGDocumentSearchResponse < Mindee::V2::Parsing::Search::BaseSearchResponse + # @return [Mindee::V2::Parsing::Search::SearchRAGDocuments] Paginated list of matching RAG documents. + attr_reader :rag_documents + + # @param raw_response [Hash] The parsed JSON payload from the API. + def initialize(raw_response) + super + + @rag_documents = Mindee::V2::Parsing::Search::SearchRAGDocuments.new(raw_response['rag_documents']) + end + + # Lines composing the response-specific body (header + items). + # @return [Array] + def body_lines + ['RAG Documents', '#############', @rag_documents.to_s] + end + end + end + end + end +end diff --git a/sig/mindee/input/base_parameters.rbs b/sig/mindee/input/base_parameters.rbs deleted file mode 100644 index 1a223afbf..000000000 --- a/sig/mindee/input/base_parameters.rbs +++ /dev/null @@ -1,36 +0,0 @@ -# lib/mindee/input/base_parameters.rb - -module Mindee - module Input - class BaseParameters - attr_reader self.slug: String - - def self.from_hash: (params: Hash[String | Symbol, untyped]) -> BaseParameters - def self.load_from_hash: (params: Hash[String | Symbol, untyped]) -> Hash[String | Symbol, untyped] - - def slug: -> String - - attr_reader model_id: String - attr_reader file_alias: String? - attr_reader webhook_ids: Array[String]? - attr_reader polling_options: PollingOptions - attr_reader close_file: bool - - def initialize: ( - String, - ?file_alias: String?, - ?webhook_ids: Array[String]?, - ?polling_options: Hash[Symbol | String, untyped] | PollingOptions | nil, - ?close_file: bool? - ) -> void - - def append_form_data: (Array[Array[untyped]]) -> Array[Array[untyped]] - def validate_async_params: () -> void - def polling_options=: (Hash[Symbol | String, untyped] | PollingOptions | nil) -> PollingOptions - - private - - def get_clean_polling_options: (Hash[String | Symbol, untyped] | PollingOptions | nil) -> PollingOptions - end - end -end diff --git a/sig/mindee/v2/client.rbs b/sig/mindee/v2/client.rbs index 625d97400..57a6150b8 100644 --- a/sig/mindee/v2/client.rbs +++ b/sig/mindee/v2/client.rbs @@ -15,15 +15,18 @@ module Mindee def get_job: (String job_id) -> V2::Parsing::JobResponse - def enqueue: [T] (HTTP::_ProductClass[T] product, Input::Source::LocalInputSource | Input::Source::URLInputSource, Hash[String | Symbol, untyped] | Input::BaseParameters params) -> V2::Parsing::JobResponse + def enqueue: [T] (HTTP::_ProductClass[T] product, Input::Source::LocalInputSource | Input::Source::URLInputSource, Hash[String | Symbol, untyped] | ClientOptions::BaseProductParameters params) -> V2::Parsing::JobResponse - def enqueue_and_get_result: [T] (HTTP::_ProductClass[T] product, Input::Source::LocalInputSource | Input::Source::URLInputSource, Hash[String | Symbol, untyped] | Input::BaseParameters params, ?Hash[String | Symbol, untyped] | Input::PollingOptions | nil) -> T + def enqueue_and_get_result: [T] (HTTP::_ProductClass[T] product, Input::Source::LocalInputSource | Input::Source::URLInputSource, Hash[String | Symbol, untyped] | ClientOptions::BaseProductParameters params, ?Hash[String | Symbol, untyped] | Input::PollingOptions | nil) -> T - def search_models: (String?, String?) -> Mindee::V2::Parsing::Search::SearchResponse + def search: [T] (HTTP::_SearchParameters[T] params) -> T + + # Deprecated: use `search` instead. + def search_models: (String?, String?) -> Mindee::V2::Search::Models::ModelSearchResponse def validate_async_params: (Integer | Float, Integer | Float, Integer) -> void - def normalize_parameters: (singleton(Input::BaseParameters) param_class, Hash[String | Symbol, untyped] | Input::BaseParameters params, ?polling_options: Hash[String | Symbol, untyped] | Input::PollingOptions | nil) -> Input::BaseParameters + def normalize_parameters: (singleton(ClientOptions::BaseProductParameters) param_class, Hash[String | Symbol, untyped] | ClientOptions::BaseProductParameters params, ?polling_options: Hash[String | Symbol, untyped] | Input::PollingOptions | nil) -> ClientOptions::BaseProductParameters end end end diff --git a/sig/mindee/v2/client_options/base_product_parameters.rbs b/sig/mindee/v2/client_options/base_product_parameters.rbs new file mode 100644 index 000000000..2077e48f3 --- /dev/null +++ b/sig/mindee/v2/client_options/base_product_parameters.rbs @@ -0,0 +1,41 @@ +# lib/mindee/v2/client_options/base_product_parameters.rb + +module Mindee + module V2 + module ClientOptions + class BaseProductParameters + attr_reader self.slug: String + + def self.from_hash: (params: Hash[String | Symbol, untyped]) -> BaseProductParameters + + def self.load_from_hash: (params: Hash[String | Symbol, untyped]) -> Hash[String | Symbol, untyped] + + def slug: -> String + + attr_reader model_id: String + attr_reader file_alias: String? + attr_reader webhook_ids: Array[String]? + attr_reader polling_options: Input::PollingOptions + attr_reader close_file: bool + + def initialize: ( + String, + ?file_alias: String?, + ?webhook_ids: Array[String]?, + ?polling_options: Hash[Symbol | String, untyped] | Input::PollingOptions | nil, + ?close_file: bool? + ) -> void + + def append_form_data: (Array[Array[untyped]]) -> Array[Array[untyped]] + + def validate_async_params: () -> void + + def polling_options=: (Hash[Symbol | String, untyped] | Input::PollingOptions | nil) -> Input::PollingOptions + + private + + def get_clean_polling_options: (Hash[String | Symbol, untyped] | Input::PollingOptions | nil) -> Input::PollingOptions + end + end + end +end diff --git a/sig/mindee/v2/client_options/base_search_parameters.rbs b/sig/mindee/v2/client_options/base_search_parameters.rbs new file mode 100644 index 000000000..629eb7387 --- /dev/null +++ b/sig/mindee/v2/client_options/base_search_parameters.rbs @@ -0,0 +1,19 @@ +module Mindee + module V2 + module ClientOptions + class BaseSearchParameters + attr_reader page: Integer? + attr_reader per_page: Integer? + + def initialize: (?page: Integer?, ?per_page: Integer?) -> void + + def request_parameters: -> Hash[String, String | Array[String]] + + def slug: -> String + def self.slug: -> String + def response_class: -> singleton(V2::Parsing::Search::BaseSearchResponse) + def self.response_class: -> singleton(V2::Parsing::Search::BaseSearchResponse) + end + end + end +end diff --git a/sig/mindee/v2/http/mindee_api_v2.rbs b/sig/mindee/v2/http/mindee_api_v2.rbs index 9cbbfe719..534f6564a 100644 --- a/sig/mindee/v2/http/mindee_api_v2.rbs +++ b/sig/mindee/v2/http/mindee_api_v2.rbs @@ -11,7 +11,15 @@ module Mindee def response_type: () -> _ResponseFactory[T] - def params_type: () -> singleton(Input::BaseParameters) + def params_type: () -> singleton(ClientOptions::BaseProductParameters) + end + + interface _SearchParameters[T] + def slug: () -> String + + def response_class: () -> _ResponseFactory[T] + + def request_parameters: () -> Hash[String, String | Array[String]] end class MindeeApiV2 @@ -21,7 +29,7 @@ module Mindee def req_get_result: [T] (_ProductClass[T] product, String resource) -> T - def req_post_enqueue: (Input::Source::LocalInputSource | Input::Source::URLInputSource, Input::BaseParameters) -> V2::Parsing::JobResponse + def req_post_product_enqueue: (Input::Source::LocalInputSource | Input::Source::URLInputSource, ClientOptions::BaseProductParameters) -> V2::Parsing::JobResponse def req_get_job: (String) -> V2::Parsing::JobResponse @@ -31,9 +39,9 @@ module Mindee def result_req_get: [T] (String, _ProductClass[T] product) -> Net::HTTPResponse - def enqueue: (Input::Source::LocalInputSource | Input::Source::URLInputSource, Input::BaseParameters) -> Net::HTTPResponse? + def enqueue: (Input::Source::LocalInputSource | Input::Source::URLInputSource, ClientOptions::BaseProductParameters) -> Net::HTTPResponse? - def search_models: (String?, String?) -> Mindee::V2::Parsing::Search::SearchResponse + def req_get_search: [T] (_SearchParameters[T] params) -> T private @@ -43,8 +51,6 @@ module Mindee def req_get_result_url: [T] (_ResponseFactory[T] result_class, String url) -> T - def req_get_search_models: (String?, String?) -> Net::HTTPResponse - def uri?: (String) -> bool end end diff --git a/sig/mindee/v2/parsing/search/base_search_response.rbs b/sig/mindee/v2/parsing/search/base_search_response.rbs new file mode 100644 index 000000000..b144c2d5b --- /dev/null +++ b/sig/mindee/v2/parsing/search/base_search_response.rbs @@ -0,0 +1,19 @@ +module Mindee + module V2 + module Parsing + module Search + class BaseSearchResponse < CommonResponse + attr_reader pagination: PaginationMetadata + + def initialize: (Hash[String|Symbol, untyped]) -> void + + def body_lines: -> Array[String] + + def pagination_metadata: -> PaginationMetadata + + def to_s: -> String + end + end + end + end +end diff --git a/sig/mindee/v2/parsing/search/search_rag_document.rbs b/sig/mindee/v2/parsing/search/search_rag_document.rbs new file mode 100644 index 000000000..fe5ae61dd --- /dev/null +++ b/sig/mindee/v2/parsing/search/search_rag_document.rbs @@ -0,0 +1,23 @@ +# lib/mindee/v2/parsing/search/search_rag_document.rb + +module Mindee + module V2 + module Parsing + module Search + class SearchRAGDocument + attr_reader created_at: Time + attr_reader filename: String + attr_reader id: String + attr_reader last_match_at: Time? + attr_reader model_id: String + attr_reader status: String + attr_reader total_matches: Integer + + def initialize: (Hash[String|Symbol, untyped]) -> void + + def to_s: -> String + end + end + end + end +end diff --git a/sig/mindee/v2/parsing/search/search_rag_documents.rbs b/sig/mindee/v2/parsing/search/search_rag_documents.rbs new file mode 100644 index 000000000..72d0753b8 --- /dev/null +++ b/sig/mindee/v2/parsing/search/search_rag_documents.rbs @@ -0,0 +1,16 @@ +# lib/mindee/v2/parsing/search/search_rag_documents.rb + +module Mindee + module V2 + module Parsing + module Search + # List of RAG documents. + class SearchRAGDocuments < Array[SearchRAGDocument] + def initialize: (Array[Hash[String|Symbol, untyped]]) -> void + + def to_s: -> String + end + end + end + end +end diff --git a/sig/mindee/v2/parsing/search/search_response.rbs b/sig/mindee/v2/parsing/search/search_response.rbs index 953ab4e79..31698859b 100644 --- a/sig/mindee/v2/parsing/search/search_response.rbs +++ b/sig/mindee/v2/parsing/search/search_response.rbs @@ -1,16 +1,11 @@ -# lib/mindee/v2/search/search_response.rb +# lib/mindee/v2/parsing/search/search_response.rb + module Mindee module V2 module Parsing module Search - class SearchResponse - attr_reader models: Array[SearchResponse] - attr_reader pagination: PaginationMetadata - attr_reader pagination_metadata: PaginationMetadata - - def initialize: (Hash[String|Symbol, untyped]) -> void - - def to_s: -> String + # Deprecated: use `Mindee::V2::Search::Models::ModelSearchResponse` instead. + class SearchResponse < V2::Search::Models::ModelSearchResponse end end end diff --git a/sig/mindee/v2/product/base_product.rbs b/sig/mindee/v2/product/base_product.rbs index aa6bdbe35..43ca94c2b 100644 --- a/sig/mindee/v2/product/base_product.rbs +++ b/sig/mindee/v2/product/base_product.rbs @@ -3,13 +3,13 @@ module Mindee module Product class BaseProduct self.@slug: String - self.@params_type: singleton(Input::BaseParameters) + self.@params_type: singleton(ClientOptions::BaseProductParameters) self.@response_type: singleton(Parsing::BaseResponse) - def self._params_type: () -> singleton(Input::BaseParameters) + def self._params_type: () -> singleton(ClientOptions::BaseProductParameters) attr_reader self.slug: String - attr_reader self.params_type: singleton(Input::BaseParameters) + attr_reader self.params_type: singleton(ClientOptions::BaseProductParameters) attr_reader self.response_type: singleton(Parsing::BaseResponse) def initialize: -> void diff --git a/sig/mindee/v2/product/classification/params/classification_parameters/classification_parameters.rbs b/sig/mindee/v2/product/classification/params/classification_parameters/classification_parameters.rbs index 638d4c1d2..ae89ac7d4 100644 --- a/sig/mindee/v2/product/classification/params/classification_parameters/classification_parameters.rbs +++ b/sig/mindee/v2/product/classification/params/classification_parameters/classification_parameters.rbs @@ -3,7 +3,7 @@ module Mindee module Product module Classification module Params - class ClassificationParameters + class ClassificationParameters < ClientOptions::BaseProductParameters def self.slug: -> String def self.from_hash: (params: Hash[String | Symbol, untyped]) -> ClassificationParameters diff --git a/sig/mindee/v2/product/crop/params/crop_parameters/crop_parameters.rbs b/sig/mindee/v2/product/crop/params/crop_parameters/crop_parameters.rbs index 4642adbde..ad5d44daa 100644 --- a/sig/mindee/v2/product/crop/params/crop_parameters/crop_parameters.rbs +++ b/sig/mindee/v2/product/crop/params/crop_parameters/crop_parameters.rbs @@ -3,7 +3,7 @@ module Mindee module Product module Crop module Params - class CropParameters + class CropParameters < ClientOptions::BaseProductParameters def self.slug: -> String def self.from_hash: (params: Hash[String | Symbol, untyped]) -> CropParameters diff --git a/sig/mindee/v2/product/extraction/params/extraction_parameters.rbs b/sig/mindee/v2/product/extraction/params/extraction_parameters.rbs index 3ec957801..39e84d99e 100644 --- a/sig/mindee/v2/product/extraction/params/extraction_parameters.rbs +++ b/sig/mindee/v2/product/extraction/params/extraction_parameters.rbs @@ -3,7 +3,7 @@ module Mindee module Product module Extraction module Params - class ExtractionParameters < Input::BaseParameters + class ExtractionParameters < ClientOptions::BaseProductParameters def self.slug: -> String diff --git a/sig/mindee/v2/product/ocr/params/ocr_parameters/ocr_parameters.rbs b/sig/mindee/v2/product/ocr/params/ocr_parameters/ocr_parameters.rbs index 6c5f4c678..944317cfa 100644 --- a/sig/mindee/v2/product/ocr/params/ocr_parameters/ocr_parameters.rbs +++ b/sig/mindee/v2/product/ocr/params/ocr_parameters/ocr_parameters.rbs @@ -3,7 +3,7 @@ module Mindee module Product module OCR module Params - class OCRParameters + class OCRParameters < ClientOptions::BaseProductParameters def self.slug: -> String def self.from_hash: (params: Hash[String | Symbol, untyped]) -> OCRParameters diff --git a/sig/mindee/v2/product/split/params/split_parameters/split_parameters.rbs b/sig/mindee/v2/product/split/params/split_parameters/split_parameters.rbs index 4518f0abd..f984c8af4 100644 --- a/sig/mindee/v2/product/split/params/split_parameters/split_parameters.rbs +++ b/sig/mindee/v2/product/split/params/split_parameters/split_parameters.rbs @@ -3,7 +3,7 @@ module Mindee module Product module Split module Params - class SplitParameters + class SplitParameters < ClientOptions::BaseProductParameters def self.slug: -> String def self.from_hash: (params: Hash[String | Symbol, untyped]) -> SplitParameters diff --git a/sig/mindee/v2/search/models/model_search_parameters.rbs b/sig/mindee/v2/search/models/model_search_parameters.rbs new file mode 100644 index 000000000..fc4c2b46e --- /dev/null +++ b/sig/mindee/v2/search/models/model_search_parameters.rbs @@ -0,0 +1,22 @@ +# lib/mindee/v2/search/models/model_search_parameters.rb + +module Mindee + module V2 + module Search + module Models + class ModelSearchParameters < ClientOptions::BaseSearchParameters + attr_reader model_type: String? + attr_reader name: String? + + def initialize: (?name: String?, ?model_type: String?, ?page: Integer?, ?per_page: Integer?) -> void + + def self.slug: -> String + def self.response_class: -> singleton(ModelSearchResponse) + def response_class: -> singleton(ModelSearchResponse) + + def request_parameters: -> Hash[String, String | Array[String]] + end + end + end + end +end diff --git a/sig/mindee/v2/search/models/model_search_response.rbs b/sig/mindee/v2/search/models/model_search_response.rbs new file mode 100644 index 000000000..ef380d9b2 --- /dev/null +++ b/sig/mindee/v2/search/models/model_search_response.rbs @@ -0,0 +1,17 @@ +# lib/mindee/v2/search/models/model_search_response.rb + +module Mindee + module V2 + module Search + module Models + class ModelSearchResponse < V2::Parsing::Search::BaseSearchResponse + attr_reader models: V2::Parsing::Search::SearchModels + + def initialize: (Hash[String|Symbol, untyped]) -> void + + def body_lines: -> Array[String] + end + end + end + end +end diff --git a/sig/mindee/v2/search/rag_documents/rag_document_search_parameters.rbs b/sig/mindee/v2/search/rag_documents/rag_document_search_parameters.rbs new file mode 100644 index 000000000..3e8f100a6 --- /dev/null +++ b/sig/mindee/v2/search/rag_documents/rag_document_search_parameters.rbs @@ -0,0 +1,22 @@ +# lib/mindee/v2/search/rag_documents/rag_document_search_parameters.rb + +module Mindee + module V2 + module Search + module RAGDocuments + class RAGDocumentSearchParameters < ClientOptions::BaseSearchParameters + attr_reader filename: String? + attr_reader model_id: String + + def initialize: (model_id: String, ?filename: String?, ?page: Integer?, ?per_page: Integer?) -> void + + def self.slug: -> String + def self.response_class: -> singleton(RAGDocumentSearchResponse) + def response_class: -> singleton(RAGDocumentSearchResponse) + + def request_parameters: -> Hash[String, String | Array[String]] + end + end + end + end +end diff --git a/sig/mindee/v2/search/rag_documents/rag_document_search_response.rbs b/sig/mindee/v2/search/rag_documents/rag_document_search_response.rbs new file mode 100644 index 000000000..ff3a8c121 --- /dev/null +++ b/sig/mindee/v2/search/rag_documents/rag_document_search_response.rbs @@ -0,0 +1,17 @@ +# lib/mindee/v2/search/rag_documents/rag_document_search_response.rb + +module Mindee + module V2 + module Search + module RAGDocuments + class RAGDocumentSearchResponse < V2::Parsing::Search::BaseSearchResponse + attr_reader rag_documents: V2::Parsing::Search::SearchRAGDocuments + + def initialize: (Hash[String|Symbol, untyped]) -> void + + def body_lines: -> Array[String] + end + end + end + end +end diff --git a/spec/bin/cli_integration.rb b/spec/bin/cli_integration.rb index acf58699d..ae8a6c0f4 100644 --- a/spec/bin/cli_integration.rb +++ b/spec/bin/cli_integration.rb @@ -21,7 +21,7 @@ def run_cli(*args) context 'search-models command' do ['classification', 'crop', 'extraction', 'ocr', 'split'].each do |model_type| it "returns model list for type #{model_type}" do - stdout, stderr, status = run_cli('search-models', '-t', model_type) + stdout, stderr, status = run_cli('search-models', '-m', model_type) expect(status.success?).to eq(true), stderr expect(stdout.strip).not_to be_empty end @@ -40,13 +40,13 @@ def run_cli(*args) end it 'returns models for name and model_type filters' do - stdout, stderr, status = run_cli('search-models', '-n', 'findoc', '-t', 'extraction') + stdout, stderr, status = run_cli('search-models', '-n', 'findoc', '-m', 'extraction') expect(status.success?).to eq(true), stderr expect(stdout.strip).not_to be_empty end it 'returns HTTP 422 on invalid model type' do - stdout, stderr, status = run_cli('search-models', '-t', 'invalid') + stdout, stderr, status = run_cli('search-models', '-m', 'invalid') expect(status.success?).to eq(false) expect("#{stdout}\n#{stderr}").to include('HTTP 422') end diff --git a/spec/data b/spec/data index e41ab97c2..4b7f33766 160000 --- a/spec/data +++ b/spec/data @@ -1 +1 @@ -Subproject commit e41ab97c2833f15ea5c4edf221c2d197d212f632 +Subproject commit 4b7f33766fab0e67804b84447b73c80a902d886a diff --git a/spec/v2/parsing/search_models_spec.rb b/spec/v2/parsing/search_models_spec.rb deleted file mode 100644 index b55a10f3a..000000000 --- a/spec/v2/parsing/search_models_spec.rb +++ /dev/null @@ -1,19 +0,0 @@ -# frozen_string_literal: true - -require 'mindee' -require 'mindee/v2/parsing/search' - -describe Mindee::V2::Parsing::Search::SearchResponse do - it 'initializes' do - json_file_path = File.join(V2_DATA_DIR, 'search', 'models.json') - - response = described_class.new(JSON.parse(File.read(json_file_path))) - - expect(response).not_to be_nil - expect(response.models.size).to eq(5) - model0 = response.models[0] - expect(model0.name).to eq('Extraction With Webhooks') - expect(model0.webhooks.size).to eq(2) - expect(model0.webhooks[0].url).to eq('https://failure.mindee.com') - end -end diff --git a/spec/v2/search/model_search_integration.rb b/spec/v2/search/model_search_integration.rb new file mode 100644 index 000000000..e3ff5463e --- /dev/null +++ b/spec/v2/search/model_search_integration.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +require 'mindee' + +describe Mindee::V2::Search::Models::ModelSearchParameters, :integration, :v2 do + let(:v2_client) do + Mindee::V2::Client.new + end + + it 'must have results' do + response = v2_client.search(described_class.new) + + expect(response).not_to be_nil + expect(response.models).not_to be_empty + expect(response.pagination).not_to be_nil + expect(response.pagination.total_items).to be >= 1 + expect(response.pagination.page).to eq(1) + end + + it 'must return empty' do + response = v2_client.search(described_class.new(name: "je n'existe pas tralala")) + + expect(response).not_to be_nil + expect(response.models).to be_empty + expect(response.pagination).not_to be_nil + expect(response.pagination.total_items).to eq(0) + expect(response.pagination.page).to eq(1) + end +end diff --git a/spec/v2/search/model_search_spec.rb b/spec/v2/search/model_search_spec.rb new file mode 100644 index 000000000..55f9a3078 --- /dev/null +++ b/spec/v2/search/model_search_spec.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true + +require 'mindee' +require 'mindee/input/local_response' +require_relative '../../data' + +describe Mindee::V2::Search::Models::ModelSearchResponse do + it 'should load search models locally' do + file_path = File.join(V2_DATA_DIR, 'search', 'models.json') + local_response = Mindee::Input::LocalResponse.new(file_path) + response = local_response.deserialize_response(described_class) + + expect(response).to be_a(described_class) + + expect(response.models.size).to eq(5) + expect(response.pagination.total_items).to eq(5) + expect(response.pagination.page).to eq(1) + expect(response.pagination.per_page).to eq(50) + expect(response.pagination.total_pages).to eq(1) + + first_item = response.models[0] + expect(first_item.name).to eq('Extraction With Webhooks') + expect(first_item.id).to eq('afde5151-aa11-aa11-9289-fa04e50ca3b9') + expect(first_item.model_type).to eq('extraction') + + expect(first_item.webhooks.size).to eq(2) + expect(first_item.webhooks[0].id).to eq('a2286ed9-aa11-aa11-bdc5-2f8496c5641a') + expect(first_item.webhooks[0].name).to eq('FAILURE') + expect(first_item.webhooks[0].url).to eq('https://failure.mindee.com') + + last_item = response.models[-1] + expect(last_item.name).to eq('Extraction Without Webhooks Key') + expect(last_item.id).to eq('e14e0923-ee55-ee55-a335-8d2110917d7b') + end +end diff --git a/spec/v2/search/rag_document_search_integration.rb b/spec/v2/search/rag_document_search_integration.rb new file mode 100644 index 000000000..bec74fd85 --- /dev/null +++ b/spec/v2/search/rag_document_search_integration.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +require 'mindee' + +describe Mindee::V2::Search::RAGDocuments::RAGDocumentSearchParameters, :integration, :v2 do + let(:findoc_model_id) do + ENV.fetch('MINDEE_V2_SE_TESTS_FINDOC_MODEL_ID', nil) + end + + let(:v2_client) do + Mindee::V2::Client.new + end + + it 'must have results' do + expect(findoc_model_id).not_to be_nil, 'MINDEE_V2_SE_TESTS_FINDOC_MODEL_ID must be set' + + response = v2_client.search(described_class.new(model_id: findoc_model_id)) + + expect(response).not_to be_nil + expect(response.rag_documents).not_to be_empty + expect(response.pagination).not_to be_nil + expect(response.pagination.total_items).to be >= 1 + expect(response.pagination.page).to eq(1) + end +end diff --git a/spec/v2/search/rag_document_search_spec.rb b/spec/v2/search/rag_document_search_spec.rb new file mode 100644 index 000000000..c95b5253c --- /dev/null +++ b/spec/v2/search/rag_document_search_spec.rb @@ -0,0 +1,48 @@ +# frozen_string_literal: true + +require 'mindee' +require 'mindee/input/local_response' +require_relative '../../data' + +describe Mindee::V2::Search::RAGDocuments::RAGDocumentSearchResponse do + it 'should load search rag documents locally' do + file_path = File.join(V2_DATA_DIR, 'search', 'rag_documents.json') + local_response = Mindee::Input::LocalResponse.new(file_path) + response = local_response.deserialize_response(described_class) + + expect(response).to be_a(described_class) + + expect(response.rag_documents.size).to eq(3) + expect(response.pagination.total_items).to eq(3) + expect(response.pagination.page).to eq(1) + expect(response.pagination.per_page).to eq(50) + expect(response.pagination.total_pages).to eq(1) + + first_item = response.rag_documents[0] + expect(first_item.id).to eq('cc831599-c545-48b7-aa27-6d7ccd5b8d32') + expect(first_item.model_id).to eq('12345678-1234-1234-1234-123456789abc') + expect(first_item.filename).to eq('invoice_01.pdf') + expect(first_item.created_at).to eq(Time.utc(2026, 6, 30, 13, 13, 46, 168_586)) + expect(first_item.total_matches).to eq(0) + expect(first_item.last_match_at).to be_nil + expect(first_item.status).to eq('Processing') + + second_item = response.rag_documents[1] + expect(second_item.id).to eq('27467e4c-5602-4315-90d9-3d2da69b05ab') + expect(second_item.model_id).to eq('12345678-1234-1234-1234-123456789abc') + expect(second_item.filename).to eq('invoice_02.pdf') + expect(second_item.created_at).to eq(Time.utc(2026, 6, 30, 13, 13, 46, 168_586)) + expect(second_item.total_matches).to eq(0) + expect(second_item.last_match_at).to be_nil + expect(second_item.status).to eq('Draft') + + third_item = response.rag_documents[2] + expect(third_item.id).to eq('a6bcae7d-0439-476b-8a63-5a39ec05dc21') + expect(third_item.model_id).to eq('12345678-1234-1234-1234-jobid1234567') + expect(third_item.filename).to eq('invoice_03.pdf') + expect(third_item.created_at).to eq(Time.utc(2026, 6, 17, 14, 35, 46, 228_006)) + expect(third_item.total_matches).to eq(5) + expect(third_item.last_match_at).to eq(Time.utc(2026, 6, 18, 14, 35, 46, 248_006)) + expect(third_item.status).to eq('Active') + end +end