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; }