Skip to content

Commit cd13967

Browse files
author
Aki
committed
initial
1 parent 9b9768f commit cd13967

33 files changed

+2794
-14
lines changed

.gitattributes

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# Normalize EOL for all files that Git considers text files.
2+
* text=auto eol=lf

.gitignore

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,5 @@
11
# Godot 4+ specific ignores
22
.godot/
3-
4-
# Godot-specific ignores
5-
.import/
6-
export.cfg
7-
export_presets.cfg
8-
9-
# Imported translations (automatically generated from CSV files)
10-
*.translation
11-
12-
# Mono-specific ignores
13-
.mono/
14-
data_*/
15-
mono_crash.*.json
3+
settings.json
4+
files/video_file.png
5+
files/video_file.png.import

README.md

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,30 @@
11
# godot-simple-gemini-api
2-
As possible as simple call Gemini API
2+
As simply as possible, call the Gemini API.
3+
## API KEYS
4+
This app requires an API key. Save it in settings.json. Take care of your keys. By default, it is added to .gitignore.
5+
## LICENSE
6+
MIT LICENSE - Akihito Miyazaki
7+
## Examples
8+
V1beta parts are not implemented yet.
9+
see https://ai.google.dev/tutorials/rest_quickstart
10+
### send_text
11+
simple send text
12+
### sent_text_safety
13+
show how to control safety.
14+
### set_text_config
15+
send text with configuration (stopsequence ,temperature ..etc)
16+
### send_text_stream
17+
Send a text stream. This code uses HttpClient. I'm not familiar with this; please handle with care.
18+
### chat_text
19+
Send multiple-turn text.
20+
### send_image
21+
Send an image and text. I tested mp4, but it's not working.
22+
### get_embedding
23+
get single embedding
24+
### batch_embedding
25+
get multiple embedding and cmpare them.
26+
### count_tokens
27+
count tokens
28+
### get_list_model
29+
get model list and info.
30+

batch_embedding.gd

Lines changed: 231 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,231 @@
1+
extends Control
2+
3+
4+
#see https://ai.google.dev/tutorials/rest_quickstart
5+
6+
var api_key = ""
7+
var http_request
8+
9+
func _ready():
10+
var settings = JSON.parse_string(FileAccess.get_file_as_string("res://settings.json"))
11+
api_key = settings.api_key
12+
http_request = HTTPRequest.new()
13+
add_child(http_request)
14+
http_request.connect("request_completed", _on_request_completed)
15+
16+
var task_type_option=find_child("TaskTypeOptionButton")
17+
task_type_option.add_item("SEMANTIC_SIMILARITY")
18+
task_type_option.add_item("RETRIEVAL_QUERY")
19+
task_type_option.add_item("RETRIEVAL_DOCUMENT")
20+
task_type_option.add_item("CLASSIFICATION")
21+
task_type_option.add_item("CLUSTERING")
22+
task_type_option.add_item("TASK_TYPE_UNSPECIFIED")
23+
24+
#test grid
25+
grid = find_child("GridContainer")
26+
#grid.visible = false
27+
#find_node("ScrollContainer").add_child(grid)
28+
_update_grid()
29+
30+
var sort_ascending = true
31+
var sort_key = "text1"
32+
var grid
33+
var datas = []
34+
func _update_grid():
35+
var headers = ["text1","text2","cosine similarity","euclidean distance"]
36+
#var grid = GridContainer.new()
37+
var scroll = find_child("ScrollContainer")
38+
39+
grid.queue_free()
40+
grid = GridContainer.new()
41+
scroll.add_child(grid)
42+
grid.columns = headers.size()
43+
for head in headers:
44+
var button = Button.new()
45+
button.connect("pressed", Callable(self, "_on_header_pressed").bind(button))
46+
button.text = head
47+
grid.add_child(button)
48+
49+
50+
51+
52+
var sort_order = "_ascending" if sort_ascending else "_descending"
53+
var sort_method = "sort_"+sort_key.to_lower()+sort_order
54+
datas.sort_custom(Callable(self,sort_method))
55+
for data in datas:
56+
_data_to_grid(data)
57+
58+
59+
func _convert_to_data(text1,text2,embedding1,embedding2) -> Dictionary:
60+
var dic = {}
61+
62+
dic["text1"] = text1
63+
dic["text2"] = text2
64+
65+
dic["cosine_similarity"] = cosine_similarity(embedding1,embedding2)
66+
dic["euclidean_distance"] = euclidean_distance(embedding1,embedding2)
67+
68+
return dic
69+
70+
func _data_to_grid(data):
71+
var label = Label.new()
72+
label.text = data["text1"]
73+
grid.add_child(label)
74+
75+
76+
var label2 = Label.new()
77+
label2.text = data["text2"]
78+
grid.add_child(label2)
79+
80+
81+
var label_cs = Label.new()
82+
label_cs.text = str(data["cosine_similarity"])
83+
84+
grid.add_child(label_cs)
85+
var label_ed = Label.new()
86+
label_ed.text = str(data["euclidean_distance"])
87+
grid.add_child(label_ed)
88+
89+
90+
func cosine_similarity(vec1: PackedFloat32Array, vec2: PackedFloat32Array) -> float:
91+
var dot_product = 0.0
92+
var magnitude1 = 0.0
93+
var magnitude2 = 0.0
94+
95+
for i in range(vec1.size()):
96+
dot_product += vec1[i] * vec2[i]
97+
magnitude1 += vec1[i] * vec1[i]
98+
magnitude2 += vec2[i] * vec2[i]
99+
100+
if magnitude1 == 0.0 or magnitude2 == 0.0:
101+
return 0.0
102+
103+
return dot_product / (sqrt(magnitude1) * sqrt(magnitude2))
104+
105+
106+
# ユークリッド距離を計算する関数
107+
func euclidean_distance(vec1: PackedFloat32Array, vec2: PackedFloat32Array) -> float:
108+
var distance = 0.0
109+
110+
for i in range(vec1.size()):
111+
distance += pow(vec1[i] - vec2[i], 2)
112+
113+
return sqrt(distance)
114+
115+
116+
func _on_header_pressed(button):
117+
118+
sort_key = button.text.replace(" ","_")
119+
120+
_update_grid()
121+
# Called every frame. 'delta' is the elapsed time since the previous frame.
122+
func _process(delta):
123+
pass
124+
125+
126+
func _get_option_selected_text(key):
127+
var option = find_child(key+"OptionButton")
128+
var text = option.get_item_text(option.get_selected_id())
129+
return text
130+
131+
132+
func _on_send_button_pressed():
133+
var input = find_child("InputEdit").text
134+
_request_batch_embeddings(input)
135+
136+
var texts = ["hello","world"]
137+
var embeddings = []
138+
func _request_batch_embeddings(prompt):
139+
var url = "https://generativelanguage.googleapis.com/v1/models/embedding-001:batchEmbedContents?key=%s"%api_key
140+
141+
142+
texts.clear()
143+
var request_value = []
144+
var lines = prompt.split("\n")
145+
for line in lines:
146+
if line.is_empty():
147+
continue
148+
texts.append(line)
149+
request_value.append({
150+
"model": "models/embedding-001",
151+
"content":
152+
{ "parts":[{
153+
"text": line
154+
}]
155+
},"taskType":_get_option_selected_text("TaskType")
156+
157+
})
158+
159+
var body = JSON.new().stringify({"requests":request_value})
160+
161+
print("send-content"+str(body))
162+
163+
find_child("SendButton").disabled = true
164+
var error = http_request.request(url, ["Content-Type: application/json"], HTTPClient.METHOD_POST, body)
165+
166+
if error != OK:
167+
push_error("requested but error happen code = %s"%error)
168+
169+
func _on_request_completed(result, responseCode, headers, body):
170+
find_child("SendButton").disabled = false
171+
var json = JSON.new()
172+
json.parse(body.get_string_from_utf8())
173+
var response = json.get_data()
174+
print("response")
175+
print(response)
176+
177+
if response == null:
178+
print("response is null")
179+
find_child("FinishedLabel").text = "No Response"
180+
find_child("FinishedLabel").visible = true
181+
return
182+
183+
if response.has("error"):
184+
find_child("FinishedLabel").text = "ERROR"
185+
find_child("FinishedLabel").visible = true
186+
find_child("ResponseEdit").text = str(response.error)
187+
#maybe blocked
188+
return
189+
190+
#No Answer
191+
if response.has("embeddings"):
192+
find_child("FinishedLabel").text = ""
193+
find_child("FinishedLabel").visible = false
194+
find_child("ResponseEdit").text = str(response.embeddings)
195+
embeddings.clear()
196+
for embedding in response.embeddings:
197+
embeddings.append(PackedFloat32Array(embedding.values))
198+
199+
else:
200+
find_child("FinishedLabel").text = "Unknown"
201+
find_child("FinishedLabel").visible = true
202+
find_child("ResponseEdit").text = str(response)
203+
204+
datas.clear()
205+
for i in range(texts.size()):
206+
for j in range(i + 1, texts.size()):
207+
datas.append(_convert_to_data(texts[i],texts[j],embeddings[i],embeddings[j]))
208+
209+
_update_grid()
210+
211+
212+
static func sort_text1_ascending(a:Dictionary, b:Dictionary) -> bool:
213+
return a["text1"] < b["text1"]
214+
215+
static func sort_text2_ascending(a:Dictionary, b:Dictionary) -> bool:
216+
return a["text2"] < b["text2"]
217+
218+
static func sort_cosine_similarity_ascending(a:Dictionary, b:Dictionary) -> bool:
219+
if a["cosine_similarity"] == b["cosine_similarity"] :
220+
return sort_text1_ascending(a,b)
221+
#In cosine similarity, a value closer to 1 indicates that the two vectors are similar.
222+
return a["cosine_similarity"] > b["cosine_similarity"]
223+
224+
static func sort_euclidean_distance_ascending(a:Dictionary, b:Dictionary) -> bool:
225+
if a["euclidean_distance"] == b["euclidean_distance"] :
226+
return sort_text1_ascending(a,b)
227+
#In Euclidean distance, a value closer to 0 indicates that the two points are similar. The larger the distance, the less similar the two points are.
228+
return a["euclidean_distance"] < b["euclidean_distance"]
229+
230+
231+

batch_embedding.tscn

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
[gd_scene load_steps=3 format=3 uid="uid://dfk1issxnp1k"]
2+
3+
[ext_resource type="Script" path="res://batch_embedding.gd" id="1_vupcq"]
4+
5+
[sub_resource type="LabelSettings" id="LabelSettings_6qyb2"]
6+
font_color = Color(1, 0, 0, 1)
7+
8+
[node name="Control" type="Control"]
9+
layout_mode = 3
10+
anchors_preset = 15
11+
anchor_right = 1.0
12+
anchor_bottom = 1.0
13+
grow_horizontal = 2
14+
grow_vertical = 2
15+
script = ExtResource("1_vupcq")
16+
17+
[node name="MarginContainer" type="MarginContainer" parent="."]
18+
layout_mode = 1
19+
anchors_preset = 15
20+
anchor_right = 1.0
21+
anchor_bottom = 1.0
22+
grow_horizontal = 2
23+
grow_vertical = 2
24+
theme_override_constants/margin_left = 8
25+
theme_override_constants/margin_top = 8
26+
theme_override_constants/margin_right = 8
27+
theme_override_constants/margin_bottom = 8
28+
29+
[node name="VBoxContainer" type="VBoxContainer" parent="MarginContainer"]
30+
layout_mode = 2
31+
32+
[node name="Label" type="Label" parent="MarginContainer/VBoxContainer"]
33+
layout_mode = 2
34+
text = "User"
35+
36+
[node name="HBoxContainer" type="HBoxContainer" parent="MarginContainer/VBoxContainer"]
37+
layout_mode = 2
38+
39+
[node name="SendButton" type="Button" parent="MarginContainer/VBoxContainer/HBoxContainer"]
40+
layout_mode = 2
41+
text = "Send"
42+
43+
[node name="InputEdit" type="TextEdit" parent="MarginContainer/VBoxContainer/HBoxContainer"]
44+
custom_minimum_size = Vector2(250, 120)
45+
layout_mode = 2
46+
size_flags_horizontal = 3
47+
text = "I love music
48+
I hate music
49+
I adore music
50+
I am not a fan of music."
51+
wrap_mode = 1
52+
53+
[node name="TaskTypeOptionButton" type="OptionButton" parent="MarginContainer/VBoxContainer/HBoxContainer"]
54+
layout_mode = 2
55+
56+
[node name="Label2" type="Label" parent="MarginContainer/VBoxContainer"]
57+
layout_mode = 2
58+
text = "Embeddings"
59+
60+
[node name="FinishedLabel" type="Label" parent="MarginContainer/VBoxContainer"]
61+
visible = false
62+
layout_mode = 2
63+
label_settings = SubResource("LabelSettings_6qyb2")
64+
65+
[node name="ScrollContainer" type="ScrollContainer" parent="MarginContainer/VBoxContainer"]
66+
layout_mode = 2
67+
size_flags_vertical = 3
68+
69+
[node name="GridContainer" type="GridContainer" parent="MarginContainer/VBoxContainer/ScrollContainer"]
70+
layout_mode = 2
71+
72+
[node name="HBoxContainer2" type="HBoxContainer" parent="MarginContainer/VBoxContainer"]
73+
layout_mode = 2
74+
75+
[node name="ResponseEdit" type="TextEdit" parent="MarginContainer/VBoxContainer/HBoxContainer2"]
76+
custom_minimum_size = Vector2(250, 140)
77+
layout_mode = 2
78+
size_flags_horizontal = 3
79+
editable = false
80+
wrap_mode = 1
81+
82+
[connection signal="pressed" from="MarginContainer/VBoxContainer/HBoxContainer/SendButton" to="." method="_on_send_button_pressed"]

0 commit comments

Comments
 (0)