gemini_cache 0.0.12 → 0.0.13

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: c7e9a54d31ede523084b82ed3d94912bcbbd33ac2f0452bbc0a87d22ddc3d749
4
- data.tar.gz: 7ca621fad09fc18f1a87938d2a42b289841ed7c9a6eaadd290869af4cd132613
3
+ metadata.gz: ebf54e6bff38c64454e4914eb2523b8e7f31afdc8679047a7f6d98cde885fea1
4
+ data.tar.gz: 2018cfa7beac9143381785b9bbabec1eb4df0f4d9faafd0dfc4b7c7900376511
5
5
  SHA512:
6
- metadata.gz: 7281d91213fa3b6243e6013e352653b89e15c0be1545ad62c11c97f3259f7afcdb673ffd82d9130c3fd61087ef555844ebe35f684c5ebb0ccd1e9fa0a9a65f7f
7
- data.tar.gz: 9648a180a9c48e3ddddc52d3006603b9a8b8f418712474311c578660d8c329ceb4ca5ee23f89ab6262eb4058818e2289910dc58979702662852d50aa3ed2a85f
6
+ metadata.gz: 79d93c0baad884c33cfef53b53e6e486c0942ce8e68cddd045dfdfcbbfe6ff9e7bec404e37a56778d756af0a86a1c4cb450eaffd04d9892bcdf449a4f0b9c7b2
7
+ data.tar.gz: b330e9737286d3997eda16126b6bc2c20e906b4825686e1e7f3d1e4530c621db534bc52d25b3899e6ac8ba96c341d6db2a7f7f964bb9b1060e118218a5f08967
data/README.md CHANGED
@@ -148,6 +148,20 @@ The methods use configurations defined in the `gemini_cache/configuration` modul
148
148
  ## Errors
149
149
  In case of conflicts or API errors, the module raises a custom exception `GeminiCache::Error`.
150
150
 
151
+ ## Examples
152
+
153
+ ```ruby
154
+ require 'gemini_cache'
155
+
156
+ parts = [
157
+ { text: 'Some text' },
158
+ GeminiCache.read_remote_file(url: '<remote_file_url>', mime_type: 'application/pdf'),
159
+ GeminiCache.read_webpage_text(url: '<webpage url>')
160
+ ]
161
+
162
+ cache = GeminiCache.create parts: parts, display_name: 'mycache'
163
+ ```
164
+
151
165
  ## Conclusion
152
166
  This documentation covers the main functionalities of the `GeminiCache` module. For more details on specific configurations, refer to the source code or official documentation.
153
167
 
@@ -52,7 +52,12 @@ module GeminiCache
52
52
  def handle_response(response)
53
53
  return JSON.parse(response.body) if response.status == 200
54
54
 
55
- error_message = JSON.parse(response.body)['error'] rescue response.body
55
+ error_message = begin
56
+ JSON.parse(response.body)['error']
57
+ rescue
58
+ response.body
59
+ end
60
+
56
61
  raise ApiError, "API request failed (#{response.status}): #{error_message}"
57
62
  rescue Faraday::Error => e
58
63
  raise ApiError, "Network error: #{e.message}"
@@ -1,21 +1,20 @@
1
1
  module GeminiCache
2
2
  class Configuration
3
- attr_accessor :api_key, :api_base_url, :default_model, :default_ttl
3
+ attr_accessor :api_key, :api_base_url, :default_model, :default_ttl, :default_timeout
4
4
 
5
5
  def initialize
6
6
  @api_base_url = 'https://generativelanguage.googleapis.com'
7
- @default_model = 'gemini-1.5-flash-8b'
7
+ @default_model = 'gemini-flash-lite-latest'
8
8
  @default_ttl = 300
9
+ @default_timeout = 300
9
10
  end
10
11
  end
11
12
 
12
- class << self
13
- def configuration
14
- @configuration ||= Configuration.new
15
- end
13
+ def self.configuration
14
+ @configuration ||= Configuration.new
15
+ end
16
16
 
17
- def configure
18
- yield(configuration)
19
- end
17
+ def self.configure
18
+ yield configuration
20
19
  end
21
20
  end
@@ -1,11 +1,9 @@
1
- # frozen_string_literal: true
2
-
3
1
  module ItemExtender
4
- GEMINI_API_BASE_URL = 'https://generativelanguage.googleapis.com'
5
- DEFAULT_TIMEOUT = 300 # seconds
6
2
  ACCURATE_MODE_CONFIG = { temperature: 0, topP: 0, topK: 1 }.freeze
7
3
 
8
- def delete = GeminiCache.delete(name: self['name'])
4
+ def delete
5
+ GeminiCache.delete(name: self['name'])
6
+ end
9
7
 
10
8
  def ttl=(new_ttl)
11
9
  GeminiCache.update(name: self['name'], content: { ttl: "#{new_ttl}s" }.to_json)
@@ -23,7 +21,7 @@ module ItemExtender
23
21
  end
24
22
 
25
23
  def single_prompt(prompt:, generation_config: :accurate_mode)
26
- config = generation_config.eql?(:accurate_mode) ? ACCURATE_MODE_CONFIG : generation_config
24
+ config = generation_config == :accurate_mode ? ACCURATE_MODE_CONFIG : generation_config
27
25
 
28
26
  generate_content(
29
27
  contents: [{ parts: [{ text: prompt }], role: 'user' }],
@@ -34,12 +32,15 @@ module ItemExtender
34
32
  private
35
33
 
36
34
  def api_client
37
- @api_client ||= Faraday.new(
38
- url: GEMINI_API_BASE_URL,
39
- headers: { 'Content-Type' => 'application/json' }
40
- ) do |f|
41
- f.options.timeout = DEFAULT_TIMEOUT
42
- f.options.open_timeout = DEFAULT_TIMEOUT
35
+ @api_client ||= begin
36
+ timeout = GeminiCache.configuration.default_timeout
37
+ Faraday.new(
38
+ url: GeminiCache.configuration.api_base_url,
39
+ headers: { 'Content-Type' => 'application/json' }
40
+ ) do |f|
41
+ f.options.timeout = timeout
42
+ f.options.open_timeout = timeout
43
+ end
43
44
  end
44
45
  end
45
46
 
@@ -50,8 +51,8 @@ module ItemExtender
50
51
  def build_request_body(contents, generation_config)
51
52
  {
52
53
  cached_content: self['name'],
53
- contents: contents,
54
- generation_config: generation_config
54
+ contents:,
55
+ generation_config:
55
56
  }.compact.to_json
56
57
  end
57
58
 
data/lib/gemini_cache.rb CHANGED
@@ -11,76 +11,88 @@ require 'gemini_cache/item_extender'
11
11
  module GeminiCache
12
12
  class Error < StandardError; end
13
13
 
14
- class << self
15
- def parse_html(url:, default_remover: true)
16
- doc = Nokogiri::HTML(URI.open(url, "User-Agent" => "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"))
17
- %w[script style].each { |element| doc.css(element).each(&:remove) } if default_remover
18
- doc
19
- end
14
+ def self.parse_html(url:, default_remover: true)
15
+ doc = Nokogiri::HTML(URI.open(url, 'User-Agent' => 'Mozilla/5.0'))
16
+ %w[script style].each { doc.css(it).remove } if default_remover
17
+ doc
18
+ end
20
19
 
21
- def read_local_file(path:, mime_type:)
22
- { inline_data: { mime_type:, data: Base64.strict_encode64(File.read(path)) } }
23
- end
20
+ def self.read_local_file(path:, mime_type:)
21
+ { inline_data: { mime_type:, data: Base64.strict_encode64(File.read(path)) } }
22
+ end
24
23
 
25
- def read_remote_file(url:, mime_type:)
26
- { inline_data: { mime_type:, data: Base64.strict_encode64(URI.open(url).read) } }
27
- end
24
+ def self.read_remote_file(url:, mime_type:)
25
+ { inline_data: { mime_type:, data: Base64.strict_encode64(URI.open(url).read) } }
26
+ end
28
27
 
29
- def read_webpage_text(url:, default_remover: true) = { text: parse_html(url:, default_remover:).inner_text }
30
-
31
- def create(parts:, display_name:, on_conflict: :raise_error, model: nil, ttl: nil)
32
- existing_cache = find_by_display_name(display_name:)
33
-
34
- if existing_cache
35
- case on_conflict
36
- when :raise_error
37
- raise Error, "Cache with display name '#{display_name}' already exists"
38
- when :get_existing
39
- return existing_cache
40
- end
41
- end
42
-
43
- content = {
44
- model: "models/#{model || configuration.default_model}",
45
- display_name: display_name,
46
- contents: [{ parts:, role: 'user' }],
47
- ttl: "#{ttl || configuration.default_ttl}s"
48
- }
49
-
50
- response = api_client.create_cache(content.to_json)
51
- find_by_name(name: response['name'])
52
- end
28
+ def self.read_webpage_text(url:, default_remover: true)
29
+ { text: parse_html(url:, default_remover:).inner_text }
30
+ end
53
31
 
54
- def create_from_text(text:, **options) = create(parts: [{ text: }], **options)
55
- def create_from_webpage(url:, **options) = create_from_text(text: read_webpage_text(url:)[:text], **options)
56
- def create_from_local_file(path:, mime_type:, **options)
57
- file_data = read_local_file(path: path, mime_type: mime_type)
58
- create(parts: [file_data], **options)
32
+ def self.create(parts:, display_name:, on_conflict: :raise_error, model: nil, ttl: nil)
33
+ existing_cache = find_by_display_name(display_name:)
34
+
35
+ if existing_cache
36
+ return existing_cache if on_conflict == :get_existing
37
+ raise Error, "Cache with display name '#{display_name}' already exists" if on_conflict == :raise_error
59
38
  end
60
39
 
61
- def create_from_remote_file(url:, mime_type:, **options)
62
- file_data = read_remote_file(url: url, mime_type: mime_type)
63
- create(parts: [file_data], **options)
64
- end
40
+ content = {
41
+ model: "models/#{model || configuration.default_model}",
42
+ display_name:,
43
+ contents: [{ parts:, role: 'user' }],
44
+ ttl: "#{ttl || configuration.default_ttl}s"
45
+ }
65
46
 
66
- def list
67
- response = api_client.list_caches
68
- return [] if response.empty?
47
+ response = api_client.create_cache(content.to_json)
48
+ find_by_name(name: response['name'])
49
+ end
69
50
 
70
- response['cachedContents'].map { |item| item.extend(ItemExtender) }
71
- end
51
+ def self.create_from_text(text:, **options)
52
+ create(parts: [{ text: }], **options)
53
+ end
72
54
 
73
- def find_by_name(name:) = list.find { |item| item['name'].eql?(name) }
74
- def find_by_display_name(display_name:) = list.find { |item| item['displayName'].eql?(display_name) }
55
+ def self.create_from_webpage(url:, **options)
56
+ create_from_text(text: read_webpage_text(url:)[:text], **options)
57
+ end
75
58
 
76
- def update(name:, content:) = api_client.update_cache(name, content)
59
+ def self.create_from_local_file(path:, mime_type:, **options)
60
+ create(parts: [read_local_file(path:, mime_type:)], **options)
61
+ end
77
62
 
78
- def delete(name:)
79
- api_client.delete_cache(name)
80
- true
81
- end
63
+ def self.create_from_remote_file(url:, mime_type:, **options)
64
+ create(parts: [read_remote_file(url:, mime_type:)], **options)
65
+ end
66
+
67
+ def self.list
68
+ response = api_client.list_caches
69
+ return [] if response.empty?
70
+
71
+ response['cachedContents'].map { it.extend(ItemExtender) }
72
+ end
73
+
74
+ def self.find_by_name(name:)
75
+ list.find { it['name'] == name }
76
+ end
77
+
78
+ def self.find_by_display_name(display_name:)
79
+ list.find { it['displayName'] == display_name }
80
+ end
82
81
 
83
- def delete_all() = list.each { |item| item.delete }
82
+ def self.update(name:, content:)
83
+ api_client.update_cache(name, content)
84
+ end
85
+
86
+ def self.delete(name:)
87
+ api_client.delete_cache(name)
88
+ true
89
+ end
90
+
91
+ def self.delete_all
92
+ list.each(&:delete)
93
+ end
94
+
95
+ class << self
84
96
  alias clear delete_all
85
97
 
86
98
  private
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gemini_cache
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.12
4
+ version: 0.0.13
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gedean Dias
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2025-01-06 00:00:00.000000000 Z
10
+ date: 2025-09-29 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: faraday
@@ -80,7 +80,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
80
80
  - !ruby/object:Gem::Version
81
81
  version: '0'
82
82
  requirements: []
83
- rubygems_version: 3.6.2
83
+ rubygems_version: 3.7.2
84
84
  specification_version: 4
85
85
  summary: Ruby Gemini Context Caching
86
86
  test_files: []