Class: Ask::Providers::Google

Inherits:
Ask::Provider
  • Object
show all
Defined in:
lib/ask/provider/google.rb

Overview

Google Gemini API provider. Also supports Vertex AI via GCP service account auth.

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(config = {}) ⇒ Google

Returns a new instance of Google.



7
8
9
10
11
12
# File 'lib/ask/provider/google.rb', line 7

def initialize(config = {})
  config = normalize_config(config)
  super(config)
  @http = build_http
  @project_id = config.project_id
end

Class Method Details

.capabilitiesObject



61
62
63
# File 'lib/ask/provider/google.rb', line 61

def capabilities
  { chat: true, streaming: true, tool_calls: true, vision: true, structured_output: true, embed: true, file_upload: true }
end

.configuration_optionsObject



64
# File 'lib/ask/provider/google.rb', line 64

def configuration_options; %i[api_key access_token vertex_token project_id api_base]; end

.configuration_requirementsObject



65
# File 'lib/ask/provider/google.rb', line 65

def configuration_requirements; %i[api_key]; end

.slugObject



66
# File 'lib/ask/provider/google.rb', line 66

def slug; "gemini"; end

Instance Method Details

#api_baseObject



14
15
16
# File 'lib/ask/provider/google.rb', line 14

def api_base
  @config.api_base || "https://generativelanguage.googleapis.com/v1beta"
end

#chat(messages, model:, tools: nil, temperature: nil, stream: nil, schema: nil, **params, &block) ⇒ Object



30
31
32
33
34
35
36
37
38
39
# File 'lib/ask/provider/google.rb', line 30

def chat(messages, model:, tools: nil, temperature: nil, stream: nil, schema: nil, **params, &block)
  msgs = messages.is_a?(Ask::Conversation) ? messages.to_a : messages
  payload = build_chat_payload(msgs, model, tools, temperature, stream, schema, **params)
  path = chat_path(model)
  if stream
    chat_stream(path, payload, model, &block)
  else
    chat_nonstream(path, payload, model)
  end
end

#embed(texts, model:) ⇒ Object



41
42
43
44
45
46
47
# File 'lib/ask/provider/google.rb', line 41

def embed(texts, model:)
  texts = Array(texts)
  response = @http.post("models/#{model}:batchEmbedContents") { |r| r.body = { requests: texts.map { |t| { model: "models/#{model}", content: { parts: [{ text: t }] } } } } }
  raise LLM::HTTP.map_error(response.status, response.body, provider: "Google") unless response.success?
  embeddings = response.body.dig("embeddings") || []
  Ask::Result.success(embeddings.map { |e| e["values"] })
end

#headersObject



18
19
20
21
22
23
24
25
26
27
28
# File 'lib/ask/provider/google.rb', line 18

def headers
  h = { "Content-Type" => "application/json" }
  if @config.api_key
    # Gemini uses query param auth by default
  elsif @config.access_token
    h["Authorization"] = "Bearer #{@config.access_token}"
  elsif @config.vertex_token
    h["Authorization"] = "Bearer #{@config.vertex_token}"
  end
  h
end

#list_modelsObject



49
50
51
52
53
# File 'lib/ask/provider/google.rb', line 49

def list_models
  response = @http.get("models") { |r| r.params["key"] = @config.api_key if @config.api_key }
  return [] unless response.success?
  (response.body["models"] || []).map { |m| Ask::ModelInfo.new(id: m["name"].sub("models/", ""), provider: slug) }
end

#parse_error(response) ⇒ Object



55
56
57
58
# File 'lib/ask/provider/google.rb', line 55

def parse_error(response)
  body = response.body rescue nil
  body&.dig("error", "message")
end