update files
Browse files- Dockerfile +28 -0
- data/all_BirdDBnode.tsv +0 -0
- data/en_aliases_vecs_all.bin +3 -0
- data/en_name_vecs.bin +3 -0
- data/ja_aliases_vecs.bin +3 -0
- data/ja_name_vecs.bin +3 -0
- data/sound_vecs.json +0 -0
- main.py +496 -0
- model/en_model/config.json +26 -0
- model/en_model/pytorch_model.bin +3 -0
- model/en_tokenizer/special_tokens_map.json +7 -0
- model/en_tokenizer/tokenizer_config.json +15 -0
- model/en_tokenizer/vocab.txt +0 -0
- model/ja_model/config.json +26 -0
- model/ja_model/pytorch_model.bin +3 -0
- model/ja_tokenizer/special_tokens_map.json +7 -0
- model/ja_tokenizer/tokenizer_config.json +19 -0
- model/ja_tokenizer/vocab.txt +0 -0
- model/wav2vec2-bird-jp-all/config.json +108 -0
- model/wav2vec2-bird-jp-all/pytorch_model.bin +3 -0
- requirements.txt +15 -0
- static/style.css +87 -0
- templates/sound_search.html +155 -0
- templates/word_search.html +83 -0
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 </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 </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>
|