ox-ai-workers 0.9.6 → 0.9.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +129 -2
- data/lib/oxaiworkers/assistant/painter.rb +0 -6
- data/lib/oxaiworkers/iterator.rb +1 -1
- data/lib/oxaiworkers/module_request.rb +3 -2
- data/lib/oxaiworkers/tool/pixels.rb +3 -23
- data/lib/oxaiworkers/version.rb +1 -1
- metadata +1 -1
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 768550f6fde8e654917a2b01404856abcbe643429ba725d7c86c853b472f4bed
         | 
| 4 | 
            +
              data.tar.gz: 9444f8c6869caa2e7039d3632605885579364942de95ba2fa6b201d5ca00c3e5
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 6a0c8f3622ab30d8a199b367ad3b0bab3c985a292cc786d3c38380515b5adbe02b945eaff4606073b199a59bf4237bb36c86a0a89b07f6c62c0bc0b738ed7593
         | 
| 7 | 
            +
              data.tar.gz: 491720defa83f4b26cccc0d389975f1125c8636821c37314814fdbe9bf714d9233f22456a09b2f8ec890e2b52d3fcb96065295563b1272336316f34461fe6667
         | 
    
        data/README.md
    CHANGED
    
    | @@ -88,6 +88,7 @@ For a more robust setup, you can configure the gem with your API keys, for examp | |
| 88 88 | 
             
            OxAiWorkers.configure do |config|
         | 
| 89 89 | 
             
                config.access_token_openai = ENV.fetch("OPENAI")
         | 
| 90 90 | 
             
                config.access_token_deepseek = ENV.fetch("DEEPSEEK")
         | 
| 91 | 
            +
                config.access_token_stability = ENV.fetch("STABILITY")
         | 
| 91 92 | 
             
                config.max_tokens = 4096   # Default
         | 
| 92 93 | 
             
                config.temperature = 0.7   # Default
         | 
| 93 94 | 
             
                config.wait_for_complete = true # Default
         | 
| @@ -420,10 +421,50 @@ image_data = File.read('local_image.jpg') | |
| 420 421 | 
             
            iterator.add_image(
         | 
| 421 422 | 
             
              text: 'Image from binary data',
         | 
| 422 423 | 
             
              binary: image_data,
         | 
| 423 | 
            -
              mime_type: 'image/jpeg' # Defaults to 'image/ | 
| 424 | 
            +
              mime_type: 'image/jpeg' # Defaults to 'image/png'
         | 
| 424 425 | 
             
            )
         | 
| 425 426 | 
             
            ```
         | 
| 426 427 |  | 
| 428 | 
            +
            #### Image Input Requirements
         | 
| 429 | 
            +
             | 
| 430 | 
            +
            When using images with the API, your input images must meet the following requirements:
         | 
| 431 | 
            +
             | 
| 432 | 
            +
            **Supported file types:**
         | 
| 433 | 
            +
             | 
| 434 | 
            +
            - PNG (.png)
         | 
| 435 | 
            +
            - JPEG (.jpeg and .jpg)
         | 
| 436 | 
            +
            - WEBP (.webp)
         | 
| 437 | 
            +
            - Non-animated GIF (.gif)
         | 
| 438 | 
            +
             | 
| 439 | 
            +
            **Size limits:**
         | 
| 440 | 
            +
             | 
| 441 | 
            +
            - Up to 20MB per image
         | 
| 442 | 
            +
            - Low-resolution: 512px x 512px
         | 
| 443 | 
            +
            - High-resolution: 768px (short side) x 2000px (long side)
         | 
| 444 | 
            +
             | 
| 445 | 
            +
            **Other requirements:**
         | 
| 446 | 
            +
             | 
| 447 | 
            +
            - No watermarks or logos
         | 
| 448 | 
            +
            - No text
         | 
| 449 | 
            +
            - No NSFW content
         | 
| 450 | 
            +
            - Clear enough for a human to understand
         | 
| 451 | 
            +
             | 
| 452 | 
            +
            **Image detail level:**
         | 
| 453 | 
            +
             | 
| 454 | 
            +
            The `detail` parameter controls what level of detail the model uses when processing the image:
         | 
| 455 | 
            +
             | 
| 456 | 
            +
            ```ruby
         | 
| 457 | 
            +
            iterator.add_image(
         | 
| 458 | 
            +
              text: 'Nature boardwalk image',
         | 
| 459 | 
            +
              url: 'https://example.com/nature.jpg',
         | 
| 460 | 
            +
              detail: 'high' # Options: 'auto', 'low', or 'high'
         | 
| 461 | 
            +
            )
         | 
| 462 | 
            +
            ```
         | 
| 463 | 
            +
             | 
| 464 | 
            +
            - `detail: 'low'`: Uses less tokens (85) and processes a low-resolution 512px x 512px version of the image. Best for simple use cases like identifying dominant colors or shapes.
         | 
| 465 | 
            +
            - `detail: 'high'`: Provides better image understanding for complex tasks requiring higher resolution detail.
         | 
| 466 | 
            +
            - `detail: 'auto'`: Lets the model decide the appropriate detail level (default if not specified).
         | 
| 467 | 
            +
             | 
| 427 468 | 
             
            ### Handling State Transitions with Callbacks
         | 
| 428 469 |  | 
| 429 470 | 
             
            You can track and respond to state transitions with callbacks:
         | 
| @@ -519,7 +560,7 @@ OxAiWorkers provides several specialized tools to extend functionality: | |
| 519 560 | 
             
              pixels = OxAiWorkers::Tool::Pixels.new(
         | 
| 520 561 | 
             
                worker: worker,                 # Required: Request or DelayedRequest instance
         | 
| 521 562 | 
             
                current_dir: Dir.pwd,           # Optional: Directory to save generated images
         | 
| 522 | 
            -
                image_model:  | 
| 563 | 
            +
                image_model: OxAiWorkers::Models::StabilityImages.new,       # Optional, default is OpenaiDalle3
         | 
| 523 564 | 
             
                only: [:generate_image]         # Optional: Limit available functions
         | 
| 524 565 | 
             
              )
         | 
| 525 566 | 
             
              ```
         | 
| @@ -654,6 +695,92 @@ module OxAiWorkers | |
| 654 695 | 
             
            end
         | 
| 655 696 | 
             
            ```
         | 
| 656 697 |  | 
| 698 | 
            +
            ## Image Generation
         | 
| 699 | 
            +
             | 
| 700 | 
            +
            OxAiWorkers supports image generation through the Painter assistant and Pixels tool, with multiple AI image generation models.
         | 
| 701 | 
            +
             | 
| 702 | 
            +
            ### Supported Image Models
         | 
| 703 | 
            +
             | 
| 704 | 
            +
            - **OpenaiDalle3** - OpenAI's DALL-E 3 model
         | 
| 705 | 
            +
            - **OpenaiGptImage** - OpenAI's GPT-Image-1 model
         | 
| 706 | 
            +
            - **StabilityImages** - Stability AI's image generation models
         | 
| 707 | 
            +
             | 
| 708 | 
            +
            ### Using the Painter Assistant
         | 
| 709 | 
            +
             | 
| 710 | 
            +
            ```ruby
         | 
| 711 | 
            +
            # Using DALL-E 3 (default)
         | 
| 712 | 
            +
            painter = OxAiWorkers::Assistant::Painter.new(current_dir: Dir.pwd)
         | 
| 713 | 
            +
            painter.task = "Create an image of a sunset over mountains"
         | 
| 714 | 
            +
             | 
| 715 | 
            +
            # Using GPT-Image-1
         | 
| 716 | 
            +
            painter = OxAiWorkers::Assistant::Painter.new(
         | 
| 717 | 
            +
              image_model: OxAiWorkers::Models::OpenaiGptImage.new,
         | 
| 718 | 
            +
              current_dir: Dir.pwd
         | 
| 719 | 
            +
            )
         | 
| 720 | 
            +
            painter.task = "Generate a photorealistic red apple"
         | 
| 721 | 
            +
             | 
| 722 | 
            +
            # Using Stability AI
         | 
| 723 | 
            +
            painter = OxAiWorkers::Assistant::Painter.new(
         | 
| 724 | 
            +
              image_model: OxAiWorkers::Models::StabilityImages.new,
         | 
| 725 | 
            +
              current_dir: Dir.pwd
         | 
| 726 | 
            +
            )
         | 
| 727 | 
            +
            painter.task = "Create a fantasy landscape with dragons"
         | 
| 728 | 
            +
            ```
         | 
| 729 | 
            +
             | 
| 730 | 
            +
            ### Using the Pixels Tool Directly
         | 
| 731 | 
            +
             | 
| 732 | 
            +
            For more direct control over image generation:
         | 
| 733 | 
            +
             | 
| 734 | 
            +
            ```ruby
         | 
| 735 | 
            +
            # Initialize with DALL-E 3
         | 
| 736 | 
            +
            pixels = OxAiWorkers::Tool::Pixels.new(
         | 
| 737 | 
            +
              worker: OxAiWorkers::Models::OpenaiDalle3.new,
         | 
| 738 | 
            +
              current_dir: Dir.pwd
         | 
| 739 | 
            +
            )
         | 
| 740 | 
            +
            pixels.generate_image(
         | 
| 741 | 
            +
              prompt: "A photorealistic red apple on a wooden table",
         | 
| 742 | 
            +
              file_name: "apple.png",
         | 
| 743 | 
            +
              size: "1024x1024",
         | 
| 744 | 
            +
              quality: "hd"
         | 
| 745 | 
            +
            )
         | 
| 746 | 
            +
             | 
| 747 | 
            +
            # Initialize with GPT-Image-1
         | 
| 748 | 
            +
            pixels = OxAiWorkers::Tool::Pixels.new(
         | 
| 749 | 
            +
              worker: OxAiWorkers::Models::OpenaiGptImage.new,
         | 
| 750 | 
            +
              current_dir: Dir.pwd
         | 
| 751 | 
            +
            )
         | 
| 752 | 
            +
            pixels.generate_image(
         | 
| 753 | 
            +
              prompt: "Futuristic cityscape at night",
         | 
| 754 | 
            +
              file_name: "city.png",
         | 
| 755 | 
            +
              size: "1536x1024",
         | 
| 756 | 
            +
              quality: "high"
         | 
| 757 | 
            +
            )
         | 
| 758 | 
            +
             | 
| 759 | 
            +
            # Initialize with Stability AI
         | 
| 760 | 
            +
            pixels = OxAiWorkers::Tool::Pixels.new(
         | 
| 761 | 
            +
              worker: OxAiWorkers::Models::StabilityImages.new,
         | 
| 762 | 
            +
              current_dir: Dir.pwd
         | 
| 763 | 
            +
            )
         | 
| 764 | 
            +
            pixels.generate_image(
         | 
| 765 | 
            +
              prompt: "Photorealistic mountain landscape",
         | 
| 766 | 
            +
              file_name: "mountains.png"
         | 
| 767 | 
            +
            )
         | 
| 768 | 
            +
            ```
         | 
| 769 | 
            +
             | 
| 770 | 
            +
            ### Model-Specific Features
         | 
| 771 | 
            +
             | 
| 772 | 
            +
            - **OpenaiDalle3**
         | 
| 773 | 
            +
              - Sizes: '1024x1024', '1024x1792', '1792x1024'
         | 
| 774 | 
            +
              - Qualities: 'standard', 'hd'
         | 
| 775 | 
            +
             | 
| 776 | 
            +
            - **OpenaiGptImage**
         | 
| 777 | 
            +
              - Sizes: 'auto', '1024x1024', '1536x1024', '1024x1536'
         | 
| 778 | 
            +
              - Qualities: 'auto', 'low', 'medium', 'high'
         | 
| 779 | 
            +
             | 
| 780 | 
            +
            - **StabilityImages**
         | 
| 781 | 
            +
              - Uses Stability AI's API with different engine options
         | 
| 782 | 
            +
              - Configuration via options parameter
         | 
| 783 | 
            +
             | 
| 657 784 | 
             
            ## Contributing
         | 
| 658 785 |  | 
| 659 786 | 
             
            Bug reports and pull requests are welcome on GitHub at <https://github.com/neonix20b/ox-ai-workers>. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/neonix20b/ox-ai-workers/blob/main/CODE_OF_CONDUCT.md).
         | 
| @@ -29,12 +29,6 @@ module OxAiWorkers | |
| 29 29 | 
             
                      on_outer_voice: ->(text:) { puts "voice: #{text}".colorize(:green) }
         | 
| 30 30 | 
             
                    )
         | 
| 31 31 | 
             
                  end
         | 
| 32 | 
            -
             | 
| 33 | 
            -
                  def cleanup
         | 
| 34 | 
            -
                    Dir.glob(File.join(@current_dir, '*.png')).each do |file|
         | 
| 35 | 
            -
                      File.delete(file) if File.exist?(file)
         | 
| 36 | 
            -
                    end
         | 
| 37 | 
            -
                  end
         | 
| 38 32 | 
             
                end
         | 
| 39 33 | 
             
              end
         | 
| 40 34 | 
             
            end
         | 
    
        data/lib/oxaiworkers/iterator.rb
    CHANGED
    
    | @@ -266,7 +266,7 @@ module OxAiWorkers | |
| 266 266 | 
             
                  add_raw_context({ role:, content: })
         | 
| 267 267 | 
             
                end
         | 
| 268 268 |  | 
| 269 | 
            -
                def add_image(text:, url: nil, binary: nil, role: :user, detail: 'auto', mime_type: 'image/ | 
| 269 | 
            +
                def add_image(text:, url: nil, binary: nil, role: :user, detail: 'auto', mime_type: 'image/png')
         | 
| 270 270 | 
             
                  content = []
         | 
| 271 271 | 
             
                  content << { type: 'text', text: } if text.present?
         | 
| 272 272 |  | 
| @@ -53,10 +53,11 @@ module OxAiWorkers | |
| 53 53 | 
             
                    frequency_penalty: @model.frequency_penalty
         | 
| 54 54 | 
             
                  }
         | 
| 55 55 | 
             
                  if @tools.present?
         | 
| 56 | 
            -
                    parameters[:tools] = @tools. | 
| 56 | 
            +
                    parameters[:tools] = @tools.select do |f|
         | 
| 57 57 | 
             
                      tool_name = f[:function][:name]
         | 
| 58 58 | 
             
                      tool_name == @last_call && @stop_double_calls.include?(tool_name)
         | 
| 59 59 | 
             
                    end
         | 
| 60 | 
            +
                    OxAiWorkers.logger.debug("tools: #{parameters[:tools]} last_call=#{@last_call} stop_double_calls=#{@stop_double_calls}", for: self.class)
         | 
| 60 61 | 
             
                    if @call_stack&.any?
         | 
| 61 62 | 
             
                      func1 = @call_stack.first
         | 
| 62 63 | 
             
                      @call_stack = @call_stack.drop(1)
         | 
| @@ -146,7 +147,7 @@ module OxAiWorkers | |
| 146 147 | 
             
                      name: function['name'].split('__').last,
         | 
| 147 148 | 
             
                      args: args
         | 
| 148 149 | 
             
                    }
         | 
| 149 | 
            -
                    @last_call = function['name']
         | 
| 150 | 
            +
                    @last_call = function['name'].to_s
         | 
| 150 151 | 
             
                  end
         | 
| 151 152 | 
             
                end
         | 
| 152 153 | 
             
              end
         | 
| @@ -62,29 +62,9 @@ module OxAiWorkers | |
| 62 62 | 
             
                    end
         | 
| 63 63 | 
             
                  end
         | 
| 64 64 |  | 
| 65 | 
            -
                  def edit_image(input_image:, prompt:, output_file_name: nil, size: nil, mask: nil)
         | 
| 66 | 
            -
             | 
| 67 | 
            -
             | 
| 68 | 
            -
             | 
| 69 | 
            -
                    response = @worker.client.images.edit(
         | 
| 70 | 
            -
                      parameters: {
         | 
| 71 | 
            -
                        image: input_image,
         | 
| 72 | 
            -
                        model: @image_model['model'],
         | 
| 73 | 
            -
                        prompt:,
         | 
| 74 | 
            -
                        size:,
         | 
| 75 | 
            -
                        mask:
         | 
| 76 | 
            -
                      }
         | 
| 77 | 
            -
                    )
         | 
| 78 | 
            -
             | 
| 79 | 
            -
                    @url = response.dig('data', 0, 'url')
         | 
| 80 | 
            -
                    revised_prompt = response.dig('data', 0, 'revised_prompt')
         | 
| 81 | 
            -
                    if output_file_name.present?
         | 
| 82 | 
            -
                      path = save_generated_image(file_name: output_file_name)
         | 
| 83 | 
            -
                      "url: #{@url}\nfile_name: #{path}\n\nrevised_prompt: #{revised_prompt}"
         | 
| 84 | 
            -
                    else
         | 
| 85 | 
            -
                      "url: #{@url}\n\nrevised_prompt: #{revised_prompt}"
         | 
| 86 | 
            -
                    end
         | 
| 87 | 
            -
                  end
         | 
| 65 | 
            +
                  # def edit_image(input_image:, prompt:, output_file_name: nil, size: nil, mask: nil)
         | 
| 66 | 
            +
                  #   # TODO: Implement edit_image
         | 
| 67 | 
            +
                  # end
         | 
| 88 68 |  | 
| 89 69 | 
             
                  def save_generated_image(file_name:, binary:)
         | 
| 90 70 | 
             
                    unless @current_dir.present?
         | 
    
        data/lib/oxaiworkers/version.rb
    CHANGED