TRMT commited on
Commit
3ff02f5
1 Parent(s): 9365924

update files

Browse files
Dockerfile ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Use the official Python 3.9 image
2
+ FROM python:3.9
3
+
4
+ # Set the working directory to /code
5
+ WORKDIR /code
6
+
7
+ # Copy the current directory contents into the container at /code
8
+ COPY ./requirements.txt /code/requirements.txt
9
+
10
+ # Install requirements.txt
11
+ RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
12
+
13
+ # Set up a new user named "user" with user ID 1000
14
+ RUN useradd -m -u 1000 user
15
+ # Switch to the "user" user
16
+ USER user
17
+ # Set home to the user's home directory
18
+ ENV HOME=/home/user \\
19
+ PATH=/home/user/.local/bin:$PATH
20
+
21
+ # Set the working directory to the user's home directory
22
+ WORKDIR $HOME/app
23
+
24
+ # Copy the current directory contents into the container at $HOME/app setting the owner to the user
25
+ COPY --chown=user . $HOME/app
26
+
27
+ # Start the FastAPI app on port 7860, the default port expected by Spaces
28
+ CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "7860"]
data/all_BirdDBnode.tsv ADDED
The diff for this file is too large to render. See raw diff
 
data/en_aliases_vecs_all.bin ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:17b6dfb3d08beadc7913fbfe29fe0fd8e173cb11cfc82ba35e255c1529bbed63
3
+ size 437145400
data/en_name_vecs.bin ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:743340b070341d71a2aad32f66aedf77e49ef5ff6b2de62b5c7a5c1f206a37f3
3
+ size 1511197579
data/ja_aliases_vecs.bin ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:ed3354357c7e92ef697e5c847d1bed4985aaa3ffc93532ab0bcd934e89424317
3
+ size 25826631
data/ja_name_vecs.bin ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:1c14efd3a6523251838e3962235f124554f036649e84e6ee82a776b7597fefca
3
+ size 251726597
data/sound_vecs.json ADDED
The diff for this file is too large to render. See raw diff
 
main.py ADDED
@@ -0,0 +1,496 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import FastAPI,UploadFile,File,Form
2
+ from typing import List,Dict
3
+ import difflib
4
+ import librosa
5
+ from collections import defaultdict
6
+ from pykakasi import kakasi
7
+ from dotenv import load_dotenv
8
+
9
+ import openai
10
+
11
+ from fastapi import FastAPI,Request
12
+ from fastapi.staticfiles import StaticFiles
13
+ from fastapi.templating import Jinja2Templates
14
+ from fastapi.responses import HTMLResponse,JSONResponse
15
+
16
+ #鍵関連
17
+ from fastapi import Depends, HTTPException
18
+ from starlette.middleware.sessions import SessionMiddleware
19
+
20
+ import numpy as np
21
+ import json
22
+ import pickle
23
+ import csv
24
+ import os
25
+ import ast
26
+ import shutil
27
+
28
+ import torch
29
+ from transformers import Wav2Vec2ForPreTraining,Wav2Vec2Processor
30
+ from transformers import BertModel,BertJapaneseTokenizer,BertTokenizer
31
+ from sklearn.metrics.pairwise import cosine_similarity
32
+
33
+ # =============アプリケーション
34
+ app = FastAPI()
35
+ app.mount("/static", StaticFiles(directory="static"), name="static")
36
+ templates = Jinja2Templates(directory="templates")
37
+
38
+ app.add_middleware(SessionMiddleware, secret_key="your_secret_key")
39
+
40
+ # =============知識グラフ
41
+ nodes=dict()
42
+ p2c=defaultdict(list)
43
+ with open('data/all_BirdDBnode.tsv', mode='r', newline='', encoding='utf-8') as f:
44
+ for row in csv.DictReader(f, delimiter = '\t'):
45
+ nodes[row["id"]] = row
46
+ p2c[row["parent_taxon"]].append(row["id"])
47
+ print("knowledge data loading is complete !")
48
+
49
+
50
+ # =============音声モデル
51
+ w2v2 = Wav2Vec2ForPreTraining.from_pretrained("model/wav2vec2-bird-jp-all")
52
+ print("sound model loading is complete !")
53
+
54
+
55
+ # =============音声埋め込み
56
+ with open('data/sound_vecs.json') as f:
57
+ sound_vecs = json.load(f)
58
+ print("sound vec data loading is complete !")
59
+
60
+
61
+ # =============言語モデル
62
+ # ローカルから日英BERTのモデル・トークナイザーを読み込み
63
+ en_model = BertModel.from_pretrained('model/en_model')
64
+ en_tokenizer = BertTokenizer.from_pretrained('model/en_tokenizer')
65
+ ja_model = BertModel.from_pretrained('model/ja_model')
66
+ ja_tokenizer = BertJapaneseTokenizer.from_pretrained('model/ja_tokenizer')
67
+ print("language model loading is complete !")
68
+
69
+ # # リモートから日英BERTのモデル・トークナイザーを読み込み
70
+ # en_tokenizer = BertTokenizer.from_pretrained('bert-base-uncased')
71
+ # en_model = BertModel.from_pretrained('bert-base-uncased')
72
+ # ja_tokenizer = BertJapaneseTokenizer.from_pretrained('cl-tohoku/bert-base-japanese-whole-word-masking')
73
+ # ja_model = BertModel.from_pretrained('cl-tohoku/bert-base-japanese-whole-word-masking')
74
+
75
+ # =============言語埋め込み
76
+ with open('data/en_name_vecs.bin','rb') as bf:
77
+ en_name_vecs = pickle.load(bf)
78
+ print("en_name_vecs data loading is complete !")
79
+
80
+ with open('data/ja_name_vecs.bin','rb') as bf:
81
+ ja_name_vecs = pickle.load(bf)
82
+ print("ja_name_vecs data loading is complete !")
83
+
84
+ with open('data/en_aliases_vecs_all.bin','rb') as bf:
85
+ en_aliases_vecs = pickle.load(bf)
86
+ print("en_aliases_vecs_all data loading is complete !")
87
+
88
+ with open('data/ja_aliases_vecs.bin','rb') as bf:
89
+ ja_aliases_vecs = pickle.load(bf)
90
+ print("ja_aliases_vecs data loading is complete !")
91
+ print("language vec data loading is complete !")
92
+
93
+ # =============queryとwordを引数にとり,類似度を返す関数=>これはBERTにしなければならない
94
+ def raito(query,word):
95
+ raito = difflib.SequenceMatcher(None, query, word).ratio()
96
+ return raito
97
+
98
+ # =============queryとwordを引数にとり,BERT類似度を返す関数
99
+ # def raito_bert_en(q_vec, word, aliases):
100
+ # # 文をBERTの分散表現に変換する
101
+ # tokenizer = en_tokenizer
102
+ # model = en_model
103
+
104
+ # if aliases == False:w_vec = en_name_vecs[word]# wordの分散表現
105
+ # else:w_vec = en_aliases_vecs[word]
106
+
107
+ # similarity = cosine_similarity(q_vec.unsqueeze(0).numpy(), w_vec.unsqueeze(0).numpy())
108
+ # return similarity[0][0]# Cosine類似度
109
+
110
+
111
+ # def raito_bert_ja(q_vec, word, aliases):
112
+ # # 文をBERTの分散表現に変換する
113
+ # tokenizer = ja_tokenizer
114
+ # model = ja_model
115
+
116
+ # if aliases == False:w_vec = ja_name_vecs[word]
117
+ # else:w_vec = ja_aliases_vecs[word]
118
+
119
+
120
+ # similarity = cosine_similarity(q_vec.unsqueeze(0).numpy(), w_vec.unsqueeze(0).numpy())
121
+ # return similarity[0][0]# Cosine類似度
122
+
123
+
124
+ # 日英両対応
125
+ def raito_b(q_vec, w_vec):
126
+ # 文をBERTの分散表現に変換する
127
+ similarity = cosine_similarity(q_vec.unsqueeze(0).numpy(), w_vec.unsqueeze(0).numpy())
128
+ return similarity[0][0]# Cosine類似度
129
+
130
+
131
+ def raito_bert(q_vec, word, en, aliases):
132
+ # 文をBERTの分散表現に変換する
133
+ if en == True:
134
+ tokenizer = en_tokenizer
135
+ model = en_model
136
+
137
+ if aliases == False:w_vec = en_name_vecs[word]# wordの分散表現
138
+ else:w_vec = en_aliases_vecs[word]
139
+
140
+ else:
141
+ tokenizer = ja_tokenizer
142
+ model = ja_model
143
+
144
+ if aliases == False:w_vec = ja_name_vecs[word]
145
+ else:w_vec = ja_aliases_vecs[word]
146
+
147
+
148
+ similarity = cosine_similarity(q_vec.unsqueeze(0).numpy(), w_vec.unsqueeze(0).numpy())
149
+ return similarity[0][0]# Cosine類似度
150
+
151
+
152
+ # ============= id=>必要な項目のみを含む自身,親,子の辞書を返す関数
153
+
154
+ def small_d(d):
155
+ if d != None:
156
+ small_d = {"id":d["id"],
157
+ "en_name":d["en_name"],
158
+ "ja_name":d["ja_name"],
159
+ "en_aliases":d["en_aliases"],
160
+ "ja_aliases":d["ja_aliases"],
161
+ "img_urls":d["img_urls"],
162
+ "taxon_name":d["taxon_name"],
163
+ "BR_id":d["BirdResearchDB_label01_32k_audio_id"],
164
+ "JP_id":d["BirdJPBookDB__data_audio_id"]
165
+ }
166
+ else:
167
+ small_d == None
168
+ return small_d
169
+
170
+
171
+ def id2ans(myself_id):
172
+ ans = {"myself":dict(),"my_parent":None,"my_children":None}
173
+ myself_d = nodes[myself_id]
174
+ parent_id = nodes[myself_id]["parent_taxon"]
175
+ parent_d = nodes[parent_id]
176
+
177
+ ans["myself"] = small_d(myself_d)
178
+ # 指定したノードidのWikiData隣接ノードを取得
179
+ if parent_id in nodes:
180
+ ans["my_parent"] = small_d(parent_d)
181
+ if myself_id in p2c:
182
+ ans["my_children"] = [small_d(nodes[chile_id]) for chile_id in p2c[myself_id]]
183
+ return ans
184
+
185
+
186
+ # ============= 2つのnumpy.arrayデータの類似度算出関数
187
+ def cos_sim(v1, v2):
188
+ return np.dot(v1, v2) / (np.linalg.norm(v1) * np.linalg.norm(v2))
189
+
190
+
191
+ # ============= 漢字および平仮名をカタカナに修正する関数
192
+ def to_katakana(text):
193
+ # kakasiオブジェクトを作成
194
+ kakasi_instance = kakasi()
195
+ kakasi_instance.setMode("J", "K") # J(漢字)をH(ひらがな)に変換
196
+ kakasi_instance.setMode("H", "K") # H(ひらがな)をK(カタカナ)に変換
197
+
198
+ # カタカナに変換
199
+ conv = kakasi_instance.getConverter()
200
+ katakana_text = conv.do(text)
201
+ return katakana_text
202
+
203
+
204
+ # =============OpenAI APIキー手動入力画面設定
205
+ @app.middleware("http")
206
+ async def some_middleware(request: Request, call_next):
207
+ response = await call_next(request)
208
+ session = request.cookies.get('session')
209
+ if session:
210
+ response.set_cookie(key='session', value=request.cookies.get('session'), httponly=True)
211
+ return response
212
+
213
+ # ============= ChatGPT応答用関数
214
+
215
+ # OpenAI APIキーを初期化(.envから読込む場合)
216
+ # load_dotenv()
217
+ # openai.api_key = os.getenv("API_KEY")
218
+ # debug_mode = os.getenv("DEBUG")
219
+
220
+ # ChatGPTに質問を送信する関数
221
+ def ask_gpt3(question,api_key,max_tokens=2600):
222
+ # bird_prompt = "次のjsonがどのような情報を持っているかを「お探しの鳥はこれかも:」から始まる簡潔な話し言葉で伝えてください。"
223
+ # bird_prompt = "このjsonデータについて,何が分かりますか?"
224
+ bird_prompt = "このデータを基にこの鳥について解説して:"
225
+
226
+ load_dotenv()
227
+ openai.api_key = api_key
228
+ debug_mode = True
229
+ json_string = json.dumps(question)
230
+
231
+ response = openai.Completion.create(
232
+ engine="text-davinci-003",
233
+ # prompt=bird_prompt+f"{question}\n",
234
+ prompt=bird_prompt+json_string,
235
+ max_tokens=max_tokens,
236
+ stop=None,
237
+ temperature=0.7,
238
+ )
239
+ return response.choices[0].text.strip()
240
+
241
+ # =============# 辞書→WebサイトHTML生成関数
242
+ def aliases_str(d_aliases):
243
+ if d_aliases == "{}":
244
+ return ""
245
+ else:
246
+ # print("d_aliases:",d_aliases)
247
+ d_aliases = ast.literal_eval(d_aliases)
248
+ aliases = ""
249
+ for k,v in d_aliases.items():
250
+ aliases = aliases+v+"/"
251
+
252
+ aliases = aliases[:-1]
253
+ if aliases != "":
254
+ aliases = "("+aliases+")"
255
+
256
+ return aliases
257
+
258
+ def imgs_list(d_img_urls):
259
+ img_urls = []
260
+ if d_img_urls == "{}":
261
+ pass
262
+ else:
263
+ d_img_urls = json.loads(d_img_urls.replace("'",'"'))
264
+ for k,v in d_img_urls.items():
265
+ img_urls.append(v)
266
+ return img_urls
267
+
268
+ def d4html(myself_d,self_or_parent,n):#word検索ではnは無し,sound検索では_1,_2,_3
269
+ print(self_or_parent+"_taxon_name"+n)
270
+ new_d ={
271
+ self_or_parent+"_taxon_name"+n:myself_d["taxon_name"],
272
+ self_or_parent+"_ja_name"+n:myself_d["ja_name"],
273
+ self_or_parent+"_ja_aliases"+n:aliases_str(myself_d["ja_aliases"]),
274
+ self_or_parent+"_en_name"+n:myself_d["en_name"],
275
+ self_or_parent+"_en_aliases"+n:aliases_str(myself_d["en_aliases"]),
276
+ self_or_parent+"_link"+n:"https://www.wikidata.org/wiki/"+myself_d["id"],
277
+ self_or_parent+"_imgs_list"+n:imgs_list(myself_d["img_urls"])
278
+ }
279
+ return new_d
280
+
281
+ def self_d4html(myself_d,n):#word検索ではnは無し,sound検索では_1,_2,_3
282
+ new_d ={"self_taxon_name"+n:myself_d["taxon_name"],
283
+ "self_ja_name"+n:myself_d["ja_name"],
284
+ "self_ja_aliases"+n:aliases_str(myself_d["ja_aliases"]),
285
+ "self_en_name"+n:myself_d["en_name"],
286
+ "self_en_aliases"+n:aliases_str(myself_d["en_aliases"]),
287
+ "self_link"+n:"https://www.wikidata.org/wiki/"+myself_d["id"],
288
+ "self_imgs_list"+n:imgs_list(myself_d["img_urls"])
289
+ }
290
+ print(new_d)
291
+ return new_d
292
+
293
+ def parent_d4html(parent_d,n):#word検索ではnは無し,sound検索では_1,_2,_3
294
+ new_d ={"parent_taxon_name"+n:parent_d["taxon_name"],
295
+ "parent_ja_name"+n:parent_d["ja_name"],
296
+ "parent_ja_aliases"+n:aliases_str(parent_d["ja_aliases"]),
297
+ "parent_en_name"+n:parent_d["en_name"],
298
+ "parent_en_aliases"+n:aliases_str(parent_d["en_aliases"]),
299
+ "parent_link"+n:"https://www.wikidata.org/wiki/"+parent_d["id"],
300
+ "parent_imgs_list"+n:imgs_list(parent_d["img_urls"])
301
+ }
302
+ return new_d
303
+
304
+ # =============# 自然言語クエリに最も近いnameを検索,対応するノードのidを取得=>自身,親,子を辞書で返す
305
+ @app.get("/word_search", response_class=HTMLResponse)
306
+ async def read_root(request:Request, api_key:str=""):
307
+ api_key = request.session.get("api_key", "please_input_your_api_key")
308
+ return templates.TemplateResponse("word_search.html", {"request": request,"api_key":api_key})
309
+
310
+
311
+ @app.post("/word_search", response_class=HTMLResponse)
312
+ async def search_adjacent_nodes(request:Request, api_key: str = Form(...), query: str = Form(...)):
313
+
314
+ form_data = await request.form()
315
+ query = form_data["query"]
316
+ query = to_katakana(query)
317
+ max_cos_in_wikidata = 0.0 # Wikidata内で最大の類似度格納変数
318
+ max_id_in_wikidata = None # Wikidata内で最大の類似度のID格納変数
319
+
320
+ #for bert
321
+ en_tokens = en_tokenizer(query, return_tensors="pt", padding=True, truncation=True)#日本語埋め込みと英語埋め込みが必要
322
+ ja_tokens = ja_tokenizer(query, return_tensors="pt", padding=True, truncation=True)#日本語埋め込みと英語埋め込みが必要
323
+
324
+ with torch.no_grad():
325
+ en_model.eval()
326
+ en_output = en_model(**en_tokens)
327
+
328
+ ja_model.eval()
329
+ ja_output = ja_model(**ja_tokens)
330
+
331
+ en_q_vec = en_output.last_hidden_state[0][0]# queryの分散表現
332
+ ja_q_vec = ja_output.last_hidden_state[0][0]# queryの分散表現
333
+
334
+ #bertによる完全一致
335
+ for node_id,node in nodes.items():
336
+ #英語名,日本語名,英語名・日本語名のエイリアスとの類似のクエリとの類似
337
+ # r_in_node: rait in node,該当ノードに含まれる関連語全般とクエリの類似度を格納
338
+ r_in_node = set()
339
+
340
+ en_name_vec = en_name_vecs[node["en_name"]]
341
+ ja_name_vec = ja_name_vecs[node["ja_name"]]
342
+
343
+ r_in_node.add(raito_b(en_q_vec,en_name_vec))#途中!
344
+ r_in_node.add(raito_b(ja_q_vec,ja_name_vec))
345
+
346
+ if isinstance(node["en_aliases"], dict):
347
+ for k,v in node["en_aliases"].items():
348
+ en_aliases_vec = en_aliases_vecs[v]
349
+ r_in_node.add(raito_b(en_q_vec,en_aliases_vec,en=True,aliases=True))
350
+ if isinstance(node["ja_aliases"], dict):
351
+ for k,v in node["ja_aliases"].items():
352
+ ja_aliases_vec = ja_aliases_vecs[v]
353
+ r_in_node.add(raito_b(ja_q_vec,ja_aliases_vec,en=False,aliases=True))
354
+
355
+
356
+ if max(r_in_node) != 0.0:
357
+ if max(r_in_node) > max_cos_in_wikidata:
358
+ max_cos_in_wikidata = max(r_in_node)
359
+ max_id_in_wikidata = node_id
360
+
361
+ #シンプルな完全一致
362
+ # for node_id,node in nodes.items():#英語名,日本語名,英語名・日本語名のエイリアスとの類似のクエリとの類似
363
+ # r_in_node = set()#rait in node,該当ノードに含まれる関連語全般とクエリの類似度を格納
364
+
365
+ # r_in_node.add(raito(query,node["en_name"]))
366
+ # r_in_node.add(raito(query,node["ja_name"]))
367
+
368
+ # if isinstance(node["en_aliases"], dict):
369
+ # for k,v in node["en_aliases"].items():
370
+ # r_in_node.add(raito(query,v))
371
+ # if isinstance(node["ja_aliases"], dict):
372
+ # for k,v in node["ja_aliases"].items():
373
+ # r_in_node.add(raito(query,v))
374
+
375
+
376
+ # if max(r_in_node) != 0.0:
377
+ # if max(r_in_node) > max_cos_in_wikidata:
378
+ # max_cos_in_wikidata = max(r_in_node)
379
+ # max_id_in_wikidata = node_id
380
+
381
+ if max_id_in_wikidata!=None:
382
+ ans_json = id2ans(max_id_in_wikidata)
383
+
384
+ #一旦
385
+ # gpt_ans_self = "ツルは、鳥類の中でも特に大きい鳥であり、ツル科(Gruidae)に属する鳥です。英語名は「Crane」となっており、体長は1.5-1.8メートル、体重は4-6キログラムとなっています。頭部の色は褐色から黒色まで変化し、胸部から尾部にかけて白色の模様が見られます。翼は非常に大きく、飛行時には振り子のような動きをします。ツルは、草原や湿地などに生息する大型の鳥であり、ミヤマツルやオオツルなどが有名です。宿泊地は冬期に南へ移動し、豊かな水源や草原を求めて���にインドや中国などの亜熱帯地域を中心に広く移動します。ツルは餌を釣り上げる行動をとり、草原の他にも沼沢地などの水辺にも行きます。ツルは繁殖期には集団で繁殖し、巣を枝、葉、茎などで作ります。ツルは、家禽類として古来から飼育され、食用、羽毛、肉などの用途に使われてきました。また、風俗習慣や文化表現などにも使用されてきました。"
386
+ # gpt_ans_parent = "ツル目とは、鳥類の一綱であるグルイフォーム(Gruiformes)に属します。グルイフォームとは、主として水辺に住む、鷺科(草原鶴)、カモ科(カモ)、コウノトリ科(コウノトリ)などの林鳥の他、カナリア科(カナリア)、サギ科(サギ)、カラス科(カラス)などの鳥類を含む綱です。グルイフォームには、大きさが大きいものから小さいものまで様々な種類の鳥がいますが、一般的には、大きな翼を持つ、とても美しい鳥として知られています。グルイフォームの鳥の標準的な外見は、長い頭、短い頭部、長い首、茶色の全身、細長い尾などが特徴的です。また、特徴的な形をしていることから、グルイフォームの鳥は、大規模な湖沼などで見かけられることが多いです。"
387
+ # gpt_ans_children = "ツル属(Grus)は、カンムリヅル属(Balearica)に分類される鳥類の総称です。ツル属は、ツル、カンムリヅル、レウコジェラヌス(Leucogeranus)、ゲラノプシス(Geranopsis)、アンスロポイデス(Anthropoides)、イオバレリカ(Eobalearica)、ブゲラヌス(Bugeranus)、カンムリヅル亜科(Balearicinae)、グリ亜科(Gruinae)などの亜科があります。 ツル属の鳥は、体長60cm前後の遠くの草原を尋ね回る大型の鳥です。また、その鳥は、褐色の上背部と、胸部には白い斑点が見られます。ツル属の鳥は、その力強い鳴き声でも知られており、多くの生息地を持つため、地域によって分布が異なります。特に、アジア、アフリカ、ヨーロッパなど、多くの国で見られます。ツル属の鳥は、家畜の餌や農作物などを食べて生活し、繁殖期間中には、川や沼津などの水場を訪れ、水辺の地形を利用して繁殖します。"
388
+ # 真のコード
389
+ gpt_ans_self = ask_gpt3(ans_json["myself"],api_key)
390
+ gpt_ans_parent = ask_gpt3(ans_json["my_parent"],api_key)
391
+ gpt_ans_children = ask_gpt3(ans_json["my_children"],api_key)
392
+ print(max_cos_in_wikidata)
393
+
394
+
395
+ return templates.TemplateResponse("word_search.html",
396
+ {**{"request": request,
397
+ "api_key":api_key,
398
+ "max_cos_in_wikidata":round(max_cos_in_wikidata,4),
399
+ "gpt_ans_self": gpt_ans_self,
400
+ "gpt_ans_parent": gpt_ans_parent,
401
+ "gpt_ans_children": gpt_ans_children},
402
+ **d4html(ans_json["myself"],"self",""),
403
+ **d4html(ans_json["my_parent"],"parent","")
404
+ })
405
+ else:
406
+ return None
407
+
408
+
409
+ # =============音声 => 再類似ノード(記事の欠陥により複数あり)・その親と子を含む辞書をリストに格納し返す関数
410
+ @app.get("/sound_search", response_class=HTMLResponse)
411
+ async def read_root(request:Request, api_key:str=""):
412
+ api_key = request.session.get("api_key", "please_input_your_api_key")
413
+ return templates.TemplateResponse("sound_search.html", {"request": request,"api_key":api_key})
414
+
415
+ @app.post("/sound_search",response_class=HTMLResponse)
416
+ async def sound_search(request: Request, api_key: str = Form(...), file: UploadFile = File(...)):
417
+ # async def sound_search(request: Request,file: UploadFile = File(...)):
418
+
419
+ uploaded_dir = "uploaded"
420
+ shutil.rmtree(uploaded_dir)
421
+ os.mkdir(uploaded_dir)
422
+
423
+ with open(uploaded_dir+"/"+file.filename, "wb") as f:
424
+ f.write(await file.read())
425
+
426
+ sound_data,_ = librosa.load("uploaded/"+file.filename, sr=16000)
427
+ result = w2v2(torch.tensor([sound_data]))
428
+ hidden_vecs = result.projected_states
429
+ input_vecs = np.mean(hidden_vecs[0].cpu().detach().numpy(), axis=0)
430
+
431
+ max_cos_sim = 0.0
432
+ max_in_sounddata = None
433
+
434
+ id_cos_d = dict()
435
+
436
+ for d in sound_vecs:
437
+ cos = cos_sim(input_vecs,d["vector"])
438
+ id_cos_d[d["id"][0]]=cos
439
+
440
+ id_cos_sorted = sorted(id_cos_d.items(), key=lambda x:x[1],reverse=True)
441
+
442
+ try:
443
+ ans_json_1 = id2ans(id_cos_sorted[0][0])
444
+ ans_json_2 = id2ans(id_cos_sorted[1][0])
445
+ ans_json_3 = id2ans(id_cos_sorted[2][0])
446
+
447
+ #真のコード
448
+ gpt_ans_self_1 = ask_gpt3(ans_json_1["myself"],api_key)
449
+ gpt_ans_parent_1 = ask_gpt3(ans_json_1["my_parent"],api_key)
450
+ gpt_ans_children_1 = ask_gpt3(ans_json_1["my_children"],api_key)
451
+
452
+ gpt_ans_self_2 = ask_gpt3(ans_json_2["myself"],api_key)
453
+ gpt_ans_parent_2 = ask_gpt3(ans_json_2["my_parent"],api_key)
454
+ gpt_ans_children_2 = ask_gpt3(ans_json_2["my_children"],api_key)
455
+
456
+ gpt_ans_self_3 = ask_gpt3(ans_json_3["myself"],api_key)
457
+ gpt_ans_parent_3 = ask_gpt3(ans_json_3["my_parent"],api_key)
458
+ gpt_ans_children_3 = ask_gpt3(ans_json_3["my_children"],api_key)
459
+
460
+ #一旦
461
+ # gpt_ans_self_1 = "test"
462
+ # gpt_ans_parent_1 = "testtest"
463
+ # gpt_ans_children_1 = "testtesttest"
464
+
465
+ # gpt_ans_self_2 = "test"
466
+ # gpt_ans_parent_2 = "testtest"
467
+ # gpt_ans_children_2 = "testtesttest"
468
+
469
+ # gpt_ans_self_3 = "test"
470
+ # gpt_ans_parent_3 = "testtest"
471
+ # gpt_ans_children_3 = "testtesttest"
472
+
473
+ return templates.TemplateResponse("sound_search.html",
474
+ {**{"request": request,
475
+ "api_key":api_key,
476
+ "max_cos_in_wikidata_1":round(id_cos_sorted[0][1],4),#類似度
477
+ "max_cos_in_wikidata_2":round(id_cos_sorted[1][1],4),
478
+ "max_cos_in_wikidata_3":round(id_cos_sorted[2][1],4),
479
+ "gpt_ans_self_1": gpt_ans_self_1,
480
+ "gpt_ans_parent_1": gpt_ans_parent_1,
481
+ "gpt_ans_children_1": gpt_ans_children_1,
482
+ "gpt_ans_self_2": gpt_ans_self_2,
483
+ "gpt_ans_parent_2": gpt_ans_parent_2,
484
+ "gpt_ans_children_2": gpt_ans_children_2,
485
+ "gpt_ans_self_3": gpt_ans_self_3,
486
+ "gpt_ans_parent_3": gpt_ans_parent_3,
487
+ "gpt_ans_children_3": gpt_ans_children_3},
488
+ **d4html(ans_json_1["myself"],"self","_1"),
489
+ **d4html(ans_json_1["my_parent"],"parent","_1"),
490
+ **d4html(ans_json_2["myself"],"self","_2"),
491
+ **d4html(ans_json_2["my_parent"],"parent","_2"),
492
+ **d4html(ans_json_3["myself"],"self","_3"),
493
+ **d4html(ans_json_3["my_parent"],"parent","_3")
494
+ })
495
+ except:
496
+ return None
model/en_model/config.json ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "_name_or_path": "bert-base-uncased",
3
+ "architectures": [
4
+ "BertModel"
5
+ ],
6
+ "attention_probs_dropout_prob": 0.1,
7
+ "classifier_dropout": null,
8
+ "gradient_checkpointing": false,
9
+ "hidden_act": "gelu",
10
+ "hidden_dropout_prob": 0.1,
11
+ "hidden_size": 768,
12
+ "initializer_range": 0.02,
13
+ "intermediate_size": 3072,
14
+ "layer_norm_eps": 1e-12,
15
+ "max_position_embeddings": 512,
16
+ "model_type": "bert",
17
+ "num_attention_heads": 12,
18
+ "num_hidden_layers": 12,
19
+ "pad_token_id": 0,
20
+ "position_embedding_type": "absolute",
21
+ "torch_dtype": "float32",
22
+ "transformers_version": "4.30.2",
23
+ "type_vocab_size": 2,
24
+ "use_cache": true,
25
+ "vocab_size": 30522
26
+ }
model/en_model/pytorch_model.bin ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:ff8e66bc015553d84e94959a0b84aa7386b59a83ae74b49189f735b107b01afc
3
+ size 437997357
model/en_tokenizer/special_tokens_map.json ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ {
2
+ "cls_token": "[CLS]",
3
+ "mask_token": "[MASK]",
4
+ "pad_token": "[PAD]",
5
+ "sep_token": "[SEP]",
6
+ "unk_token": "[UNK]"
7
+ }
model/en_tokenizer/tokenizer_config.json ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "clean_up_tokenization_spaces": true,
3
+ "cls_token": "[CLS]",
4
+ "do_basic_tokenize": true,
5
+ "do_lower_case": true,
6
+ "mask_token": "[MASK]",
7
+ "model_max_length": 512,
8
+ "never_split": null,
9
+ "pad_token": "[PAD]",
10
+ "sep_token": "[SEP]",
11
+ "strip_accents": null,
12
+ "tokenize_chinese_chars": true,
13
+ "tokenizer_class": "BertTokenizer",
14
+ "unk_token": "[UNK]"
15
+ }
model/en_tokenizer/vocab.txt ADDED
The diff for this file is too large to render. See raw diff
 
model/ja_model/config.json ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "_name_or_path": "cl-tohoku/bert-base-japanese-whole-word-masking",
3
+ "architectures": [
4
+ "BertModel"
5
+ ],
6
+ "attention_probs_dropout_prob": 0.1,
7
+ "classifier_dropout": null,
8
+ "hidden_act": "gelu",
9
+ "hidden_dropout_prob": 0.1,
10
+ "hidden_size": 768,
11
+ "initializer_range": 0.02,
12
+ "intermediate_size": 3072,
13
+ "layer_norm_eps": 1e-12,
14
+ "max_position_embeddings": 512,
15
+ "model_type": "bert",
16
+ "num_attention_heads": 12,
17
+ "num_hidden_layers": 12,
18
+ "pad_token_id": 0,
19
+ "position_embedding_type": "absolute",
20
+ "tokenizer_class": "BertJapaneseTokenizer",
21
+ "torch_dtype": "float32",
22
+ "transformers_version": "4.30.2",
23
+ "type_vocab_size": 2,
24
+ "use_cache": true,
25
+ "vocab_size": 32000
26
+ }
model/ja_model/pytorch_model.bin ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:050afbbe947c1ad144388cb5614ae92bc3ebe4489eed2789797bd569dddf20a2
3
+ size 442537773
model/ja_tokenizer/special_tokens_map.json ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ {
2
+ "cls_token": "[CLS]",
3
+ "mask_token": "[MASK]",
4
+ "pad_token": "[PAD]",
5
+ "sep_token": "[SEP]",
6
+ "unk_token": "[UNK]"
7
+ }
model/ja_tokenizer/tokenizer_config.json ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "clean_up_tokenization_spaces": true,
3
+ "cls_token": "[CLS]",
4
+ "do_lower_case": false,
5
+ "do_subword_tokenize": true,
6
+ "do_word_tokenize": true,
7
+ "jumanpp_kwargs": null,
8
+ "mask_token": "[MASK]",
9
+ "mecab_kwargs": null,
10
+ "model_max_length": 512,
11
+ "never_split": null,
12
+ "pad_token": "[PAD]",
13
+ "sep_token": "[SEP]",
14
+ "subword_tokenizer_type": "wordpiece",
15
+ "sudachi_kwargs": null,
16
+ "tokenizer_class": "BertJapaneseTokenizer",
17
+ "unk_token": "[UNK]",
18
+ "word_tokenizer_type": "mecab"
19
+ }
model/ja_tokenizer/vocab.txt ADDED
The diff for this file is too large to render. See raw diff
 
model/wav2vec2-bird-jp-all/config.json ADDED
@@ -0,0 +1,108 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "_name_or_path": "./wav2vec2-bird-jp-all",
3
+ "activation_dropout": 0.0,
4
+ "adapter_kernel_size": 3,
5
+ "adapter_stride": 2,
6
+ "add_adapter": false,
7
+ "apply_spec_augment": true,
8
+ "architectures": [
9
+ "Wav2Vec2ForPreTraining"
10
+ ],
11
+ "attention_dropout": 0.0,
12
+ "bos_token_id": 1,
13
+ "classifier_proj_size": 256,
14
+ "codevector_dim": 256,
15
+ "contrastive_logits_temperature": 0.1,
16
+ "conv_bias": true,
17
+ "conv_dim": [
18
+ 512,
19
+ 512,
20
+ 512,
21
+ 512,
22
+ 512,
23
+ 512,
24
+ 512
25
+ ],
26
+ "conv_kernel": [
27
+ 10,
28
+ 3,
29
+ 3,
30
+ 3,
31
+ 3,
32
+ 2,
33
+ 2
34
+ ],
35
+ "conv_stride": [
36
+ 5,
37
+ 2,
38
+ 2,
39
+ 2,
40
+ 2,
41
+ 2,
42
+ 2
43
+ ],
44
+ "ctc_loss_reduction": "sum",
45
+ "ctc_zero_infinity": false,
46
+ "diversity_loss_weight": 0.1,
47
+ "do_stable_layer_norm": true,
48
+ "eos_token_id": 2,
49
+ "feat_extract_activation": "gelu",
50
+ "feat_extract_dropout": 0.0,
51
+ "feat_extract_norm": "layer",
52
+ "feat_proj_dropout": 0.0,
53
+ "feat_quantizer_dropout": 0.0,
54
+ "final_dropout": 0.0,
55
+ "hidden_act": "gelu",
56
+ "hidden_dropout": 0.0,
57
+ "hidden_dropout_prob": 0.0,
58
+ "hidden_size": 768,
59
+ "initializer_range": 0.02,
60
+ "intermediate_size": 3072,
61
+ "layer_norm_eps": 1e-05,
62
+ "layerdrop": 0.0,
63
+ "mask_feature_length": 10,
64
+ "mask_feature_min_masks": 0,
65
+ "mask_feature_prob": 0.0,
66
+ "mask_time_length": 5,
67
+ "mask_time_min_masks": 2,
68
+ "mask_time_prob": 0.65,
69
+ "model_type": "wav2vec2",
70
+ "num_adapter_layers": 3,
71
+ "num_attention_heads": 12,
72
+ "num_codevector_groups": 2,
73
+ "num_codevectors_per_group": 320,
74
+ "num_conv_pos_embedding_groups": 16,
75
+ "num_conv_pos_embeddings": 128,
76
+ "num_feat_extract_layers": 7,
77
+ "num_hidden_layers": 12,
78
+ "num_negatives": 100,
79
+ "output_hidden_size": 768,
80
+ "pad_token_id": 0,
81
+ "proj_codevector_dim": 256,
82
+ "tdnn_dilation": [
83
+ 1,
84
+ 2,
85
+ 3,
86
+ 1,
87
+ 1
88
+ ],
89
+ "tdnn_dim": [
90
+ 512,
91
+ 512,
92
+ 512,
93
+ 512,
94
+ 1500
95
+ ],
96
+ "tdnn_kernel": [
97
+ 5,
98
+ 3,
99
+ 3,
100
+ 1,
101
+ 1
102
+ ],
103
+ "torch_dtype": "float32",
104
+ "transformers_version": "4.24.0",
105
+ "use_weighted_layer_sum": false,
106
+ "vocab_size": 32,
107
+ "xvector_output_dim": 512
108
+ }
model/wav2vec2-bird-jp-all/pytorch_model.bin ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:49ae524d3dd798da7e6d1506daf3bc51475a08491f03cc50b4d80da278dff9e9
3
+ size 380295745
requirements.txt ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ transformers==4.30.2
2
+ torch==2.0.1
3
+ fastapi==0.95.2
4
+ uvicorn==0.22.0
5
+ librosa==0.10.0
6
+ json5==0.9.5
7
+ numpy==1.24.3
8
+ openai==0.28.0
9
+ python-dotenv==1.0.0
10
+ pykakasi==2.2.1
11
+ jinja2==3.0.1
12
+ MarkupSafe==2.0.1
13
+ starlette==0.27.0
14
+ fugashi==1.0.5
15
+ ipadic==1.0.0
static/style.css ADDED
@@ -0,0 +1,87 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ body {
2
+ background-color: #f0f0f0;
3
+ border: none;
4
+ /* font-size: 10pt;*/
5
+ color: #333;
6
+ margin: 0;
7
+ padding: 0;
8
+ margin-top: 40px;
9
+ margin-bottom: 40px;
10
+ margin-left: 70px;
11
+ margin-right: 70px;
12
+ }
13
+
14
+ header {
15
+ background-color: #333;
16
+ color: #fff;
17
+ padding: 1rem;
18
+ text-align: center;
19
+ }
20
+
21
+ main {
22
+ max-width: 800px;
23
+ margin: 2rem auto;
24
+ padding: 1rem;
25
+ background-color: #fff;
26
+ border-radius: 8px;
27
+ box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
28
+ }
29
+
30
+ /* ボタンのスタイリング */
31
+ button {
32
+ background-color: #333;
33
+ color: #fff;
34
+ border: none;
35
+ cursor: pointer;
36
+ transition: background-color 0.2s;
37
+ }
38
+
39
+ .long-input {
40
+ width: 243px;
41
+ padding: 0.2rem;
42
+ }
43
+
44
+ button:hover {
45
+ background-color: #555;
46
+ }
47
+
48
+ footer {
49
+ background-color: #333;
50
+ color: #fff;
51
+ text-align: center;
52
+ padding: 1rem;
53
+ }
54
+
55
+ blockquote {
56
+ margin-top: -20px;
57
+ margin-bottom: 40px;
58
+ margin-left: 0px;
59
+ margin-right: 0px;
60
+
61
+ padding-top: 1px;
62
+ padding-bottom: 40px;
63
+ padding-left: 10px;
64
+ padding-right: 10px;
65
+ /* padding: 0.5rem;*/
66
+
67
+ }
68
+
69
+ p {
70
+ font-size: 10pt;
71
+ }
72
+
73
+
74
+ .smallArea {
75
+ /* 基本的なサイズの設定 */
76
+ background-color: #e8e8e8;
77
+ }
78
+
79
+
80
+ /* レスポンシブデザイン */
81
+ @media (max-width: 600px) {
82
+ main {
83
+ /* font-size: 10pt;*/
84
+ margin: 1rem;
85
+ padding: 0.5rem;
86
+ }
87
+ }
templates/sound_search.html ADDED
@@ -0,0 +1,155 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>Multimodal Bird Search</title>
5
+ <link rel="stylesheet" type="text/css" href="/static/style.css">
6
+ </head>
7
+ <body>
8
+ <!-- <form action="/sound_search" method="post">
9
+ <div>
10
+ <label for="api_key">ChatGPT API Key:</label>
11
+ <input type="text" id="api_key" name="api_key" value="{{ api_key }}" required>
12
+ <button type="submit">入力</button>
13
+ </div>
14
+ </form> -->
15
+
16
+ <!-- <br> -->
17
+
18
+ <!-- <a href="/word_search">単語検索へ</a>
19
+ <form action="/sound_search" method="post" enctype="multipart/form-data">
20
+ <div>
21
+ <label>音声検索:</label>
22
+ <input type="file" name="file" placeholder="Input bird song file">
23
+ <button type="submit">検索</button>
24
+ </div>
25
+ </form> -->
26
+
27
+ <a href="/word_search">単語検索へ</a>
28
+ <form id="api_key_form" action="/sound_search" method="post" enctype="multipart/form-data">
29
+ <div>
30
+ <label for="api_key">ChatGPT API Key&nbsp;</label>
31
+ <input type="text" id="api_key" name="api_key" value="{{ api_key }}" required>
32
+
33
+ <br>
34
+
35
+ <label>音声検索</label>
36
+ <input type="file" name="file" placeholder="Input bird song file">
37
+ <button type="submit" id="submit-button">検索</button>
38
+ </div>
39
+ </form>
40
+
41
+ <!--
42
+ "self_taxon_name"
43
+ "self_ja_name"
44
+ "self_ja_aliases"
45
+ "self_en_name"
46
+ "self_en_aliases"
47
+ "self_link"
48
+ "self_imgs_list"-->
49
+ <br>
50
+
51
+ <h3>類似度:{{ max_cos_in_wikidata_1 }}</h3>
52
+ <blockquote class=smallArea>
53
+ <h3>和名:<a href="{{ self_link_1 }}">{{ self_ja_name_1 }}</a> {{ self_ja_aliases_1 }}
54
+ <br>英名:<a href="{{ self_link_1 }}">{{ self_en_name_1 }}</a> {{ self_en_aliases_1 }}</h3>
55
+
56
+ {% for img in self_imgs_list_1 %}
57
+ <iframe src="{{ img }}" width="500" height="300" frameborder="0"></iframe>
58
+ {% endfor %}
59
+
60
+ <h3>解説:</h3>
61
+ <p>{{ gpt_ans_self_1 }}</p>
62
+
63
+ <hr>
64
+
65
+ <h3>上位概念</h3>
66
+ <h4>和名:<a href="{{ parent_link_1 }}">{{ parent_ja_name_1 }}</a> {{ parent_ja_aliases_1 }}
67
+ <br>英名:<a href="{{ parent_link_1 }}">{{ parent_en_name_1 }}</a> {{ parent_en_aliases_1 }}</h4>
68
+
69
+ {% for img in parent_imgs_list_1 %}
70
+ <iframe src="{{ img }}" width="500" height="300" frameborder="0"></iframe>
71
+ {% endfor %}
72
+
73
+ <h4>解説:</h4>
74
+ <p>{{ gpt_ans_parent_1 }}</p>
75
+
76
+ <hr>
77
+
78
+ <h3>下位概念</h3>
79
+ <h4>解説:</h4>
80
+ <p>{{ gpt_ans_children_1 }}</p>
81
+ </blockquote>
82
+
83
+
84
+ <!-- ================================================================================== -->
85
+
86
+
87
+ <h3>類似度:{{ max_cos_in_wikidata_2 }}</h3>
88
+ <blockquote class=smallArea>
89
+ <h3>和名:<a href="{{ self_link_2 }}">{{ self_ja_name_2 }}</a> {{ self_ja_aliases_2 }}
90
+ <br>英名:<a href="{{ self_link_2 }}">{{ self_en_name_2 }}</a> {{ self_en_aliases_2 }}</h3>
91
+
92
+ {% for img in self_imgs_list_2 %}
93
+ <iframe src="{{ img }}" width="500" height="300" frameborder="0"></iframe>
94
+ {% endfor %}
95
+
96
+ <h3>解説:</h3>
97
+ <p>{{ gpt_ans_self_2 }}</p>
98
+
99
+ <hr>
100
+
101
+ <h3>上位概念</h3>
102
+ <h4>和名:<a href="{{ parent_link_2 }}">{{ parent_ja_name_2 }}</a> {{ parent_ja_aliases_2 }}
103
+ <br>英名:<a href="{{ parent_link_2 }}">{{ parent_en_name_2 }}</a> {{ parent_en_aliases_2 }}</h4>
104
+
105
+ {% for img in parent_imgs_list_2 %}
106
+ <iframe src="{{ img }}" width="500" height="300" frameborder="0"></iframe>
107
+ {% endfor %}
108
+
109
+ <h4>解説:</h4>
110
+ <p>{{ gpt_ans_parent_2 }}</p>
111
+
112
+ <hr>
113
+
114
+ <h3>下位概念</h3>
115
+ <h4>解説:</h4>
116
+ <p>{{ gpt_ans_children_2 }}</p>
117
+ </blockquote>
118
+
119
+
120
+ <!-- ================================================================================== -->
121
+
122
+
123
+ <h3>類似度:{{ max_cos_in_wikidata_3 }}</h3>
124
+ <blockquote class=smallArea>
125
+ <h3>和名:<a href="{{ self_link_3 }}">{{ self_ja_name_3 }}</a> {{ self_ja_aliases_3 }}
126
+ <br>英名:<a href="{{ self_link_3 }}">{{ self_en_name_3 }}</a> {{ self_en_aliases_3 }}</h3>
127
+
128
+ {% for img in self_imgs_list_3 %}
129
+ <iframe src="{{ img }}" width="500" height="300" frameborder="0"></iframe>
130
+ {% endfor %}
131
+
132
+ <h3>解説:</h3>
133
+ <p>{{ gpt_ans_self_3 }}</p>
134
+
135
+ <hr>
136
+
137
+ <h3>上位概念</h3>
138
+ <h4>和名:<a href="{{ parent_link_3 }}">{{ parent_ja_name_3 }}</a> {{ parent_ja_aliases_3 }}
139
+ <br>英名:<a href="{{ parent_link_3 }}">{{ parent_en_name_3 }}</a> {{ parent_en_aliases_3 }}</h4>
140
+
141
+ {% for img in parent_imgs_list_3 %}
142
+ <iframe src="{{ img }}" width="500" height="300" frameborder="0"></iframe>
143
+ {% endfor %}
144
+
145
+ <h4>解説:</h4>
146
+ <p>{{ gpt_ans_parent_3 }}</p>
147
+
148
+ <hr>
149
+
150
+ <h3>下位概念</h3>
151
+ <h4>解説:</h4>
152
+ <p>{{ gpt_ans_children_3 }}</p>
153
+ </blockquote>
154
+ </body>
155
+ </html>
templates/word_search.html ADDED
@@ -0,0 +1,83 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>Multimodal Bird Search</title>
5
+ <link rel="stylesheet" type="text/css" href="/static/style.css">
6
+ </head>
7
+ <body>
8
+ <a href="/sound_search">音声検索へ</a>
9
+ <form id="api_key_form" action="/word_search" method="post">
10
+ <div>
11
+ <label for="api_key">ChatGPT API Key&nbsp;</label><!-- 追加 -->
12
+ <input type="text" id="api_key" name="api_key" value="{{ api_key }}" required><!-- 追加 -->
13
+ <!-- <button type="button" id="submit-button">入力</button> -->
14
+ <!-- </div> -->
15
+ <!-- </form> -->
16
+
17
+ <br>
18
+
19
+ <!-- <a href="/sound_search">音声検索へ</a> -->
20
+ <!-- <form action="/word_search" method="post"> -->
21
+ <!-- <div> -->
22
+ <label>単語検索</label>
23
+ <input class=long-input type="text" name="query" placeholder="Input bird name">
24
+ <!-- <button type="submit">検索</button> -->
25
+ <button type="submit" id="submit-button">検索</button>
26
+ </div>
27
+ </form>
28
+
29
+ <!--
30
+ "self_taxon_name"
31
+ "self_ja_name"
32
+ "self_ja_aliases"
33
+ "self_en_name"
34
+ "self_en_aliases"
35
+ "self_link"
36
+ "self_imgs_list"-->
37
+ <br>
38
+ <!-- <h1>Welcome to the Test Page, {{ dammy_data }}!</h1> -->
39
+
40
+ <h3>類似度:{{max_cos_in_wikidata}}</h3>
41
+ <blockquote class=smallArea>
42
+ <h3>和名:<a href="{{ self_link }}">{{ self_ja_name }}</a> {{ self_ja_aliases }}
43
+ <br>英名:<a href="{{ self_link }}">{{ self_en_name }}</a> {{ self_en_aliases }}</h3>
44
+
45
+ {% for img in self_imgs_list %}
46
+ <iframe src="{{ img }}" width="500" height="300" frameborder="0"></iframe>
47
+ {% endfor %}
48
+
49
+ <h3>解説:</h3>
50
+ <p>{{ gpt_ans_self }}</p>
51
+
52
+ <hr>
53
+
54
+ <h3>上位概念</h3>
55
+ <h4>和名:<a href="{{ parent_link }}">{{ parent_ja_name }}</a> {{ parent_ja_aliases }}
56
+ <br>英名:<a href="{{ parent_link }}">{{ parent_en_name }}</a> {{ parent_en_aliases }}</h4>
57
+
58
+ {% for img in parent_imgs_list %}
59
+ <iframe src="{{ img }}" width="500" height="300" frameborder="0"></iframe>
60
+ {% endfor %}
61
+
62
+ <h4>解説:</h4>
63
+ <p>{{ gpt_ans_parent }}</p>
64
+
65
+ <hr>
66
+
67
+ <h3>下位概念</h3>
68
+ <h4>解説:</h4>
69
+ <p>{{ gpt_ans_children }}</p>
70
+ </blockquote>
71
+
72
+
73
+ <!-- <script>
74
+ // Submitボタンがクリックされたときの処理
75
+ document.getElementById("submit-button").addEventListener("click", function () {
76
+ const apiKey = document.getElementById("api_key").value;
77
+ const form = document.getElementById("api_key_form");
78
+ form.action = `/word_search/?api_key=${apiKey}`;
79
+ form.submit();
80
+ });
81
+ </script> -->
82
+ </body>
83
+ </html>