ruby_llm 0.1.0.pre39 → 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 +4 -4
- data/.rspec_status +2 -0
- data/README.md +8 -1
- data/lib/ruby_llm/content.rb +32 -1
- data/lib/ruby_llm/provider.rb +11 -2
- data/lib/ruby_llm/providers/anthropic/chat.rb +1 -1
- data/lib/ruby_llm/providers/anthropic/media.rb +66 -0
- data/lib/ruby_llm/providers/anthropic.rb +1 -0
- data/lib/ruby_llm/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e6a58fa5d1286364224b46aced4e7150aa935988ca5e6a5f5a12d760da76c214
|
4
|
+
data.tar.gz: 7d24ed72b786fea8b030191e796facd27c6ac6d45efe499ea2a25d3a5d01fab1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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"
|
data/lib/ruby_llm/content.rb
CHANGED
@@ -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)
|
data/lib/ruby_llm/provider.rb
CHANGED
@@ -143,11 +143,20 @@ module RubyLLM
|
|
143
143
|
maybe_json
|
144
144
|
end
|
145
145
|
|
146
|
-
def parse_error(response)
|
146
|
+
def parse_error(response) # rubocop:disable Metrics/MethodLength
|
147
147
|
return if response.body.empty?
|
148
148
|
|
149
149
|
body = try_parse_json(response.body)
|
150
|
-
|
150
|
+
case body
|
151
|
+
when Hash
|
152
|
+
body.dig('error', 'message')
|
153
|
+
when Array
|
154
|
+
body.map do |part|
|
155
|
+
part.dig('error', 'message')
|
156
|
+
end.join('. ')
|
157
|
+
else
|
158
|
+
body
|
159
|
+
end
|
151
160
|
end
|
152
161
|
|
153
162
|
class << self
|
@@ -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
|
data/lib/ruby_llm/version.rb
CHANGED
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.
|
4
|
+
version: 0.1.0.pre41
|
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-
|
11
|
+
date: 2025-02-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: event_stream_parser
|
@@ -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
|