ruby-gemini-api 0.1.0
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 +7 -0
- data/CHANGELOG.md +5 -0
- data/LICENSE.txt +21 -0
- data/README.md +764 -0
- data/lib/gemini/audio.rb +127 -0
- data/lib/gemini/cached_content.rb +151 -0
- data/lib/gemini/client.rb +540 -0
- data/lib/gemini/documents.rb +141 -0
- data/lib/gemini/embeddings.rb +27 -0
- data/lib/gemini/files.rb +149 -0
- data/lib/gemini/http.rb +226 -0
- data/lib/gemini/http_headers.rb +24 -0
- data/lib/gemini/images.rb +122 -0
- data/lib/gemini/messages.rb +131 -0
- data/lib/gemini/models.rb +20 -0
- data/lib/gemini/response.rb +402 -0
- data/lib/gemini/runs.rb +158 -0
- data/lib/gemini/threads.rb +74 -0
- data/lib/gemini/version.rb +5 -0
- data/lib/gemini.rb +81 -0
- data/lib/ruby/gemini.rb +1 -0
- metadata +193 -0
data/lib/gemini/audio.rb
ADDED
@@ -0,0 +1,127 @@
|
|
1
|
+
module Gemini
|
2
|
+
class Audio
|
3
|
+
def initialize(client:)
|
4
|
+
@client = client
|
5
|
+
end
|
6
|
+
|
7
|
+
# Transcribe an audio file
|
8
|
+
def transcribe(parameters: {})
|
9
|
+
file = parameters.delete(:file)
|
10
|
+
file_uri = parameters.delete(:file_uri)
|
11
|
+
model = parameters.delete(:model) || "gemini-1.5-flash"
|
12
|
+
language = parameters.delete(:language)
|
13
|
+
content_text = parameters.delete(:content_text) || "Transcribe this audio clip"
|
14
|
+
|
15
|
+
if !file && !file_uri
|
16
|
+
raise ArgumentError, "No audio file specified"
|
17
|
+
end
|
18
|
+
|
19
|
+
if file_uri
|
20
|
+
return transcribe_with_file_uri(file_uri, model, language, content_text, parameters)
|
21
|
+
end
|
22
|
+
|
23
|
+
# Get MIME type (simple detection)
|
24
|
+
mime_type = determine_mime_type(file)
|
25
|
+
|
26
|
+
# Base64 encode the file
|
27
|
+
file.rewind
|
28
|
+
require 'base64'
|
29
|
+
file_data = Base64.strict_encode64(file.read)
|
30
|
+
|
31
|
+
# Language setting for transcription request
|
32
|
+
if language
|
33
|
+
content_text += " in #{language}"
|
34
|
+
end
|
35
|
+
|
36
|
+
# Build request parameters
|
37
|
+
request_params = {
|
38
|
+
contents: [{
|
39
|
+
parts: [
|
40
|
+
{ text: content_text },
|
41
|
+
{
|
42
|
+
inline_data: {
|
43
|
+
mime_type: mime_type,
|
44
|
+
data: file_data
|
45
|
+
}
|
46
|
+
}
|
47
|
+
]
|
48
|
+
}]
|
49
|
+
}
|
50
|
+
|
51
|
+
# Merge additional parameters (add to top level except contents)
|
52
|
+
parameters.each do |key, value|
|
53
|
+
request_params[key] = value unless key == :contents
|
54
|
+
end
|
55
|
+
|
56
|
+
# Send generateContent request
|
57
|
+
response = @client.json_post(
|
58
|
+
path: "models/#{model}:generateContent",
|
59
|
+
parameters: request_params
|
60
|
+
)
|
61
|
+
|
62
|
+
Gemini::Response.new(response)
|
63
|
+
end
|
64
|
+
|
65
|
+
private
|
66
|
+
|
67
|
+
# Transcribe using pre-uploaded file URI
|
68
|
+
def transcribe_with_file_uri(file_uri, model, language, content_text, parameters)
|
69
|
+
# Language setting for transcription request
|
70
|
+
if language
|
71
|
+
content_text += " in #{language}"
|
72
|
+
end
|
73
|
+
|
74
|
+
# Build request parameters
|
75
|
+
request_params = {
|
76
|
+
contents: [{
|
77
|
+
parts: [
|
78
|
+
{ text: content_text },
|
79
|
+
{
|
80
|
+
file_data: {
|
81
|
+
mime_type: "audio/mp3", # Cannot determine MIME type from URI, so using default value
|
82
|
+
file_uri: file_uri
|
83
|
+
}
|
84
|
+
}
|
85
|
+
]
|
86
|
+
}]
|
87
|
+
}
|
88
|
+
|
89
|
+
# Merge additional parameters (add to top level except contents)
|
90
|
+
parameters.each do |key, value|
|
91
|
+
request_params[key] = value unless key == :contents
|
92
|
+
end
|
93
|
+
|
94
|
+
# Send generateContent request
|
95
|
+
response = @client.json_post(
|
96
|
+
path: "models/#{model}:generateContent",
|
97
|
+
parameters: request_params
|
98
|
+
)
|
99
|
+
|
100
|
+
Gemini::Response.new(response)
|
101
|
+
end
|
102
|
+
|
103
|
+
# Simple MIME type determination from file extension
|
104
|
+
def determine_mime_type(file)
|
105
|
+
return "application/octet-stream" unless file.respond_to?(:path)
|
106
|
+
|
107
|
+
ext = File.extname(file.path).downcase
|
108
|
+
case ext
|
109
|
+
when ".wav"
|
110
|
+
"audio/wav"
|
111
|
+
when ".mp3"
|
112
|
+
"audio/mp3"
|
113
|
+
when ".aiff"
|
114
|
+
"audio/aiff"
|
115
|
+
when ".aac"
|
116
|
+
"audio/aac"
|
117
|
+
when ".ogg"
|
118
|
+
"audio/ogg"
|
119
|
+
when ".flac"
|
120
|
+
"audio/flac"
|
121
|
+
else
|
122
|
+
# Default value (assume mp3)
|
123
|
+
"audio/mp3"
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
@@ -0,0 +1,151 @@
|
|
1
|
+
module Gemini
|
2
|
+
class CachedContent
|
3
|
+
def initialize(client:)
|
4
|
+
@client = client
|
5
|
+
end
|
6
|
+
|
7
|
+
# コンテンツをキャッシュに保存
|
8
|
+
def create(file_path: nil, file_uri: nil, system_instruction: nil, mime_type: nil, model: nil, ttl: "86400s", **parameters)
|
9
|
+
# ファイルパスが指定されている場合はアップロード
|
10
|
+
if file_path && !file_uri
|
11
|
+
file = File.open(file_path, "rb")
|
12
|
+
begin
|
13
|
+
upload_result = @client.files.upload(file: file)
|
14
|
+
file_uri = upload_result["file"]["uri"]
|
15
|
+
ensure
|
16
|
+
file.close
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
# file_uriが必須
|
21
|
+
raise ArgumentError, "file_uri parameter is required" unless file_uri
|
22
|
+
|
23
|
+
# MIMEタイプを判定
|
24
|
+
mime_type ||= file_path ? @client.determine_mime_type(file_path) : "application/octet-stream"
|
25
|
+
|
26
|
+
# モデルを取得(models/プレフィックスを追加)
|
27
|
+
model_name = model || parameters[:model] || "gemini-1.5-flash"
|
28
|
+
model_name = "models/#{model_name}" unless model_name.start_with?("models/")
|
29
|
+
|
30
|
+
# キャッシュリクエストを構築(キャメルケースに注意)
|
31
|
+
request = {
|
32
|
+
model: model_name,
|
33
|
+
contents: [
|
34
|
+
{
|
35
|
+
parts: [
|
36
|
+
{ file_data: { mime_type: mime_type, file_uri: file_uri } }
|
37
|
+
],
|
38
|
+
role: "user"
|
39
|
+
}
|
40
|
+
],
|
41
|
+
ttl: ttl
|
42
|
+
}
|
43
|
+
|
44
|
+
# システム指示が指定されている場合は追加(キャメルケースで指定)
|
45
|
+
if system_instruction
|
46
|
+
request[:systemInstruction] = {
|
47
|
+
parts: [{ text: system_instruction }],
|
48
|
+
role: "system"
|
49
|
+
}
|
50
|
+
end
|
51
|
+
|
52
|
+
# その他のパラメータを追加(ただしmime_typeとmodelは除外)
|
53
|
+
parameters.each do |key, value|
|
54
|
+
next if [:mime_type, :model].include?(key)
|
55
|
+
|
56
|
+
# スネークケースをキャメルケースに変換(必要に応じて)
|
57
|
+
camel_key = key.to_s.gsub(/_([a-z])/) { $1.upcase }.to_sym
|
58
|
+
request[camel_key] = value
|
59
|
+
end
|
60
|
+
|
61
|
+
# リクエストURLを直接構築
|
62
|
+
full_url = "https://generativelanguage.googleapis.com/v1beta/cachedContents"
|
63
|
+
|
64
|
+
# 直接Faradayを使用してリクエストを送信
|
65
|
+
conn = @client.conn
|
66
|
+
response = conn.post(full_url) do |req|
|
67
|
+
# ここでheadersメソッドを直接使用するのではなく、Content-Typeを手動で設定
|
68
|
+
req.headers = { 'Content-Type' => 'application/json' }
|
69
|
+
req.params = { key: @client.api_key }
|
70
|
+
req.body = request.to_json
|
71
|
+
end
|
72
|
+
|
73
|
+
parsed_response = begin
|
74
|
+
JSON.parse(response.body)
|
75
|
+
rescue JSON::ParserError
|
76
|
+
response.body
|
77
|
+
end
|
78
|
+
|
79
|
+
Gemini::Response.new(parsed_response)
|
80
|
+
end
|
81
|
+
|
82
|
+
# キャッシュの一覧を取得
|
83
|
+
def list(parameters: {})
|
84
|
+
# パラメータをキャメルケースに変換
|
85
|
+
camel_params = {}
|
86
|
+
parameters.each do |key, value|
|
87
|
+
camel_key = key.to_s.gsub(/_([a-z])/) { $1.upcase }
|
88
|
+
camel_params[camel_key] = value
|
89
|
+
end
|
90
|
+
|
91
|
+
# 直接URLを構築
|
92
|
+
full_url = "https://generativelanguage.googleapis.com/v1beta/cachedContents"
|
93
|
+
|
94
|
+
# 直接Faradayを使用
|
95
|
+
conn = @client.conn
|
96
|
+
response = conn.get(full_url) do |req|
|
97
|
+
# ここでheadersメソッドを直接使用するのではなく、Content-Typeを手動で設定
|
98
|
+
req.headers = { 'Content-Type' => 'application/json' }
|
99
|
+
req.params = camel_params.merge(key: @client.api_key)
|
100
|
+
end
|
101
|
+
|
102
|
+
parsed_response = begin
|
103
|
+
JSON.parse(response.body)
|
104
|
+
rescue JSON::ParserError
|
105
|
+
response.body
|
106
|
+
end
|
107
|
+
|
108
|
+
Gemini::Response.new(parsed_response)
|
109
|
+
end
|
110
|
+
|
111
|
+
# キャッシュを更新
|
112
|
+
def update(name:, ttl: "86400s")
|
113
|
+
full_url = "https://generativelanguage.googleapis.com/v1beta/#{name}"
|
114
|
+
|
115
|
+
conn = @client.conn
|
116
|
+
response = conn.patch(full_url) do |req|
|
117
|
+
# ここでheadersメソッドを直接使用するのではなく、Content-Typeを手動で設定
|
118
|
+
req.headers = { 'Content-Type' => 'application/json' }
|
119
|
+
req.params = { key: @client.api_key }
|
120
|
+
req.body = { ttl: ttl }.to_json
|
121
|
+
end
|
122
|
+
|
123
|
+
parsed_response = begin
|
124
|
+
JSON.parse(response.body)
|
125
|
+
rescue JSON::ParserError
|
126
|
+
response.body
|
127
|
+
end
|
128
|
+
|
129
|
+
Gemini::Response.new(parsed_response)
|
130
|
+
end
|
131
|
+
|
132
|
+
def delete(name:)
|
133
|
+
full_url = "https://generativelanguage.googleapis.com/v1beta/#{name}"
|
134
|
+
|
135
|
+
conn = @client.conn
|
136
|
+
response = conn.delete(full_url) do |req|
|
137
|
+
# ここでheadersメソッドを直接使用するのではなく、Content-Typeを手動で設定
|
138
|
+
req.headers = { 'Content-Type' => 'application/json' }
|
139
|
+
req.params = { key: @client.api_key }
|
140
|
+
end
|
141
|
+
|
142
|
+
parsed_response = begin
|
143
|
+
JSON.parse(response.body)
|
144
|
+
rescue JSON::ParserError
|
145
|
+
response.body
|
146
|
+
end
|
147
|
+
|
148
|
+
Gemini::Response.new(parsed_response)
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|