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 +4 -4
- data/README.md +14 -0
- data/lib/gemini_cache/api_client.rb +6 -1
- data/lib/gemini_cache/configuration.rb +8 -9
- data/lib/gemini_cache/item_extender.rb +15 -14
- data/lib/gemini_cache.rb +70 -58
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ebf54e6bff38c64454e4914eb2523b8e7f31afdc8679047a7f6d98cde885fea1
|
4
|
+
data.tar.gz: 2018cfa7beac9143381785b9bbabec1eb4df0f4d9faafd0dfc4b7c7900376511
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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 =
|
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-
|
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
|
-
|
13
|
-
|
14
|
-
|
15
|
-
end
|
13
|
+
def self.configuration
|
14
|
+
@configuration ||= Configuration.new
|
15
|
+
end
|
16
16
|
|
17
|
-
|
18
|
-
|
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
|
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
|
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 ||=
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
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
|
54
|
-
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
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
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
|
-
|
22
|
-
|
23
|
-
|
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
|
-
|
26
|
-
|
27
|
-
|
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
|
-
|
30
|
-
|
31
|
-
|
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
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
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
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
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
|
-
|
67
|
-
|
68
|
-
|
47
|
+
response = api_client.create_cache(content.to_json)
|
48
|
+
find_by_name(name: response['name'])
|
49
|
+
end
|
69
50
|
|
70
|
-
|
71
|
-
|
51
|
+
def self.create_from_text(text:, **options)
|
52
|
+
create(parts: [{ text: }], **options)
|
53
|
+
end
|
72
54
|
|
73
|
-
|
74
|
-
|
55
|
+
def self.create_from_webpage(url:, **options)
|
56
|
+
create_from_text(text: read_webpage_text(url:)[:text], **options)
|
57
|
+
end
|
75
58
|
|
76
|
-
|
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
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
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
|
-
|
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.
|
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-
|
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.
|
83
|
+
rubygems_version: 3.7.2
|
84
84
|
specification_version: 4
|
85
85
|
summary: Ruby Gemini Context Caching
|
86
86
|
test_files: []
|