From 80162f10ba9ea59468c03947c203ea998b0a5018 Mon Sep 17 00:00:00 2001 From: tsukumi Date: Wed, 25 Dec 2024 12:48:51 +0900 Subject: [PATCH] =?UTF-8?q?Add:=20=E9=9F=B3=E5=A3=B0=E5=90=88=E6=88=90?= =?UTF-8?q?=E3=83=A2=E3=83=87=E3=83=AB=E7=AE=A1=E7=90=86=E7=94=BB=E9=9D=A2?= =?UTF-8?q?=E3=81=AB=E3=83=A2=E3=83=87=E3=83=AB=E3=81=AE=E6=9B=B4=E6=96=B0?= =?UTF-8?q?=E7=A2=BA=E8=AA=8D=E3=83=BB=E3=82=A2=E3=83=83=E3=83=97=E3=83=87?= =?UTF-8?q?=E3=83=BC=E3=83=88=E3=83=BB=E3=83=AD=E3=83=BC=E3=83=89=E3=83=BB?= =?UTF-8?q?=E3=82=A2=E3=83=B3=E3=83=AD=E3=83=BC=E3=83=89=E6=A9=9F=E8=83=BD?= =?UTF-8?q?=E3=82=92=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ようやく一通り実装できて安堵 --- src/components/Dialog/ModelManageDialog.vue | 285 +++++++++++++----- .../Dialog/TextDialog/MessageDialog.vue | 1 + .../Dialog/TextDialog/QuestionDialog.vue | 1 + 3 files changed, 217 insertions(+), 70 deletions(-) diff --git a/src/components/Dialog/ModelManageDialog.vue b/src/components/Dialog/ModelManageDialog.vue index ebc1a467..20f9412b 100644 --- a/src/components/Dialog/ModelManageDialog.vue +++ b/src/components/Dialog/ModelManageDialog.vue @@ -34,6 +34,8 @@ {{ aivmInfo.manifest.name }} {{ aivmInfo.manifest.speakers.length }} Speakers / Version {{ aivmInfo.manifest.version }} + Update! @@ -51,75 +53,88 @@ -
-
- {{ activeAivmInfo.manifest.name }} - - - - {{ speaker.name }} - +
+
+
+ {{ activeAivmInfo.manifest.name }} + + + - {{ speaker.name }} + +
+
+ {{ activeAivmInfo.manifest.speakers.length }} Speakers / Version {{ activeAivmInfo.manifest.version }} + + (Version {{ activeAivmInfo.latestVersion }} に更新できます) + +
-
- {{ activeAivmInfo.manifest.speakers.length }} Speakers / Version {{ activeAivmInfo.manifest.version }} +
+
+ {{ activeAivmInfo.manifest.speakers.reduce((acc, speaker) => acc + speaker.styles.length, 0) }}スタイル +
+
+ {{ speaker.styles.map(style => style.name).join(' / ') }} +
-
-
-
- {{ activeAivmInfo.manifest.speakers.reduce((acc, speaker) => acc + speaker.styles.length, 0) }}スタイル +
+ Model Architecture: {{ activeAivmInfo.manifest.modelArchitecture }} + Model Format: {{ activeAivmInfo.manifest.modelFormat }}
-
- {{ speaker.styles.map(style => style.name).join(' / ') }} +
+ + {{ activeAivmInfo.manifest.creators!.length >= 2 ? 'Creators: ' : 'Creator: ' }} + {{ activeAivmInfo.manifest.creators!.length >= 1 ? activeAivmInfo.manifest.creators!.join(' / ') : '不明' }}
-
-
- Model Architecture: {{ activeAivmInfo.manifest.modelArchitecture }} - Model Format: {{ activeAivmInfo.manifest.modelFormat }} -
-
- - {{ activeAivmInfo.manifest.creators!.length >= 2 ? 'Creators: ' : 'Creator: ' }} - {{ activeAivmInfo.manifest.creators!.length >= 1 ? activeAivmInfo.manifest.creators!.join(' / ') : '不明' }} -
-
- {{ activeAivmInfo.manifest.description === '' ? - '(この音声合成モデルの説明は提供されていません)' : - activeAivmInfo.manifest.description - }} -
-
ボイスサンプル
-
-
-
-
-
- -
{{ style.name }}
-
-
-
- (このスタイルのボイスサンプルは提供されていません) +
+ {{ activeAivmInfo.manifest.description === '' ? + '(この音声合成モデルの説明は提供されていません)' : + activeAivmInfo.manifest.description + }} +
+
ボイスサンプル
+
+
+
+
+
+ +
{{ style.name }}
-
-
- +
+
+ (このスタイルのボイスサンプルは提供されていません) +
+
+
+ +
+
{{ sample.transcript }}
-
{{ sample.transcript }}
-
+
+ +
@@ -326,7 +341,7 @@ const cancelInstall = () => { // 音声合成モデルをインストールする const installModel = async () => { void store.actions.SHOW_LOADING_SCREEN({ - message: "インストール中...", + message: "インストールしています...", }); try { const apiInstance = await getApiInstance(); @@ -352,8 +367,8 @@ const installModel = async () => { void store.actions.SHOW_ALERT_DIALOG({ type: "error", title: "インストール失敗", - message: `音声合成モデルのインストールに失敗しました。 - (HTTP Error ${error.response.status} / ${await error.response.text()})`, + message: `音声合成モデルのインストールに失敗しました。\n` + + `(HTTP Error ${error.response.status} / ${await error.response.text()})`, }); } else { // assert characterInfo !== undefined エラーを無視 @@ -407,8 +422,8 @@ const unInstallAivmModel = async () => { void store.actions.SHOW_ALERT_DIALOG({ type: "error", title: "アンインストール失敗", - message: `音声合成モデル「${activeAivmInfo.value?.manifest.name}」のアンインストールに失敗しました。 - (HTTP Error ${error.response.status} / ${await error.response.text()})`, + message: `音声合成モデル「${activeAivmInfo.value?.manifest.name}」のアンインストールに失敗しました。\n` + + `(HTTP Error ${error.response.status} / ${await error.response.text()})`, }); } else { // assert characterInfo !== undefined エラーを無視 @@ -433,6 +448,109 @@ const unInstallAivmModel = async () => { } }; +// モデルのロード/アンロードを切り替える +const toggleModelLoad = async () => { + if (activeAivmUuid.value == null) { + throw new Error('aivm model is not selected'); + } + + void store.actions.SHOW_LOADING_SCREEN({ + message: activeAivmInfo.value?.isLoaded ? 'モデルをアンロードしています...' : 'モデルをロードしています...', + }); + + try { + const apiInstance = await getApiInstance(); + if (activeAivmInfo.value?.isLoaded) { + await apiInstance.invoke('unloadAivmAivmModelsAivmUuidUnloadPost')({ aivmUuid: activeAivmUuid.value }); + } else { + await apiInstance.invoke('loadAivmAivmModelsAivmUuidLoadPost')({ aivmUuid: activeAivmUuid.value }); + } + } catch (error) { + console.error(error); + if (error instanceof ResponseError) { + void store.actions.SHOW_ALERT_DIALOG({ + type: 'error', + title: activeAivmInfo.value?.isLoaded ? 'アンロード失敗' : 'ロード失敗', + message: `音声合成モデル「${activeAivmInfo.value?.manifest.name}」の${activeAivmInfo.value?.isLoaded ? 'アンロード' : 'ロード'}に失敗しました。\n` + + `(HTTP Error ${error.response.status} / ${await error.response.text()})`, + }); + } else { + void store.actions.SHOW_ALERT_DIALOG({ + type: 'error', + title: activeAivmInfo.value?.isLoaded ? 'アンロード失敗' : 'ロード失敗', + // eslint-disable-next-line @typescript-eslint/restrict-template-expressions + message: `音声合成モデル「${activeAivmInfo.value?.manifest.name}」の${activeAivmInfo.value?.isLoaded ? 'アンロード' : 'ロード'}に失敗しました。(${error})`, + }); + } + } finally { + await store.actions.HIDE_ALL_LOADING_SCREEN(); + void getAivmInfos(); // 再取得 + } +}; + +// モデルをアップデートする +const updateAivmModel = async () => { + if (activeAivmUuid.value == null) { + throw new Error('aivm model is not selected'); + } + + const result = await store.actions.SHOW_CONFIRM_DIALOG({ + title: 'アップデートの確認', + message: `音声合成モデル「${activeAivmInfo.value?.manifest.name}」を Version ${activeAivmInfo.value?.latestVersion} へアップデートしますか?\n` + + 'アップデート後、前のバージョンに戻すことはできません。', + actionName: 'アップデート', + }); + + if (result === 'OK') { + void store.actions.SHOW_LOADING_SCREEN({ + message: 'アップデートしています...', + }); + + try { + const apiInstance = await getApiInstance(); + await apiInstance.invoke('updateAivmAivmModelsAivmUuidUpdatePost')({ aivmUuid: activeAivmUuid.value }); + // アップデート成功時の処理 + // 話者・スタイル一覧を再読み込み + await store.actions.LOAD_CHARACTER({ engineId: store.getters.DEFAULT_ENGINE_ID }); + await store.actions.LOAD_DEFAULT_STYLE_IDS(); + // プリセットを再作成 + await store.actions.CREATE_ALL_DEFAULT_PRESET(); + void store.actions.SHOW_ALERT_DIALOG({ + title: 'アップデート完了', + message: '音声合成モデルが正常にアップデートされました。', + }); + } catch (error) { + console.error(error); + if (error instanceof ResponseError) { + void store.actions.SHOW_ALERT_DIALOG({ + type: 'error', + title: 'アップデート失敗', + message: `音声合成モデル「${activeAivmInfo.value?.manifest.name}」のアップデートに失敗しました。\n` + + `(HTTP Error ${error.response.status} / ${await error.response.text()})`, + }); + } else { + // assert characterInfo !== undefined エラーを無視 + if (error instanceof Error && error.message === 'assert characterInfo !== undefined') { + // アップデート成功時の処理を実行 + await store.actions.LOAD_CHARACTER({ engineId: store.getters.DEFAULT_ENGINE_ID }); + await store.actions.LOAD_DEFAULT_STYLE_IDS(); + await store.actions.CREATE_ALL_DEFAULT_PRESET(); + } else { + void store.actions.SHOW_ALERT_DIALOG({ + type: 'error', + title: 'アップデート失敗', + // eslint-disable-next-line @typescript-eslint/restrict-template-expressions + message: `音声合成モデル「${activeAivmInfo.value?.manifest.name}」のアップデートに失敗しました。(${error})`, + }); + } + } + } finally { + await store.actions.HIDE_ALL_LOADING_SCREEN(); + void getAivmInfos(); // 再取得 + } + } +}; + // コンポーネントがアンマウントされる時に音声を停止し、イベントリスナーを削除する onUnmounted(() => { Object.values(audioElements).forEach(audio => { @@ -452,7 +570,7 @@ onUnmounted(() => { background: rgba(colors.$primary-rgb, 0.4); } -.model-list, .model-detail { +.model-list { height: calc( 100vh - #{vars.$menubar-height + vars.$toolbar-height + vars.$window-border-width} @@ -460,6 +578,39 @@ onUnmounted(() => { overflow-y: auto; } +.text-power-on { + color: #86df9f; +} + +.text-power-off { + color: #dfd686; +} + +.model-detail { + + .q-tab-panel { + padding: 0 !important; + } + + .model-detail-content { + height: calc( + 100vh - #{vars.$menubar-height + vars.$toolbar-height + + vars.$window-border-width} - 66px + ); + padding: 16px; + overflow-y: auto; + } + + .fixed-bottom-buttons { + display: flex; + justify-content: flex-end; + padding: 16px; + padding-top: 14px; + height: 66px; + border-top: 2px solid var(--color-splitter); + } +} + .model-list-disable-overlay { background-color: rgba($color: #000000, $alpha: 0.4); width: 100%; @@ -509,7 +660,7 @@ onUnmounted(() => { color: #FBEEEA; font-size: 14px; font-weight: 700; - line-height: 19.20px; + line-height: 1.6; word-wrap: break-word; } @@ -551,14 +702,8 @@ onUnmounted(() => { color: white; font-size: 13.50px; font-weight: 400; - line-height: 19.58px; + line-height: 1.6; word-wrap: break-word; } -.right-pane-buttons { - display: flex; - flex: 1; - align-items: flex-end; -} - \ No newline at end of file diff --git a/src/components/Dialog/TextDialog/MessageDialog.vue b/src/components/Dialog/TextDialog/MessageDialog.vue index 0b61b71e..1b412f29 100644 --- a/src/components/Dialog/TextDialog/MessageDialog.vue +++ b/src/components/Dialog/TextDialog/MessageDialog.vue @@ -87,5 +87,6 @@ function onOk() { .message { word-break: break-all; white-space: pre-wrap; + line-height: 1.65; } diff --git a/src/components/Dialog/TextDialog/QuestionDialog.vue b/src/components/Dialog/TextDialog/QuestionDialog.vue index eeb3afd2..96dbe6a6 100644 --- a/src/components/Dialog/TextDialog/QuestionDialog.vue +++ b/src/components/Dialog/TextDialog/QuestionDialog.vue @@ -105,5 +105,6 @@ const onClick = (index: number) => { .message { word-break: break-all; white-space: pre-wrap; + line-height: 1.65; }