ruby_llm 0.1.0.pre26 → 0.1.0.pre28

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.
@@ -55,7 +55,7 @@ module RubyLLM
55
55
  def refresh!
56
56
  @all = RubyLLM.providers.flat_map do |provider|
57
57
  provider.new.list_models
58
- end
58
+ end.sort_by(&:id)
59
59
  end
60
60
  end
61
61
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RubyLLM
4
- VERSION = '0.1.0.pre26'
4
+ VERSION = '0.1.0.pre28'
5
5
  end
@@ -1,8 +1,66 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- namespace :ruby_llm do
3
+ require 'English'
4
+ require 'faraday'
5
+ require 'nokogiri'
6
+
7
+ # URLs to process
8
+ PROVIDER_DOCS = {
9
+ openai: {
10
+ models: 'https://platform.openai.com/docs/models',
11
+ pricing: 'https://platform.openai.com/docs/pricing'
12
+ },
13
+ gemini: {
14
+ models: 'https://ai.google.dev/gemini-api/docs/models/gemini',
15
+ pricing: 'https://ai.google.dev/pricing'
16
+ },
17
+ deepseek: {
18
+ models: 'https://api-docs.deepseek.com/quick_start/pricing/'
19
+ }
20
+ }.freeze
21
+
22
+ def fetch_page(url) # rubocop:disable Metrics/AbcSize,Metrics/MethodLength
23
+ if url.include?('openai.com')
24
+ puts "Please visit #{url} and paste the content below (type 'END' on a new line when done):"
25
+ original_separator = $INPUT_RECORD_SEPARATOR
26
+ $/ = 'END'
27
+ content = $stdin.gets&.chomp
28
+ $/ = original_separator
29
+
30
+ raise "No content provided for #{url}" unless content
31
+
32
+ content
33
+ else
34
+ response = http_client.get(url)
35
+ html = Nokogiri::HTML(response.body)
36
+
37
+ # Remove script tags and comments
38
+ html.css('script').remove
39
+ html.xpath('//comment()').remove
40
+
41
+ # Extract text content
42
+ text = html.css('body').text
43
+
44
+ # Clean up whitespace
45
+ text.gsub!(/\s+/, ' ')
46
+ text.strip!
47
+
48
+ text
49
+ end
50
+ rescue StandardError => e
51
+ raise "Failed to fetch #{url}: #{e.message}"
52
+ end
53
+
54
+ def http_client
55
+ @http_client ||= Faraday.new do |f|
56
+ f.response :raise_error
57
+ f.response :logger, RubyLLM.logger, { headers: false, bodies: true }
58
+ end
59
+ end
60
+
61
+ namespace :models do # rubocop:disable Metrics/BlockLength
4
62
  desc 'Update available models from providers'
5
- task :update_models do
63
+ task :update do
6
64
  require 'ruby_llm'
7
65
 
8
66
  # Configure API keys
@@ -26,4 +84,108 @@ namespace :ruby_llm do
26
84
  puts "#{provider_name} models: #{models.count { |m| m.provider == provider_sym.to_s }}"
27
85
  end
28
86
  end
87
+
88
+ desc 'Update model capabilities modules by scraping provider documentation'
89
+ task :update_capabilities do # rubocop:disable Metrics/BlockLength
90
+ require 'ruby_llm'
91
+ require 'fileutils'
92
+
93
+ # Configure API keys
94
+ RubyLLM.configure do |config|
95
+ config.openai_api_key = ENV.fetch('OPENAI_API_KEY')
96
+ config.anthropic_api_key = ENV.fetch('ANTHROPIC_API_KEY')
97
+ config.gemini_api_key = ENV.fetch('GEMINI_API_KEY')
98
+ end
99
+
100
+ # Process each provider
101
+ PROVIDER_DOCS.each do |provider, urls| # rubocop:disable Metrics/BlockLength
102
+ puts "Processing #{provider}..."
103
+
104
+ # Initialize our AI assistants
105
+ gemini = RubyLLM.chat(model: 'gemini-2.0-flash').with_temperature(0)
106
+ claude = RubyLLM.chat(model: 'claude-3-5-sonnet-20241022').with_temperature(0)
107
+
108
+ # Read existing capabilities file if present
109
+ existing_file = "lib/ruby_llm/model_capabilities/#{provider}.rb"
110
+ existing_code = File.read(existing_file) if File.exist?(existing_file)
111
+
112
+ begin
113
+ # Download documentation
114
+ docs = urls.map do |type, url|
115
+ puts " Getting #{type} documentation..."
116
+ content = fetch_page(url)
117
+
118
+ puts "\nHere's what I got:\n\n"
119
+ puts "#{content.slice(0, 500)}...\n\n"
120
+
121
+ loop do
122
+ print 'Does this content look correct? (y/n): '
123
+ answer = $stdin.gets&.chomp&.downcase
124
+ break if answer == 'y'
125
+ raise "Content verification failed for #{url}" if answer == 'n'
126
+ end
127
+
128
+ "#{type.to_s.upcase} DOCUMENTATION:\n\n#{content}"
129
+ end.join("\n\n")
130
+
131
+ # Extract relevant information with Gemini
132
+ puts ' Extracting model information...'
133
+ extraction_prompt = <<~PROMPT
134
+ Extract relevant model capabilities information from this documentation:
135
+
136
+ #{docs}
137
+
138
+ Focus on:
139
+ 1. Available models and their IDs
140
+ 2. Context window sizes
141
+ 3. Maximum output tokens
142
+ 4. Pricing information
143
+ 5. Model capabilities (vision, function calling, etc)
144
+
145
+ Format the information clearly and concisely, focusing only on facts about the models.
146
+ PROMPT
147
+
148
+ model_info = gemini.ask(extraction_prompt).content
149
+
150
+ # Generate Ruby code with Claude
151
+ puts ' Generating Ruby code...'
152
+ code_prompt = <<~PROMPT
153
+ I need you to generate a Ruby module for #{provider}'s model capabilities.
154
+ Use this extracted model information:
155
+
156
+ #{model_info}
157
+
158
+ The module should go in lib/ruby_llm/model_capabilities/#{provider}.rb and follow these conventions:
159
+
160
+ 1. Module name should be RubyLLM::ModelCapabilities::#{provider.to_s.capitalize}
161
+ 2. Include methods for determining context windows, token limits, pricing, and capabilities
162
+ 3. Use consistent naming with other providers
163
+ 4. Include detailed pricing information in a PRICES constant
164
+ 5. Follow the existing structure in the codebase
165
+ 6. Use Ruby idioms and clean code practices
166
+ 7. Include module_function to make methods callable at module level
167
+ 8. Include all necessary method documentation
168
+
169
+ Here's the existing implementation for reference (maintain similar structure):
170
+
171
+ #{existing_code}
172
+
173
+ Focus on accuracy and maintaining consistency with the existing codebase structure.
174
+ PROMPT
175
+
176
+ response = claude.ask(code_prompt)
177
+
178
+ # Save the file
179
+ file_path = "lib/ruby_llm/model_capabilities/#{provider}.rb"
180
+ puts " Writing #{file_path}..."
181
+
182
+ FileUtils.mkdir_p(File.dirname(file_path))
183
+ File.write(file_path, response.content)
184
+ rescue StandardError => e
185
+ raise "Failed to process #{provider}: #{e.message}"
186
+ end
187
+ end
188
+
189
+ puts "Done! Don't forget to review the generated code and run the tests."
190
+ end
29
191
  end
data/ruby_llm.gemspec CHANGED
@@ -10,9 +10,9 @@ Gem::Specification.new do |spec|
10
10
 
11
11
  spec.summary = 'Clean Ruby interface to modern AI language models'
12
12
  spec.description = 'A delightful Ruby way to work with AI language models. Provides a unified interface to OpenAI' \
13
- ' and Anthropic models with automatic token counting, proper streaming support, and a focus on' \
14
- ' developer happiness. No wrapping your head around multiple APIs - just clean Ruby code that' \
15
- ' works.'
13
+ ', Anthropic, Google, and DeepSeek models with automatic token counting, proper streaming' \
14
+ ' support, and a focus on developer happiness. No wrapping your head around multiple APIs' \
15
+ ' - just clean Ruby code that works.'
16
16
  spec.homepage = 'https://github.com/crmne/ruby_llm'
17
17
  spec.license = 'MIT'
18
18
  spec.required_ruby_version = Gem::Requirement.new('>= 3.1.0')
@@ -46,6 +46,7 @@ Gem::Specification.new do |spec|
46
46
  spec.add_development_dependency 'bundler', '>= 2.0'
47
47
  spec.add_development_dependency 'dotenv'
48
48
  spec.add_development_dependency 'irb'
49
+ spec.add_development_dependency 'nokogiri'
49
50
  spec.add_development_dependency 'overcommit', '>= 0.66'
50
51
  spec.add_development_dependency 'pry', '>= 0.14'
51
52
  spec.add_development_dependency 'rake', '>= 13.0'
@@ -54,7 +55,6 @@ Gem::Specification.new do |spec|
54
55
  spec.add_development_dependency 'rspec', '~> 3.12'
55
56
  spec.add_development_dependency 'rubocop', '>= 1.0'
56
57
  spec.add_development_dependency 'rubocop-rake', '>= 0.6'
57
- spec.add_development_dependency 'rubocop-rspec', '>= 3.4'
58
58
  spec.add_development_dependency 'simplecov', '>= 0.21'
59
59
  spec.add_development_dependency 'webmock', '~> 3.18'
60
60
  spec.add_development_dependency 'yard', '>= 0.9'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby_llm
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0.pre26
4
+ version: 0.1.0.pre28
5
5
  platform: ruby
6
6
  authors:
7
7
  - Carmine Paolino
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2025-02-16 00:00:00.000000000 Z
11
+ date: 2025-02-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: event_stream_parser
@@ -154,6 +154,20 @@ dependencies:
154
154
  - - ">="
155
155
  - !ruby/object:Gem::Version
156
156
  version: '0'
157
+ - !ruby/object:Gem::Dependency
158
+ name: nokogiri
159
+ requirement: !ruby/object:Gem::Requirement
160
+ requirements:
161
+ - - ">="
162
+ - !ruby/object:Gem::Version
163
+ version: '0'
164
+ type: :development
165
+ prerelease: false
166
+ version_requirements: !ruby/object:Gem::Requirement
167
+ requirements:
168
+ - - ">="
169
+ - !ruby/object:Gem::Version
170
+ version: '0'
157
171
  - !ruby/object:Gem::Dependency
158
172
  name: overcommit
159
173
  requirement: !ruby/object:Gem::Requirement
@@ -266,20 +280,6 @@ dependencies:
266
280
  - - ">="
267
281
  - !ruby/object:Gem::Version
268
282
  version: '0.6'
269
- - !ruby/object:Gem::Dependency
270
- name: rubocop-rspec
271
- requirement: !ruby/object:Gem::Requirement
272
- requirements:
273
- - - ">="
274
- - !ruby/object:Gem::Version
275
- version: '3.4'
276
- type: :development
277
- prerelease: false
278
- version_requirements: !ruby/object:Gem::Requirement
279
- requirements:
280
- - - ">="
281
- - !ruby/object:Gem::Version
282
- version: '3.4'
283
283
  - !ruby/object:Gem::Dependency
284
284
  name: simplecov
285
285
  requirement: !ruby/object:Gem::Requirement
@@ -323,9 +323,9 @@ dependencies:
323
323
  - !ruby/object:Gem::Version
324
324
  version: '0.9'
325
325
  description: A delightful Ruby way to work with AI language models. Provides a unified
326
- interface to OpenAI and Anthropic models with automatic token counting, proper streaming
327
- support, and a focus on developer happiness. No wrapping your head around multiple
328
- APIs - just clean Ruby code that works.
326
+ interface to OpenAI, Anthropic, Google, and DeepSeek models with automatic token
327
+ counting, proper streaming support, and a focus on developer happiness. No wrapping
328
+ your head around multiple APIs - just clean Ruby code that works.
329
329
  email:
330
330
  - carmine@paolino.me
331
331
  executables: []