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,110 @@
|
|
|
1
|
+
# <%= @root_namespace %>::Image Upscalers
|
|
2
|
+
|
|
3
|
+
This directory contains image upscaling services. All upscalers inherit from `ApplicationImageUpscaler`.
|
|
4
|
+
|
|
5
|
+
## Creating a New Upscaler
|
|
6
|
+
|
|
7
|
+
Use the generator:
|
|
8
|
+
```bash
|
|
9
|
+
rails generate ruby_llm_agents:image_upscaler UpscalerName
|
|
10
|
+
rails generate ruby_llm_agents:image_upscaler Photo --scale 4
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Or create manually:
|
|
14
|
+
```ruby
|
|
15
|
+
module <%= @root_namespace %>
|
|
16
|
+
module Image
|
|
17
|
+
class PhotoUpscaler < ApplicationImageUpscaler
|
|
18
|
+
model "esrgan"
|
|
19
|
+
scale 4
|
|
20
|
+
denoise true
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## DSL Reference
|
|
27
|
+
|
|
28
|
+
| Method | Description | Example |
|
|
29
|
+
|--------|-------------|---------|
|
|
30
|
+
| `model` | Upscaling model | `model "esrgan"` |
|
|
31
|
+
| `scale` | Scale factor (2, 4, 8) | `scale 4` |
|
|
32
|
+
| `denoise` | Apply noise reduction | `denoise true` |
|
|
33
|
+
| `sharpen` | Apply sharpening | `sharpen true` |
|
|
34
|
+
|
|
35
|
+
### Scale Factors
|
|
36
|
+
- `2` - Double resolution (512x512 -> 1024x1024)
|
|
37
|
+
- `4` - Quadruple resolution (512x512 -> 2048x2048)
|
|
38
|
+
- `8` - 8x resolution (may be slow)
|
|
39
|
+
|
|
40
|
+
## Using Upscalers
|
|
41
|
+
|
|
42
|
+
```ruby
|
|
43
|
+
result = <%= @root_namespace %>::Image::PhotoUpscaler.call(image: "small.jpg")
|
|
44
|
+
|
|
45
|
+
result.url # Upscaled image URL
|
|
46
|
+
result.image_data # Binary data
|
|
47
|
+
result.original_size # "512x512"
|
|
48
|
+
result.upscaled_size # "2048x2048"
|
|
49
|
+
result.save("large.png")
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Override Scale
|
|
53
|
+
|
|
54
|
+
```ruby
|
|
55
|
+
result = <%= @root_namespace %>::Image::PhotoUpscaler.call(
|
|
56
|
+
image: "thumbnail.jpg",
|
|
57
|
+
scale: 2 # Just double it
|
|
58
|
+
)
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Use Cases
|
|
62
|
+
|
|
63
|
+
### Thumbnail Enhancement
|
|
64
|
+
|
|
65
|
+
```ruby
|
|
66
|
+
module <%= @root_namespace %>
|
|
67
|
+
module Image
|
|
68
|
+
class ThumbnailUpscaler < ApplicationImageUpscaler
|
|
69
|
+
scale 4
|
|
70
|
+
denoise true
|
|
71
|
+
sharpen true
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### Print Preparation
|
|
78
|
+
|
|
79
|
+
```ruby
|
|
80
|
+
module <%= @root_namespace %>
|
|
81
|
+
module Image
|
|
82
|
+
class PrintUpscaler < ApplicationImageUpscaler
|
|
83
|
+
scale 4
|
|
84
|
+
denoise false # Preserve original detail
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### Avatar Enhancement
|
|
91
|
+
|
|
92
|
+
```ruby
|
|
93
|
+
module <%= @root_namespace %>
|
|
94
|
+
module Image
|
|
95
|
+
class AvatarUpscaler < ApplicationImageUpscaler
|
|
96
|
+
scale 2 # Modest upscale
|
|
97
|
+
denoise true
|
|
98
|
+
sharpen true
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## Best Practices
|
|
105
|
+
|
|
106
|
+
1. **Choose appropriate scale** - Don't over-upscale
|
|
107
|
+
2. **Enable denoise for low-quality sources** - Helps with compression artifacts
|
|
108
|
+
3. **Sharpen selectively** - Can introduce artifacts
|
|
109
|
+
4. **Consider file size** - Larger images = larger files
|
|
110
|
+
5. **Test with similar images** - Results vary by content type
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# <%= @root_namespace %>::Image Variators
|
|
2
|
+
|
|
3
|
+
This directory contains image variation services. All variators inherit from `ApplicationImageVariator`.
|
|
4
|
+
|
|
5
|
+
## Creating a New Variator
|
|
6
|
+
|
|
7
|
+
Use the generator:
|
|
8
|
+
```bash
|
|
9
|
+
rails generate ruby_llm_agents:image_variator VariatorName
|
|
10
|
+
rails generate ruby_llm_agents:image_variator Product --count 4
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Or create manually:
|
|
14
|
+
```ruby
|
|
15
|
+
module <%= @root_namespace %>
|
|
16
|
+
module Image
|
|
17
|
+
class ProductVariator < ApplicationImageVariator
|
|
18
|
+
model "gpt-image-1"
|
|
19
|
+
count 4
|
|
20
|
+
size "1024x1024"
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## DSL Reference
|
|
27
|
+
|
|
28
|
+
| Method | Description | Example |
|
|
29
|
+
|--------|-------------|---------|
|
|
30
|
+
| `model` | Variation model | `model "gpt-image-1"` |
|
|
31
|
+
| `count` | Number of variations | `count 4` |
|
|
32
|
+
| `size` | Output size | `size "1024x1024"` |
|
|
33
|
+
| `variation_strength` | How different from original | `variation_strength 0.5` |
|
|
34
|
+
|
|
35
|
+
### Variation Strength
|
|
36
|
+
- `0.1-0.3` - Very similar to original
|
|
37
|
+
- `0.4-0.6` - Moderate differences
|
|
38
|
+
- `0.7-1.0` - Significant variations
|
|
39
|
+
|
|
40
|
+
## Using Variators
|
|
41
|
+
|
|
42
|
+
```ruby
|
|
43
|
+
result = <%= @root_namespace %>::Image::ProductVariator.call(image: "product.png")
|
|
44
|
+
|
|
45
|
+
result.urls # Array of variation URLs
|
|
46
|
+
result.images # Array of image data
|
|
47
|
+
result.count # Number of variations
|
|
48
|
+
result.total_cost # Combined cost
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Override Count
|
|
52
|
+
|
|
53
|
+
```ruby
|
|
54
|
+
result = <%= @root_namespace %>::Image::ProductVariator.call(
|
|
55
|
+
image: "logo.png",
|
|
56
|
+
count: 8 # Generate 8 variations
|
|
57
|
+
)
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Save All Variations
|
|
61
|
+
|
|
62
|
+
```ruby
|
|
63
|
+
result = <%= @root_namespace %>::Image::ProductVariator.call(image: "design.png")
|
|
64
|
+
|
|
65
|
+
result.images.each_with_index do |image_data, i|
|
|
66
|
+
File.write("variation_#{i}.png", image_data)
|
|
67
|
+
end
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Use Cases
|
|
71
|
+
|
|
72
|
+
### Design Exploration
|
|
73
|
+
|
|
74
|
+
```ruby
|
|
75
|
+
module <%= @root_namespace %>
|
|
76
|
+
module Image
|
|
77
|
+
class DesignVariator < ApplicationImageVariator
|
|
78
|
+
count 6
|
|
79
|
+
variation_strength 0.5 # Moderate differences
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# Generate design alternatives
|
|
85
|
+
result = <%= @root_namespace %>::Image::DesignVariator.call(image: "concept.png")
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### A/B Testing Assets
|
|
89
|
+
|
|
90
|
+
```ruby
|
|
91
|
+
module <%= @root_namespace %>
|
|
92
|
+
module Image
|
|
93
|
+
class MarketingVariator < ApplicationImageVariator
|
|
94
|
+
count 4
|
|
95
|
+
variation_strength 0.3 # Similar but different
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### Avatar Options
|
|
102
|
+
|
|
103
|
+
```ruby
|
|
104
|
+
module <%= @root_namespace %>
|
|
105
|
+
module Image
|
|
106
|
+
class AvatarVariator < ApplicationImageVariator
|
|
107
|
+
count 8
|
|
108
|
+
size "512x512"
|
|
109
|
+
variation_strength 0.4
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## Best Practices
|
|
116
|
+
|
|
117
|
+
1. **Start with fewer variations** - Generate more if needed
|
|
118
|
+
2. **Adjust strength for use case** - Subtle for refinement, strong for exploration
|
|
119
|
+
3. **Use high-quality source** - Better input = better variations
|
|
120
|
+
4. **Consider cost** - Each variation costs separately
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
# <%= @root_namespace %>::Audio Speakers
|
|
2
|
+
|
|
3
|
+
This directory contains text-to-speech (TTS) speakers. All speakers inherit from `ApplicationSpeaker`.
|
|
4
|
+
|
|
5
|
+
## Creating a New Speaker
|
|
6
|
+
|
|
7
|
+
Use the generator:
|
|
8
|
+
```bash
|
|
9
|
+
rails generate ruby_llm_agents:speaker SpeakerName
|
|
10
|
+
rails generate ruby_llm_agents:speaker Narrator --provider openai --voice nova
|
|
11
|
+
rails generate ruby_llm_agents:speaker Podcast --provider elevenlabs --voice Rachel
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Or create manually:
|
|
15
|
+
```ruby
|
|
16
|
+
module <%= @root_namespace %>
|
|
17
|
+
module Audio
|
|
18
|
+
class NarratorSpeaker < ApplicationSpeaker
|
|
19
|
+
provider :openai
|
|
20
|
+
model "tts-1"
|
|
21
|
+
voice "nova"
|
|
22
|
+
speed 1.0
|
|
23
|
+
output_format :mp3
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## DSL Reference
|
|
30
|
+
|
|
31
|
+
### Provider Configuration
|
|
32
|
+
|
|
33
|
+
| Method | Description | Example |
|
|
34
|
+
|--------|-------------|---------|
|
|
35
|
+
| `provider` | TTS provider | `provider :openai` or `provider :elevenlabs` |
|
|
36
|
+
| `model` | TTS model | `model "tts-1"` or `model "tts-1-hd"` |
|
|
37
|
+
| `voice` | Voice to use | `voice "nova"` |
|
|
38
|
+
| `speed` | Speech speed (0.25-4.0) | `speed 1.25` |
|
|
39
|
+
| `output_format` | Audio format | `output_format :mp3` |
|
|
40
|
+
|
|
41
|
+
### OpenAI Voices
|
|
42
|
+
- `alloy` - Neutral, balanced
|
|
43
|
+
- `echo` - Male, warm
|
|
44
|
+
- `fable` - British, storytelling
|
|
45
|
+
- `onyx` - Male, deep
|
|
46
|
+
- `nova` - Female, friendly
|
|
47
|
+
- `shimmer` - Female, soft
|
|
48
|
+
|
|
49
|
+
### OpenAI Models
|
|
50
|
+
- `tts-1` - Standard quality, faster
|
|
51
|
+
- `tts-1-hd` - High definition, slower
|
|
52
|
+
|
|
53
|
+
### ElevenLabs Configuration
|
|
54
|
+
|
|
55
|
+
```ruby
|
|
56
|
+
class PodcastSpeaker < ApplicationSpeaker
|
|
57
|
+
provider :elevenlabs
|
|
58
|
+
model "eleven_multilingual_v2"
|
|
59
|
+
voice "Rachel"
|
|
60
|
+
|
|
61
|
+
voice_settings do
|
|
62
|
+
stability 0.5
|
|
63
|
+
similarity_boost 0.75
|
|
64
|
+
style 0.5
|
|
65
|
+
speaker_boost true
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### Caching
|
|
71
|
+
|
|
72
|
+
```ruby
|
|
73
|
+
cache_for 7.days # Cache audio output
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### Custom Pronunciation
|
|
77
|
+
|
|
78
|
+
```ruby
|
|
79
|
+
lexicon do
|
|
80
|
+
pronounce 'API', 'A P I'
|
|
81
|
+
pronounce 'SQL', 'sequel'
|
|
82
|
+
pronounce 'PostgreSQL', 'post-gres-Q-L'
|
|
83
|
+
pronounce 'RubyLLM', 'ruby L L M'
|
|
84
|
+
end
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## Using Speakers
|
|
88
|
+
|
|
89
|
+
### Generate Speech
|
|
90
|
+
|
|
91
|
+
```ruby
|
|
92
|
+
result = <%= @root_namespace %>::Audio::NarratorSpeaker.call(text: "Hello world")
|
|
93
|
+
|
|
94
|
+
result.audio # Binary audio data
|
|
95
|
+
result.format # :mp3
|
|
96
|
+
result.duration # Duration in seconds (if available)
|
|
97
|
+
result.total_cost # Cost in USD
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### Save to File
|
|
101
|
+
|
|
102
|
+
```ruby
|
|
103
|
+
result = <%= @root_namespace %>::Audio::NarratorSpeaker.call(text: "Hello world")
|
|
104
|
+
result.save_to("output.mp3")
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### Stream Audio
|
|
108
|
+
|
|
109
|
+
For long text, stream chunks as they're generated:
|
|
110
|
+
|
|
111
|
+
```ruby
|
|
112
|
+
<%= @root_namespace %>::Audio::NarratorSpeaker.stream(text: long_article) do |chunk|
|
|
113
|
+
audio_player.play(chunk.audio)
|
|
114
|
+
end
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### Override Settings at Runtime
|
|
118
|
+
|
|
119
|
+
```ruby
|
|
120
|
+
result = <%= @root_namespace %>::Audio::NarratorSpeaker.call(
|
|
121
|
+
text: "Speak slowly and clearly",
|
|
122
|
+
voice: "onyx",
|
|
123
|
+
speed: 0.8
|
|
124
|
+
)
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
## Use Cases
|
|
128
|
+
|
|
129
|
+
### Article Narration
|
|
130
|
+
|
|
131
|
+
```ruby
|
|
132
|
+
module <%= @root_namespace %>
|
|
133
|
+
module Audio
|
|
134
|
+
class ArticleNarratorSpeaker < ApplicationSpeaker
|
|
135
|
+
provider :openai
|
|
136
|
+
model "tts-1-hd"
|
|
137
|
+
voice "fable"
|
|
138
|
+
speed 0.9
|
|
139
|
+
|
|
140
|
+
cache_for 30.days
|
|
141
|
+
|
|
142
|
+
lexicon do
|
|
143
|
+
pronounce 'JavaScript', 'java-script'
|
|
144
|
+
pronounce 'TypeScript', 'type-script'
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
# Usage
|
|
151
|
+
article = Article.find(params[:id])
|
|
152
|
+
result = <%= @root_namespace %>::Audio::ArticleNarratorSpeaker.call(text: article.body)
|
|
153
|
+
result.save_to("public/audio/articles/#{article.id}.mp3")
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### Voice Announcements
|
|
157
|
+
|
|
158
|
+
```ruby
|
|
159
|
+
module <%= @root_namespace %>
|
|
160
|
+
module Audio
|
|
161
|
+
class AnnouncementSpeaker < ApplicationSpeaker
|
|
162
|
+
provider :openai
|
|
163
|
+
voice "nova"
|
|
164
|
+
speed 1.1
|
|
165
|
+
output_format :mp3
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
# Usage
|
|
171
|
+
<%= @root_namespace %>::Audio::AnnouncementSpeaker.call(
|
|
172
|
+
text: "Your order has been shipped!"
|
|
173
|
+
)
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
### Multilingual TTS
|
|
177
|
+
|
|
178
|
+
```ruby
|
|
179
|
+
module <%= @root_namespace %>
|
|
180
|
+
module Audio
|
|
181
|
+
class MultilingualSpeaker < ApplicationSpeaker
|
|
182
|
+
provider :elevenlabs
|
|
183
|
+
model "eleven_multilingual_v2"
|
|
184
|
+
voice "Rachel"
|
|
185
|
+
end
|
|
186
|
+
end
|
|
187
|
+
end
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
## Testing Speakers
|
|
191
|
+
|
|
192
|
+
```ruby
|
|
193
|
+
RSpec.describe <%= @root_namespace %>::Audio::NarratorSpeaker do
|
|
194
|
+
describe ".call" do
|
|
195
|
+
it "generates audio from text" do
|
|
196
|
+
result = described_class.call(text: "Hello world")
|
|
197
|
+
|
|
198
|
+
expect(result.audio).to be_present
|
|
199
|
+
expect(result.format).to eq(:mp3)
|
|
200
|
+
end
|
|
201
|
+
end
|
|
202
|
+
end
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
## Best Practices
|
|
206
|
+
|
|
207
|
+
1. **Use caching** - Same text produces same audio
|
|
208
|
+
2. **Choose appropriate voices** - Match voice to content type
|
|
209
|
+
3. **Add pronunciation lexicon** - For technical terms and acronyms
|
|
210
|
+
4. **Use HD models for quality** - When audio quality matters
|
|
211
|
+
5. **Stream long content** - Don't wait for entire audio to generate
|
|
212
|
+
6. **Consider file sizes** - MP3 is smaller, WAV is lossless
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
# <%= @root_namespace %> Tools
|
|
2
|
+
|
|
3
|
+
This directory contains tools that agents can use to perform actions. Tools allow LLM agents to interact with external systems, APIs, databases, and more.
|
|
4
|
+
|
|
5
|
+
## Creating a Tool
|
|
6
|
+
|
|
7
|
+
Tools use the RubyLLM tool interface. Create a class that includes `RubyLLM::Tool`:
|
|
8
|
+
|
|
9
|
+
```ruby
|
|
10
|
+
module <%= @root_namespace %>
|
|
11
|
+
class SearchTool
|
|
12
|
+
include RubyLLM::Tool
|
|
13
|
+
|
|
14
|
+
description "Searches the knowledge base for relevant documents"
|
|
15
|
+
|
|
16
|
+
param :query, type: :string, description: "The search query", required: true
|
|
17
|
+
param :limit, type: :integer, description: "Maximum results to return", default: 10
|
|
18
|
+
|
|
19
|
+
def execute(query:, limit: 10)
|
|
20
|
+
# Implement your tool logic here
|
|
21
|
+
results = Document.search(query).limit(limit)
|
|
22
|
+
|
|
23
|
+
results.map do |doc|
|
|
24
|
+
{ title: doc.title, content: doc.content, score: doc.score }
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Tool DSL Reference
|
|
32
|
+
|
|
33
|
+
### `description`
|
|
34
|
+
Human-readable description of what the tool does. The LLM uses this to decide when to call the tool.
|
|
35
|
+
|
|
36
|
+
```ruby
|
|
37
|
+
description "Fetches current weather data for a given location"
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### `param`
|
|
41
|
+
Define parameters the tool accepts:
|
|
42
|
+
|
|
43
|
+
```ruby
|
|
44
|
+
param :name, type: :string, description: "Parameter description", required: true
|
|
45
|
+
param :count, type: :integer, description: "Optional count", default: 5
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
**Supported types:**
|
|
49
|
+
- `:string` - Text values
|
|
50
|
+
- `:integer` - Whole numbers
|
|
51
|
+
- `:number` - Decimal numbers
|
|
52
|
+
- `:boolean` - true/false
|
|
53
|
+
- `:array` - Lists of values
|
|
54
|
+
- `:object` - Nested objects
|
|
55
|
+
|
|
56
|
+
### `execute`
|
|
57
|
+
The method that runs when the tool is called. Receives keyword arguments matching the defined params.
|
|
58
|
+
|
|
59
|
+
```ruby
|
|
60
|
+
def execute(query:, limit: 10)
|
|
61
|
+
# Tool implementation
|
|
62
|
+
# Return value is passed back to the LLM
|
|
63
|
+
end
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Using Tools with Agents
|
|
67
|
+
|
|
68
|
+
Register tools in your agent:
|
|
69
|
+
|
|
70
|
+
```ruby
|
|
71
|
+
module <%= @root_namespace %>
|
|
72
|
+
class ResearchAgent < ApplicationAgent
|
|
73
|
+
model "gpt-4o"
|
|
74
|
+
|
|
75
|
+
tools [SearchTool, CalculatorTool, WebFetchTool]
|
|
76
|
+
|
|
77
|
+
param :question, required: true
|
|
78
|
+
|
|
79
|
+
private
|
|
80
|
+
|
|
81
|
+
def system_prompt
|
|
82
|
+
<<~PROMPT
|
|
83
|
+
You are a research assistant. Use the available tools to answer questions.
|
|
84
|
+
Always cite your sources.
|
|
85
|
+
PROMPT
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def user_prompt
|
|
89
|
+
question
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## Tool Patterns
|
|
96
|
+
|
|
97
|
+
### Database Query Tool
|
|
98
|
+
|
|
99
|
+
```ruby
|
|
100
|
+
module <%= @root_namespace %>
|
|
101
|
+
class CustomerLookupTool
|
|
102
|
+
include RubyLLM::Tool
|
|
103
|
+
|
|
104
|
+
description "Looks up customer information by email or ID"
|
|
105
|
+
|
|
106
|
+
param :email, type: :string, description: "Customer email address"
|
|
107
|
+
param :id, type: :integer, description: "Customer ID"
|
|
108
|
+
|
|
109
|
+
def execute(email: nil, id: nil)
|
|
110
|
+
customer = if id
|
|
111
|
+
Customer.find_by(id: id)
|
|
112
|
+
elsif email
|
|
113
|
+
Customer.find_by(email: email)
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
return { error: "Customer not found" } unless customer
|
|
117
|
+
|
|
118
|
+
{
|
|
119
|
+
id: customer.id,
|
|
120
|
+
name: customer.name,
|
|
121
|
+
email: customer.email,
|
|
122
|
+
plan: customer.subscription_plan
|
|
123
|
+
}
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### API Integration Tool
|
|
130
|
+
|
|
131
|
+
```ruby
|
|
132
|
+
module <%= @root_namespace %>
|
|
133
|
+
class WeatherTool
|
|
134
|
+
include RubyLLM::Tool
|
|
135
|
+
|
|
136
|
+
description "Gets current weather for a location"
|
|
137
|
+
|
|
138
|
+
param :city, type: :string, description: "City name", required: true
|
|
139
|
+
param :units, type: :string, description: "Temperature units (celsius/fahrenheit)", default: "celsius"
|
|
140
|
+
|
|
141
|
+
def execute(city:, units: "celsius")
|
|
142
|
+
response = HTTP.get("https://api.weather.com/current", params: {
|
|
143
|
+
q: city,
|
|
144
|
+
units: units == "celsius" ? "metric" : "imperial"
|
|
145
|
+
})
|
|
146
|
+
|
|
147
|
+
data = JSON.parse(response.body)
|
|
148
|
+
|
|
149
|
+
{
|
|
150
|
+
temperature: data["temp"],
|
|
151
|
+
conditions: data["conditions"],
|
|
152
|
+
humidity: data["humidity"]
|
|
153
|
+
}
|
|
154
|
+
rescue HTTP::Error => e
|
|
155
|
+
{ error: "Failed to fetch weather: #{e.message}" }
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### Action Tool
|
|
162
|
+
|
|
163
|
+
```ruby
|
|
164
|
+
module <%= @root_namespace %>
|
|
165
|
+
class SendEmailTool
|
|
166
|
+
include RubyLLM::Tool
|
|
167
|
+
|
|
168
|
+
description "Sends an email to a recipient"
|
|
169
|
+
|
|
170
|
+
param :to, type: :string, description: "Recipient email", required: true
|
|
171
|
+
param :subject, type: :string, description: "Email subject", required: true
|
|
172
|
+
param :body, type: :string, description: "Email body content", required: true
|
|
173
|
+
|
|
174
|
+
def execute(to:, subject:, body:)
|
|
175
|
+
# Validate email format
|
|
176
|
+
unless to.match?(URI::MailTo::EMAIL_REGEXP)
|
|
177
|
+
return { error: "Invalid email address" }
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
UserMailer.custom_email(to: to, subject: subject, body: body).deliver_later
|
|
181
|
+
|
|
182
|
+
{ success: true, message: "Email queued for delivery to #{to}" }
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
end
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
## Best Practices
|
|
189
|
+
|
|
190
|
+
1. **Clear descriptions** - Write descriptions that help the LLM understand when to use the tool
|
|
191
|
+
2. **Validate inputs** - Check parameters before executing
|
|
192
|
+
3. **Handle errors gracefully** - Return error objects instead of raising exceptions
|
|
193
|
+
4. **Keep tools focused** - One tool, one purpose
|
|
194
|
+
5. **Return structured data** - Return hashes that the LLM can interpret
|
|
195
|
+
6. **Consider rate limits** - Add throttling for API-calling tools
|
|
196
|
+
7. **Log tool usage** - Track which tools are called and how often
|
|
197
|
+
|
|
198
|
+
## Testing Tools
|
|
199
|
+
|
|
200
|
+
```ruby
|
|
201
|
+
RSpec.describe <%= @root_namespace %>::SearchTool do
|
|
202
|
+
describe "#execute" do
|
|
203
|
+
it "returns search results" do
|
|
204
|
+
tool = described_class.new
|
|
205
|
+
results = tool.execute(query: "ruby programming", limit: 5)
|
|
206
|
+
|
|
207
|
+
expect(results).to be_an(Array)
|
|
208
|
+
expect(results.length).to be <= 5
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
it "handles empty results" do
|
|
212
|
+
tool = described_class.new
|
|
213
|
+
results = tool.execute(query: "xyznonexistent123", limit: 5)
|
|
214
|
+
|
|
215
|
+
expect(results).to eq([])
|
|
216
|
+
end
|
|
217
|
+
end
|
|
218
|
+
end
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
## Security Considerations
|
|
222
|
+
|
|
223
|
+
- **Sanitize inputs** - Never trust LLM-provided parameters directly
|
|
224
|
+
- **Limit scope** - Tools should only access what they need
|
|
225
|
+
- **Audit actions** - Log destructive operations
|
|
226
|
+
- **Rate limit** - Prevent abuse of expensive operations
|
|
227
|
+
- **Validate permissions** - Check user authorization before actions
|