Class: Gemini::Response
- Inherits:
-
Object
- Object
- Gemini::Response
- Defined in:
- lib/gemini/response.rb
Instance Attribute Summary collapse
-
#raw_data ⇒ Object
readonly
Raw response data from API.
Instance Method Summary collapse
- #as_json_array(model_class) ⇒ Object
- #as_json_object(model_class) ⇒ Object
- #as_json_with_keys(*keys) ⇒ Object
-
#audio_data ⇒ Object
Base64-encoded audio data from a TTS response.
-
#audio_mime_type ⇒ Object
MIME type of the audio payload (e.g. “audio/L16;codec=pcm;rate=24000”).
-
#audio_part ⇒ Object
Get the first audio inlineData part (TTS responses use camelCase “inlineData”).
-
#audio_response? ⇒ Boolean
True if the response contains audio inlineData.
-
#build_function_call_parts_with_signature ⇒ Object
関数呼び出しにSignatureを付与してパーツを構築.
-
#cached_content_token_count ⇒ Object
Cached content token count reported by countTokens.
-
#candidates ⇒ Object
Get all candidates (if multiple candidates are present).
-
#completion_tokens ⇒ Object
Get number of tokens used for completion.
-
#count_tokens ⇒ Object
Total tokens reported by the countTokens API (top-level totalTokens).
-
#count_tokens_response? ⇒ Boolean
Check whether this response is a countTokens API result.
-
#embedding ⇒ Object
Get the embedding values as an Array of Floats.
-
#embedding_dimension ⇒ Object
Get the dimensionality (length) of the first embedding vector.
-
#embedding_response? ⇒ Boolean
Check if the raw response contains embedding data.
-
#embeddings ⇒ Object
Get all embedding value arrays for batch responses.
-
#error ⇒ Object
Get error message if any.
-
#finish_reason ⇒ Object
Get finish reason (STOP, SAFETY, etc.).
-
#first_candidate ⇒ Object
Get the first candidate.
-
#first_thought_signature ⇒ Object
最初のThought Signatureを取得.
-
#formatted_text ⇒ Object
Get formatted text (HTML/markdown, etc.).
-
#full_content ⇒ Object
Get all content with string representation.
-
#function_calls ⇒ Object
Get function call information.
-
#gemini_3? ⇒ Boolean
Gemini 3系かどうか.
-
#grounded? ⇒ Boolean
Check if response has grounding metadata.
-
#grounding_chunks ⇒ Object
Get grounding chunks (source references).
-
#grounding_metadata ⇒ Object
Get grounding metadata (for Google Search grounding).
-
#grounding_sources ⇒ Object
Get formatted grounding sources (simplified access).
-
#has_thought_signature? ⇒ Boolean
Signatureが存在するか.
-
#image ⇒ Object
画像生成結果から最初の画像を取得(Base64エンコード形式).
-
#image_mime_types ⇒ Object
画像のMIMEタイプを取得.
-
#image_parts ⇒ Object
Get image parts (if any).
-
#image_urls ⇒ Object
Get image URLs from multimodal responses (if any).
-
#images ⇒ Object
画像生成結果からすべての画像を取得(Base64エンコード形式の配列).
-
#initialize(response_data) ⇒ Response
constructor
A new instance of Response.
-
#inspect ⇒ Object
Inspection method for debugging.
- #json ⇒ Object
- #json? ⇒ Boolean
-
#model_version ⇒ Object
モデルバージョンを取得.
-
#parts ⇒ Object
Get all content parts.
-
#prompt_tokens ⇒ Object
Get number of prompt tokens used.
-
#prompt_tokens_details ⇒ Object
Per-modality token breakdown reported by countTokens.
-
#retrieved_urls ⇒ Object
Get retrieved URLs from URL context.
-
#role ⇒ Object
Get response role (usually “model”).
-
#safety_blocked? ⇒ Boolean
Check if response was blocked for safety reasons.
-
#safety_ratings ⇒ Object
Get safety ratings.
-
#save_audio(filepath) ⇒ Object
Save audio to a file.
-
#save_image(filepath) ⇒ Object
最初の画像をファイルに保存.
-
#save_images(filepaths) ⇒ Object
複数の画像をファイルに保存.
-
#search_entry_point ⇒ Object
Get search entry point URL (if available).
-
#stream_chunks ⇒ Object
Process chunks for streaming responses.
-
#success? ⇒ Boolean
Check if response was successful.
-
#text ⇒ Object
Get simple text response (combines multiple parts if present).
-
#text_parts ⇒ Object
Get all text parts as an array.
-
#thought_signatures ⇒ Object
Thought Signatureを取得(配列).
-
#thoughts_token_count ⇒ Object
思考トークン数を取得.
- #to_formatted_json(pretty: false) ⇒ Object
-
#to_s ⇒ Object
Override to_s method to return text.
-
#total_tokens ⇒ Object
Get total tokens used.
-
#url_context? ⇒ Boolean
Check if response has URL context metadata.
-
#url_context_metadata ⇒ Object
Get URL context metadata (for URL Context tool).
-
#url_retrieval_statuses ⇒ Object
Get URL retrieval statuses.
-
#usage ⇒ Object
Get token usage information.
-
#valid? ⇒ Boolean
Check if response is valid.
Constructor Details
#initialize(response_data) ⇒ Response
Returns a new instance of Response.
6 7 8 |
# File 'lib/gemini/response.rb', line 6 def initialize(response_data) @raw_data = response_data end |
Instance Attribute Details
#raw_data ⇒ Object (readonly)
Raw response data from API
4 5 6 |
# File 'lib/gemini/response.rb', line 4 def raw_data @raw_data end |
Instance Method Details
#as_json_array(model_class) ⇒ Object
603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 |
# File 'lib/gemini/response.rb', line 603 def as_json_array(model_class) json_data = json return [] unless json_data && json_data.is_a?(Array) begin json_data.map do |item| if model_class.respond_to?(:from_json) model_class.from_json(item) elsif defined?(ActiveModel::Model) && model_class.ancestors.include?(ActiveModel::Model) model_class.new(item) else instance = model_class.new item.each do |key, value| setter_method = "#{key}=" if instance.respond_to?(setter_method) instance.send(setter_method, value) end end instance end end rescue => e [] end end |
#as_json_object(model_class) ⇒ Object
577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 |
# File 'lib/gemini/response.rb', line 577 def as_json_object(model_class) json_data = json return nil unless json_data begin if model_class.respond_to?(:from_json) model_class.from_json(json_data) elsif defined?(ActiveModel::Model) && model_class.ancestors.include?(ActiveModel::Model) model_class.new(json_data) else instance = model_class.new json_data.each do |key, value| setter_method = "#{key}=" if instance.respond_to?(setter_method) instance.send(setter_method, value) end end instance end rescue => e nil end end |
#as_json_with_keys(*keys) ⇒ Object
631 632 633 634 635 636 637 638 639 640 |
# File 'lib/gemini/response.rb', line 631 def as_json_with_keys(*keys) json_data = json return [] unless json_data && json_data.is_a?(Array) json_data.map do |item| keys.each_with_object({}) do |key, result| result[key.to_s] = item[key.to_s] if item.key?(key.to_s) end end end |
#audio_data ⇒ Object
Base64-encoded audio data from a TTS response
61 62 63 64 65 66 |
# File 'lib/gemini/response.rb', line 61 def audio_data part = audio_part return nil unless part data_key = part["inlineData"] || part["inline_data"] data_key["data"] end |
#audio_mime_type ⇒ Object
MIME type of the audio payload (e.g. “audio/L16;codec=pcm;rate=24000”)
69 70 71 72 73 74 |
# File 'lib/gemini/response.rb', line 69 def audio_mime_type part = audio_part return nil unless part data_key = part["inlineData"] || part["inline_data"] data_key["mimeType"] || data_key["mime_type"] end |
#audio_part ⇒ Object
Get the first audio inlineData part (TTS responses use camelCase “inlineData”)
49 50 51 52 53 54 55 56 57 58 |
# File 'lib/gemini/response.rb', line 49 def audio_part return nil unless valid? parts.find do |part| data_key = part["inlineData"] || part["inline_data"] next false unless data_key mt = data_key["mimeType"] || data_key["mime_type"] mt.is_a?(String) && mt.start_with?("audio/") end end |
#audio_response? ⇒ Boolean
True if the response contains audio inlineData
77 78 79 |
# File 'lib/gemini/response.rb', line 77 def audio_response? !audio_part.nil? end |
#build_function_call_parts_with_signature ⇒ Object
関数呼び出しにSignatureを付与してパーツを構築
397 398 399 400 401 402 403 404 405 406 407 |
# File 'lib/gemini/response.rb', line 397 def build_function_call_parts_with_signature function_call_parts = parts.select { |p| p['functionCall'] } signature = first_thought_signature function_call_parts.map.with_index do |part, index| fc_part = { functionCall: part['functionCall'] } # 最初のパートにのみSignatureを付与 fc_part[:thoughtSignature] = signature if index == 0 && signature fc_part end end |
#cached_content_token_count ⇒ Object
Cached content token count reported by countTokens
323 324 325 |
# File 'lib/gemini/response.rb', line 323 def cached_content_token_count @raw_data&.dig("cachedContentTokenCount") || 0 end |
#candidates ⇒ Object
Get all candidates (if multiple candidates are present)
141 142 143 |
# File 'lib/gemini/response.rb', line 141 def candidates @raw_data&.dig("candidates") || [] end |
#completion_tokens ⇒ Object
Get number of tokens used for completion
301 302 303 |
# File 'lib/gemini/response.rb', line 301 def completion_tokens usage&.dig("candidateTokens") || 0 end |
#count_tokens ⇒ Object
Total tokens reported by the countTokens API (top-level totalTokens)
318 319 320 |
# File 'lib/gemini/response.rb', line 318 def count_tokens @raw_data&.dig("totalTokens") end |
#count_tokens_response? ⇒ Boolean
Check whether this response is a countTokens API result
311 312 313 314 315 |
# File 'lib/gemini/response.rb', line 311 def count_tokens_response? !@raw_data.nil? && @raw_data.key?("totalTokens") && !@raw_data.key?("candidates") && !@raw_data.key?("predictions") && ! end |
#embedding ⇒ Object
Get the embedding values as an Array of Floats. For single embedContent responses returns the values array. For batchEmbedContents responses returns the first embedding’s values.
164 165 166 167 168 169 170 171 |
# File 'lib/gemini/response.rb', line 164 def return nil unless @raw_data if @raw_data["embedding"].is_a?(Hash) @raw_data["embedding"]["values"] elsif @raw_data["embeddings"].is_a?(Array) && @raw_data["embeddings"].first.is_a?(Hash) @raw_data["embeddings"].first["values"] end end |
#embedding_dimension ⇒ Object
Get the dimensionality (length) of the first embedding vector
188 189 190 191 |
# File 'lib/gemini/response.rb', line 188 def values = values.is_a?(Array) ? values.length : 0 end |
#embedding_response? ⇒ Boolean
Check if the raw response contains embedding data
155 156 157 158 159 |
# File 'lib/gemini/response.rb', line 155 def return false if @raw_data.nil? (@raw_data.key?("embedding") && !@raw_data["embedding"].nil?) || (@raw_data.key?("embeddings") && @raw_data["embeddings"].is_a?(Array) && !@raw_data["embeddings"].empty?) end |
#embeddings ⇒ Object
Get all embedding value arrays for batch responses. Returns an Array of Arrays of Floats. For single embedContent responses, returns a single-element array.
176 177 178 179 180 181 182 183 184 185 |
# File 'lib/gemini/response.rb', line 176 def return [] unless @raw_data if @raw_data["embeddings"].is_a?(Array) @raw_data["embeddings"].map { |e| e["values"] }.compact elsif @raw_data["embedding"].is_a?(Hash) && @raw_data["embedding"]["values"] [@raw_data["embedding"]["values"]] else [] end end |
#error ⇒ Object
Get error message if any
194 195 196 197 198 199 200 201 |
# File 'lib/gemini/response.rb', line 194 def error return nil if valid? # Return nil for empty responses (to display "Empty response" in to_s method) return nil if @raw_data.nil? || @raw_data.empty? @raw_data&.dig("error", "message") || "Unknown error" end |
#finish_reason ⇒ Object
Get finish reason (STOP, SAFETY, etc.)
209 210 211 |
# File 'lib/gemini/response.rb', line 209 def finish_reason first_candidate&.dig("finishReason") end |
#first_candidate ⇒ Object
Get the first candidate
136 137 138 |
# File 'lib/gemini/response.rb', line 136 def first_candidate @raw_data&.dig("candidates", 0) end |
#first_thought_signature ⇒ Object
最初のThought Signatureを取得
377 378 379 |
# File 'lib/gemini/response.rb', line 377 def first_thought_signature thought_signatures.first end |
#formatted_text ⇒ Object
Get formatted text (HTML/markdown, etc.)
21 22 23 24 25 |
# File 'lib/gemini/response.rb', line 21 def formatted_text return nil unless valid? text # Currently returns plain text, but could add formatting in the future end |
#full_content ⇒ Object
Get all content with string representation
123 124 125 126 127 128 129 130 131 132 133 |
# File 'lib/gemini/response.rb', line 123 def full_content parts.map do |part| if part.key?("text") part["text"] elsif part.key?("inline_data") && part["inline_data"]["mime_type"].start_with?("image/") "[IMAGE: #{part["inline_data"]["mime_type"]}]" else "[UNKNOWN CONTENT]" end end.join("\n") end |
#function_calls ⇒ Object
Get function call information
349 350 351 352 |
# File 'lib/gemini/response.rb', line 349 def function_calls parts = first_candidate.dig("content", "parts") || [] parts.map { |part| part["functionCall"] }.compact end |
#gemini_3? ⇒ Boolean
Gemini 3系かどうか
392 393 394 |
# File 'lib/gemini/response.rb', line 392 def gemini_3? model_version&.start_with?('gemini-3') || false end |
#grounded? ⇒ Boolean
Check if response has grounding metadata
224 225 226 |
# File 'lib/gemini/response.rb', line 224 def grounded? !.nil? && !.empty? end |
#grounding_chunks ⇒ Object
Get grounding chunks (source references)
229 230 231 |
# File 'lib/gemini/response.rb', line 229 def grounding_chunks &.dig("groundingChunks") || [] end |
#grounding_metadata ⇒ Object
Get grounding metadata (for Google Search grounding)
219 220 221 |
# File 'lib/gemini/response.rb', line 219 def first_candidate&.dig("groundingMetadata") end |
#grounding_sources ⇒ Object
Get formatted grounding sources (simplified access)
239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 |
# File 'lib/gemini/response.rb', line 239 def grounding_sources return [] unless grounded? grounding_chunks.map do |chunk| if chunk["web"] { url: chunk["web"]["uri"], title: chunk["web"]["title"], type: "web" } else # Handle other potential chunk types { type: "unknown", data: chunk } end end end |
#has_thought_signature? ⇒ Boolean
Signatureが存在するか
382 383 384 |
# File 'lib/gemini/response.rb', line 382 def has_thought_signature? !thought_signatures.empty? end |
#image ⇒ Object
画像生成結果から最初の画像を取得(Base64エンコード形式)
410 411 412 |
# File 'lib/gemini/response.rb', line 410 def image images.first end |
#image_mime_types ⇒ Object
画像のMIMEタイプを取得
471 472 473 474 475 476 477 478 479 480 481 482 |
# File 'lib/gemini/response.rb', line 471 def image_mime_types return [] unless valid? if first_candidate&.dig("content", "parts") first_candidate["content"]["parts"] .select { |part| part.key?("inline_data") && part["inline_data"]["mime_type"].start_with?("image/") } .map { |part| part["inline_data"]["mime_type"] } else # Imagen 3のデフォルトはPNG Array.new(images.size, "image/png") end end |
#image_parts ⇒ Object
Get image parts (if any)
42 43 44 45 46 |
# File 'lib/gemini/response.rb', line 42 def image_parts return [] unless valid? parts.select { |part| part.key?("inline_data") && part["inline_data"]["mime_type"].start_with?("image/") } end |
#image_urls ⇒ Object
Get image URLs from multimodal responses (if any)
340 341 342 343 344 345 346 |
# File 'lib/gemini/response.rb', line 340 def image_urls return [] unless valid? first_candidate&.dig("content", "parts") &.select { |part| part.key?("image_url") } &.map { |part| part.dig("image_url", "url") } || [] end |
#images ⇒ Object
画像生成結果からすべての画像を取得(Base64エンコード形式の配列)
415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 |
# File 'lib/gemini/response.rb', line 415 def images image_array = [] return image_array unless @raw_data # Gemini 2.0スタイルレスポンスを正確に解析 # キーはcamelCase形式で使用されているので注意(inlineDataなど) if @raw_data.key?('candidates') && !@raw_data['candidates'].empty? candidate = @raw_data['candidates'][0] if candidate.key?('content') && candidate['content'].key?('parts') parts = candidate['content']['parts'] parts.each do |part| # キャメルケースでアクセス(inlineData) if part.key?('inlineData') inline_data = part['inlineData'] if inline_data.key?('mimeType') && inline_data['mimeType'].to_s.start_with?('image/') && inline_data.key?('data') # 画像データを追加 image_array << inline_data['data'] puts "画像データを検出しました: #{inline_data['mimeType']}" if ENV["DEBUG"] end end end end # Imagen 3スタイルレスポンスのチェック elsif @raw_data.key?('predictions') @raw_data['predictions'].each do |pred| if pred.key?('bytesBase64Encoded') image_array << pred['bytesBase64Encoded'] puts "Imagen 3形式の画像データを検出しました" if ENV["DEBUG"] end end end # フォールバック:直接JSONから抽出 if image_array.empty? puts "標準的な方法で画像データが見つかりませんでした。正規表現による抽出を試みます..." if ENV["DEBUG"] raw_json = @raw_data.to_json # "data"キーで長いBase64文字列を検索 base64_matches = raw_json.scan(/"data":"([A-Za-z0-9+\/=]{100,})"/) if !base64_matches.empty? puts "検出したBase64データ: #{base64_matches.size}個" if ENV["DEBUG"] base64_matches.each do |match| image_array << match[0] end end end puts "検出した画像データ数: #{image_array.size}" if ENV["DEBUG"] image_array end |
#inspect ⇒ Object
Inspection method for debugging
552 553 554 |
# File 'lib/gemini/response.rb', line 552 def inspect "#<Gemini::Response text=#{text ? text[0..30] + (text.length > 30 ? '...' : '') : 'nil'} success=#{success?}>" end |
#json ⇒ Object
556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 |
# File 'lib/gemini/response.rb', line 556 def json return nil unless valid? text_content = text return nil unless text_content begin if text_content.strip.start_with?('{') || text_content.strip.start_with?('[') JSON.parse(text_content) else nil end rescue JSON::ParserError => e nil end end |
#json? ⇒ Boolean
573 574 575 |
# File 'lib/gemini/response.rb', line 573 def json? !json.nil? end |
#model_version ⇒ Object
モデルバージョンを取得
387 388 389 |
# File 'lib/gemini/response.rb', line 387 def model_version @raw_data['modelVersion'] end |
#parts ⇒ Object
Get all content parts
28 29 30 31 32 |
# File 'lib/gemini/response.rb', line 28 def parts return [] unless valid? first_candidate&.dig("content", "parts") || [] end |
#prompt_tokens ⇒ Object
Get number of prompt tokens used
296 297 298 |
# File 'lib/gemini/response.rb', line 296 def prompt_tokens usage&.dig("promptTokens") || 0 end |
#prompt_tokens_details ⇒ Object
Per-modality token breakdown reported by countTokens
328 329 330 |
# File 'lib/gemini/response.rb', line 328 def prompt_tokens_details @raw_data&.dig("promptTokensDetails") || [] end |
#retrieved_urls ⇒ Object
Get retrieved URLs from URL context
270 271 272 273 274 |
# File 'lib/gemini/response.rb', line 270 def retrieved_urls return [] unless url_context? &.dig("urlMetadata") || [] end |
#role ⇒ Object
Get response role (usually “model”)
355 356 357 |
# File 'lib/gemini/response.rb', line 355 def role first_candidate&.dig("content", "role") end |
#safety_blocked? ⇒ Boolean
Check if response was blocked for safety reasons
214 215 216 |
# File 'lib/gemini/response.rb', line 214 def safety_blocked? finish_reason == "SAFETY" end |
#safety_ratings ⇒ Object
Get safety ratings
360 361 362 |
# File 'lib/gemini/response.rb', line 360 def first_candidate&.dig("safetyRatings") || [] end |
#save_audio(filepath) ⇒ Object
Save audio to a file. PCM (L16) payloads are wrapped in a WAV header so the result is directly playable; other audio MIME types are written as-is. Returns the written file path or nil if no audio is present.
84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 |
# File 'lib/gemini/response.rb', line 84 def save_audio(filepath) data_b64 = audio_data return nil unless data_b64 require 'base64' raw = Base64.strict_decode64(data_b64) mime = audio_mime_type.to_s if mime.include?("L16") || mime.include?("pcm") rate = mime[/rate=(\d+)/, 1]&.to_i || 24000 channels = 1 bits_per_sample = 16 byte_rate = rate * channels * bits_per_sample / 8 block_align = channels * bits_per_sample / 8 data_size = raw.bytesize header = +"" header << "RIFF" header << [36 + data_size].pack("V") header << "WAVE" header << "fmt " header << [16].pack("V") header << [1].pack("v") header << [channels].pack("v") header << [rate].pack("V") header << [byte_rate].pack("V") header << [block_align].pack("v") header << [bits_per_sample].pack("v") header << "data" header << [data_size].pack("V") File.binwrite(filepath, header + raw) else File.binwrite(filepath, raw) end filepath end |
#save_image(filepath) ⇒ Object
最初の画像をファイルに保存
485 486 487 |
# File 'lib/gemini/response.rb', line 485 def save_image(filepath) save_images([filepath]).first end |
#save_images(filepaths) ⇒ Object
複数の画像をファイルに保存
490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 |
# File 'lib/gemini/response.rb', line 490 def save_images(filepaths) require 'base64' result = [] image_data = images puts "保存する画像データ数: #{image_data.size}" if ENV["DEBUG"] # ファイルパスと画像データの数が一致しない場合 if filepaths.size < image_data.size puts "警告: ファイルパスの数(#{filepaths.size})が画像データの数(#{image_data.size})より少ないです" if ENV["DEBUG"] # ファイルパスの数に合わせて画像データを切り詰める image_data = image_data[0...filepaths.size] elsif filepaths.size > image_data.size puts "警告: ファイルパスの数(#{filepaths.size})が画像データの数(#{image_data.size})より多いです" if ENV["DEBUG"] # 画像データの数に合わせてファイルパスを切り詰める filepaths = filepaths[0...image_data.size] end image_data.each_with_index do |data, i| begin if !data || data.empty? puts "警告: インデックス #{i} の画像データが空です" if ENV["DEBUG"] result << nil next end # データがBase64エンコードされていることを確認 if data.match?(/^[A-Za-z0-9+\/=]+$/) # 一般的なBase64データ decoded_data = Base64.strict_decode64(data) else # データプレフィックスがある場合など(例: data:image/png;base64,xxxxx) if data.include?('base64,') base64_part = data.split('base64,').last decoded_data = Base64.strict_decode64(base64_part) else puts "警告: インデックス #{i} のデータはBase64形式ではありません" if ENV["DEBUG"] decoded_data = data # 既にバイナリかもしれない end end File.open(filepaths[i], 'wb') do |f| f.write(decoded_data) end result << filepaths[i] rescue => e puts "エラー: 画像 #{i} の保存中にエラーが発生しました: #{e.}" if ENV["DEBUG"] puts e.backtrace.join("\n") if ENV["DEBUG"] result << nil end end result end |
#search_entry_point ⇒ Object
Get search entry point URL (if available)
234 235 236 |
# File 'lib/gemini/response.rb', line 234 def search_entry_point &.dig("searchEntryPoint", "renderedContent") end |
#stream_chunks ⇒ Object
Process chunks for streaming responses
333 334 335 336 337 |
# File 'lib/gemini/response.rb', line 333 def stream_chunks return [] unless @raw_data.is_a?(Array) @raw_data end |
#success? ⇒ Boolean
Check if response was successful
204 205 206 |
# File 'lib/gemini/response.rb', line 204 def success? valid? && !@raw_data.key?("error") end |
#text ⇒ Object
Get simple text response (combines multiple parts if present)
11 12 13 14 15 16 17 18 |
# File 'lib/gemini/response.rb', line 11 def text return nil unless valid? first_candidate&.dig("content", "parts") &.select { |part| part.key?("text") } &.map { |part| part["text"] } &.join("\n") || "" end |
#text_parts ⇒ Object
Get all text parts as an array
35 36 37 38 39 |
# File 'lib/gemini/response.rb', line 35 def text_parts return [] unless valid? parts.select { |part| part.key?("text") }.map { |part| part["text"] } end |
#thought_signatures ⇒ Object
Thought Signatureを取得(配列)
372 373 374 |
# File 'lib/gemini/response.rb', line 372 def thought_signatures parts.filter_map { |p| p['thoughtSignature'] } end |
#thoughts_token_count ⇒ Object
思考トークン数を取得
367 368 369 |
# File 'lib/gemini/response.rb', line 367 def thoughts_token_count @raw_data.dig('usageMetadata', 'thoughtsTokenCount') end |
#to_formatted_json(pretty: false) ⇒ Object
642 643 644 645 646 647 648 649 650 651 |
# File 'lib/gemini/response.rb', line 642 def to_formatted_json(pretty: false) json_data = json return nil unless json_data if pretty JSON.pretty_generate(json_data) else JSON.generate(json_data) end end |
#to_s ⇒ Object
Override to_s method to return text
547 548 549 |
# File 'lib/gemini/response.rb', line 547 def to_s text || error || "Empty response" end |
#total_tokens ⇒ Object
Get total tokens used
306 307 308 |
# File 'lib/gemini/response.rb', line 306 def total_tokens usage&.dig("totalTokens") || 0 end |
#url_context? ⇒ Boolean
Check if response has URL context metadata
265 266 267 |
# File 'lib/gemini/response.rb', line 265 def url_context? !.nil? && !.empty? end |
#url_context_metadata ⇒ Object
Get URL context metadata (for URL Context tool)
260 261 262 |
# File 'lib/gemini/response.rb', line 260 def first_candidate&.dig("urlContextMetadata") end |
#url_retrieval_statuses ⇒ Object
Get URL retrieval statuses
277 278 279 280 281 282 283 284 285 286 287 |
# File 'lib/gemini/response.rb', line 277 def url_retrieval_statuses return [] unless url_context? retrieved_urls.map do |url_info| { url: url_info["retrievedUrl"], status: url_info["urlRetrievalStatus"], title: url_info["title"] } end end |
#usage ⇒ Object
Get token usage information
291 292 293 |
# File 'lib/gemini/response.rb', line 291 def usage @raw_data&.dig("usage") || {} end |
#valid? ⇒ Boolean
Check if response is valid
146 147 148 149 150 151 152 |
# File 'lib/gemini/response.rb', line 146 def valid? !@raw_data.nil? && ((@raw_data.key?("candidates") && !@raw_data["candidates"].empty?) || (@raw_data.key?("predictions") && !@raw_data["predictions"].empty?) || || count_tokens_response?) end |