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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ba751abef4a7f8f6f6c856d782c9e43dfcc27cfb64e6d69a6b6b095522fba338
4
- data.tar.gz: 5dbef856507a550b7b739a5d972991ab822f36ca0aafef4bd5576df3b920c9c6
3
+ metadata.gz: 5f3682e46bf67ce3fae20c5e27210eafdadc25338a54eecfec4c9f48a726ce7a
4
+ data.tar.gz: '0393aa11b0f296e72cbd7604be9061ad0186df90cfaeb6d5665b4d77d893d700'
5
5
  SHA512:
6
- metadata.gz: 032fc3e2f78e791b55d82a63c15094eb325f5778ac4232dfb088e38b99bbd2402f9381ed79c12e03051768a2d488719f6be786cc815dd927927320942f2e8800
7
- data.tar.gz: 31944aa6d6cbe592fd98909b465a1521b2049772d9436d09ad1663c9088473e7aae954ad7e224e4393670ca7d4cb7791295adff9be40a0b1536ecb5ab3b3f3cb
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
- def self.read_local_file(file_path) = Base64.strict_encode64(File.read(file_path))
8
- def self.read_remote_file(file_url) = Base64.strict_encode64(URI.open(file_url).read)
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
- def self.create(parts:, display_name:, model: 'gemini-1.5-flash-8b', ttl: 600)
17
- raise "Cache name already exist: '#{display_name}'" if GeminiCache.get(display_name:)
18
-
19
- content = {
20
- model: "models/#{model}",
21
- display_name:,
22
- contents: [parts:, role: 'user'],
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
- def self.get(name: nil, display_name: nil)
44
- raise 'Nome do cache ou display name é obrigatório' if name.nil? && display_name.nil?
45
- raise 'Nome do cache e display name não podem ser informados juntos' if !name.nil? && !display_name.nil?
46
-
47
- return GeminiCache.list.find { |item| item['name'].eql? name } if !name.nil?
48
- return GeminiCache.list.find { |item| item['displayName'].eql? display_name } if !display_name.nil?
49
- end
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
- def self.create_from_local_file(file_path:, mime_type:, display_name:, model: 'gemini-1.5-flash-8b', ttl: 600)
60
- parts = [{ inline_data: { mime_type:, data: GeminiCache.read_local_file(file_path) } }]
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
- GeminiCache.create(parts:, display_name:, model:, ttl:)
63
- end
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
- def self.create_from_remote_file(file_url:, mime_type:, display_name:, model: 'gemini-1.5-flash-8b', ttl: 600)
66
- parts = [{ inline_data: { mime_type:, data: GeminiCache.read_remote_file(file_url) } }]
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
- GeminiCache.create(parts:, display_name:, model:, ttl:)
69
- end
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
- body = {
97
- cached_content: self['name'],
98
- contents:
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
- body[:generation_config] = generation_config if !generation_config.nil?
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
- response = conn.post("/v1beta/models/#{self['model'].split('/').last}:generateContent") do |req|
104
- req.params['key'] = ENV.fetch('GEMINI_API_KEY')
105
- req.body = body.to_json
106
- end
107
-
108
- if response.status == 200
109
- resp = JSON.parse(response.body)
110
- def resp.content = dig('candidates', 0, 'content', 'parts', 0, 'text')
111
- return resp
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
- raise "Erro ao gerar conteúdo: #{response.body}"
115
- rescue Faraday::Error => e
116
- raise "Erro na requisição: #{e.message}"
117
- end
118
-
119
- def item.single_prompt(prompt:, generation_config: :accurate_mode)
120
- # accurate_mode: less creative, more accurate
121
- generation_config = { temperature: 0, topP: 0, topK: 1 } if generation_config.eql?(:accurate_mode)
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
- generate_content(contents: [{ parts: [{ text: prompt }], role: 'user' }], generation_config:).content
124
- end
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
- rescue Faraday::Error => e
130
- raise "Erro na requisição: #{e.message}"
131
- end
132
-
133
- def self.update(name:, content:)
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
- return JSON.parse(response.body) if response.status == 200
145
-
146
- raise "Erro ao atualizar cache: #{response.body}"
147
- rescue Faraday::Error => e
148
- raise "Erro na requisição: #{e.message}"
149
- end
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
- def self.delete(name:)
152
- conn = Faraday.new(
153
- url: 'https://generativelanguage.googleapis.com',
154
- headers: { 'Content-Type' => 'application/json' }
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
- response = conn.delete("/v1beta/#{name}") do |req|
158
- req.params['key'] = ENV.fetch('GEMINI_API_KEY')
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
- return true if response.status == 200
162
-
163
- raise "Erro ao deletar cache: #{response.body}"
164
- rescue Faraday::Error => e
165
- raise "Erro na requisição: #{e.message}"
166
- end
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
- def self.delete_all
169
- GeminiCache.list.each { |item| item.delete }
170
- end
166
+ private
171
167
 
172
- class << self
173
- alias clear delete_all
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.7
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-23 00:00:00.000000000 Z
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