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
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rails/generators"
|
|
4
|
+
|
|
5
|
+
module RubyLlmAgents
|
|
6
|
+
# BackgroundRemover generator for creating new background removers
|
|
7
|
+
#
|
|
8
|
+
# Usage:
|
|
9
|
+
# rails generate ruby_llm_agents:background_remover Product
|
|
10
|
+
# rails generate ruby_llm_agents:background_remover Portrait --model segment-anything --alpha_matting
|
|
11
|
+
# rails generate ruby_llm_agents:background_remover Photo --refine_edges --return_mask
|
|
12
|
+
# rails generate ruby_llm_agents:background_remover Product --root=ai
|
|
13
|
+
#
|
|
14
|
+
# This will create:
|
|
15
|
+
# - app/{root}/image/background_removers/product_background_remover.rb
|
|
16
|
+
#
|
|
17
|
+
class BackgroundRemoverGenerator < ::Rails::Generators::NamedBase
|
|
18
|
+
source_root File.expand_path("templates", __dir__)
|
|
19
|
+
|
|
20
|
+
class_option :model, type: :string, default: "rembg",
|
|
21
|
+
desc: "The segmentation model to use"
|
|
22
|
+
class_option :output_format, type: :string, default: "png",
|
|
23
|
+
desc: "Output format (png, webp)"
|
|
24
|
+
class_option :refine_edges, type: :boolean, default: false,
|
|
25
|
+
desc: "Enable edge refinement"
|
|
26
|
+
class_option :alpha_matting, type: :boolean, default: false,
|
|
27
|
+
desc: "Enable alpha matting for better edges"
|
|
28
|
+
class_option :return_mask, type: :boolean, default: false,
|
|
29
|
+
desc: "Also return the segmentation mask"
|
|
30
|
+
class_option :cache, type: :string, default: nil,
|
|
31
|
+
desc: "Cache TTL (e.g., '1.hour', '1.day')"
|
|
32
|
+
class_option :root,
|
|
33
|
+
type: :string,
|
|
34
|
+
default: nil,
|
|
35
|
+
desc: "Root directory name (default: uses config or 'llm')"
|
|
36
|
+
class_option :namespace,
|
|
37
|
+
type: :string,
|
|
38
|
+
default: nil,
|
|
39
|
+
desc: "Root namespace (default: camelized root or config)"
|
|
40
|
+
|
|
41
|
+
def ensure_base_class_and_skill_file
|
|
42
|
+
@root_namespace = root_namespace
|
|
43
|
+
@image_namespace = "#{root_namespace}::Image"
|
|
44
|
+
removers_dir = "app/#{root_directory}/image/background_removers"
|
|
45
|
+
|
|
46
|
+
# Create directory if needed
|
|
47
|
+
empty_directory removers_dir
|
|
48
|
+
|
|
49
|
+
# Create base class if it doesn't exist
|
|
50
|
+
base_class_path = "#{removers_dir}/application_background_remover.rb"
|
|
51
|
+
unless File.exist?(File.join(destination_root, base_class_path))
|
|
52
|
+
template "application_background_remover.rb.tt", base_class_path
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# Create skill file if it doesn't exist
|
|
56
|
+
skill_file_path = "#{removers_dir}/BACKGROUND_REMOVERS.md"
|
|
57
|
+
unless File.exist?(File.join(destination_root, skill_file_path))
|
|
58
|
+
template "skills/BACKGROUND_REMOVERS.md.tt", skill_file_path
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def create_background_remover_file
|
|
63
|
+
@root_namespace = root_namespace
|
|
64
|
+
@image_namespace = "#{root_namespace}::Image"
|
|
65
|
+
remover_path = name.underscore
|
|
66
|
+
template "background_remover.rb.tt", "app/#{root_directory}/image/background_removers/#{remover_path}_background_remover.rb"
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def show_usage
|
|
70
|
+
remover_class_name = name.split("/").map(&:camelize).join("::")
|
|
71
|
+
full_class_name = "#{root_namespace}::Image::#{remover_class_name}BackgroundRemover"
|
|
72
|
+
say ""
|
|
73
|
+
say "Background remover #{full_class_name} created!", :green
|
|
74
|
+
say ""
|
|
75
|
+
say "Usage:"
|
|
76
|
+
say " # Remove background from an image"
|
|
77
|
+
say " result = #{full_class_name}.call(image: 'photo.jpg')"
|
|
78
|
+
say " result.url # => 'https://...' (transparent PNG)"
|
|
79
|
+
say " result.has_alpha? # => true"
|
|
80
|
+
say ""
|
|
81
|
+
say " # Override settings at runtime"
|
|
82
|
+
say " result = #{full_class_name}.call("
|
|
83
|
+
say " image: 'portrait.jpg',"
|
|
84
|
+
say " alpha_matting: true,"
|
|
85
|
+
say " return_mask: true"
|
|
86
|
+
say " )"
|
|
87
|
+
say ""
|
|
88
|
+
say " # Access the segmentation mask"
|
|
89
|
+
say " result.mask_url # => 'https://...' (if return_mask was enabled)"
|
|
90
|
+
say ""
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
private
|
|
94
|
+
|
|
95
|
+
def root_directory
|
|
96
|
+
@root_directory ||= options[:root] || RubyLLM::Agents.configuration.root_directory
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def root_namespace
|
|
100
|
+
@root_namespace ||= options[:namespace] || camelize(root_directory)
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def camelize(str)
|
|
104
|
+
return "AI" if str.downcase == "ai"
|
|
105
|
+
return "ML" if str.downcase == "ml"
|
|
106
|
+
return "LLM" if str.downcase == "llm"
|
|
107
|
+
str.split(/[-_]/).map(&:capitalize).join
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
end
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rails/generators"
|
|
4
|
+
|
|
5
|
+
module RubyLlmAgents
|
|
6
|
+
# Embedder generator for creating new embedders
|
|
7
|
+
#
|
|
8
|
+
# Usage:
|
|
9
|
+
# rails generate ruby_llm_agents:embedder Document
|
|
10
|
+
# rails generate ruby_llm_agents:embedder Document --model text-embedding-3-large
|
|
11
|
+
# rails generate ruby_llm_agents:embedder Document --dimensions 512
|
|
12
|
+
# rails generate ruby_llm_agents:embedder Document --root=ai
|
|
13
|
+
#
|
|
14
|
+
# This will create:
|
|
15
|
+
# - app/{root}/text/embedders/document_embedder.rb
|
|
16
|
+
#
|
|
17
|
+
class EmbedderGenerator < ::Rails::Generators::NamedBase
|
|
18
|
+
source_root File.expand_path("templates", __dir__)
|
|
19
|
+
|
|
20
|
+
class_option :model, type: :string, default: "text-embedding-3-small",
|
|
21
|
+
desc: "The embedding model to use"
|
|
22
|
+
class_option :dimensions, type: :numeric, default: nil,
|
|
23
|
+
desc: "Vector dimensions (nil for model default)"
|
|
24
|
+
class_option :batch_size, type: :numeric, default: 100,
|
|
25
|
+
desc: "Texts per API call for batch processing"
|
|
26
|
+
class_option :cache, type: :string, default: nil,
|
|
27
|
+
desc: "Cache TTL (e.g., '1.week', '1.day')"
|
|
28
|
+
class_option :root,
|
|
29
|
+
type: :string,
|
|
30
|
+
default: nil,
|
|
31
|
+
desc: "Root directory name (default: uses config or 'llm')"
|
|
32
|
+
class_option :namespace,
|
|
33
|
+
type: :string,
|
|
34
|
+
default: nil,
|
|
35
|
+
desc: "Root namespace (default: camelized root or config)"
|
|
36
|
+
|
|
37
|
+
def ensure_base_class_and_skill_file
|
|
38
|
+
@root_namespace = root_namespace
|
|
39
|
+
@text_namespace = "#{root_namespace}::Text"
|
|
40
|
+
embedders_dir = "app/#{root_directory}/text/embedders"
|
|
41
|
+
|
|
42
|
+
# Create directory if needed
|
|
43
|
+
empty_directory embedders_dir
|
|
44
|
+
|
|
45
|
+
# Create base class if it doesn't exist
|
|
46
|
+
base_class_path = "#{embedders_dir}/application_embedder.rb"
|
|
47
|
+
unless File.exist?(File.join(destination_root, base_class_path))
|
|
48
|
+
template "application_embedder.rb.tt", base_class_path
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Create skill file if it doesn't exist
|
|
52
|
+
skill_file_path = "#{embedders_dir}/EMBEDDERS.md"
|
|
53
|
+
unless File.exist?(File.join(destination_root, skill_file_path))
|
|
54
|
+
template "skills/EMBEDDERS.md.tt", skill_file_path
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def create_embedder_file
|
|
59
|
+
# Support nested paths: "search/document" -> "app/{root}/text/embedders/search/document_embedder.rb"
|
|
60
|
+
@root_namespace = root_namespace
|
|
61
|
+
@text_namespace = "#{root_namespace}::Text"
|
|
62
|
+
embedder_path = name.underscore
|
|
63
|
+
template "embedder.rb.tt", "app/#{root_directory}/text/embedders/#{embedder_path}_embedder.rb"
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def show_usage
|
|
67
|
+
# Build full class name from path
|
|
68
|
+
embedder_class_name = name.split("/").map(&:camelize).join("::")
|
|
69
|
+
full_class_name = "#{root_namespace}::Text::#{embedder_class_name}Embedder"
|
|
70
|
+
say ""
|
|
71
|
+
say "Embedder #{full_class_name} created!", :green
|
|
72
|
+
say ""
|
|
73
|
+
say "Usage:"
|
|
74
|
+
say " # Single text"
|
|
75
|
+
say " #{full_class_name}.call(text: \"Hello world\")"
|
|
76
|
+
say ""
|
|
77
|
+
say " # Multiple texts (batch)"
|
|
78
|
+
say " #{full_class_name}.call(texts: [\"Hello\", \"World\"])"
|
|
79
|
+
say ""
|
|
80
|
+
say " # With progress tracking"
|
|
81
|
+
say " #{full_class_name}.call(texts: large_array) do |batch, idx|"
|
|
82
|
+
say " puts \"Processed batch \#{idx}\""
|
|
83
|
+
say " end"
|
|
84
|
+
say ""
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
private
|
|
88
|
+
|
|
89
|
+
def root_directory
|
|
90
|
+
@root_directory ||= options[:root] || RubyLLM::Agents.configuration.root_directory
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def root_namespace
|
|
94
|
+
@root_namespace ||= options[:namespace] || camelize(root_directory)
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def camelize(str)
|
|
98
|
+
# Handle special cases for common abbreviations
|
|
99
|
+
return "AI" if str.downcase == "ai"
|
|
100
|
+
return "ML" if str.downcase == "ml"
|
|
101
|
+
return "LLM" if str.downcase == "llm"
|
|
102
|
+
|
|
103
|
+
# Standard camelization
|
|
104
|
+
str.split(/[-_]/).map(&:capitalize).join
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
end
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rails/generators"
|
|
4
|
+
|
|
5
|
+
module RubyLlmAgents
|
|
6
|
+
# ImageAnalyzer generator for creating new image analyzers
|
|
7
|
+
#
|
|
8
|
+
# Usage:
|
|
9
|
+
# rails generate ruby_llm_agents:image_analyzer Product
|
|
10
|
+
# rails generate ruby_llm_agents:image_analyzer Content --model gpt-4o --analysis_type detailed
|
|
11
|
+
# rails generate ruby_llm_agents:image_analyzer Photo --extract_colors --detect_objects
|
|
12
|
+
# rails generate ruby_llm_agents:image_analyzer Product --root=ai
|
|
13
|
+
#
|
|
14
|
+
# This will create:
|
|
15
|
+
# - app/{root}/image/analyzers/product_analyzer.rb
|
|
16
|
+
#
|
|
17
|
+
class ImageAnalyzerGenerator < ::Rails::Generators::NamedBase
|
|
18
|
+
source_root File.expand_path("templates", __dir__)
|
|
19
|
+
|
|
20
|
+
class_option :model, type: :string, default: "gpt-4o",
|
|
21
|
+
desc: "The vision model to use"
|
|
22
|
+
class_option :analysis_type, type: :string, default: "detailed",
|
|
23
|
+
desc: "Analysis type (caption, detailed, tags, objects, colors, all)"
|
|
24
|
+
class_option :extract_colors, type: :boolean, default: false,
|
|
25
|
+
desc: "Enable color extraction"
|
|
26
|
+
class_option :detect_objects, type: :boolean, default: false,
|
|
27
|
+
desc: "Enable object detection"
|
|
28
|
+
class_option :extract_text, type: :boolean, default: false,
|
|
29
|
+
desc: "Enable text extraction (OCR)"
|
|
30
|
+
class_option :max_tags, type: :string, default: "10",
|
|
31
|
+
desc: "Maximum number of tags to return"
|
|
32
|
+
class_option :cache, type: :string, default: nil,
|
|
33
|
+
desc: "Cache TTL (e.g., '1.hour', '1.day')"
|
|
34
|
+
class_option :root,
|
|
35
|
+
type: :string,
|
|
36
|
+
default: nil,
|
|
37
|
+
desc: "Root directory name (default: uses config or 'llm')"
|
|
38
|
+
class_option :namespace,
|
|
39
|
+
type: :string,
|
|
40
|
+
default: nil,
|
|
41
|
+
desc: "Root namespace (default: camelized root or config)"
|
|
42
|
+
|
|
43
|
+
def ensure_base_class_and_skill_file
|
|
44
|
+
@root_namespace = root_namespace
|
|
45
|
+
@image_namespace = "#{root_namespace}::Image"
|
|
46
|
+
analyzers_dir = "app/#{root_directory}/image/analyzers"
|
|
47
|
+
|
|
48
|
+
# Create directory if needed
|
|
49
|
+
empty_directory analyzers_dir
|
|
50
|
+
|
|
51
|
+
# Create base class if it doesn't exist
|
|
52
|
+
base_class_path = "#{analyzers_dir}/application_image_analyzer.rb"
|
|
53
|
+
unless File.exist?(File.join(destination_root, base_class_path))
|
|
54
|
+
template "application_image_analyzer.rb.tt", base_class_path
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# Create skill file if it doesn't exist
|
|
58
|
+
skill_file_path = "#{analyzers_dir}/IMAGE_ANALYZERS.md"
|
|
59
|
+
unless File.exist?(File.join(destination_root, skill_file_path))
|
|
60
|
+
template "skills/IMAGE_ANALYZERS.md.tt", skill_file_path
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def create_image_analyzer_file
|
|
65
|
+
@root_namespace = root_namespace
|
|
66
|
+
@image_namespace = "#{root_namespace}::Image"
|
|
67
|
+
analyzer_path = name.underscore
|
|
68
|
+
template "image_analyzer.rb.tt", "app/#{root_directory}/image/analyzers/#{analyzer_path}_analyzer.rb"
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def show_usage
|
|
72
|
+
analyzer_class_name = name.split("/").map(&:camelize).join("::")
|
|
73
|
+
full_class_name = "#{root_namespace}::Image::#{analyzer_class_name}Analyzer"
|
|
74
|
+
say ""
|
|
75
|
+
say "Image analyzer #{full_class_name} created!", :green
|
|
76
|
+
say ""
|
|
77
|
+
say "Usage:"
|
|
78
|
+
say " # Analyze an image"
|
|
79
|
+
say " result = #{full_class_name}.call(image: 'photo.jpg')"
|
|
80
|
+
say " result.caption # => 'A sunset over mountains'"
|
|
81
|
+
say " result.tags # => ['sunset', 'mountains', 'nature']"
|
|
82
|
+
say " result.description # => 'Detailed description...'"
|
|
83
|
+
say ""
|
|
84
|
+
say " # Override settings at runtime"
|
|
85
|
+
say " result = #{full_class_name}.call("
|
|
86
|
+
say " image: 'product.jpg',"
|
|
87
|
+
say " analysis_type: :all,"
|
|
88
|
+
say " extract_colors: true,"
|
|
89
|
+
say " detect_objects: true"
|
|
90
|
+
say " )"
|
|
91
|
+
say ""
|
|
92
|
+
say " # Access detected objects and colors"
|
|
93
|
+
say " result.objects # => [{name: 'laptop', location: 'center', confidence: 'high'}]"
|
|
94
|
+
say " result.colors # => [{hex: '#C0C0C0', name: 'silver', percentage: 45}]"
|
|
95
|
+
say ""
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
private
|
|
99
|
+
|
|
100
|
+
def root_directory
|
|
101
|
+
@root_directory ||= options[:root] || RubyLLM::Agents.configuration.root_directory
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def root_namespace
|
|
105
|
+
@root_namespace ||= options[:namespace] || camelize(root_directory)
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def camelize(str)
|
|
109
|
+
return "AI" if str.downcase == "ai"
|
|
110
|
+
return "ML" if str.downcase == "ml"
|
|
111
|
+
return "LLM" if str.downcase == "llm"
|
|
112
|
+
str.split(/[-_]/).map(&:capitalize).join
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
end
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rails/generators"
|
|
4
|
+
|
|
5
|
+
module RubyLlmAgents
|
|
6
|
+
# ImageEditor generator for creating new image editors
|
|
7
|
+
#
|
|
8
|
+
# Usage:
|
|
9
|
+
# rails generate ruby_llm_agents:image_editor Product
|
|
10
|
+
# rails generate ruby_llm_agents:image_editor Background --model gpt-image-1 --size 1024x1024
|
|
11
|
+
# rails generate ruby_llm_agents:image_editor Photo --content_policy strict
|
|
12
|
+
# rails generate ruby_llm_agents:image_editor Product --root=ai
|
|
13
|
+
#
|
|
14
|
+
# This will create:
|
|
15
|
+
# - app/{root}/image/editors/product_editor.rb
|
|
16
|
+
#
|
|
17
|
+
class ImageEditorGenerator < ::Rails::Generators::NamedBase
|
|
18
|
+
source_root File.expand_path("templates", __dir__)
|
|
19
|
+
|
|
20
|
+
class_option :model, type: :string, default: "gpt-image-1",
|
|
21
|
+
desc: "The image model to use"
|
|
22
|
+
class_option :size, type: :string, default: "1024x1024",
|
|
23
|
+
desc: "Output image size (e.g., 1024x1024)"
|
|
24
|
+
class_option :content_policy, type: :string, default: "standard",
|
|
25
|
+
desc: "Content policy level (none, standard, moderate, strict)"
|
|
26
|
+
class_option :cache, type: :string, default: nil,
|
|
27
|
+
desc: "Cache TTL (e.g., '1.hour', '1.day')"
|
|
28
|
+
class_option :root,
|
|
29
|
+
type: :string,
|
|
30
|
+
default: nil,
|
|
31
|
+
desc: "Root directory name (default: uses config or 'llm')"
|
|
32
|
+
class_option :namespace,
|
|
33
|
+
type: :string,
|
|
34
|
+
default: nil,
|
|
35
|
+
desc: "Root namespace (default: camelized root or config)"
|
|
36
|
+
|
|
37
|
+
def ensure_base_class_and_skill_file
|
|
38
|
+
@root_namespace = root_namespace
|
|
39
|
+
@image_namespace = "#{root_namespace}::Image"
|
|
40
|
+
editors_dir = "app/#{root_directory}/image/editors"
|
|
41
|
+
|
|
42
|
+
# Create directory if needed
|
|
43
|
+
empty_directory editors_dir
|
|
44
|
+
|
|
45
|
+
# Create base class if it doesn't exist
|
|
46
|
+
base_class_path = "#{editors_dir}/application_image_editor.rb"
|
|
47
|
+
unless File.exist?(File.join(destination_root, base_class_path))
|
|
48
|
+
template "application_image_editor.rb.tt", base_class_path
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Create skill file if it doesn't exist
|
|
52
|
+
skill_file_path = "#{editors_dir}/IMAGE_EDITORS.md"
|
|
53
|
+
unless File.exist?(File.join(destination_root, skill_file_path))
|
|
54
|
+
template "skills/IMAGE_EDITORS.md.tt", skill_file_path
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def create_image_editor_file
|
|
59
|
+
@root_namespace = root_namespace
|
|
60
|
+
@image_namespace = "#{root_namespace}::Image"
|
|
61
|
+
editor_path = name.underscore
|
|
62
|
+
template "image_editor.rb.tt", "app/#{root_directory}/image/editors/#{editor_path}_editor.rb"
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def show_usage
|
|
66
|
+
editor_class_name = name.split("/").map(&:camelize).join("::")
|
|
67
|
+
full_class_name = "#{root_namespace}::Image::#{editor_class_name}Editor"
|
|
68
|
+
say ""
|
|
69
|
+
say "Image editor #{full_class_name} created!", :green
|
|
70
|
+
say ""
|
|
71
|
+
say "Usage:"
|
|
72
|
+
say " # Edit an image with a mask"
|
|
73
|
+
say " result = #{full_class_name}.call("
|
|
74
|
+
say " image: 'photo.png',"
|
|
75
|
+
say " mask: 'mask.png',"
|
|
76
|
+
say " prompt: 'Replace the background with a beach scene'"
|
|
77
|
+
say " )"
|
|
78
|
+
say " result.url # => 'https://...'"
|
|
79
|
+
say ""
|
|
80
|
+
say " # Generate multiple edit variations"
|
|
81
|
+
say " result = #{full_class_name}.call("
|
|
82
|
+
say " image: 'photo.png',"
|
|
83
|
+
say " mask: 'mask.png',"
|
|
84
|
+
say " prompt: 'Add a sunset',"
|
|
85
|
+
say " count: 3"
|
|
86
|
+
say " )"
|
|
87
|
+
say " result.urls # => ['https://...', ...]"
|
|
88
|
+
say ""
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
private
|
|
92
|
+
|
|
93
|
+
def root_directory
|
|
94
|
+
@root_directory ||= options[:root] || RubyLLM::Agents.configuration.root_directory
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def root_namespace
|
|
98
|
+
@root_namespace ||= options[:namespace] || camelize(root_directory)
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def camelize(str)
|
|
102
|
+
return "AI" if str.downcase == "ai"
|
|
103
|
+
return "ML" if str.downcase == "ml"
|
|
104
|
+
return "LLM" if str.downcase == "llm"
|
|
105
|
+
str.split(/[-_]/).map(&:capitalize).join
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
end
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rails/generators"
|
|
4
|
+
|
|
5
|
+
module RubyLlmAgents
|
|
6
|
+
# ImageGenerator generator for creating new image generators
|
|
7
|
+
#
|
|
8
|
+
# Usage:
|
|
9
|
+
# rails generate ruby_llm_agents:image_generator Logo
|
|
10
|
+
# rails generate ruby_llm_agents:image_generator Product --model gpt-image-1 --size 1024x1024
|
|
11
|
+
# rails generate ruby_llm_agents:image_generator Avatar --quality hd --style vivid
|
|
12
|
+
# rails generate ruby_llm_agents:image_generator Logo --root=ai
|
|
13
|
+
#
|
|
14
|
+
# This will create:
|
|
15
|
+
# - app/{root}/image/generators/logo_generator.rb
|
|
16
|
+
#
|
|
17
|
+
class ImageGeneratorGenerator < ::Rails::Generators::NamedBase
|
|
18
|
+
source_root File.expand_path("templates", __dir__)
|
|
19
|
+
|
|
20
|
+
class_option :model, type: :string, default: "gpt-image-1",
|
|
21
|
+
desc: "The image generation model to use"
|
|
22
|
+
class_option :size, type: :string, default: "1024x1024",
|
|
23
|
+
desc: "Image size (e.g., 1024x1024, 1792x1024)"
|
|
24
|
+
class_option :quality, type: :string, default: "standard",
|
|
25
|
+
desc: "Image quality (standard, hd)"
|
|
26
|
+
class_option :style, type: :string, default: "vivid",
|
|
27
|
+
desc: "Image style (vivid, natural)"
|
|
28
|
+
class_option :content_policy, type: :string, default: "standard",
|
|
29
|
+
desc: "Content policy level (none, standard, moderate, strict)"
|
|
30
|
+
class_option :cache, type: :string, default: nil,
|
|
31
|
+
desc: "Cache TTL (e.g., '1.hour', '1.day')"
|
|
32
|
+
class_option :root,
|
|
33
|
+
type: :string,
|
|
34
|
+
default: nil,
|
|
35
|
+
desc: "Root directory name (default: uses config or 'llm')"
|
|
36
|
+
class_option :namespace,
|
|
37
|
+
type: :string,
|
|
38
|
+
default: nil,
|
|
39
|
+
desc: "Root namespace (default: camelized root or config)"
|
|
40
|
+
|
|
41
|
+
def ensure_base_class_and_skill_file
|
|
42
|
+
@root_namespace = root_namespace
|
|
43
|
+
@image_namespace = "#{root_namespace}::Image"
|
|
44
|
+
generators_dir = "app/#{root_directory}/image/generators"
|
|
45
|
+
|
|
46
|
+
# Create directory if needed
|
|
47
|
+
empty_directory generators_dir
|
|
48
|
+
|
|
49
|
+
# Create base class if it doesn't exist
|
|
50
|
+
base_class_path = "#{generators_dir}/application_image_generator.rb"
|
|
51
|
+
unless File.exist?(File.join(destination_root, base_class_path))
|
|
52
|
+
template "application_image_generator.rb.tt", base_class_path
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# Create skill file if it doesn't exist
|
|
56
|
+
skill_file_path = "#{generators_dir}/IMAGE_GENERATORS.md"
|
|
57
|
+
unless File.exist?(File.join(destination_root, skill_file_path))
|
|
58
|
+
template "skills/IMAGE_GENERATORS.md.tt", skill_file_path
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def create_image_generator_file
|
|
63
|
+
# Support nested paths: "product/hero" -> "app/{root}/image/generators/product/hero_generator.rb"
|
|
64
|
+
@root_namespace = root_namespace
|
|
65
|
+
@image_namespace = "#{root_namespace}::Image"
|
|
66
|
+
generator_path = name.underscore
|
|
67
|
+
template "image_generator.rb.tt", "app/#{root_directory}/image/generators/#{generator_path}_generator.rb"
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def show_usage
|
|
71
|
+
# Build full class name from path
|
|
72
|
+
generator_class_name = name.split("/").map(&:camelize).join("::")
|
|
73
|
+
full_class_name = "#{root_namespace}::Image::#{generator_class_name}Generator"
|
|
74
|
+
say ""
|
|
75
|
+
say "Image generator #{full_class_name} created!", :green
|
|
76
|
+
say ""
|
|
77
|
+
say "Usage:"
|
|
78
|
+
say " # Generate a single image"
|
|
79
|
+
say " result = #{full_class_name}.call(prompt: \"A beautiful sunset\")"
|
|
80
|
+
say " result.url # => \"https://...\""
|
|
81
|
+
say " result.save(\"sunset.png\")"
|
|
82
|
+
say ""
|
|
83
|
+
say " # Generate multiple images"
|
|
84
|
+
say " result = #{full_class_name}.call(prompt: \"Logos\", count: 4)"
|
|
85
|
+
say " result.urls # => [\"https://...\", ...]"
|
|
86
|
+
say ""
|
|
87
|
+
say " # Override settings at runtime"
|
|
88
|
+
say " result = #{full_class_name}.call("
|
|
89
|
+
say " prompt: \"High quality portrait\","
|
|
90
|
+
say " quality: \"hd\","
|
|
91
|
+
say " size: \"1792x1024\""
|
|
92
|
+
say " )"
|
|
93
|
+
say ""
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
private
|
|
97
|
+
|
|
98
|
+
def root_directory
|
|
99
|
+
@root_directory ||= options[:root] || RubyLLM::Agents.configuration.root_directory
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def root_namespace
|
|
103
|
+
@root_namespace ||= options[:namespace] || camelize(root_directory)
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def camelize(str)
|
|
107
|
+
# Handle special cases for common abbreviations
|
|
108
|
+
return "AI" if str.downcase == "ai"
|
|
109
|
+
return "ML" if str.downcase == "ml"
|
|
110
|
+
return "LLM" if str.downcase == "llm"
|
|
111
|
+
|
|
112
|
+
# Standard camelization
|
|
113
|
+
str.split(/[-_]/).map(&:capitalize).join
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
end
|