gemini_cache 0.0.7 → 0.0.11
Sign up to get free protection for your applications and to get access to all the features.
- 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 +89 -0
- data/lib/gemini_cache.rb +141 -144
- metadata +34 -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
|
@@ -0,0 +1,89 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ItemExtender
|
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
|
7
|
+
|
8
|
+
# Deletes the cached item
|
9
|
+
# @return [void]
|
10
|
+
def delete
|
11
|
+
GeminiCache.delete(name: self['name'])
|
12
|
+
end
|
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
|
26
|
+
def generate_content(contents:, generation_config: nil)
|
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,
|
55
|
+
headers: { 'Content-Type' => 'application/json' }
|
56
|
+
) do |f|
|
57
|
+
f.options.timeout = DEFAULT_TIMEOUT
|
58
|
+
f.options.open_timeout = DEFAULT_TIMEOUT
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def generate_content_endpoint
|
63
|
+
"/v1beta/models/#{self['model'].split('/').last}:generateContent"
|
64
|
+
end
|
65
|
+
|
66
|
+
def build_request_body(contents, generation_config)
|
67
|
+
{
|
68
|
+
cached_content: self['name'],
|
69
|
+
contents: contents,
|
70
|
+
generation_config: generation_config
|
71
|
+
}.compact.to_json
|
72
|
+
end
|
73
|
+
|
74
|
+
def handle_response(response)
|
75
|
+
return parse_successful_response(response) if response.status == 200
|
76
|
+
|
77
|
+
raise GeminiAPIError, "Content generation failed: #{response.body}"
|
78
|
+
end
|
79
|
+
|
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
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
class GeminiAPIError < StandardError; end
|
data/lib/gemini_cache.rb
CHANGED
@@ -2,174 +2,171 @@ require 'faraday'
|
|
2
2
|
require 'open-uri'
|
3
3
|
require 'nokogiri'
|
4
4
|
require 'json'
|
5
|
-
|
5
|
+
require 'base64'
|
6
|
+
|
7
|
+
require 'gemini_cache/configuration'
|
8
|
+
require 'gemini_cache/api_client'
|
9
|
+
require 'gemini_cache/item_extender'
|
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
|
+
# )
|
6
22
|
module GeminiCache
|
7
|
-
|
8
|
-
|
9
|
-
def self.read_html(url, default_remover: true)
|
10
|
-
doc = Nokogiri::HTML(URI.open(url))
|
11
|
-
%w[script style].each { |element| doc.css(element).each(&:remove) } if default_remover
|
12
|
-
|
13
|
-
doc
|
14
|
-
end
|
23
|
+
# Custom error class for GeminiCache-specific errors
|
24
|
+
class Error < StandardError; end
|
15
25
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
ttl: "#{ttl}s"
|
24
|
-
}.to_json
|
25
|
-
|
26
|
-
conn = Faraday.new(
|
27
|
-
url: 'https://generativelanguage.googleapis.com',
|
28
|
-
headers: { 'Content-Type' => 'application/json' }
|
29
|
-
)
|
30
|
-
|
31
|
-
response = conn.post('/v1beta/cachedContents') do |req|
|
32
|
-
req.params['key'] = ENV.fetch('GEMINI_API_KEY')
|
33
|
-
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)) } }
|
34
33
|
end
|
35
|
-
|
36
|
-
return get(name: JSON.parse(response.body)['name']) if response.status == 200
|
37
|
-
|
38
|
-
raise "Erro ao criar cache: #{response.status} - #{response.body}"
|
39
|
-
rescue Faraday::Error => e
|
40
|
-
raise "Erro na requisição: #{e.message}"
|
41
|
-
end
|
42
34
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
def self.create_from_text(text:, display_name:, model: 'gemini-1.5-flash-8b', ttl: 600)
|
52
|
-
GeminiCache.create(parts: [{ text: }], display_name:, model:, ttl:)
|
53
|
-
end
|
54
|
-
|
55
|
-
def self.create_from_webpage(url:, display_name:, model: 'gemini-1.5-flash-8b', ttl: 600)
|
56
|
-
GeminiCache.create(parts: [{ text: GeminiCache.read_html(url).inner_text }], display_name:, model:, ttl:)
|
57
|
-
end
|
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
|
58
42
|
|
59
|
-
|
60
|
-
|
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
|
61
52
|
|
62
|
-
|
63
|
-
|
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
|
64
72
|
|
65
|
-
|
66
|
-
|
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
|
+
}
|
67
79
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
def self.list
|
72
|
-
conn = Faraday.new(
|
73
|
-
url: 'https://generativelanguage.googleapis.com',
|
74
|
-
headers: { 'Content-Type' => 'application/json' }
|
75
|
-
)
|
76
|
-
|
77
|
-
response = conn.get("/v1beta/cachedContents") do |req|
|
78
|
-
req.params['key'] = ENV.fetch('GEMINI_API_KEY')
|
80
|
+
response = api_client.create_cache(content.to_json)
|
81
|
+
find_by_name(name: response['name'])
|
79
82
|
end
|
80
|
-
|
81
|
-
return [] if JSON.parse(response.body).empty?
|
82
|
-
|
83
|
-
JSON.parse(response.body)['cachedContents'].map do |item|
|
84
|
-
def item.delete = GeminiCache.delete(name: self['name'])
|
85
|
-
def item.set_ttl(ttl = 120) = GeminiCache.update(name: self['name'], content: { ttl: "#{ttl}s" })
|
86
|
-
|
87
|
-
def item.generate_content(contents:, generation_config: nil)
|
88
|
-
conn = Faraday.new(
|
89
|
-
url: 'https://generativelanguage.googleapis.com',
|
90
|
-
headers: { 'Content-Type' => 'application/json' }
|
91
|
-
) do |f|
|
92
|
-
f.options.timeout = 300 # timeout em segundos para a requisição completa
|
93
|
-
f.options.open_timeout = 300 # timeout em segundos para abrir a conexão
|
94
|
-
end
|
95
83
|
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
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
|
100
91
|
|
101
|
-
|
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
|
102
99
|
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
end
|
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
|
113
109
|
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
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)
|
118
|
+
end
|
122
119
|
|
123
|
-
|
124
|
-
|
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?
|
125
125
|
|
126
|
-
item
|
126
|
+
response['cachedContents'].map { |item| item.extend(ItemExtender) }
|
127
127
|
end
|
128
128
|
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
conn = Faraday.new(
|
135
|
-
url: 'https://generativelanguage.googleapis.com',
|
136
|
-
headers: { 'Content-Type' => 'application/json' }
|
137
|
-
)
|
138
|
-
|
139
|
-
response = conn.patch("/v1beta/#{name}") do |req|
|
140
|
-
req.params['key'] = ENV.fetch('GEMINI_API_KEY')
|
141
|
-
req.body = content.to_json
|
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) }
|
142
134
|
end
|
143
135
|
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
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) }
|
141
|
+
end
|
150
142
|
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
)
|
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
|
156
150
|
|
157
|
-
|
158
|
-
|
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
|
159
157
|
end
|
160
158
|
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
159
|
+
# Deletes all caches
|
160
|
+
# @return [void]
|
161
|
+
def delete_all
|
162
|
+
list.each { |item| item.delete }
|
163
|
+
end
|
164
|
+
alias clear delete_all
|
167
165
|
|
168
|
-
|
169
|
-
GeminiCache.list.each { |item| item.delete }
|
170
|
-
end
|
166
|
+
private
|
171
167
|
|
172
|
-
|
173
|
-
|
168
|
+
def api_client
|
169
|
+
@api_client ||= ApiClient.new
|
170
|
+
end
|
174
171
|
end
|
175
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
|
@@ -24,13 +24,45 @@ dependencies:
|
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '2'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: base64
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 0.2.0
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 0.2.0
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: nokogiri
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1'
|
27
55
|
description: Ruby's Gemini Context Caching wrapper
|
28
56
|
email: gedean.dias@gmail.com
|
29
57
|
executables: []
|
30
58
|
extensions: []
|
31
59
|
extra_rdoc_files: []
|
32
60
|
files:
|
61
|
+
- README.md
|
33
62
|
- lib/gemini_cache.rb
|
63
|
+
- lib/gemini_cache/api_client.rb
|
64
|
+
- lib/gemini_cache/configuration.rb
|
65
|
+
- lib/gemini_cache/item_extender.rb
|
34
66
|
homepage: https://github.com/gedean/gemini_cache
|
35
67
|
licenses:
|
36
68
|
- MIT
|