ruby_llm 1.4.0 → 1.5.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 +27 -5
- data/lib/generators/ruby_llm/install_generator.rb +7 -7
- data/lib/ruby_llm/configuration.rb +2 -0
- data/lib/ruby_llm/model/info.rb +2 -2
- data/lib/ruby_llm/models.json +2319 -383
- data/lib/ruby_llm/models_schema.json +168 -0
- data/lib/ruby_llm/providers/gemini/capabilities.rb +3 -0
- data/lib/ruby_llm/providers/mistral/capabilities.rb +163 -0
- data/lib/ruby_llm/providers/mistral/chat.rb +26 -0
- data/lib/ruby_llm/providers/mistral/embeddings.rb +36 -0
- data/lib/ruby_llm/providers/mistral/models.rb +49 -0
- data/lib/ruby_llm/providers/mistral.rb +37 -0
- data/lib/ruby_llm/providers/perplexity/capabilities.rb +167 -0
- data/lib/ruby_llm/providers/perplexity/chat.rb +17 -0
- data/lib/ruby_llm/providers/perplexity/models.rb +42 -0
- data/lib/ruby_llm/providers/perplexity.rb +57 -0
- data/lib/ruby_llm/utils.rb +12 -0
- data/lib/ruby_llm/version.rb +1 -1
- data/lib/ruby_llm.rb +9 -5
- data/lib/tasks/models_docs.rake +5 -6
- data/lib/tasks/models_update.rake +28 -0
- metadata +11 -1
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RubyLLM
|
4
|
+
module Providers
|
5
|
+
module Perplexity
|
6
|
+
# Models methods of the Perplexity API integration
|
7
|
+
module Models
|
8
|
+
def list_models(**)
|
9
|
+
slug = 'perplexity'
|
10
|
+
capabilities = Perplexity::Capabilities
|
11
|
+
parse_list_models_response(nil, slug, capabilities)
|
12
|
+
end
|
13
|
+
|
14
|
+
def parse_list_models_response(_response, slug, capabilities)
|
15
|
+
[
|
16
|
+
create_model_info('sonar', slug, capabilities),
|
17
|
+
create_model_info('sonar-pro', slug, capabilities),
|
18
|
+
create_model_info('sonar-reasoning', slug, capabilities),
|
19
|
+
create_model_info('sonar-reasoning-pro', slug, capabilities),
|
20
|
+
create_model_info('sonar-deep-research', slug, capabilities)
|
21
|
+
]
|
22
|
+
end
|
23
|
+
|
24
|
+
def create_model_info(id, slug, capabilities)
|
25
|
+
Model::Info.new(
|
26
|
+
id: id,
|
27
|
+
name: capabilities.format_display_name(id),
|
28
|
+
provider: slug,
|
29
|
+
family: capabilities.model_family(id).to_s,
|
30
|
+
created_at: Time.now,
|
31
|
+
context_window: capabilities.context_window_for(id),
|
32
|
+
max_output_tokens: capabilities.max_tokens_for(id),
|
33
|
+
modalities: capabilities.modalities_for(id),
|
34
|
+
capabilities: capabilities.capabilities_for(id),
|
35
|
+
pricing: capabilities.pricing_for(id),
|
36
|
+
metadata: {}
|
37
|
+
)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RubyLLM
|
4
|
+
module Providers
|
5
|
+
# Perplexity API integration.
|
6
|
+
module Perplexity
|
7
|
+
extend OpenAI
|
8
|
+
extend Perplexity::Chat
|
9
|
+
extend Perplexity::Models
|
10
|
+
|
11
|
+
module_function
|
12
|
+
|
13
|
+
def api_base(_config)
|
14
|
+
'https://api.perplexity.ai'
|
15
|
+
end
|
16
|
+
|
17
|
+
def headers(config)
|
18
|
+
{
|
19
|
+
'Authorization' => "Bearer #{config.perplexity_api_key}",
|
20
|
+
'Content-Type' => 'application/json'
|
21
|
+
}
|
22
|
+
end
|
23
|
+
|
24
|
+
def capabilities
|
25
|
+
Perplexity::Capabilities
|
26
|
+
end
|
27
|
+
|
28
|
+
def slug
|
29
|
+
'perplexity'
|
30
|
+
end
|
31
|
+
|
32
|
+
def configuration_requirements
|
33
|
+
%i[perplexity_api_key]
|
34
|
+
end
|
35
|
+
|
36
|
+
def parse_error(response)
|
37
|
+
body = response.body
|
38
|
+
return if body.empty?
|
39
|
+
|
40
|
+
# If response is HTML (Perplexity returns HTML for auth errors)
|
41
|
+
if body.include?('<html>') && body.include?('<title>')
|
42
|
+
# Extract title content
|
43
|
+
title_match = body.match(%r{<title>(.+?)</title>})
|
44
|
+
if title_match
|
45
|
+
# Clean up the title - remove status code if present
|
46
|
+
message = title_match[1]
|
47
|
+
message = message.sub(/^\d+\s+/, '') # Remove leading digits and space
|
48
|
+
return message
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# Fall back to parent's implementation
|
53
|
+
super
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
data/lib/ruby_llm/utils.rb
CHANGED
@@ -24,6 +24,18 @@ module RubyLLM
|
|
24
24
|
end
|
25
25
|
end
|
26
26
|
|
27
|
+
def to_time(value)
|
28
|
+
return unless value
|
29
|
+
|
30
|
+
value.is_a?(Time) ? value : Time.parse(value.to_s)
|
31
|
+
end
|
32
|
+
|
33
|
+
def to_date(value)
|
34
|
+
return unless value
|
35
|
+
|
36
|
+
value.is_a?(Date) ? value : Date.parse(value.to_s)
|
37
|
+
end
|
38
|
+
|
27
39
|
def deep_merge(params, payload)
|
28
40
|
params.merge(payload) do |_key, params_value, payload_value|
|
29
41
|
if params_value.is_a?(Hash) && payload_value.is_a?(Hash)
|
data/lib/ruby_llm/version.rb
CHANGED
data/lib/ruby_llm.rb
CHANGED
@@ -16,9 +16,11 @@ loader.inflector.inflect(
|
|
16
16
|
'openai' => 'OpenAI',
|
17
17
|
'api' => 'API',
|
18
18
|
'deepseek' => 'DeepSeek',
|
19
|
+
'perplexity' => 'Perplexity',
|
19
20
|
'bedrock' => 'Bedrock',
|
20
21
|
'openrouter' => 'OpenRouter',
|
21
22
|
'gpustack' => 'GPUStack',
|
23
|
+
'mistral' => 'Mistral',
|
22
24
|
'pdf' => 'PDF'
|
23
25
|
)
|
24
26
|
loader.ignore("#{__dir__}/tasks")
|
@@ -78,14 +80,16 @@ module RubyLLM
|
|
78
80
|
end
|
79
81
|
end
|
80
82
|
|
81
|
-
RubyLLM::Provider.register :openai, RubyLLM::Providers::OpenAI
|
82
83
|
RubyLLM::Provider.register :anthropic, RubyLLM::Providers::Anthropic
|
83
|
-
RubyLLM::Provider.register :gemini, RubyLLM::Providers::Gemini
|
84
|
-
RubyLLM::Provider.register :deepseek, RubyLLM::Providers::DeepSeek
|
85
84
|
RubyLLM::Provider.register :bedrock, RubyLLM::Providers::Bedrock
|
86
|
-
RubyLLM::Provider.register :
|
87
|
-
RubyLLM::Provider.register :
|
85
|
+
RubyLLM::Provider.register :deepseek, RubyLLM::Providers::DeepSeek
|
86
|
+
RubyLLM::Provider.register :gemini, RubyLLM::Providers::Gemini
|
88
87
|
RubyLLM::Provider.register :gpustack, RubyLLM::Providers::GPUStack
|
88
|
+
RubyLLM::Provider.register :mistral, RubyLLM::Providers::Mistral
|
89
|
+
RubyLLM::Provider.register :ollama, RubyLLM::Providers::Ollama
|
90
|
+
RubyLLM::Provider.register :openai, RubyLLM::Providers::OpenAI
|
91
|
+
RubyLLM::Provider.register :openrouter, RubyLLM::Providers::OpenRouter
|
92
|
+
RubyLLM::Provider.register :perplexity, RubyLLM::Providers::Perplexity
|
89
93
|
|
90
94
|
if defined?(Rails::Railtie)
|
91
95
|
require 'ruby_llm/railtie'
|
data/lib/tasks/models_docs.rake
CHANGED
@@ -6,14 +6,14 @@ require 'fileutils'
|
|
6
6
|
namespace :models do
|
7
7
|
desc 'Generate available models documentation'
|
8
8
|
task :docs do
|
9
|
-
FileUtils.mkdir_p('docs
|
9
|
+
FileUtils.mkdir_p('docs') # ensure output directory exists
|
10
10
|
|
11
11
|
# Generate markdown content
|
12
12
|
output = generate_models_markdown
|
13
13
|
|
14
14
|
# Write the output
|
15
|
-
File.write('docs/
|
16
|
-
puts 'Generated docs/
|
15
|
+
File.write('docs/available-models.md', output)
|
16
|
+
puts 'Generated docs/available-models.md'
|
17
17
|
end
|
18
18
|
end
|
19
19
|
|
@@ -22,9 +22,8 @@ def generate_models_markdown
|
|
22
22
|
---
|
23
23
|
layout: default
|
24
24
|
title: Available Models
|
25
|
-
|
26
|
-
|
27
|
-
permalink: /guides/available-models
|
25
|
+
nav_order: 5
|
26
|
+
permalink: /available-models
|
28
27
|
description: Browse hundreds of AI models from every major provider. Always up-to-date, automatically generated.
|
29
28
|
---
|
30
29
|
|
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
require 'dotenv/load'
|
4
4
|
require 'ruby_llm'
|
5
|
+
require 'json-schema'
|
5
6
|
|
6
7
|
task default: ['models:update']
|
7
8
|
|
@@ -22,7 +23,9 @@ def configure_from_env
|
|
22
23
|
config.anthropic_api_key = ENV.fetch('ANTHROPIC_API_KEY', nil)
|
23
24
|
config.gemini_api_key = ENV.fetch('GEMINI_API_KEY', nil)
|
24
25
|
config.deepseek_api_key = ENV.fetch('DEEPSEEK_API_KEY', nil)
|
26
|
+
config.perplexity_api_key = ENV.fetch('PERPLEXITY_API_KEY', nil)
|
25
27
|
config.openrouter_api_key = ENV.fetch('OPENROUTER_API_KEY', nil)
|
28
|
+
config.mistral_api_key = ENV.fetch('MISTRAL_API_KEY', nil)
|
26
29
|
configure_bedrock(config)
|
27
30
|
config.request_timeout = 30
|
28
31
|
end
|
@@ -47,6 +50,9 @@ def refresh_models
|
|
47
50
|
elsif models.all.size == initial_count && initial_count.positive?
|
48
51
|
puts 'Warning: Model list unchanged.'
|
49
52
|
else
|
53
|
+
puts 'Validating models...'
|
54
|
+
validate_models!(models)
|
55
|
+
|
50
56
|
puts "Saving models.json (#{models.all.size} models)"
|
51
57
|
models.save_models
|
52
58
|
end
|
@@ -54,6 +60,28 @@ def refresh_models
|
|
54
60
|
@models = models
|
55
61
|
end
|
56
62
|
|
63
|
+
def validate_models!(models)
|
64
|
+
schema_path = File.expand_path('../ruby_llm/models_schema.json', __dir__)
|
65
|
+
models_data = models.all.map(&:to_h)
|
66
|
+
|
67
|
+
validation_errors = JSON::Validator.fully_validate(schema_path, models_data)
|
68
|
+
|
69
|
+
unless validation_errors.empty?
|
70
|
+
# Save failed models for inspection
|
71
|
+
failed_path = File.expand_path('../ruby_llm/models.failed.json', __dir__)
|
72
|
+
File.write(failed_path, JSON.pretty_generate(models_data))
|
73
|
+
|
74
|
+
puts 'ERROR: Models validation failed:'
|
75
|
+
puts "\nValidation errors:"
|
76
|
+
validation_errors.first(10).each { |error| puts " - #{error}" }
|
77
|
+
puts " ... and #{validation_errors.size - 10} more errors" if validation_errors.size > 10
|
78
|
+
puts "-> Failed models saved to: #{failed_path}"
|
79
|
+
exit(1)
|
80
|
+
end
|
81
|
+
|
82
|
+
puts '✓ Models validation passed'
|
83
|
+
end
|
84
|
+
|
57
85
|
def display_model_stats
|
58
86
|
puts "\nModel count:"
|
59
87
|
provider_counts = @models.all.group_by(&:provider).transform_values(&:count)
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruby_llm
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.5.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Carmine Paolino
|
@@ -168,6 +168,7 @@ files:
|
|
168
168
|
- lib/ruby_llm/model/pricing_tier.rb
|
169
169
|
- lib/ruby_llm/models.json
|
170
170
|
- lib/ruby_llm/models.rb
|
171
|
+
- lib/ruby_llm/models_schema.json
|
171
172
|
- lib/ruby_llm/provider.rb
|
172
173
|
- lib/ruby_llm/providers/anthropic.rb
|
173
174
|
- lib/ruby_llm/providers/anthropic/capabilities.rb
|
@@ -204,6 +205,11 @@ files:
|
|
204
205
|
- lib/ruby_llm/providers/gpustack.rb
|
205
206
|
- lib/ruby_llm/providers/gpustack/chat.rb
|
206
207
|
- lib/ruby_llm/providers/gpustack/models.rb
|
208
|
+
- lib/ruby_llm/providers/mistral.rb
|
209
|
+
- lib/ruby_llm/providers/mistral/capabilities.rb
|
210
|
+
- lib/ruby_llm/providers/mistral/chat.rb
|
211
|
+
- lib/ruby_llm/providers/mistral/embeddings.rb
|
212
|
+
- lib/ruby_llm/providers/mistral/models.rb
|
207
213
|
- lib/ruby_llm/providers/ollama.rb
|
208
214
|
- lib/ruby_llm/providers/ollama/chat.rb
|
209
215
|
- lib/ruby_llm/providers/ollama/media.rb
|
@@ -218,6 +224,10 @@ files:
|
|
218
224
|
- lib/ruby_llm/providers/openai/tools.rb
|
219
225
|
- lib/ruby_llm/providers/openrouter.rb
|
220
226
|
- lib/ruby_llm/providers/openrouter/models.rb
|
227
|
+
- lib/ruby_llm/providers/perplexity.rb
|
228
|
+
- lib/ruby_llm/providers/perplexity/capabilities.rb
|
229
|
+
- lib/ruby_llm/providers/perplexity/chat.rb
|
230
|
+
- lib/ruby_llm/providers/perplexity/models.rb
|
221
231
|
- lib/ruby_llm/railtie.rb
|
222
232
|
- lib/ruby_llm/stream_accumulator.rb
|
223
233
|
- lib/ruby_llm/streaming.rb
|