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,338 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "base64"
|
|
4
|
+
|
|
5
|
+
module RubyLLM
|
|
6
|
+
module Agents
|
|
7
|
+
# Result object for text-to-speech operations
|
|
8
|
+
#
|
|
9
|
+
# Wraps audio output with metadata about the operation including
|
|
10
|
+
# duration, format, cost, and utility methods for saving audio.
|
|
11
|
+
#
|
|
12
|
+
# @example Basic usage
|
|
13
|
+
# result = ArticleNarrator.call(text: "Hello world")
|
|
14
|
+
# result.audio # => Binary audio data
|
|
15
|
+
# result.duration # => 1.5 (seconds)
|
|
16
|
+
# result.total_cost # => 0.0003
|
|
17
|
+
#
|
|
18
|
+
# @example Saving audio
|
|
19
|
+
# result.save_to("/path/to/output.mp3")
|
|
20
|
+
#
|
|
21
|
+
# @example Base64 encoding
|
|
22
|
+
# result.to_base64 # => "//uQx..."
|
|
23
|
+
#
|
|
24
|
+
# @api public
|
|
25
|
+
class SpeechResult
|
|
26
|
+
# @!group Audio Content
|
|
27
|
+
|
|
28
|
+
# @!attribute [r] audio
|
|
29
|
+
# @return [String, nil] Binary audio data
|
|
30
|
+
attr_reader :audio
|
|
31
|
+
|
|
32
|
+
# @!attribute [r] audio_url
|
|
33
|
+
# @return [String, nil] URL if audio was stored remotely
|
|
34
|
+
attr_reader :audio_url
|
|
35
|
+
|
|
36
|
+
# @!attribute [r] audio_key
|
|
37
|
+
# @return [String, nil] Storage key if stored
|
|
38
|
+
attr_reader :audio_key
|
|
39
|
+
|
|
40
|
+
# @!attribute [r] audio_path
|
|
41
|
+
# @return [String, nil] Local file path if saved
|
|
42
|
+
attr_reader :audio_path
|
|
43
|
+
|
|
44
|
+
# @!endgroup
|
|
45
|
+
|
|
46
|
+
# @!group Audio Metadata
|
|
47
|
+
|
|
48
|
+
# @!attribute [r] duration
|
|
49
|
+
# @return [Float, nil] Duration in seconds
|
|
50
|
+
attr_reader :duration
|
|
51
|
+
|
|
52
|
+
# @!attribute [r] format
|
|
53
|
+
# @return [Symbol, nil] Audio format (:mp3, :wav, :ogg, etc.)
|
|
54
|
+
attr_reader :format
|
|
55
|
+
|
|
56
|
+
# @!attribute [r] sample_rate
|
|
57
|
+
# @return [Integer, nil] Sample rate in Hz
|
|
58
|
+
attr_reader :sample_rate
|
|
59
|
+
|
|
60
|
+
# @!attribute [r] bitrate
|
|
61
|
+
# @return [Integer, nil] Bitrate in kbps
|
|
62
|
+
attr_reader :bitrate
|
|
63
|
+
|
|
64
|
+
# @!attribute [r] file_size
|
|
65
|
+
# @return [Integer, nil] Size in bytes
|
|
66
|
+
attr_reader :file_size
|
|
67
|
+
|
|
68
|
+
# @!endgroup
|
|
69
|
+
|
|
70
|
+
# @!group Input Metadata
|
|
71
|
+
|
|
72
|
+
# @!attribute [r] characters
|
|
73
|
+
# @return [Integer, nil] Character count (for billing)
|
|
74
|
+
attr_reader :characters
|
|
75
|
+
|
|
76
|
+
# @!attribute [r] text_length
|
|
77
|
+
# @return [Integer, nil] Original text length
|
|
78
|
+
attr_reader :text_length
|
|
79
|
+
|
|
80
|
+
# @!endgroup
|
|
81
|
+
|
|
82
|
+
# @!group Voice Info
|
|
83
|
+
|
|
84
|
+
# @!attribute [r] provider
|
|
85
|
+
# @return [Symbol, nil] Provider (:openai, :elevenlabs, :google, :polly)
|
|
86
|
+
attr_reader :provider
|
|
87
|
+
|
|
88
|
+
# @!attribute [r] model_id
|
|
89
|
+
# @return [String, nil] Model identifier
|
|
90
|
+
attr_reader :model_id
|
|
91
|
+
|
|
92
|
+
# @!attribute [r] voice_id
|
|
93
|
+
# @return [String, nil] Voice identifier
|
|
94
|
+
attr_reader :voice_id
|
|
95
|
+
|
|
96
|
+
# @!attribute [r] voice_name
|
|
97
|
+
# @return [String, nil] Voice display name
|
|
98
|
+
attr_reader :voice_name
|
|
99
|
+
|
|
100
|
+
# @!endgroup
|
|
101
|
+
|
|
102
|
+
# @!group Timing
|
|
103
|
+
|
|
104
|
+
# @!attribute [r] duration_ms
|
|
105
|
+
# @return [Integer, nil] Execution duration in milliseconds
|
|
106
|
+
attr_reader :duration_ms
|
|
107
|
+
|
|
108
|
+
# @!attribute [r] started_at
|
|
109
|
+
# @return [Time, nil] When execution started
|
|
110
|
+
attr_reader :started_at
|
|
111
|
+
|
|
112
|
+
# @!attribute [r] completed_at
|
|
113
|
+
# @return [Time, nil] When execution completed
|
|
114
|
+
attr_reader :completed_at
|
|
115
|
+
|
|
116
|
+
# @!endgroup
|
|
117
|
+
|
|
118
|
+
# @!group Cost & Usage
|
|
119
|
+
|
|
120
|
+
# @!attribute [r] total_cost
|
|
121
|
+
# @return [Float, nil] Total cost in USD
|
|
122
|
+
attr_reader :total_cost
|
|
123
|
+
|
|
124
|
+
# @!endgroup
|
|
125
|
+
|
|
126
|
+
# @!group Status
|
|
127
|
+
|
|
128
|
+
# @!attribute [r] status
|
|
129
|
+
# @return [Symbol] Status (:success, :partial, :failed)
|
|
130
|
+
attr_reader :status
|
|
131
|
+
|
|
132
|
+
# @!endgroup
|
|
133
|
+
|
|
134
|
+
# @!group Multi-tenancy
|
|
135
|
+
|
|
136
|
+
# @!attribute [r] tenant_id
|
|
137
|
+
# @return [String, nil] Tenant identifier if multi-tenancy enabled
|
|
138
|
+
attr_reader :tenant_id
|
|
139
|
+
|
|
140
|
+
# @!endgroup
|
|
141
|
+
|
|
142
|
+
# @!group Error
|
|
143
|
+
|
|
144
|
+
# @!attribute [r] error_class
|
|
145
|
+
# @return [String, nil] Exception class name if failed
|
|
146
|
+
attr_reader :error_class
|
|
147
|
+
|
|
148
|
+
# @!attribute [r] error_message
|
|
149
|
+
# @return [String, nil] Exception message if failed
|
|
150
|
+
attr_reader :error_message
|
|
151
|
+
|
|
152
|
+
# @!endgroup
|
|
153
|
+
|
|
154
|
+
# Creates a new SpeechResult instance
|
|
155
|
+
#
|
|
156
|
+
# @param attributes [Hash] Result attributes
|
|
157
|
+
# @option attributes [String] :audio Binary audio data
|
|
158
|
+
# @option attributes [String] :audio_url URL if stored remotely
|
|
159
|
+
# @option attributes [String] :audio_key Storage key
|
|
160
|
+
# @option attributes [String] :audio_path Local file path
|
|
161
|
+
# @option attributes [Float] :duration Duration in seconds
|
|
162
|
+
# @option attributes [Symbol] :format Audio format
|
|
163
|
+
# @option attributes [Integer] :sample_rate Sample rate in Hz
|
|
164
|
+
# @option attributes [Integer] :bitrate Bitrate in kbps
|
|
165
|
+
# @option attributes [Integer] :file_size Size in bytes
|
|
166
|
+
# @option attributes [Integer] :characters Character count
|
|
167
|
+
# @option attributes [Integer] :text_length Original text length
|
|
168
|
+
# @option attributes [Symbol] :provider Provider name
|
|
169
|
+
# @option attributes [String] :model_id Model identifier
|
|
170
|
+
# @option attributes [String] :voice_id Voice identifier
|
|
171
|
+
# @option attributes [String] :voice_name Voice display name
|
|
172
|
+
# @option attributes [Integer] :duration_ms Execution duration
|
|
173
|
+
# @option attributes [Time] :started_at Start time
|
|
174
|
+
# @option attributes [Time] :completed_at Completion time
|
|
175
|
+
# @option attributes [Float] :total_cost Cost in USD
|
|
176
|
+
# @option attributes [Symbol] :status Status
|
|
177
|
+
# @option attributes [String] :tenant_id Tenant identifier
|
|
178
|
+
# @option attributes [String] :error_class Error class
|
|
179
|
+
# @option attributes [String] :error_message Error message
|
|
180
|
+
def initialize(attributes = {})
|
|
181
|
+
# Audio content
|
|
182
|
+
@audio = attributes[:audio]
|
|
183
|
+
@audio_url = attributes[:audio_url]
|
|
184
|
+
@audio_key = attributes[:audio_key]
|
|
185
|
+
@audio_path = attributes[:audio_path]
|
|
186
|
+
|
|
187
|
+
# Audio metadata
|
|
188
|
+
@duration = attributes[:duration]
|
|
189
|
+
@format = attributes[:format]
|
|
190
|
+
@sample_rate = attributes[:sample_rate]
|
|
191
|
+
@bitrate = attributes[:bitrate]
|
|
192
|
+
@file_size = attributes[:file_size] || @audio&.bytesize
|
|
193
|
+
|
|
194
|
+
# Input metadata
|
|
195
|
+
@characters = attributes[:characters]
|
|
196
|
+
@text_length = attributes[:text_length]
|
|
197
|
+
|
|
198
|
+
# Voice info
|
|
199
|
+
@provider = attributes[:provider]
|
|
200
|
+
@model_id = attributes[:model_id]
|
|
201
|
+
@voice_id = attributes[:voice_id]
|
|
202
|
+
@voice_name = attributes[:voice_name]
|
|
203
|
+
|
|
204
|
+
# Timing
|
|
205
|
+
@duration_ms = attributes[:duration_ms]
|
|
206
|
+
@started_at = attributes[:started_at]
|
|
207
|
+
@completed_at = attributes[:completed_at]
|
|
208
|
+
|
|
209
|
+
# Cost & usage
|
|
210
|
+
@total_cost = attributes[:total_cost]
|
|
211
|
+
|
|
212
|
+
# Status
|
|
213
|
+
@status = attributes[:status] || :success
|
|
214
|
+
|
|
215
|
+
# Multi-tenancy
|
|
216
|
+
@tenant_id = attributes[:tenant_id]
|
|
217
|
+
|
|
218
|
+
# Error
|
|
219
|
+
@error_class = attributes[:error_class]
|
|
220
|
+
@error_message = attributes[:error_message]
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
# Returns whether the speech generation succeeded
|
|
224
|
+
#
|
|
225
|
+
# @return [Boolean] true if no error occurred
|
|
226
|
+
def success?
|
|
227
|
+
error_class.nil? && status == :success
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
# Returns whether the speech generation failed
|
|
231
|
+
#
|
|
232
|
+
# @return [Boolean] true if an error occurred
|
|
233
|
+
def error?
|
|
234
|
+
!success?
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
# Saves the audio to a file
|
|
238
|
+
#
|
|
239
|
+
# @param path [String] File path to save to
|
|
240
|
+
# @return [String] The path where audio was saved
|
|
241
|
+
# @raise [StandardError] If audio data is not available
|
|
242
|
+
def save_to(path)
|
|
243
|
+
raise StandardError, "No audio data available" unless audio
|
|
244
|
+
|
|
245
|
+
File.binwrite(path, audio)
|
|
246
|
+
@audio_path = path
|
|
247
|
+
path
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
# Returns the audio as a Base64-encoded string
|
|
251
|
+
#
|
|
252
|
+
# @return [String, nil] Base64-encoded audio or nil if no audio
|
|
253
|
+
def to_base64
|
|
254
|
+
return nil unless audio
|
|
255
|
+
|
|
256
|
+
Base64.strict_encode64(audio)
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
# Returns the audio as a data URI
|
|
260
|
+
#
|
|
261
|
+
# @return [String, nil] Data URI or nil if no audio
|
|
262
|
+
def to_data_uri
|
|
263
|
+
return nil unless audio
|
|
264
|
+
|
|
265
|
+
mime_type = mime_type_for_format
|
|
266
|
+
"data:#{mime_type};base64,#{to_base64}"
|
|
267
|
+
end
|
|
268
|
+
|
|
269
|
+
# Returns words per second of generated audio
|
|
270
|
+
#
|
|
271
|
+
# @return [Float, nil] Words per second or nil if not calculable
|
|
272
|
+
def words_per_second
|
|
273
|
+
return nil unless text_length && duration && duration > 0
|
|
274
|
+
|
|
275
|
+
# Rough estimate: average word length is 5 characters
|
|
276
|
+
word_count = text_length / 5.0
|
|
277
|
+
word_count / duration
|
|
278
|
+
end
|
|
279
|
+
|
|
280
|
+
# Converts the result to a hash
|
|
281
|
+
#
|
|
282
|
+
# @return [Hash] All result data as a hash
|
|
283
|
+
def to_h
|
|
284
|
+
{
|
|
285
|
+
audio_url: audio_url,
|
|
286
|
+
audio_key: audio_key,
|
|
287
|
+
audio_path: audio_path,
|
|
288
|
+
duration: duration,
|
|
289
|
+
format: format,
|
|
290
|
+
sample_rate: sample_rate,
|
|
291
|
+
bitrate: bitrate,
|
|
292
|
+
file_size: file_size,
|
|
293
|
+
characters: characters,
|
|
294
|
+
text_length: text_length,
|
|
295
|
+
provider: provider,
|
|
296
|
+
model_id: model_id,
|
|
297
|
+
voice_id: voice_id,
|
|
298
|
+
voice_name: voice_name,
|
|
299
|
+
duration_ms: duration_ms,
|
|
300
|
+
started_at: started_at,
|
|
301
|
+
completed_at: completed_at,
|
|
302
|
+
total_cost: total_cost,
|
|
303
|
+
status: status,
|
|
304
|
+
tenant_id: tenant_id,
|
|
305
|
+
error_class: error_class,
|
|
306
|
+
error_message: error_message
|
|
307
|
+
# Note: audio binary data excluded for serialization safety
|
|
308
|
+
}
|
|
309
|
+
end
|
|
310
|
+
|
|
311
|
+
private
|
|
312
|
+
|
|
313
|
+
# Returns MIME type for the audio format
|
|
314
|
+
#
|
|
315
|
+
# @return [String] MIME type
|
|
316
|
+
def mime_type_for_format
|
|
317
|
+
case format
|
|
318
|
+
when :mp3
|
|
319
|
+
"audio/mpeg"
|
|
320
|
+
when :wav
|
|
321
|
+
"audio/wav"
|
|
322
|
+
when :ogg
|
|
323
|
+
"audio/ogg"
|
|
324
|
+
when :flac
|
|
325
|
+
"audio/flac"
|
|
326
|
+
when :aac
|
|
327
|
+
"audio/aac"
|
|
328
|
+
when :opus
|
|
329
|
+
"audio/opus"
|
|
330
|
+
when :pcm
|
|
331
|
+
"audio/pcm"
|
|
332
|
+
else
|
|
333
|
+
"audio/mpeg" # Default to mp3
|
|
334
|
+
end
|
|
335
|
+
end
|
|
336
|
+
end
|
|
337
|
+
end
|
|
338
|
+
end
|