ruby_llm 0.1.0.pre40 → 0.1.0.pre41

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: db95ae0d7103334e7760659d58200e1cc882b970a2d3f67f56180a9879bad976
4
- data.tar.gz: f2a95fb00c476cbea2bf060ff5502c4fb61ed2d652578133cf7eee6ff4c7297f
3
+ metadata.gz: e6a58fa5d1286364224b46aced4e7150aa935988ca5e6a5f5a12d760da76c214
4
+ data.tar.gz: 7d24ed72b786fea8b030191e796facd27c6ac6d45efe499ea2a25d3a5d01fab1
5
5
  SHA512:
6
- metadata.gz: 3a3624f1c5d8184d5f36aca807528b4bc627a66aebe3829ff9e90bb62348a12863b764352d4b466931c0ef3469c1d952832a1b7726f93231b72324b13228ffb1
7
- data.tar.gz: 4bef0ae0373be0c2cd8d4702ddfc2f7a76883fe7c60e5ae5ef501c6f808744328919fba3f16dedf075d6f1cb1585120f46103415579a046306fd1a4d1c81f20b
6
+ metadata.gz: 293c57036acd3a7b0b5fdeda7866d0bf1599f52138aeac058bb248bc53d4b687caff047ab84aa57b1b50ae034e8cfb25729bd1e027af3febd1c50ce640bebf44
7
+ data.tar.gz: 762c75a2d0e7dc02829c2b7d7171c6fc57932656c72890ca0d1656fefc7d9d5cfa5989726ee40fa3b5d63cac81b1a2dc66c0439cb487272e70288718d993c21e
data/.rspec_status CHANGED
@@ -7,6 +7,8 @@ example_id | status | run_time |
7
7
  ./spec/ruby_llm/chat_content_spec.rb[1:1:3] | passed | 2.54 seconds |
8
8
  ./spec/ruby_llm/chat_content_spec.rb[1:2:1] | passed | 2.77 seconds |
9
9
  ./spec/ruby_llm/chat_content_spec.rb[1:2:2] | passed | 2.1 seconds |
10
+ ./spec/ruby_llm/chat_pdf_spec.rb[1:1:1] | passed | 7.75 seconds |
11
+ ./spec/ruby_llm/chat_pdf_spec.rb[1:1:2] | passed | 13.88 seconds |
10
12
  ./spec/ruby_llm/chat_spec.rb[1:1:1:1] | passed | 1.02 seconds |
11
13
  ./spec/ruby_llm/chat_spec.rb[1:1:1:2] | passed | 3.95 seconds |
12
14
  ./spec/ruby_llm/chat_spec.rb[1:1:2:1] | passed | 0.4854 seconds |
data/README.md CHANGED
@@ -16,7 +16,6 @@ A delightful Ruby way to work with AI. Chat in text, analyze and generate images
16
16
  <a href="https://badge.fury.io/rb/ruby_llm"><img src="https://badge.fury.io/rb/ruby_llm.svg" alt="Gem Version" /></a>
17
17
  <a href="https://github.com/testdouble/standard"><img src="https://img.shields.io/badge/code_style-standard-brightgreen.svg" alt="Ruby Style Guide" /></a>
18
18
  <a href="https://rubygems.org/gems/ruby_llm"><img alt="Gem Total Downloads" src="https://img.shields.io/gem/dt/ruby_llm"></a>
19
- <a href="https://github.com/crmne/ruby_llm/actions/workflows/cicd.yml"><img src="https://github.com/crmne/ruby_llm/actions/workflows/cicd.yml/badge.svg" alt="CI" /></a>
20
19
  <a href="https://codecov.io/gh/crmne/ruby_llm"><img src="https://codecov.io/gh/crmne/ruby_llm/branch/main/graph/badge.svg" alt="codecov" /></a>
21
20
  </p>
22
21
 
@@ -25,6 +24,7 @@ A delightful Ruby way to work with AI. Chat in text, analyze and generate images
25
24
  ## Features
26
25
 
27
26
  - 💬 **Beautiful Chat Interface** - Converse with AI models as easily as `RubyLLM.chat.ask "teach me Ruby"`
27
+ - 📄 **PDF Analysis** - Analyze PDF documents directly with Claude models using `chat.ask "What's in this?", with: { pdf: "document.pdf" }`
28
28
  - 🎵 **Audio Analysis** - Get audio transcription and understanding with `chat.ask "what's said here?", with: { audio: "clip.wav" }`
29
29
  - 👁️ **Vision Understanding** - Let AIs analyze images with a simple `chat.ask "what's in this?", with: { image: "photo.jpg" }`
30
30
  - 🌊 **Streaming** - Real-time responses with proper Ruby streaming with `chat.ask "hello" do |chunk| puts chunk.content end`
@@ -116,6 +116,13 @@ chat.ask "What's being said in this recording?", with: { audio: "meeting.wav" }
116
116
  # Combine multiple pieces of content
117
117
  chat.ask "Compare these diagrams", with: { image: ["diagram1.png", "diagram2.png"] }
118
118
 
119
+ # Ask about PDFs (currently supported with Claude models)
120
+ chat = RubyLLM.chat(model: 'claude-3-7-sonnet-20250219')
121
+ chat.ask "Summarize this research paper", with: { pdf: "research.pdf" }
122
+
123
+ # Multiple PDFs work too
124
+ chat.ask "Compare these contracts", with: { pdf: ["contract1.pdf", "contract2.pdf"] }
125
+
119
126
  # Check token usage
120
127
  last_message = chat.messages.last
121
128
  puts "Conversation used #{last_message.input_tokens} input tokens and #{last_message.output_tokens} output tokens"
@@ -5,7 +5,7 @@ module RubyLLM
5
5
  # Stores data in a standard internal format, letting providers
6
6
  # handle their own formatting needs.
7
7
  class Content
8
- def initialize(text = nil, attachments = {})
8
+ def initialize(text = nil, attachments = {}) # rubocop:disable Metrics/AbcSize,Metrics/MethodLength
9
9
  @parts = []
10
10
  @parts << { type: 'text', text: text } unless text.nil? || text.empty?
11
11
 
@@ -16,6 +16,10 @@ module RubyLLM
16
16
  Array(attachments[:audio]).each do |source|
17
17
  @parts << attach_audio(source)
18
18
  end
19
+
20
+ Array(attachments[:pdf]).each do |source|
21
+ @parts << attach_pdf(source)
22
+ end
19
23
  end
20
24
 
21
25
  def to_a
@@ -64,6 +68,33 @@ module RubyLLM
64
68
  }
65
69
  end
66
70
 
71
+ def attach_pdf(source) # rubocop:disable Metrics/AbcSize,Metrics/MethodLength
72
+ source = File.expand_path(source) unless source.start_with?('http')
73
+
74
+ pdf_data = {
75
+ type: 'pdf',
76
+ source: source
77
+ }
78
+
79
+ # For local files, validate they exist
80
+ unless source.start_with?('http')
81
+ raise Error, "PDF file not found: #{source}" unless File.exist?(source)
82
+
83
+ # Simple check for PDF file type (could be more robust)
84
+ unless source.downcase.end_with?('.pdf') || File.read(source, 5) == '%PDF-'
85
+ RubyLLM.logger.warn "File may not be a valid PDF: #{source}"
86
+ end
87
+
88
+ # Preload file content for providers that need it
89
+ pdf_data[:content] = File.read(source)
90
+ end
91
+
92
+ pdf_data
93
+ rescue StandardError => e
94
+ RubyLLM.logger.error "Error attaching PDF #{source}: #{e.message}"
95
+ raise Error, "Failed to attach PDF: #{e.message}"
96
+ end
97
+
67
98
  def encode_file(source)
68
99
  if source.start_with?('http')
69
100
  response = Faraday.get(source)
@@ -62,7 +62,7 @@ module RubyLLM
62
62
  def format_basic_message(msg)
63
63
  {
64
64
  role: convert_role(msg.role),
65
- content: msg.content
65
+ content: Media.format_content(msg.content)
66
66
  }
67
67
  end
68
68
 
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyLLM
4
+ module Providers
5
+ module Anthropic
6
+ # Handles formatting of media content (images, PDFs, audio) for Anthropic
7
+ module Media
8
+ module_function
9
+
10
+ def format_content(content) # rubocop:disable Metrics/MethodLength
11
+ return content unless content.is_a?(Array)
12
+
13
+ content.map do |part|
14
+ case part[:type]
15
+ when 'image'
16
+ format_image(part)
17
+ when 'pdf'
18
+ format_pdf(part)
19
+ when 'text'
20
+ format_text_block(part[:text])
21
+ else
22
+ part
23
+ end
24
+ end
25
+ end
26
+
27
+ def format_image(part)
28
+ # Handle image formatting for Anthropic
29
+ # This is just a placeholder - implement based on Anthropic's requirements
30
+ part
31
+ end
32
+
33
+ def format_pdf(part) # rubocop:disable Metrics/MethodLength
34
+ source = part[:source]
35
+
36
+ if source.start_with?('http')
37
+ # For URLs
38
+ {
39
+ type: 'document',
40
+ source: { url: source }
41
+ }
42
+ else
43
+ # For local files
44
+ data = Base64.strict_encode64(part[:content])
45
+
46
+ {
47
+ type: 'document',
48
+ source: {
49
+ type: 'base64',
50
+ media_type: 'application/pdf',
51
+ data: data
52
+ }
53
+ }
54
+ end
55
+ end
56
+
57
+ def format_text_block(text)
58
+ {
59
+ type: 'text',
60
+ text: text
61
+ }
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
@@ -8,6 +8,7 @@ module RubyLLM
8
8
  extend Provider
9
9
  extend Anthropic::Chat
10
10
  extend Anthropic::Embeddings
11
+ extend Anthropic::Media
11
12
  extend Anthropic::Models
12
13
  extend Anthropic::Streaming
13
14
  extend Anthropic::Tools
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RubyLLM
4
- VERSION = '0.1.0.pre40'
4
+ VERSION = '0.1.0.pre41'
5
5
  end
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: 0.1.0.pre40
4
+ version: 0.1.0.pre41
5
5
  platform: ruby
6
6
  authors:
7
7
  - Carmine Paolino
@@ -129,6 +129,7 @@ files:
129
129
  - lib/ruby_llm/providers/anthropic/capabilities.rb
130
130
  - lib/ruby_llm/providers/anthropic/chat.rb
131
131
  - lib/ruby_llm/providers/anthropic/embeddings.rb
132
+ - lib/ruby_llm/providers/anthropic/media.rb
132
133
  - lib/ruby_llm/providers/anthropic/models.rb
133
134
  - lib/ruby_llm/providers/anthropic/streaming.rb
134
135
  - lib/ruby_llm/providers/anthropic/tools.rb