ruby_llm-agents 0.5.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.
Files changed (190) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +189 -31
  3. data/app/controllers/ruby_llm/agents/agents_controller.rb +136 -16
  4. data/app/controllers/ruby_llm/agents/dashboard_controller.rb +29 -9
  5. data/app/controllers/ruby_llm/agents/workflows_controller.rb +355 -0
  6. data/app/helpers/ruby_llm/agents/application_helper.rb +25 -0
  7. data/app/models/ruby_llm/agents/execution.rb +3 -0
  8. data/app/models/ruby_llm/agents/tenant_budget.rb +58 -15
  9. data/app/services/ruby_llm/agents/agent_registry.rb +51 -12
  10. data/app/views/layouts/ruby_llm/agents/application.html.erb +2 -29
  11. data/app/views/ruby_llm/agents/agents/_agent.html.erb +13 -1
  12. data/app/views/ruby_llm/agents/agents/_config_agent.html.erb +235 -0
  13. data/app/views/ruby_llm/agents/agents/_config_embedder.html.erb +70 -0
  14. data/app/views/ruby_llm/agents/agents/_config_image_generator.html.erb +152 -0
  15. data/app/views/ruby_llm/agents/agents/_config_moderator.html.erb +63 -0
  16. data/app/views/ruby_llm/agents/agents/_config_speaker.html.erb +108 -0
  17. data/app/views/ruby_llm/agents/agents/_config_transcriber.html.erb +91 -0
  18. data/app/views/ruby_llm/agents/agents/_workflow.html.erb +1 -1
  19. data/app/views/ruby_llm/agents/agents/index.html.erb +74 -9
  20. data/app/views/ruby_llm/agents/agents/show.html.erb +18 -378
  21. data/app/views/ruby_llm/agents/dashboard/_agent_comparison.html.erb +269 -15
  22. data/app/views/ruby_llm/agents/executions/show.html.erb +16 -0
  23. data/app/views/ruby_llm/agents/shared/_agent_type_badge.html.erb +93 -0
  24. data/app/views/ruby_llm/agents/workflows/_step_performance.html.erb +236 -0
  25. data/app/views/ruby_llm/agents/workflows/_structure_parallel.html.erb +76 -0
  26. data/app/views/ruby_llm/agents/workflows/_structure_pipeline.html.erb +74 -0
  27. data/app/views/ruby_llm/agents/workflows/_structure_router.html.erb +108 -0
  28. data/app/views/ruby_llm/agents/workflows/show.html.erb +442 -0
  29. data/config/routes.rb +1 -0
  30. data/lib/generators/ruby_llm_agents/agent_generator.rb +56 -7
  31. data/lib/generators/ruby_llm_agents/background_remover_generator.rb +110 -0
  32. data/lib/generators/ruby_llm_agents/embedder_generator.rb +107 -0
  33. data/lib/generators/ruby_llm_agents/image_analyzer_generator.rb +115 -0
  34. data/lib/generators/ruby_llm_agents/image_editor_generator.rb +108 -0
  35. data/lib/generators/ruby_llm_agents/image_generator_generator.rb +116 -0
  36. data/lib/generators/ruby_llm_agents/image_pipeline_generator.rb +178 -0
  37. data/lib/generators/ruby_llm_agents/image_transformer_generator.rb +109 -0
  38. data/lib/generators/ruby_llm_agents/image_upscaler_generator.rb +103 -0
  39. data/lib/generators/ruby_llm_agents/image_variator_generator.rb +102 -0
  40. data/lib/generators/ruby_llm_agents/install_generator.rb +76 -4
  41. data/lib/generators/ruby_llm_agents/restructure_generator.rb +292 -0
  42. data/lib/generators/ruby_llm_agents/speaker_generator.rb +121 -0
  43. data/lib/generators/ruby_llm_agents/templates/add_execution_type_migration.rb.tt +8 -0
  44. data/lib/generators/ruby_llm_agents/templates/agent.rb.tt +99 -84
  45. data/lib/generators/ruby_llm_agents/templates/application_agent.rb.tt +42 -40
  46. data/lib/generators/ruby_llm_agents/templates/application_background_remover.rb.tt +26 -0
  47. data/lib/generators/ruby_llm_agents/templates/application_embedder.rb.tt +50 -0
  48. data/lib/generators/ruby_llm_agents/templates/application_image_analyzer.rb.tt +26 -0
  49. data/lib/generators/ruby_llm_agents/templates/application_image_editor.rb.tt +20 -0
  50. data/lib/generators/ruby_llm_agents/templates/application_image_generator.rb.tt +38 -0
  51. data/lib/generators/ruby_llm_agents/templates/application_image_pipeline.rb.tt +139 -0
  52. data/lib/generators/ruby_llm_agents/templates/application_image_transformer.rb.tt +21 -0
  53. data/lib/generators/ruby_llm_agents/templates/application_image_upscaler.rb.tt +20 -0
  54. data/lib/generators/ruby_llm_agents/templates/application_image_variator.rb.tt +20 -0
  55. data/lib/generators/ruby_llm_agents/templates/application_speaker.rb.tt +49 -0
  56. data/lib/generators/ruby_llm_agents/templates/application_transcriber.rb.tt +53 -0
  57. data/lib/generators/ruby_llm_agents/templates/background_remover.rb.tt +44 -0
  58. data/lib/generators/ruby_llm_agents/templates/embedder.rb.tt +41 -0
  59. data/lib/generators/ruby_llm_agents/templates/image_analyzer.rb.tt +45 -0
  60. data/lib/generators/ruby_llm_agents/templates/image_editor.rb.tt +35 -0
  61. data/lib/generators/ruby_llm_agents/templates/image_generator.rb.tt +47 -0
  62. data/lib/generators/ruby_llm_agents/templates/image_pipeline.rb.tt +50 -0
  63. data/lib/generators/ruby_llm_agents/templates/image_transformer.rb.tt +44 -0
  64. data/lib/generators/ruby_llm_agents/templates/image_upscaler.rb.tt +38 -0
  65. data/lib/generators/ruby_llm_agents/templates/image_variator.rb.tt +33 -0
  66. data/lib/generators/ruby_llm_agents/templates/skills/AGENTS.md.tt +228 -0
  67. data/lib/generators/ruby_llm_agents/templates/skills/BACKGROUND_REMOVERS.md.tt +131 -0
  68. data/lib/generators/ruby_llm_agents/templates/skills/EMBEDDERS.md.tt +255 -0
  69. data/lib/generators/ruby_llm_agents/templates/skills/IMAGE_ANALYZERS.md.tt +120 -0
  70. data/lib/generators/ruby_llm_agents/templates/skills/IMAGE_EDITORS.md.tt +102 -0
  71. data/lib/generators/ruby_llm_agents/templates/skills/IMAGE_GENERATORS.md.tt +282 -0
  72. data/lib/generators/ruby_llm_agents/templates/skills/IMAGE_PIPELINES.md.tt +228 -0
  73. data/lib/generators/ruby_llm_agents/templates/skills/IMAGE_TRANSFORMERS.md.tt +120 -0
  74. data/lib/generators/ruby_llm_agents/templates/skills/IMAGE_UPSCALERS.md.tt +110 -0
  75. data/lib/generators/ruby_llm_agents/templates/skills/IMAGE_VARIATORS.md.tt +120 -0
  76. data/lib/generators/ruby_llm_agents/templates/skills/SPEAKERS.md.tt +212 -0
  77. data/lib/generators/ruby_llm_agents/templates/skills/TOOLS.md.tt +227 -0
  78. data/lib/generators/ruby_llm_agents/templates/skills/TRANSCRIBERS.md.tt +251 -0
  79. data/lib/generators/ruby_llm_agents/templates/skills/WORKFLOWS.md.tt +300 -0
  80. data/lib/generators/ruby_llm_agents/templates/speaker.rb.tt +56 -0
  81. data/lib/generators/ruby_llm_agents/templates/transcriber.rb.tt +51 -0
  82. data/lib/generators/ruby_llm_agents/transcriber_generator.rb +107 -0
  83. data/lib/generators/ruby_llm_agents/upgrade_generator.rb +152 -1
  84. data/lib/ruby_llm/agents/audio/speaker.rb +553 -0
  85. data/lib/ruby_llm/agents/audio/transcriber.rb +669 -0
  86. data/lib/ruby_llm/agents/base_agent.rb +675 -0
  87. data/lib/ruby_llm/agents/core/base/moderation_dsl.rb +181 -0
  88. data/lib/ruby_llm/agents/core/base/moderation_execution.rb +274 -0
  89. data/lib/ruby_llm/agents/core/base.rb +135 -0
  90. data/lib/ruby_llm/agents/core/configuration.rb +981 -0
  91. data/lib/ruby_llm/agents/core/errors.rb +150 -0
  92. data/lib/ruby_llm/agents/{instrumentation.rb → core/instrumentation.rb} +22 -1
  93. data/lib/ruby_llm/agents/core/llm_tenant.rb +358 -0
  94. data/lib/ruby_llm/agents/{version.rb → core/version.rb} +1 -1
  95. data/lib/ruby_llm/agents/dsl/base.rb +110 -0
  96. data/lib/ruby_llm/agents/dsl/caching.rb +142 -0
  97. data/lib/ruby_llm/agents/dsl/reliability.rb +307 -0
  98. data/lib/ruby_llm/agents/dsl.rb +41 -0
  99. data/lib/ruby_llm/agents/image/analyzer/dsl.rb +130 -0
  100. data/lib/ruby_llm/agents/image/analyzer/execution.rb +402 -0
  101. data/lib/ruby_llm/agents/image/analyzer.rb +90 -0
  102. data/lib/ruby_llm/agents/image/background_remover/dsl.rb +154 -0
  103. data/lib/ruby_llm/agents/image/background_remover/execution.rb +240 -0
  104. data/lib/ruby_llm/agents/image/background_remover.rb +89 -0
  105. data/lib/ruby_llm/agents/image/concerns/image_operation_dsl.rb +91 -0
  106. data/lib/ruby_llm/agents/image/concerns/image_operation_execution.rb +165 -0
  107. data/lib/ruby_llm/agents/image/editor/dsl.rb +56 -0
  108. data/lib/ruby_llm/agents/image/editor/execution.rb +207 -0
  109. data/lib/ruby_llm/agents/image/editor.rb +92 -0
  110. data/lib/ruby_llm/agents/image/generator/active_storage_support.rb +127 -0
  111. data/lib/ruby_llm/agents/image/generator/content_policy.rb +95 -0
  112. data/lib/ruby_llm/agents/image/generator/pricing.rb +353 -0
  113. data/lib/ruby_llm/agents/image/generator/templates.rb +124 -0
  114. data/lib/ruby_llm/agents/image/generator.rb +455 -0
  115. data/lib/ruby_llm/agents/image/pipeline/dsl.rb +213 -0
  116. data/lib/ruby_llm/agents/image/pipeline/execution.rb +382 -0
  117. data/lib/ruby_llm/agents/image/pipeline.rb +97 -0
  118. data/lib/ruby_llm/agents/image/transformer/dsl.rb +148 -0
  119. data/lib/ruby_llm/agents/image/transformer/execution.rb +223 -0
  120. data/lib/ruby_llm/agents/image/transformer.rb +95 -0
  121. data/lib/ruby_llm/agents/image/upscaler/dsl.rb +83 -0
  122. data/lib/ruby_llm/agents/image/upscaler/execution.rb +219 -0
  123. data/lib/ruby_llm/agents/image/upscaler.rb +81 -0
  124. data/lib/ruby_llm/agents/image/variator/dsl.rb +62 -0
  125. data/lib/ruby_llm/agents/image/variator/execution.rb +189 -0
  126. data/lib/ruby_llm/agents/image/variator.rb +80 -0
  127. data/lib/ruby_llm/agents/{alert_manager.rb → infrastructure/alert_manager.rb} +17 -22
  128. data/lib/ruby_llm/agents/infrastructure/budget/budget_query.rb +145 -0
  129. data/lib/ruby_llm/agents/infrastructure/budget/config_resolver.rb +149 -0
  130. data/lib/ruby_llm/agents/infrastructure/budget/forecaster.rb +68 -0
  131. data/lib/ruby_llm/agents/infrastructure/budget/spend_recorder.rb +279 -0
  132. data/lib/ruby_llm/agents/infrastructure/budget_tracker.rb +275 -0
  133. data/lib/ruby_llm/agents/{execution_logger_job.rb → infrastructure/execution_logger_job.rb} +17 -1
  134. data/lib/ruby_llm/agents/{reliability → infrastructure/reliability}/executor.rb +2 -1
  135. data/lib/ruby_llm/agents/{reliability → infrastructure/reliability}/retry_strategy.rb +9 -3
  136. data/lib/ruby_llm/agents/{reliability.rb → infrastructure/reliability.rb} +11 -21
  137. data/lib/ruby_llm/agents/pipeline/builder.rb +215 -0
  138. data/lib/ruby_llm/agents/pipeline/context.rb +255 -0
  139. data/lib/ruby_llm/agents/pipeline/executor.rb +86 -0
  140. data/lib/ruby_llm/agents/pipeline/middleware/base.rb +124 -0
  141. data/lib/ruby_llm/agents/pipeline/middleware/budget.rb +95 -0
  142. data/lib/ruby_llm/agents/pipeline/middleware/cache.rb +171 -0
  143. data/lib/ruby_llm/agents/pipeline/middleware/instrumentation.rb +415 -0
  144. data/lib/ruby_llm/agents/pipeline/middleware/reliability.rb +276 -0
  145. data/lib/ruby_llm/agents/pipeline/middleware/tenant.rb +196 -0
  146. data/lib/ruby_llm/agents/pipeline.rb +68 -0
  147. data/lib/ruby_llm/agents/{engine.rb → rails/engine.rb} +79 -11
  148. data/lib/ruby_llm/agents/results/background_removal_result.rb +286 -0
  149. data/lib/ruby_llm/agents/{result.rb → results/base.rb} +73 -1
  150. data/lib/ruby_llm/agents/results/embedding_result.rb +243 -0
  151. data/lib/ruby_llm/agents/results/image_analysis_result.rb +314 -0
  152. data/lib/ruby_llm/agents/results/image_edit_result.rb +250 -0
  153. data/lib/ruby_llm/agents/results/image_generation_result.rb +346 -0
  154. data/lib/ruby_llm/agents/results/image_pipeline_result.rb +399 -0
  155. data/lib/ruby_llm/agents/results/image_transform_result.rb +251 -0
  156. data/lib/ruby_llm/agents/results/image_upscale_result.rb +255 -0
  157. data/lib/ruby_llm/agents/results/image_variation_result.rb +237 -0
  158. data/lib/ruby_llm/agents/results/moderation_result.rb +158 -0
  159. data/lib/ruby_llm/agents/results/speech_result.rb +338 -0
  160. data/lib/ruby_llm/agents/results/transcription_result.rb +408 -0
  161. data/lib/ruby_llm/agents/text/embedder.rb +444 -0
  162. data/lib/ruby_llm/agents/text/moderator.rb +237 -0
  163. data/lib/ruby_llm/agents/workflow/async.rb +220 -0
  164. data/lib/ruby_llm/agents/workflow/async_executor.rb +156 -0
  165. data/lib/ruby_llm/agents/{workflow.rb → workflow/orchestrator.rb} +6 -5
  166. data/lib/ruby_llm/agents/workflow/parallel.rb +34 -17
  167. data/lib/ruby_llm/agents/workflow/thread_pool.rb +185 -0
  168. data/lib/ruby_llm/agents.rb +86 -20
  169. metadata +172 -34
  170. data/lib/ruby_llm/agents/base/caching.rb +0 -40
  171. data/lib/ruby_llm/agents/base/cost_calculation.rb +0 -105
  172. data/lib/ruby_llm/agents/base/dsl.rb +0 -324
  173. data/lib/ruby_llm/agents/base/execution.rb +0 -366
  174. data/lib/ruby_llm/agents/base/reliability_dsl.rb +0 -82
  175. data/lib/ruby_llm/agents/base/reliability_execution.rb +0 -136
  176. data/lib/ruby_llm/agents/base/response_building.rb +0 -86
  177. data/lib/ruby_llm/agents/base/tool_tracking.rb +0 -57
  178. data/lib/ruby_llm/agents/base.rb +0 -210
  179. data/lib/ruby_llm/agents/budget_tracker.rb +0 -733
  180. data/lib/ruby_llm/agents/configuration.rb +0 -394
  181. /data/lib/ruby_llm/agents/{deprecations.rb → core/deprecations.rb} +0 -0
  182. /data/lib/ruby_llm/agents/{inflections.rb → core/inflections.rb} +0 -0
  183. /data/lib/ruby_llm/agents/{resolved_config.rb → core/resolved_config.rb} +0 -0
  184. /data/lib/ruby_llm/agents/{attempt_tracker.rb → infrastructure/attempt_tracker.rb} +0 -0
  185. /data/lib/ruby_llm/agents/{cache_helper.rb → infrastructure/cache_helper.rb} +0 -0
  186. /data/lib/ruby_llm/agents/{circuit_breaker.rb → infrastructure/circuit_breaker.rb} +0 -0
  187. /data/lib/ruby_llm/agents/{redactor.rb → infrastructure/redactor.rb} +0 -0
  188. /data/lib/ruby_llm/agents/{reliability → infrastructure/reliability}/breaker_manager.rb +0 -0
  189. /data/lib/ruby_llm/agents/{reliability → infrastructure/reliability}/execution_constraints.rb +0 -0
  190. /data/lib/ruby_llm/agents/{reliability → infrastructure/reliability}/fallback_routing.rb +0 -0
@@ -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