|
| 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 | + |
0 commit comments