gemini_cache 0.0.9 → 0.0.11
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 +145 -0
- data/lib/gemini_cache/api_client.rb +86 -0
- data/lib/gemini_cache/configuration.rb +35 -0
- data/lib/gemini_cache/item_extender.rb +74 -31
- data/lib/gemini_cache.rb +141 -94
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5f3682e46bf67ce3fae20c5e27210eafdadc25338a54eecfec4c9f48a726ce7a
|
4
|
+
data.tar.gz: '0393aa11b0f296e72cbd7604be9061ad0186df90cfaeb6d5665b4d77d893d700'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5caf764b56efeb6234a03248b9dca22d7f84d2a885e7dca10651b80c49c2c390f473db4cd92037965af2f2ee3718cc78565db2bb257963b8137a9504056590ea
|
7
|
+
data.tar.gz: fba129ed606d3c62a5f39149cd2359fd5d6c18d01a978ffee0bff4a3968fc2c9f2f49723ffe6421192399b021e0023d9766fc7601ebf321e9619ea2b54a77834
|
data/README.md
ADDED
@@ -0,0 +1,145 @@
|
|
1
|
+
# GeminiCache
|
2
|
+
|
3
|
+
GeminiCache é uma biblioteca Ruby para interagir com a API de Cache do Google Gemini. Ela fornece uma interface simples para criar, gerenciar e manipular caches de conteúdo para uso com os modelos de IA do Gemini.
|
4
|
+
|
5
|
+
## Instalação
|
6
|
+
|
7
|
+
Adicione esta linha ao Gemfile da sua aplicação:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
gem 'gemini_cache'
|
11
|
+
```
|
12
|
+
|
13
|
+
E então execute:
|
14
|
+
|
15
|
+
```bash
|
16
|
+
$ bundle install
|
17
|
+
```
|
18
|
+
|
19
|
+
Ou instale manualmente:
|
20
|
+
|
21
|
+
```bash
|
22
|
+
$ gem install gemini_cache
|
23
|
+
```
|
24
|
+
|
25
|
+
## Configuração
|
26
|
+
|
27
|
+
Antes de usar a biblioteca, você precisa configurar sua chave de API do Google Gemini. Você pode fazer isso de duas maneiras:
|
28
|
+
|
29
|
+
### 1. Usando variáveis de ambiente
|
30
|
+
|
31
|
+
```bash
|
32
|
+
export GEMINI_API_KEY='sua_chave_api_aqui'
|
33
|
+
```
|
34
|
+
|
35
|
+
### 2. Usando o bloco de configuração
|
36
|
+
|
37
|
+
```ruby
|
38
|
+
GeminiCache.configure do |config|
|
39
|
+
config.api_key = 'sua_chave_api_aqui'
|
40
|
+
config.timeout = 30 # opcional, tempo limite em segundos
|
41
|
+
config.cache_dir = '/path/to/cache' # opcional, diretório para cache local
|
42
|
+
end
|
43
|
+
```
|
44
|
+
|
45
|
+
## Uso Básico
|
46
|
+
|
47
|
+
### Inicializando o Cliente
|
48
|
+
|
49
|
+
```ruby
|
50
|
+
cache = GeminiCache::Client.new
|
51
|
+
```
|
52
|
+
|
53
|
+
### Operações Básicas
|
54
|
+
|
55
|
+
#### Armazenando dados no cache
|
56
|
+
|
57
|
+
```ruby
|
58
|
+
# Armazena um valor com uma chave
|
59
|
+
cache.set('minha_chave', 'meu_valor')
|
60
|
+
|
61
|
+
# Armazena com tempo de expiração (em segundos)
|
62
|
+
cache.set('minha_chave', 'meu_valor', expires_in: 3600)
|
63
|
+
```
|
64
|
+
|
65
|
+
#### Recuperando dados do cache
|
66
|
+
|
67
|
+
```ruby
|
68
|
+
# Recupera um valor
|
69
|
+
valor = cache.get('minha_chave')
|
70
|
+
|
71
|
+
# Recupera com valor padrão se a chave não existir
|
72
|
+
valor = cache.get('minha_chave', default: 'valor_padrao')
|
73
|
+
```
|
74
|
+
|
75
|
+
#### Removendo dados do cache
|
76
|
+
|
77
|
+
```ruby
|
78
|
+
# Remove uma chave específica
|
79
|
+
cache.delete('minha_chave')
|
80
|
+
|
81
|
+
# Limpa todo o cache
|
82
|
+
cache.clear
|
83
|
+
```
|
84
|
+
|
85
|
+
### Uso Avançado
|
86
|
+
|
87
|
+
#### Cache em Lote
|
88
|
+
|
89
|
+
```ruby
|
90
|
+
# Armazena múltiplos valores
|
91
|
+
cache.set_multi({
|
92
|
+
'chave1' => 'valor1',
|
93
|
+
'chave2' => 'valor2'
|
94
|
+
})
|
95
|
+
|
96
|
+
# Recupera múltiplos valores
|
97
|
+
valores = cache.get_multi(['chave1', 'chave2'])
|
98
|
+
```
|
99
|
+
|
100
|
+
#### Cache com Blocos
|
101
|
+
|
102
|
+
```ruby
|
103
|
+
# Executa o bloco apenas se o valor não estiver em cache
|
104
|
+
resultado = cache.fetch('minha_chave') do
|
105
|
+
# código computacionalmente intensivo aqui
|
106
|
+
resultado_computado
|
107
|
+
end
|
108
|
+
```
|
109
|
+
|
110
|
+
## Exemplos de Uso com Gemini AI
|
111
|
+
|
112
|
+
```ruby
|
113
|
+
# Cacheia resultados de chamadas à API do Gemini
|
114
|
+
resposta = cache.fetch('consulta_gemini') do
|
115
|
+
gemini_client.generate_content('Qual é o sentido da vida?')
|
116
|
+
end
|
117
|
+
|
118
|
+
# Cache com namespace para diferentes modelos
|
119
|
+
cache_pro = GeminiCache::Client.new(namespace: 'gemini-pro')
|
120
|
+
cache_vision = GeminiCache::Client.new(namespace: 'gemini-vision')
|
121
|
+
```
|
122
|
+
|
123
|
+
## Tratamento de Erros
|
124
|
+
|
125
|
+
```ruby
|
126
|
+
begin
|
127
|
+
cache.get('minha_chave')
|
128
|
+
rescue GeminiCache::ConnectionError => e
|
129
|
+
puts "Erro de conexão: #{e.message}"
|
130
|
+
rescue GeminiCache::TimeoutError => e
|
131
|
+
puts "Tempo limite excedido: #{e.message}"
|
132
|
+
end
|
133
|
+
```
|
134
|
+
|
135
|
+
## Contribuindo
|
136
|
+
|
137
|
+
1. Faça um fork do projeto
|
138
|
+
2. Crie sua feature branch (`git checkout -b feature/nova-feature`)
|
139
|
+
3. Faça commit das suas alterações (`git commit -am 'Adiciona nova feature'`)
|
140
|
+
4. Faça push para a branch (`git push origin feature/nova-feature`)
|
141
|
+
5. Crie um novo Pull Request
|
142
|
+
|
143
|
+
## Licença
|
144
|
+
|
145
|
+
Esta gem está disponível como código aberto sob os termos da [Licença MIT](https://opensource.org/licenses/MIT).
|
@@ -0,0 +1,86 @@
|
|
1
|
+
module GeminiCache
|
2
|
+
# Client for making HTTP requests to the Gemini API
|
3
|
+
class ApiClient
|
4
|
+
# Error class for API-related errors
|
5
|
+
class ApiError < StandardError; end
|
6
|
+
|
7
|
+
# Initializes a new API client
|
8
|
+
def initialize
|
9
|
+
@conn = Faraday.new(
|
10
|
+
url: GeminiCache.configuration.api_base_url,
|
11
|
+
headers: { 'Content-Type' => 'application/json' }
|
12
|
+
)
|
13
|
+
end
|
14
|
+
|
15
|
+
# Creates a new cache
|
16
|
+
# @param content [String] JSON string of cache content
|
17
|
+
# @return [Hash] API response
|
18
|
+
# @raise [ApiError] if the request fails
|
19
|
+
def create_cache(content)
|
20
|
+
response = @conn.post('/v1beta/cachedContents') do |req|
|
21
|
+
req.params['key'] = api_key
|
22
|
+
req.body = content
|
23
|
+
end
|
24
|
+
|
25
|
+
handle_response(response)
|
26
|
+
end
|
27
|
+
|
28
|
+
# Lists all caches
|
29
|
+
# @return [Hash] API response
|
30
|
+
# @raise [ApiError] if the request fails
|
31
|
+
def list_caches
|
32
|
+
response = @conn.get('/v1beta/cachedContents') do |req|
|
33
|
+
req.params['key'] = api_key
|
34
|
+
end
|
35
|
+
|
36
|
+
handle_response(response)
|
37
|
+
end
|
38
|
+
|
39
|
+
# Updates an existing cache
|
40
|
+
# @param name [String] cache name
|
41
|
+
# @param content [String] JSON string of new content
|
42
|
+
# @return [Hash] API response
|
43
|
+
# @raise [ApiError] if the request fails
|
44
|
+
def update_cache(name, content)
|
45
|
+
response = @conn.patch("/v1beta/#{name}") do |req|
|
46
|
+
req.params['key'] = api_key
|
47
|
+
req.body = content
|
48
|
+
end
|
49
|
+
|
50
|
+
handle_response(response)
|
51
|
+
end
|
52
|
+
|
53
|
+
# Deletes a cache
|
54
|
+
# @param name [String] cache name
|
55
|
+
# @return [Hash] API response
|
56
|
+
# @raise [ApiError] if the request fails
|
57
|
+
def delete_cache(name)
|
58
|
+
response = @conn.delete("/v1beta/#{name}") do |req|
|
59
|
+
req.params['key'] = api_key
|
60
|
+
end
|
61
|
+
|
62
|
+
handle_response(response)
|
63
|
+
end
|
64
|
+
|
65
|
+
private
|
66
|
+
|
67
|
+
# Gets the API key from configuration or environment
|
68
|
+
# @return [String] API key
|
69
|
+
def api_key
|
70
|
+
GeminiCache.configuration.api_key || ENV.fetch('GEMINI_API_KEY')
|
71
|
+
end
|
72
|
+
|
73
|
+
# Handles API responses
|
74
|
+
# @param response [Faraday::Response] HTTP response
|
75
|
+
# @return [Hash] parsed response body
|
76
|
+
# @raise [ApiError] if response status is not 200
|
77
|
+
def handle_response(response)
|
78
|
+
return JSON.parse(response.body) if response.status == 200
|
79
|
+
|
80
|
+
error_message = JSON.parse(response.body)['error'] rescue response.body
|
81
|
+
raise ApiError, "API request failed (#{response.status}): #{error_message}"
|
82
|
+
rescue Faraday::Error => e
|
83
|
+
raise ApiError, "Network error: #{e.message}"
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module GeminiCache
|
2
|
+
# Configuration class for GeminiCache settings
|
3
|
+
# @attr [String] api_key The API key for Gemini API
|
4
|
+
# @attr [String] api_base_url The base URL for the Gemini API
|
5
|
+
# @attr [String] default_model The default model to use
|
6
|
+
# @attr [Integer] default_ttl The default time-to-live in seconds
|
7
|
+
class Configuration
|
8
|
+
attr_accessor :api_key, :api_base_url, :default_model, :default_ttl
|
9
|
+
|
10
|
+
# Initializes a new Configuration with default values
|
11
|
+
def initialize
|
12
|
+
@api_base_url = 'https://generativelanguage.googleapis.com'
|
13
|
+
@default_model = 'gemini-1.5-flash-8b'
|
14
|
+
@default_ttl = 300
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class << self
|
19
|
+
# @return [Configuration] current configuration
|
20
|
+
def configuration
|
21
|
+
@configuration ||= Configuration.new
|
22
|
+
end
|
23
|
+
|
24
|
+
# Configures GeminiCache
|
25
|
+
# @yield [Configuration] configuration object
|
26
|
+
# @example
|
27
|
+
# GeminiCache.configure do |config|
|
28
|
+
# config.api_key = 'your-api-key'
|
29
|
+
# config.default_ttl = 600
|
30
|
+
# end
|
31
|
+
def configure
|
32
|
+
yield(configuration)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -1,46 +1,89 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ItemExtender
|
2
|
-
|
4
|
+
GEMINI_API_BASE_URL = 'https://generativelanguage.googleapis.com'
|
5
|
+
DEFAULT_TIMEOUT = 300 # seconds
|
6
|
+
ACCURATE_MODE_CONFIG = { temperature: 0, topP: 0, topK: 1 }.freeze
|
3
7
|
|
4
|
-
|
5
|
-
|
6
|
-
|
8
|
+
# Deletes the cached item
|
9
|
+
# @return [void]
|
10
|
+
def delete
|
11
|
+
GeminiCache.delete(name: self['name'])
|
7
12
|
end
|
8
13
|
|
14
|
+
# Updates the TTL of the cached item
|
15
|
+
# @param new_ttl [Integer] new TTL value in seconds
|
16
|
+
# @return [void]
|
17
|
+
def ttl=(new_ttl)
|
18
|
+
GeminiCache.update(name: self['name'], content: { ttl: "#{new_ttl}s" }.to_json)
|
19
|
+
end
|
20
|
+
|
21
|
+
# Generates content using the Gemini API
|
22
|
+
# @param contents [Array<Hash>] array of content parts
|
23
|
+
# @param generation_config [Hash, nil] optional generation configuration
|
24
|
+
# @return [Hash] response with added #content method
|
25
|
+
# @raise [GeminiAPIError] when the API request fails
|
9
26
|
def generate_content(contents:, generation_config: nil)
|
10
|
-
|
11
|
-
|
27
|
+
response = api_client.post(generate_content_endpoint) do |req|
|
28
|
+
req.params['key'] = ENV.fetch('GEMINI_API_KEY')
|
29
|
+
req.body = build_request_body(contents, generation_config)
|
30
|
+
end
|
31
|
+
|
32
|
+
handle_response(response)
|
33
|
+
rescue Faraday::Error => e
|
34
|
+
raise GeminiAPIError, "Request failed: #{e.message}"
|
35
|
+
end
|
36
|
+
|
37
|
+
# Generates content from a single prompt
|
38
|
+
# @param prompt [String] the input prompt
|
39
|
+
# @param generation_config [Hash, Symbol] generation configuration or :accurate_mode
|
40
|
+
# @return [String] generated content
|
41
|
+
def single_prompt(prompt:, generation_config: :accurate_mode)
|
42
|
+
config = generation_config.eql?(:accurate_mode) ? ACCURATE_MODE_CONFIG : generation_config
|
43
|
+
|
44
|
+
generate_content(
|
45
|
+
contents: [{ parts: [{ text: prompt }], role: 'user' }],
|
46
|
+
generation_config: config
|
47
|
+
).content
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def api_client
|
53
|
+
@api_client ||= Faraday.new(
|
54
|
+
url: GEMINI_API_BASE_URL,
|
12
55
|
headers: { 'Content-Type' => 'application/json' }
|
13
56
|
) do |f|
|
14
|
-
f.options.timeout =
|
15
|
-
f.options.open_timeout =
|
57
|
+
f.options.timeout = DEFAULT_TIMEOUT
|
58
|
+
f.options.open_timeout = DEFAULT_TIMEOUT
|
16
59
|
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def generate_content_endpoint
|
63
|
+
"/v1beta/models/#{self['model'].split('/').last}:generateContent"
|
64
|
+
end
|
17
65
|
|
18
|
-
|
66
|
+
def build_request_body(contents, generation_config)
|
67
|
+
{
|
19
68
|
cached_content: self['name'],
|
20
|
-
contents:
|
21
|
-
|
69
|
+
contents: contents,
|
70
|
+
generation_config: generation_config
|
71
|
+
}.compact.to_json
|
72
|
+
end
|
22
73
|
|
23
|
-
|
74
|
+
def handle_response(response)
|
75
|
+
return parse_successful_response(response) if response.status == 200
|
24
76
|
|
25
|
-
|
26
|
-
|
27
|
-
req.body = body.to_json
|
28
|
-
end
|
29
|
-
|
30
|
-
if response.status == 200
|
31
|
-
resp = JSON.parse(response.body)
|
32
|
-
def resp.content = dig('candidates', 0, 'content', 'parts', 0, 'text')
|
33
|
-
return resp
|
34
|
-
end
|
77
|
+
raise GeminiAPIError, "Content generation failed: #{response.body}"
|
78
|
+
end
|
35
79
|
|
36
|
-
|
37
|
-
|
38
|
-
|
80
|
+
def parse_successful_response(response)
|
81
|
+
resp = JSON.parse(response.body)
|
82
|
+
def resp.content
|
83
|
+
dig('candidates', 0, 'content', 'parts', 0, 'text')
|
84
|
+
end
|
85
|
+
resp
|
39
86
|
end
|
40
|
-
|
41
|
-
def single_prompt(prompt:, generation_config: :accurate_mode)
|
42
|
-
# accurate_mode: less creative, more accurate
|
43
|
-
generation_config = { temperature: 0, topP: 0, topK: 1 } if generation_config.eql?(:accurate_mode)
|
44
|
-
generate_content(contents: [{ parts: [{ text: prompt }], role: 'user' }], generation_config:).content
|
45
|
-
end
|
46
87
|
end
|
88
|
+
|
89
|
+
class GeminiAPIError < StandardError; end
|
data/lib/gemini_cache.rb
CHANGED
@@ -4,122 +4,169 @@ require 'nokogiri'
|
|
4
4
|
require 'json'
|
5
5
|
require 'base64'
|
6
6
|
|
7
|
+
require 'gemini_cache/configuration'
|
8
|
+
require 'gemini_cache/api_client'
|
7
9
|
require 'gemini_cache/item_extender'
|
8
10
|
|
11
|
+
# Module for interacting with Google's Gemini API cached contents
|
12
|
+
# @example Basic usage
|
13
|
+
# GeminiCache.configure do |config|
|
14
|
+
# config.api_key = 'your-api-key'
|
15
|
+
# end
|
16
|
+
#
|
17
|
+
# # Create a cache from text
|
18
|
+
# cache = GeminiCache.create_from_text(
|
19
|
+
# text: "Hello, world!",
|
20
|
+
# display_name: "my-cache"
|
21
|
+
# )
|
9
22
|
module GeminiCache
|
10
|
-
|
11
|
-
|
12
|
-
def self.read_html(url:, default_remover: true)
|
13
|
-
doc = Nokogiri::HTML(URI.open(url))
|
14
|
-
%w[script style].each { |element| doc.css(element).each(&:remove) } if default_remover
|
23
|
+
# Custom error class for GeminiCache-specific errors
|
24
|
+
class Error < StandardError; end
|
15
25
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
model: "models/#{model}",
|
24
|
-
display_name:,
|
25
|
-
contents: [parts:, role: 'user'],
|
26
|
-
ttl: "#{ttl}s"
|
27
|
-
}.to_json
|
28
|
-
|
29
|
-
conn = Faraday.new(
|
30
|
-
url: 'https://generativelanguage.googleapis.com',
|
31
|
-
headers: { 'Content-Type' => 'application/json' }
|
32
|
-
)
|
33
|
-
|
34
|
-
response = conn.post('/v1beta/cachedContents') do |req|
|
35
|
-
req.params['key'] = ENV.fetch('GEMINI_API_KEY')
|
36
|
-
req.body = content
|
26
|
+
class << self
|
27
|
+
# Reads a local file and prepares it for the Gemini API
|
28
|
+
# @param path [String] path to the local file
|
29
|
+
# @param mime_type [String] MIME type of the file
|
30
|
+
# @return [Hash] formatted data for the API
|
31
|
+
def read_local_file(path:, mime_type:)
|
32
|
+
{ inline_data: { mime_type:, data: Base64.strict_encode64(File.read(path)) } }
|
37
33
|
end
|
38
|
-
|
39
|
-
return get_by_name(name: JSON.parse(response.body)['name']) if response.status == 200
|
40
|
-
|
41
|
-
raise "Erro ao criar cache: #{response.status} - #{response.body}"
|
42
|
-
rescue Faraday::Error => e
|
43
|
-
raise "Erro na requisição: #{e.message}"
|
44
|
-
end
|
45
34
|
|
46
|
-
|
47
|
-
|
48
|
-
|
35
|
+
# Reads a remote file and prepares it for the Gemini API
|
36
|
+
# @param url [String] URL of the remote file
|
37
|
+
# @param mime_type [String] MIME type of the file
|
38
|
+
# @return [Hash] formatted data for the API
|
39
|
+
def read_remote_file(url:, mime_type:)
|
40
|
+
{ inline_data: { mime_type:, data: Base64.strict_encode64(URI.open(url).read) } }
|
41
|
+
end
|
49
42
|
|
50
|
-
|
51
|
-
|
52
|
-
|
43
|
+
# Reads and parses HTML content from a URL
|
44
|
+
# @param url [String] URL of the webpage
|
45
|
+
# @param default_remover [Boolean] whether to remove script and style tags
|
46
|
+
# @return [Nokogiri::HTML::Document] parsed HTML document
|
47
|
+
def read_html(url:, default_remover: true)
|
48
|
+
doc = Nokogiri::HTML(URI.open(url))
|
49
|
+
%w[script style].each { |element| doc.css(element).each(&:remove) } if default_remover
|
50
|
+
doc
|
51
|
+
end
|
53
52
|
|
54
|
-
|
55
|
-
|
56
|
-
|
53
|
+
# Creates a new cache in the Gemini API
|
54
|
+
# @param parts [Array<Hash>] content parts to cache
|
55
|
+
# @param display_name [String] unique display name for the cache
|
56
|
+
# @param on_conflict [:raise_error, :get_existing] action to take if cache exists
|
57
|
+
# @param model [String, nil] Gemini model to use
|
58
|
+
# @param ttl [Integer, nil] time-to-live in seconds
|
59
|
+
# @return [Hash] created cache data
|
60
|
+
# @raise [Error] if cache already exists and on_conflict is :raise_error
|
61
|
+
def create(parts:, display_name:, on_conflict: :raise_error, model: nil, ttl: nil)
|
62
|
+
existing_cache = find_by_display_name(display_name:)
|
63
|
+
|
64
|
+
if existing_cache
|
65
|
+
case on_conflict
|
66
|
+
when :raise_error
|
67
|
+
raise Error, "Cache with display name '#{display_name}' already exists"
|
68
|
+
when :get_existing
|
69
|
+
return existing_cache
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
content = {
|
74
|
+
model: "models/#{model || configuration.default_model}",
|
75
|
+
display_name: display_name,
|
76
|
+
contents: [{ parts:, role: 'user' }],
|
77
|
+
ttl: "#{ttl || configuration.default_ttl}s"
|
78
|
+
}
|
79
|
+
|
80
|
+
response = api_client.create_cache(content.to_json)
|
81
|
+
find_by_name(name: response['name'])
|
82
|
+
end
|
57
83
|
|
58
|
-
|
59
|
-
|
60
|
-
|
84
|
+
# Creates a cache from plain text
|
85
|
+
# @param text [String] text content to cache
|
86
|
+
# @param options [Hash] additional options passed to #create
|
87
|
+
# @return [Hash] created cache data
|
88
|
+
def create_from_text(text:, **options)
|
89
|
+
create(parts: [{ text: }], **options)
|
90
|
+
end
|
61
91
|
|
62
|
-
|
63
|
-
|
92
|
+
# Creates a cache from a webpage's content
|
93
|
+
# @param url [String] URL of the webpage
|
94
|
+
# @param options [Hash] additional options passed to #create
|
95
|
+
# @return [Hash] created cache data
|
96
|
+
def create_from_webpage(url:, **options)
|
97
|
+
create_from_text(text: read_html(url:).inner_text, **options)
|
98
|
+
end
|
64
99
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
100
|
+
# Creates a cache from a local file
|
101
|
+
# @param path [String] path to the local file
|
102
|
+
# @param mime_type [String] MIME type of the file
|
103
|
+
# @param options [Hash] additional options passed to #create
|
104
|
+
# @return [Hash] created cache data
|
105
|
+
def create_from_local_file(path:, mime_type:, **options)
|
106
|
+
file_data = read_local_file(path: path, mime_type: mime_type)
|
107
|
+
create(parts: [file_data], **options)
|
108
|
+
end
|
70
109
|
|
71
|
-
|
72
|
-
|
110
|
+
# Creates a cache from a remote file
|
111
|
+
# @param url [String] URL of the remote file
|
112
|
+
# @param mime_type [String] MIME type of the file
|
113
|
+
# @param options [Hash] additional options passed to #create
|
114
|
+
# @return [Hash] created cache data
|
115
|
+
def create_from_remote_file(url:, mime_type:, **options)
|
116
|
+
file_data = read_remote_file(url: url, mime_type: mime_type)
|
117
|
+
create(parts: [file_data], **options)
|
73
118
|
end
|
74
|
-
|
75
|
-
return [] if JSON.parse(response.body).empty?
|
76
119
|
|
77
|
-
|
120
|
+
# Lists all available caches
|
121
|
+
# @return [Array<Hash>] list of caches with ItemExtender mixed in
|
122
|
+
def list
|
123
|
+
response = api_client.list_caches
|
124
|
+
return [] if response.empty?
|
78
125
|
|
79
|
-
|
80
|
-
raise "Erro na requisição: #{e.message}"
|
81
|
-
end
|
82
|
-
|
83
|
-
def self.update(name:, content:)
|
84
|
-
conn = Faraday.new(
|
85
|
-
url: 'https://generativelanguage.googleapis.com',
|
86
|
-
headers: { 'Content-Type' => 'application/json' }
|
87
|
-
)
|
88
|
-
|
89
|
-
response = conn.patch("/v1beta/#{name}") do |req|
|
90
|
-
req.params['key'] = ENV.fetch('GEMINI_API_KEY')
|
91
|
-
req.body = content.to_json
|
126
|
+
response['cachedContents'].map { |item| item.extend(ItemExtender) }
|
92
127
|
end
|
93
128
|
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
def self.delete(name:)
|
102
|
-
conn = Faraday.new(
|
103
|
-
url: 'https://generativelanguage.googleapis.com',
|
104
|
-
headers: { 'Content-Type' => 'application/json' }
|
105
|
-
)
|
129
|
+
# Finds a cache by its internal name
|
130
|
+
# @param name [String] internal name of the cache
|
131
|
+
# @return [Hash, nil] cache data if found, nil otherwise
|
132
|
+
def find_by_name(name:)
|
133
|
+
list.find { |item| item['name'].eql?(name) }
|
134
|
+
end
|
106
135
|
|
107
|
-
|
108
|
-
|
136
|
+
# Finds a cache by its display name
|
137
|
+
# @param display_name [String] display name of the cache
|
138
|
+
# @return [Hash, nil] cache data if found, nil otherwise
|
139
|
+
def find_by_display_name(display_name:)
|
140
|
+
list.find { |item| item['displayName'].eql?(display_name) }
|
109
141
|
end
|
110
142
|
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
143
|
+
# Updates an existing cache
|
144
|
+
# @param name [String] internal name of the cache
|
145
|
+
# @param content [Hash] new content for the cache
|
146
|
+
# @return [Hash] updated cache data
|
147
|
+
def update(name:, content:)
|
148
|
+
api_client.update_cache(name, content)
|
149
|
+
end
|
117
150
|
|
118
|
-
|
119
|
-
|
120
|
-
|
151
|
+
# Deletes a specific cache
|
152
|
+
# @param name [String] internal name of the cache to delete
|
153
|
+
# @return [Boolean] true if successful
|
154
|
+
def delete(name:)
|
155
|
+
api_client.delete_cache(name)
|
156
|
+
true
|
157
|
+
end
|
121
158
|
|
122
|
-
|
159
|
+
# Deletes all caches
|
160
|
+
# @return [void]
|
161
|
+
def delete_all
|
162
|
+
list.each { |item| item.delete }
|
163
|
+
end
|
123
164
|
alias clear delete_all
|
165
|
+
|
166
|
+
private
|
167
|
+
|
168
|
+
def api_client
|
169
|
+
@api_client ||= ApiClient.new
|
170
|
+
end
|
124
171
|
end
|
125
172
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
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.11
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Gedean Dias
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-11-
|
11
|
+
date: 2024-11-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: faraday
|
@@ -58,7 +58,10 @@ executables: []
|
|
58
58
|
extensions: []
|
59
59
|
extra_rdoc_files: []
|
60
60
|
files:
|
61
|
+
- README.md
|
61
62
|
- lib/gemini_cache.rb
|
63
|
+
- lib/gemini_cache/api_client.rb
|
64
|
+
- lib/gemini_cache/configuration.rb
|
62
65
|
- lib/gemini_cache/item_extender.rb
|
63
66
|
homepage: https://github.com/gedean/gemini_cache
|
64
67
|
licenses:
|