Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ユーザー辞書のインポート、エクスポートをUIに追加 #676

Merged
merged 13 commits into from
Dec 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions run.py
Original file line number Diff line number Diff line change
Expand Up @@ -1133,6 +1133,8 @@ def setting_post(
# 更新した設定へ上書き
setting_loader.dump_setting_file(settings)

message = "設定を保存しました。"

if allow_origin is None:
allow_origin = ""

Expand All @@ -1142,6 +1144,7 @@ def setting_post(
"request": request,
"cors_policy_mode": cors_policy_mode,
"allow_origin": allow_origin,
"message": message,
},
)

Expand Down
169 changes: 160 additions & 9 deletions ui_template/ui.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<!DOCTYPE html>
<!doctype html>
<html lang="ja">
<head>
<meta charset="utf-8" />
Expand All @@ -23,7 +23,7 @@

<body>
<div class="container p-3">
<form method="post">
<form method="post" enctype="multipart/form-data">
<div class="alert alert-warning" role="alert">
設定の変更の更新にはエンジンの再起動が必要です。
</div>
Expand Down Expand Up @@ -67,6 +67,62 @@
</div>
</div>

<button
type="button"
class="btn btn-primary mb-3"
data-bs-toggle="modal"
data-bs-target="#submitModal"
>
保存
</button>

<hr />

<div id="mb-3">
<label class="form-label"
>ユーザー辞書のエクスポート&インポート</label
>
<div class="form-text">辞書のエクスポートをします。</div>
<a
download="VOICEVOXユーザー辞書.json"
class="btn btn-primary mb-3"
href="/user_dict"
onclick="showToastWithMessage('辞書をエクスポートしました。');"
target="_blank"
rel="noopener noreferrer"
>
エクスポート
</a>
<div class="form-text">辞書のインポートをします。</div>
<input
class="m-3 form-control"
type="file"
name="user_dictionary_file"
accept="application/json"
id="userDictFile"
/>
<input
class="ms-3 form-check-input"
type="checkbox"
name="allow_override"
value="true"
id="allowOverride"
/>
<label class="mb-3 form-check-label" for="allowOverride"
>辞書の上書きを許可する。</label
>
</div>

<!-- TODO: 辞書パスが未入力の場合Disableにする -->
<button
type="button"
class="btn btn-primary"
data-bs-toggle="modal"
data-bs-target="#dictSubmitModal"
>
インポート
</button>

<div
class="modal fade"
id="submitModal"
Expand Down Expand Up @@ -106,15 +162,110 @@ <h5 class="modal-title" id="submitModalLabel">
</div>
</div>

<button
type="button"
class="btn btn-primary"
data-bs-toggle="modal"
data-bs-target="#submitModal"
<div
class="modal fade"
id="dictSubmitModal"
tabindex="-1"
aria-labelledby="dictSubmitModalLabel"
aria-hidden="true"
>
保存
</button>
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5
class="modal-title"
id="dictSubmitModalLabel"
>
ユーザー辞書のインポート
</h5>
<button
type="button"
class="btn-close"
data-bs-dismiss="modal"
aria-label="Close"
></button>
</div>
<div class="modal-body">
ユーザー辞書をインポートします。よろしいですか?
</div>
<div class="modal-footer">
<button
type="button"
class="btn btn-secondary"
data-bs-dismiss="modal"
>
キャンセル
</button>
<button
type="button"
onclick="importUserDict()"
class="btn btn-primary"
data-bs-dismiss="modal"
>
インポート
</button>
</div>
</div>
</div>
</div>
</form>
</div>

<div class="position-fixed bottom-0 end-0 p-3" style="z-index: 5">
<div
class="toast align-items-center hide text-white bg-success"
role="alert"
aria-live="assertive"
aria-atomic="true"
id="toast"
>
<div class="d-flex">
<div class="toast-body"></div>
</div>
</div>
</div>
<script>
const reader = new FileReader();

const allowOverrideElement =
document.getElementById("allowOverride");

const toastElement = document.getElementById("toast");
const toast = new bootstrap.Toast(toastElement);
const toastBody = toastElement.getElementsByClassName("toast-body");

const showToastWithMessage = (message) => {
toast.show();
toastBody[0].innerHTML = message;
};

// 読み込み時にメッセージがあれば表示する
var msg = "{{message}}";
if (msg) {
showToastWithMessage(msg);
}

reader.addEventListener("load", async () => {
const params = {
override: allowOverrideElement.checked ? true : false,
};
const query_params = new URLSearchParams(params);

await fetch(`/import_user_dict?${query_params}`, {
method: "POST",
mode: "same-origin",
headers: { "Content-Type": "application/json" },
body: reader.result,
});

showToastWithMessage("辞書をインポートしました。");
});

const importUserDict = () => {
const userDictFile =
document.getElementById("userDictFile").files[0];
reader.readAsText(userDictFile);
};
</script>
</body>
</html>