ruby_llm-agents 0.4.0 → 1.0.0.beta.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 +225 -34
- data/app/controllers/ruby_llm/agents/agents_controller.rb +136 -16
- data/app/controllers/ruby_llm/agents/api_configurations_controller.rb +214 -0
- data/app/controllers/ruby_llm/agents/dashboard_controller.rb +29 -9
- data/app/controllers/ruby_llm/agents/{settings_controller.rb → system_config_controller.rb} +3 -3
- data/app/controllers/ruby_llm/agents/tenants_controller.rb +109 -0
- data/app/controllers/ruby_llm/agents/workflows_controller.rb +355 -0
- data/app/helpers/ruby_llm/agents/application_helper.rb +25 -0
- data/app/models/ruby_llm/agents/api_configuration.rb +386 -0
- data/app/models/ruby_llm/agents/execution.rb +3 -0
- data/app/models/ruby_llm/agents/tenant_budget.rb +112 -14
- data/app/services/ruby_llm/agents/agent_registry.rb +51 -12
- data/app/views/layouts/ruby_llm/agents/application.html.erb +5 -30
- data/app/views/ruby_llm/agents/agents/_agent.html.erb +13 -1
- data/app/views/ruby_llm/agents/agents/_config_agent.html.erb +235 -0
- data/app/views/ruby_llm/agents/agents/_config_embedder.html.erb +70 -0
- data/app/views/ruby_llm/agents/agents/_config_image_generator.html.erb +152 -0
- data/app/views/ruby_llm/agents/agents/_config_moderator.html.erb +63 -0
- data/app/views/ruby_llm/agents/agents/_config_speaker.html.erb +108 -0
- data/app/views/ruby_llm/agents/agents/_config_transcriber.html.erb +91 -0
- data/app/views/ruby_llm/agents/agents/_workflow.html.erb +1 -1
- data/app/views/ruby_llm/agents/agents/index.html.erb +74 -9
- data/app/views/ruby_llm/agents/agents/show.html.erb +18 -378
- data/app/views/ruby_llm/agents/api_configurations/_api_key_field.html.erb +34 -0
- data/app/views/ruby_llm/agents/api_configurations/_form.html.erb +288 -0
- data/app/views/ruby_llm/agents/api_configurations/edit.html.erb +95 -0
- data/app/views/ruby_llm/agents/api_configurations/edit_tenant.html.erb +97 -0
- data/app/views/ruby_llm/agents/api_configurations/show.html.erb +211 -0
- data/app/views/ruby_llm/agents/api_configurations/tenant.html.erb +179 -0
- data/app/views/ruby_llm/agents/dashboard/_action_center.html.erb +1 -1
- data/app/views/ruby_llm/agents/dashboard/_agent_comparison.html.erb +269 -15
- data/app/views/ruby_llm/agents/executions/show.html.erb +98 -0
- data/app/views/ruby_llm/agents/shared/_agent_type_badge.html.erb +93 -0
- data/app/views/ruby_llm/agents/{settings → system_config}/show.html.erb +1 -1
- data/app/views/ruby_llm/agents/tenants/_form.html.erb +150 -0
- data/app/views/ruby_llm/agents/tenants/edit.html.erb +13 -0
- data/app/views/ruby_llm/agents/tenants/index.html.erb +129 -0
- data/app/views/ruby_llm/agents/tenants/show.html.erb +374 -0
- data/app/views/ruby_llm/agents/workflows/_step_performance.html.erb +236 -0
- data/app/views/ruby_llm/agents/workflows/_structure_parallel.html.erb +76 -0
- data/app/views/ruby_llm/agents/workflows/_structure_pipeline.html.erb +74 -0
- data/app/views/ruby_llm/agents/workflows/_structure_router.html.erb +108 -0
- data/app/views/ruby_llm/agents/workflows/show.html.erb +442 -0
- data/config/routes.rb +13 -1
- data/lib/generators/ruby_llm_agents/agent_generator.rb +56 -7
- data/lib/generators/ruby_llm_agents/api_configuration_generator.rb +100 -0
- data/lib/generators/ruby_llm_agents/background_remover_generator.rb +110 -0
- data/lib/generators/ruby_llm_agents/embedder_generator.rb +107 -0
- data/lib/generators/ruby_llm_agents/image_analyzer_generator.rb +115 -0
- data/lib/generators/ruby_llm_agents/image_editor_generator.rb +108 -0
- data/lib/generators/ruby_llm_agents/image_generator_generator.rb +116 -0
- data/lib/generators/ruby_llm_agents/image_pipeline_generator.rb +178 -0
- data/lib/generators/ruby_llm_agents/image_transformer_generator.rb +109 -0
- data/lib/generators/ruby_llm_agents/image_upscaler_generator.rb +103 -0
- data/lib/generators/ruby_llm_agents/image_variator_generator.rb +102 -0
- data/lib/generators/ruby_llm_agents/install_generator.rb +76 -4
- data/lib/generators/ruby_llm_agents/restructure_generator.rb +292 -0
- data/lib/generators/ruby_llm_agents/speaker_generator.rb +121 -0
- data/lib/generators/ruby_llm_agents/templates/add_execution_type_migration.rb.tt +8 -0
- data/lib/generators/ruby_llm_agents/templates/agent.rb.tt +99 -84
- data/lib/generators/ruby_llm_agents/templates/application_agent.rb.tt +42 -40
- data/lib/generators/ruby_llm_agents/templates/application_background_remover.rb.tt +26 -0
- data/lib/generators/ruby_llm_agents/templates/application_embedder.rb.tt +50 -0
- data/lib/generators/ruby_llm_agents/templates/application_image_analyzer.rb.tt +26 -0
- data/lib/generators/ruby_llm_agents/templates/application_image_editor.rb.tt +20 -0
- data/lib/generators/ruby_llm_agents/templates/application_image_generator.rb.tt +38 -0
- data/lib/generators/ruby_llm_agents/templates/application_image_pipeline.rb.tt +139 -0
- data/lib/generators/ruby_llm_agents/templates/application_image_transformer.rb.tt +21 -0
- data/lib/generators/ruby_llm_agents/templates/application_image_upscaler.rb.tt +20 -0
- data/lib/generators/ruby_llm_agents/templates/application_image_variator.rb.tt +20 -0
- data/lib/generators/ruby_llm_agents/templates/application_speaker.rb.tt +49 -0
- data/lib/generators/ruby_llm_agents/templates/application_transcriber.rb.tt +53 -0
- data/lib/generators/ruby_llm_agents/templates/background_remover.rb.tt +44 -0
- data/lib/generators/ruby_llm_agents/templates/create_api_configurations_migration.rb.tt +90 -0
- data/lib/generators/ruby_llm_agents/templates/embedder.rb.tt +41 -0
- data/lib/generators/ruby_llm_agents/templates/image_analyzer.rb.tt +45 -0
- data/lib/generators/ruby_llm_agents/templates/image_editor.rb.tt +35 -0
- data/lib/generators/ruby_llm_agents/templates/image_generator.rb.tt +47 -0
- data/lib/generators/ruby_llm_agents/templates/image_pipeline.rb.tt +50 -0
- data/lib/generators/ruby_llm_agents/templates/image_transformer.rb.tt +44 -0
- data/lib/generators/ruby_llm_agents/templates/image_upscaler.rb.tt +38 -0
- data/lib/generators/ruby_llm_agents/templates/image_variator.rb.tt +33 -0
- data/lib/generators/ruby_llm_agents/templates/skills/AGENTS.md.tt +228 -0
- data/lib/generators/ruby_llm_agents/templates/skills/BACKGROUND_REMOVERS.md.tt +131 -0
- data/lib/generators/ruby_llm_agents/templates/skills/EMBEDDERS.md.tt +255 -0
- data/lib/generators/ruby_llm_agents/templates/skills/IMAGE_ANALYZERS.md.tt +120 -0
- data/lib/generators/ruby_llm_agents/templates/skills/IMAGE_EDITORS.md.tt +102 -0
- data/lib/generators/ruby_llm_agents/templates/skills/IMAGE_GENERATORS.md.tt +282 -0
- data/lib/generators/ruby_llm_agents/templates/skills/IMAGE_PIPELINES.md.tt +228 -0
- data/lib/generators/ruby_llm_agents/templates/skills/IMAGE_TRANSFORMERS.md.tt +120 -0
- data/lib/generators/ruby_llm_agents/templates/skills/IMAGE_UPSCALERS.md.tt +110 -0
- data/lib/generators/ruby_llm_agents/templates/skills/IMAGE_VARIATORS.md.tt +120 -0
- data/lib/generators/ruby_llm_agents/templates/skills/SPEAKERS.md.tt +212 -0
- data/lib/generators/ruby_llm_agents/templates/skills/TOOLS.md.tt +227 -0
- data/lib/generators/ruby_llm_agents/templates/skills/TRANSCRIBERS.md.tt +251 -0
- data/lib/generators/ruby_llm_agents/templates/skills/WORKFLOWS.md.tt +300 -0
- data/lib/generators/ruby_llm_agents/templates/speaker.rb.tt +56 -0
- data/lib/generators/ruby_llm_agents/templates/transcriber.rb.tt +51 -0
- data/lib/generators/ruby_llm_agents/transcriber_generator.rb +107 -0
- data/lib/generators/ruby_llm_agents/upgrade_generator.rb +152 -1
- data/lib/ruby_llm/agents/audio/speaker.rb +553 -0
- data/lib/ruby_llm/agents/audio/transcriber.rb +669 -0
- data/lib/ruby_llm/agents/base_agent.rb +675 -0
- data/lib/ruby_llm/agents/core/base/moderation_dsl.rb +181 -0
- data/lib/ruby_llm/agents/core/base/moderation_execution.rb +274 -0
- data/lib/ruby_llm/agents/core/base.rb +135 -0
- data/lib/ruby_llm/agents/core/configuration.rb +981 -0
- data/lib/ruby_llm/agents/core/errors.rb +150 -0
- data/lib/ruby_llm/agents/{instrumentation.rb → core/instrumentation.rb} +93 -4
- data/lib/ruby_llm/agents/core/llm_tenant.rb +358 -0
- data/lib/ruby_llm/agents/core/resolved_config.rb +348 -0
- data/lib/ruby_llm/agents/{version.rb → core/version.rb} +1 -1
- data/lib/ruby_llm/agents/dsl/base.rb +110 -0
- data/lib/ruby_llm/agents/dsl/caching.rb +142 -0
- data/lib/ruby_llm/agents/dsl/reliability.rb +307 -0
- data/lib/ruby_llm/agents/dsl.rb +41 -0
- data/lib/ruby_llm/agents/image/analyzer/dsl.rb +130 -0
- data/lib/ruby_llm/agents/image/analyzer/execution.rb +402 -0
- data/lib/ruby_llm/agents/image/analyzer.rb +90 -0
- data/lib/ruby_llm/agents/image/background_remover/dsl.rb +154 -0
- data/lib/ruby_llm/agents/image/background_remover/execution.rb +240 -0
- data/lib/ruby_llm/agents/image/background_remover.rb +89 -0
- data/lib/ruby_llm/agents/image/concerns/image_operation_dsl.rb +91 -0
- data/lib/ruby_llm/agents/image/concerns/image_operation_execution.rb +165 -0
- data/lib/ruby_llm/agents/image/editor/dsl.rb +56 -0
- data/lib/ruby_llm/agents/image/editor/execution.rb +207 -0
- data/lib/ruby_llm/agents/image/editor.rb +92 -0
- data/lib/ruby_llm/agents/image/generator/active_storage_support.rb +127 -0
- data/lib/ruby_llm/agents/image/generator/content_policy.rb +95 -0
- data/lib/ruby_llm/agents/image/generator/pricing.rb +353 -0
- data/lib/ruby_llm/agents/image/generator/templates.rb +124 -0
- data/lib/ruby_llm/agents/image/generator.rb +455 -0
- data/lib/ruby_llm/agents/image/pipeline/dsl.rb +213 -0
- data/lib/ruby_llm/agents/image/pipeline/execution.rb +382 -0
- data/lib/ruby_llm/agents/image/pipeline.rb +97 -0
- data/lib/ruby_llm/agents/image/transformer/dsl.rb +148 -0
- data/lib/ruby_llm/agents/image/transformer/execution.rb +223 -0
- data/lib/ruby_llm/agents/image/transformer.rb +95 -0
- data/lib/ruby_llm/agents/image/upscaler/dsl.rb +83 -0
- data/lib/ruby_llm/agents/image/upscaler/execution.rb +219 -0
- data/lib/ruby_llm/agents/image/upscaler.rb +81 -0
- data/lib/ruby_llm/agents/image/variator/dsl.rb +62 -0
- data/lib/ruby_llm/agents/image/variator/execution.rb +189 -0
- data/lib/ruby_llm/agents/image/variator.rb +80 -0
- data/lib/ruby_llm/agents/{alert_manager.rb → infrastructure/alert_manager.rb} +17 -22
- data/lib/ruby_llm/agents/infrastructure/budget/budget_query.rb +145 -0
- data/lib/ruby_llm/agents/infrastructure/budget/config_resolver.rb +149 -0
- data/lib/ruby_llm/agents/infrastructure/budget/forecaster.rb +68 -0
- data/lib/ruby_llm/agents/infrastructure/budget/spend_recorder.rb +279 -0
- data/lib/ruby_llm/agents/infrastructure/budget_tracker.rb +275 -0
- data/lib/ruby_llm/agents/{execution_logger_job.rb → infrastructure/execution_logger_job.rb} +17 -1
- data/lib/ruby_llm/agents/{reliability → infrastructure/reliability}/executor.rb +2 -1
- data/lib/ruby_llm/agents/{reliability → infrastructure/reliability}/retry_strategy.rb +9 -3
- data/lib/ruby_llm/agents/{reliability.rb → infrastructure/reliability.rb} +11 -21
- data/lib/ruby_llm/agents/pipeline/builder.rb +215 -0
- data/lib/ruby_llm/agents/pipeline/context.rb +255 -0
- data/lib/ruby_llm/agents/pipeline/executor.rb +86 -0
- data/lib/ruby_llm/agents/pipeline/middleware/base.rb +124 -0
- data/lib/ruby_llm/agents/pipeline/middleware/budget.rb +95 -0
- data/lib/ruby_llm/agents/pipeline/middleware/cache.rb +171 -0
- data/lib/ruby_llm/agents/pipeline/middleware/instrumentation.rb +415 -0
- data/lib/ruby_llm/agents/pipeline/middleware/reliability.rb +276 -0
- data/lib/ruby_llm/agents/pipeline/middleware/tenant.rb +196 -0
- data/lib/ruby_llm/agents/pipeline.rb +68 -0
- data/lib/ruby_llm/agents/{engine.rb → rails/engine.rb} +79 -10
- data/lib/ruby_llm/agents/results/background_removal_result.rb +286 -0
- data/lib/ruby_llm/agents/{result.rb → results/base.rb} +73 -1
- data/lib/ruby_llm/agents/results/embedding_result.rb +243 -0
- data/lib/ruby_llm/agents/results/image_analysis_result.rb +314 -0
- data/lib/ruby_llm/agents/results/image_edit_result.rb +250 -0
- data/lib/ruby_llm/agents/results/image_generation_result.rb +346 -0
- data/lib/ruby_llm/agents/results/image_pipeline_result.rb +399 -0
- data/lib/ruby_llm/agents/results/image_transform_result.rb +251 -0
- data/lib/ruby_llm/agents/results/image_upscale_result.rb +255 -0
- data/lib/ruby_llm/agents/results/image_variation_result.rb +237 -0
- data/lib/ruby_llm/agents/results/moderation_result.rb +158 -0
- data/lib/ruby_llm/agents/results/speech_result.rb +338 -0
- data/lib/ruby_llm/agents/results/transcription_result.rb +408 -0
- data/lib/ruby_llm/agents/text/embedder.rb +444 -0
- data/lib/ruby_llm/agents/text/moderator.rb +237 -0
- data/lib/ruby_llm/agents/workflow/async.rb +220 -0
- data/lib/ruby_llm/agents/workflow/async_executor.rb +156 -0
- data/lib/ruby_llm/agents/{workflow.rb → workflow/orchestrator.rb} +6 -5
- data/lib/ruby_llm/agents/workflow/parallel.rb +34 -17
- data/lib/ruby_llm/agents/workflow/thread_pool.rb +185 -0
- data/lib/ruby_llm/agents.rb +86 -20
- metadata +189 -35
- data/lib/ruby_llm/agents/base/caching.rb +0 -40
- data/lib/ruby_llm/agents/base/cost_calculation.rb +0 -105
- data/lib/ruby_llm/agents/base/dsl.rb +0 -324
- data/lib/ruby_llm/agents/base/execution.rb +0 -283
- data/lib/ruby_llm/agents/base/reliability_dsl.rb +0 -82
- data/lib/ruby_llm/agents/base/reliability_execution.rb +0 -136
- data/lib/ruby_llm/agents/base/response_building.rb +0 -86
- data/lib/ruby_llm/agents/base/tool_tracking.rb +0 -57
- data/lib/ruby_llm/agents/base.rb +0 -209
- data/lib/ruby_llm/agents/budget_tracker.rb +0 -471
- data/lib/ruby_llm/agents/configuration.rb +0 -357
- /data/lib/ruby_llm/agents/{deprecations.rb → core/deprecations.rb} +0 -0
- /data/lib/ruby_llm/agents/{inflections.rb → core/inflections.rb} +0 -0
- /data/lib/ruby_llm/agents/{attempt_tracker.rb → infrastructure/attempt_tracker.rb} +0 -0
- /data/lib/ruby_llm/agents/{cache_helper.rb → infrastructure/cache_helper.rb} +0 -0
- /data/lib/ruby_llm/agents/{circuit_breaker.rb → infrastructure/circuit_breaker.rb} +0 -0
- /data/lib/ruby_llm/agents/{redactor.rb → infrastructure/redactor.rb} +0 -0
- /data/lib/ruby_llm/agents/{reliability → infrastructure/reliability}/breaker_manager.rb +0 -0
- /data/lib/ruby_llm/agents/{reliability → infrastructure/reliability}/execution_constraints.rb +0 -0
- /data/lib/ruby_llm/agents/{reliability → infrastructure/reliability}/fallback_routing.rb +0 -0
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# <%= @root_namespace %>::Image Background Removers
|
|
2
|
+
|
|
3
|
+
This directory contains background removal services. All removers inherit from `ApplicationBackgroundRemover`.
|
|
4
|
+
|
|
5
|
+
## Creating a New Remover
|
|
6
|
+
|
|
7
|
+
Use the generator:
|
|
8
|
+
```bash
|
|
9
|
+
rails generate ruby_llm_agents:background_remover RemoverName
|
|
10
|
+
rails generate ruby_llm_agents:background_remover Product --edge_refinement high
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Or create manually:
|
|
14
|
+
```ruby
|
|
15
|
+
module <%= @root_namespace %>
|
|
16
|
+
module Image
|
|
17
|
+
class ProductRemover < ApplicationBackgroundRemover
|
|
18
|
+
model "remove-bg"
|
|
19
|
+
edge_refinement :high
|
|
20
|
+
output_format :png
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## DSL Reference
|
|
27
|
+
|
|
28
|
+
| Method | Description | Example |
|
|
29
|
+
|--------|-------------|---------|
|
|
30
|
+
| `model` | Background removal model | `model "remove-bg"` |
|
|
31
|
+
| `edge_refinement` | Edge quality | `edge_refinement :high` |
|
|
32
|
+
| `output_format` | Output format | `output_format :png` |
|
|
33
|
+
| `background_color` | Replace with color | `background_color "#FFFFFF"` |
|
|
34
|
+
|
|
35
|
+
### Edge Refinement
|
|
36
|
+
- `:low` - Fastest, rough edges
|
|
37
|
+
- `:medium` - Balanced (default)
|
|
38
|
+
- `:high` - Slow, clean edges
|
|
39
|
+
|
|
40
|
+
### Output Formats
|
|
41
|
+
- `:png` - Transparent background (default)
|
|
42
|
+
- `:jpg` - With background color
|
|
43
|
+
- `:webp` - Modern format, smaller size
|
|
44
|
+
|
|
45
|
+
## Using Removers
|
|
46
|
+
|
|
47
|
+
```ruby
|
|
48
|
+
result = <%= @root_namespace %>::Image::ProductRemover.call(image: "product.jpg")
|
|
49
|
+
|
|
50
|
+
result.url # Image URL with transparent background
|
|
51
|
+
result.image_data # PNG binary data
|
|
52
|
+
result.has_alpha? # true (has transparency)
|
|
53
|
+
result.save("product_nobg.png")
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### With Background Color
|
|
57
|
+
|
|
58
|
+
```ruby
|
|
59
|
+
result = <%= @root_namespace %>::Image::ProductRemover.call(
|
|
60
|
+
image: "product.jpg",
|
|
61
|
+
background_color: "#FFFFFF" # White background
|
|
62
|
+
)
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### Override Settings
|
|
66
|
+
|
|
67
|
+
```ruby
|
|
68
|
+
result = <%= @root_namespace %>::Image::ProductRemover.call(
|
|
69
|
+
image: "complex_photo.jpg",
|
|
70
|
+
edge_refinement: :high,
|
|
71
|
+
output_format: :webp
|
|
72
|
+
)
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Use Cases
|
|
76
|
+
|
|
77
|
+
### E-commerce Product Photos
|
|
78
|
+
|
|
79
|
+
```ruby
|
|
80
|
+
module <%= @root_namespace %>
|
|
81
|
+
module Image
|
|
82
|
+
class ProductBackgroundRemover < ApplicationBackgroundRemover
|
|
83
|
+
edge_refinement :high
|
|
84
|
+
output_format :png
|
|
85
|
+
|
|
86
|
+
cache_for 30.days # Product images don't change often
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### Profile Photo Processing
|
|
93
|
+
|
|
94
|
+
```ruby
|
|
95
|
+
module <%= @root_namespace %>
|
|
96
|
+
module Image
|
|
97
|
+
class AvatarBackgroundRemover < ApplicationBackgroundRemover
|
|
98
|
+
edge_refinement :high
|
|
99
|
+
output_format :png
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
# Remove background and resize
|
|
105
|
+
result = <%= @root_namespace %>::Image::AvatarBackgroundRemover.call(image: uploaded_photo)
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### Batch Processing
|
|
109
|
+
|
|
110
|
+
```ruby
|
|
111
|
+
Product.where(background_removed: false).find_each do |product|
|
|
112
|
+
result = <%= @root_namespace %>::Image::ProductBackgroundRemover.call(
|
|
113
|
+
image: product.original_image.download
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
product.processed_image.attach(
|
|
117
|
+
io: StringIO.new(result.image_data),
|
|
118
|
+
filename: "#{product.id}_nobg.png",
|
|
119
|
+
content_type: "image/png"
|
|
120
|
+
)
|
|
121
|
+
product.update!(background_removed: true)
|
|
122
|
+
end
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
## Best Practices
|
|
126
|
+
|
|
127
|
+
1. **Use high edge refinement for products** - Clean edges look professional
|
|
128
|
+
2. **PNG for transparency** - JPG doesn't support alpha
|
|
129
|
+
3. **Cache aggressively** - Same image = same result
|
|
130
|
+
4. **Consider file size** - PNG is larger than JPG
|
|
131
|
+
5. **Test edge cases** - Complex backgrounds, similar colors
|
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
# <%= @root_namespace %>::Text Embedders
|
|
2
|
+
|
|
3
|
+
This directory contains text embedding services for vector search and semantic similarity. All embedders inherit from `ApplicationEmbedder`.
|
|
4
|
+
|
|
5
|
+
## Creating a New Embedder
|
|
6
|
+
|
|
7
|
+
Use the generator:
|
|
8
|
+
```bash
|
|
9
|
+
rails generate ruby_llm_agents:embedder EmbedderName
|
|
10
|
+
rails generate ruby_llm_agents:embedder Document --model text-embedding-3-large
|
|
11
|
+
rails generate ruby_llm_agents:embedder Search --dimensions 512 --batch_size 50
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Or create manually:
|
|
15
|
+
```ruby
|
|
16
|
+
module <%= @root_namespace %>
|
|
17
|
+
module Text
|
|
18
|
+
class DocumentEmbedder < ApplicationEmbedder
|
|
19
|
+
model "text-embedding-3-small"
|
|
20
|
+
dimensions 1536
|
|
21
|
+
batch_size 100
|
|
22
|
+
cache_for 1.week
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## DSL Reference
|
|
29
|
+
|
|
30
|
+
### Model Configuration
|
|
31
|
+
|
|
32
|
+
| Method | Description | Example |
|
|
33
|
+
|--------|-------------|---------|
|
|
34
|
+
| `model` | Embedding model | `model "text-embedding-3-large"` |
|
|
35
|
+
| `dimensions` | Vector dimensions | `dimensions 512` |
|
|
36
|
+
| `batch_size` | Texts per API call | `batch_size 100` |
|
|
37
|
+
|
|
38
|
+
### Available Models
|
|
39
|
+
|
|
40
|
+
**OpenAI:**
|
|
41
|
+
- `text-embedding-3-small` - 1536 dimensions, fastest, cheapest
|
|
42
|
+
- `text-embedding-3-large` - 3072 dimensions, best quality
|
|
43
|
+
- `text-embedding-ada-002` - 1536 dimensions, legacy
|
|
44
|
+
|
|
45
|
+
**Dimension reduction:** You can reduce dimensions for storage efficiency:
|
|
46
|
+
```ruby
|
|
47
|
+
dimensions 256 # Reduce from default
|
|
48
|
+
dimensions 512 # Good balance of quality/size
|
|
49
|
+
dimensions 1024 # Higher quality
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Caching
|
|
53
|
+
|
|
54
|
+
```ruby
|
|
55
|
+
cache_for 1.week # Cache embeddings
|
|
56
|
+
cache_for 30.days # Long-term caching
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Optional Methods
|
|
60
|
+
|
|
61
|
+
### `preprocess(text)`
|
|
62
|
+
Normalize text before embedding:
|
|
63
|
+
|
|
64
|
+
```ruby
|
|
65
|
+
def preprocess(text)
|
|
66
|
+
text
|
|
67
|
+
.strip
|
|
68
|
+
.downcase
|
|
69
|
+
.gsub(/\s+/, ' ')
|
|
70
|
+
.truncate(8000) # Model token limit
|
|
71
|
+
end
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Using Embedders
|
|
75
|
+
|
|
76
|
+
### Single Text Embedding
|
|
77
|
+
|
|
78
|
+
```ruby
|
|
79
|
+
result = <%= @root_namespace %>::Text::DocumentEmbedder.call(text: "Hello world")
|
|
80
|
+
|
|
81
|
+
result.embedding # [0.123, -0.456, ...] vector array
|
|
82
|
+
result.dimensions # 1536
|
|
83
|
+
result.model_id # "text-embedding-3-small"
|
|
84
|
+
result.total_cost # Cost in USD
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Batch Embedding
|
|
88
|
+
|
|
89
|
+
Process multiple texts efficiently:
|
|
90
|
+
|
|
91
|
+
```ruby
|
|
92
|
+
texts = ["Hello world", "Goodbye world", "Ruby programming"]
|
|
93
|
+
result = <%= @root_namespace %>::Text::DocumentEmbedder.call(texts: texts)
|
|
94
|
+
|
|
95
|
+
result.embeddings # Array of embedding vectors
|
|
96
|
+
result.count # 3
|
|
97
|
+
result.total_cost # Combined cost
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### Vector Storage
|
|
101
|
+
|
|
102
|
+
Store embeddings in PostgreSQL with pgvector:
|
|
103
|
+
|
|
104
|
+
```ruby
|
|
105
|
+
# Migration
|
|
106
|
+
add_column :documents, :embedding, :vector, limit: 1536
|
|
107
|
+
|
|
108
|
+
# Model
|
|
109
|
+
class Document < ApplicationRecord
|
|
110
|
+
has_neighbors :embedding
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
# Generate and store embedding
|
|
114
|
+
document = Document.find(1)
|
|
115
|
+
result = <%= @root_namespace %>::Text::DocumentEmbedder.call(text: document.content)
|
|
116
|
+
document.update!(embedding: result.embedding)
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### Semantic Search
|
|
120
|
+
|
|
121
|
+
```ruby
|
|
122
|
+
# Embed the query
|
|
123
|
+
query_result = <%= @root_namespace %>::Text::SearchEmbedder.call(text: "ruby web framework")
|
|
124
|
+
|
|
125
|
+
# Find similar documents
|
|
126
|
+
similar = Document.nearest_neighbors(:embedding, query_result.embedding, distance: "cosine")
|
|
127
|
+
.limit(10)
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## Use Cases
|
|
131
|
+
|
|
132
|
+
### Document Embedding
|
|
133
|
+
|
|
134
|
+
```ruby
|
|
135
|
+
module <%= @root_namespace %>
|
|
136
|
+
module Text
|
|
137
|
+
class DocumentEmbedder < ApplicationEmbedder
|
|
138
|
+
model "text-embedding-3-large"
|
|
139
|
+
dimensions 1024
|
|
140
|
+
batch_size 50
|
|
141
|
+
cache_for 30.days
|
|
142
|
+
|
|
143
|
+
def preprocess(text)
|
|
144
|
+
text
|
|
145
|
+
.strip
|
|
146
|
+
.gsub(/\s+/, ' ')
|
|
147
|
+
.truncate(8000)
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### Search Query Embedding
|
|
155
|
+
|
|
156
|
+
```ruby
|
|
157
|
+
module <%= @root_namespace %>
|
|
158
|
+
module Text
|
|
159
|
+
class SearchEmbedder < ApplicationEmbedder
|
|
160
|
+
model "text-embedding-3-small"
|
|
161
|
+
dimensions 512
|
|
162
|
+
cache_for 1.hour # Queries may repeat
|
|
163
|
+
|
|
164
|
+
def preprocess(text)
|
|
165
|
+
text.strip.downcase
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### Code Embedding
|
|
173
|
+
|
|
174
|
+
```ruby
|
|
175
|
+
module <%= @root_namespace %>
|
|
176
|
+
module Text
|
|
177
|
+
class CodeEmbedder < ApplicationEmbedder
|
|
178
|
+
model "text-embedding-3-large"
|
|
179
|
+
cache_for 7.days
|
|
180
|
+
|
|
181
|
+
def preprocess(text)
|
|
182
|
+
# Remove comments, normalize whitespace
|
|
183
|
+
text
|
|
184
|
+
.gsub(/#.*$/, '')
|
|
185
|
+
.gsub(/\/\/.*$/, '')
|
|
186
|
+
.gsub(/\s+/, ' ')
|
|
187
|
+
.strip
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
end
|
|
191
|
+
end
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
### Batch Processing
|
|
195
|
+
|
|
196
|
+
```ruby
|
|
197
|
+
# Embed all documents in batches
|
|
198
|
+
Document.find_each(batch_size: 100) do |doc|
|
|
199
|
+
next if doc.embedding.present?
|
|
200
|
+
|
|
201
|
+
result = <%= @root_namespace %>::Text::DocumentEmbedder.call(text: doc.content)
|
|
202
|
+
doc.update!(embedding: result.embedding)
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
# Or batch multiple at once
|
|
206
|
+
texts = Document.where(embedding: nil).limit(100).pluck(:id, :content)
|
|
207
|
+
results = <%= @root_namespace %>::Text::DocumentEmbedder.call(texts: texts.map(&:last))
|
|
208
|
+
|
|
209
|
+
texts.each_with_index do |(id, _), index|
|
|
210
|
+
Document.find(id).update!(embedding: results.embeddings[index])
|
|
211
|
+
end
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
## Testing Embedders
|
|
215
|
+
|
|
216
|
+
```ruby
|
|
217
|
+
RSpec.describe <%= @root_namespace %>::Text::DocumentEmbedder do
|
|
218
|
+
describe ".call" do
|
|
219
|
+
it "returns embedding vector" do
|
|
220
|
+
result = described_class.call(text: "Hello world")
|
|
221
|
+
|
|
222
|
+
expect(result.embedding).to be_an(Array)
|
|
223
|
+
expect(result.dimensions).to eq(1536)
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
it "handles batch embedding" do
|
|
227
|
+
texts = ["Hello", "World"]
|
|
228
|
+
result = described_class.call(texts: texts)
|
|
229
|
+
|
|
230
|
+
expect(result.embeddings.length).to eq(2)
|
|
231
|
+
end
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
describe "#preprocess" do
|
|
235
|
+
it "normalizes text" do
|
|
236
|
+
embedder = described_class.new(text: "test")
|
|
237
|
+
text = " Multiple Spaces "
|
|
238
|
+
|
|
239
|
+
result = embedder.preprocess(text)
|
|
240
|
+
|
|
241
|
+
expect(result).to eq("multiple spaces")
|
|
242
|
+
end
|
|
243
|
+
end
|
|
244
|
+
end
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
## Best Practices
|
|
248
|
+
|
|
249
|
+
1. **Use caching** - Same text always produces same embedding
|
|
250
|
+
2. **Choose appropriate dimensions** - Lower for storage, higher for accuracy
|
|
251
|
+
3. **Batch when possible** - More efficient than single calls
|
|
252
|
+
4. **Preprocess consistently** - Same preprocessing for indexing and search
|
|
253
|
+
5. **Match models** - Use same model for indexing and querying
|
|
254
|
+
6. **Consider truncation** - Handle texts longer than model limits
|
|
255
|
+
7. **Use smaller models for search** - Faster query embedding
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# <%= @root_namespace %>::Image Analyzers
|
|
2
|
+
|
|
3
|
+
This directory contains image analysis services. All analyzers inherit from `ApplicationImageAnalyzer`.
|
|
4
|
+
|
|
5
|
+
## Creating a New Analyzer
|
|
6
|
+
|
|
7
|
+
Use the generator:
|
|
8
|
+
```bash
|
|
9
|
+
rails generate ruby_llm_agents:image_analyzer AnalyzerName
|
|
10
|
+
rails generate ruby_llm_agents:image_analyzer Product --model gpt-4o
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Or create manually:
|
|
14
|
+
```ruby
|
|
15
|
+
module <%= @root_namespace %>
|
|
16
|
+
module Image
|
|
17
|
+
class ProductAnalyzer < ApplicationImageAnalyzer
|
|
18
|
+
model "gpt-4o"
|
|
19
|
+
analysis_type :detailed
|
|
20
|
+
extract_colors true
|
|
21
|
+
detect_objects true
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## DSL Reference
|
|
28
|
+
|
|
29
|
+
| Method | Description | Example |
|
|
30
|
+
|--------|-------------|---------|
|
|
31
|
+
| `model` | Vision model | `model "gpt-4o"` |
|
|
32
|
+
| `analysis_type` | Detail level | `analysis_type :detailed` |
|
|
33
|
+
| `extract_colors` | Extract color palette | `extract_colors true` |
|
|
34
|
+
| `detect_objects` | Detect objects in image | `detect_objects true` |
|
|
35
|
+
|
|
36
|
+
### Analysis Types
|
|
37
|
+
- `:basic` - Quick overview
|
|
38
|
+
- `:detailed` - Comprehensive analysis
|
|
39
|
+
- `:custom` - With custom prompt
|
|
40
|
+
|
|
41
|
+
## Using Analyzers
|
|
42
|
+
|
|
43
|
+
```ruby
|
|
44
|
+
result = <%= @root_namespace %>::Image::ProductAnalyzer.call(image: "product.jpg")
|
|
45
|
+
|
|
46
|
+
result.description # Text description
|
|
47
|
+
result.objects # Detected objects
|
|
48
|
+
result.colors # Color palette
|
|
49
|
+
result.tags # Suggested tags
|
|
50
|
+
result.total_cost # Cost in USD
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### Analyze URL
|
|
54
|
+
|
|
55
|
+
```ruby
|
|
56
|
+
result = <%= @root_namespace %>::Image::ProductAnalyzer.call(
|
|
57
|
+
image: "https://example.com/photo.jpg"
|
|
58
|
+
)
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### Custom Analysis Prompt
|
|
62
|
+
|
|
63
|
+
```ruby
|
|
64
|
+
module <%= @root_namespace %>
|
|
65
|
+
module Image
|
|
66
|
+
class CustomAnalyzer < ApplicationImageAnalyzer
|
|
67
|
+
model "gpt-4o"
|
|
68
|
+
analysis_type :custom
|
|
69
|
+
|
|
70
|
+
def analysis_prompt
|
|
71
|
+
"Analyze this image for: composition, lighting, color harmony. " \
|
|
72
|
+
"Return JSON with scores from 1-10 for each aspect."
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Use Cases
|
|
80
|
+
|
|
81
|
+
### Content Moderation
|
|
82
|
+
|
|
83
|
+
```ruby
|
|
84
|
+
module <%= @root_namespace %>
|
|
85
|
+
module Image
|
|
86
|
+
class ModerationAnalyzer < ApplicationImageAnalyzer
|
|
87
|
+
model "gpt-4o"
|
|
88
|
+
|
|
89
|
+
def analysis_prompt
|
|
90
|
+
"Analyze this image for inappropriate content. " \
|
|
91
|
+
"Return JSON with: safe (boolean), reason (string if unsafe)"
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### Product Categorization
|
|
99
|
+
|
|
100
|
+
```ruby
|
|
101
|
+
module <%= @root_namespace %>
|
|
102
|
+
module Image
|
|
103
|
+
class CategoryAnalyzer < ApplicationImageAnalyzer
|
|
104
|
+
model "gpt-4o"
|
|
105
|
+
detect_objects true
|
|
106
|
+
|
|
107
|
+
def analysis_prompt
|
|
108
|
+
"Identify the product category, brand if visible, and condition."
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## Best Practices
|
|
116
|
+
|
|
117
|
+
1. **Choose appropriate model** - GPT-4o for detailed analysis
|
|
118
|
+
2. **Use structured prompts** - Request JSON for parsing
|
|
119
|
+
3. **Enable object detection** - When identifying items
|
|
120
|
+
4. **Extract colors** - For visual matching/search
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# <%= @root_namespace %>::Image Editors
|
|
2
|
+
|
|
3
|
+
This directory contains image editing services (inpainting, masked edits). All editors inherit from `ApplicationImageEditor`.
|
|
4
|
+
|
|
5
|
+
## Creating a New Editor
|
|
6
|
+
|
|
7
|
+
Use the generator:
|
|
8
|
+
```bash
|
|
9
|
+
rails generate ruby_llm_agents:image_editor EditorName
|
|
10
|
+
rails generate ruby_llm_agents:image_editor Background --model gpt-image-1
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Or create manually:
|
|
14
|
+
```ruby
|
|
15
|
+
module <%= @root_namespace %>
|
|
16
|
+
module Image
|
|
17
|
+
class BackgroundEditor < ApplicationImageEditor
|
|
18
|
+
model "gpt-image-1"
|
|
19
|
+
size "1024x1024"
|
|
20
|
+
content_policy :standard
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## DSL Reference
|
|
27
|
+
|
|
28
|
+
| Method | Description | Example |
|
|
29
|
+
|--------|-------------|---------|
|
|
30
|
+
| `model` | Image editing model | `model "gpt-image-1"` |
|
|
31
|
+
| `size` | Output size | `size "1024x1024"` |
|
|
32
|
+
| `content_policy` | Content filtering | `content_policy :strict` |
|
|
33
|
+
|
|
34
|
+
## Using Editors
|
|
35
|
+
|
|
36
|
+
### Basic Edit with Mask
|
|
37
|
+
|
|
38
|
+
```ruby
|
|
39
|
+
result = <%= @root_namespace %>::Image::BackgroundEditor.call(
|
|
40
|
+
image: "photo.png",
|
|
41
|
+
mask: "mask.png",
|
|
42
|
+
prompt: "Beautiful sunset sky background"
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
result.url # Edited image URL
|
|
46
|
+
result.image_data # Binary data
|
|
47
|
+
result.save("edited.png")
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### Edit Specific Area
|
|
51
|
+
|
|
52
|
+
```ruby
|
|
53
|
+
# Mask should be PNG with transparent areas indicating regions to edit
|
|
54
|
+
result = <%= @root_namespace %>::Image::BackgroundEditor.call(
|
|
55
|
+
image: original_image,
|
|
56
|
+
mask: mask_with_transparent_areas,
|
|
57
|
+
prompt: "Modern city skyline"
|
|
58
|
+
)
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Use Cases
|
|
62
|
+
|
|
63
|
+
### Background Replacement
|
|
64
|
+
|
|
65
|
+
```ruby
|
|
66
|
+
module <%= @root_namespace %>
|
|
67
|
+
module Image
|
|
68
|
+
class BackgroundReplacer < ApplicationImageEditor
|
|
69
|
+
model "gpt-image-1"
|
|
70
|
+
size "1024x1024"
|
|
71
|
+
|
|
72
|
+
def default_prompt
|
|
73
|
+
"Professional studio background, soft lighting"
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### Object Removal
|
|
81
|
+
|
|
82
|
+
```ruby
|
|
83
|
+
module <%= @root_namespace %>
|
|
84
|
+
module Image
|
|
85
|
+
class ObjectRemover < ApplicationImageEditor
|
|
86
|
+
model "gpt-image-1"
|
|
87
|
+
|
|
88
|
+
# Mask covers the object to remove
|
|
89
|
+
def default_prompt
|
|
90
|
+
"Seamless continuation of the surrounding area"
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## Best Practices
|
|
98
|
+
|
|
99
|
+
1. **Create accurate masks** - Transparent areas indicate edit regions
|
|
100
|
+
2. **Match image sizes** - Mask and image should be same dimensions
|
|
101
|
+
3. **Use descriptive prompts** - Be specific about desired result
|
|
102
|
+
4. **PNG format** - Use PNG for mask transparency support
|