From bcb51729a5452bc5404ab8004b9fbf457334e9a2 Mon Sep 17 00:00:00 2001 From: LJH-rgsze <3241304429@qq.com> Date: Wed, 7 Jan 2026 16:00:35 +0800 Subject: [PATCH 1/7] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E6=92=AD=E6=94=BE?= =?UTF-8?q?=E6=8C=89=E9=92=AE=E7=9A=84=E6=98=BE=E7=A4=BA=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../xiaozhi/modules/model/dto/VoiceDTO.java | 12 ++++++ .../service/impl/TimbreServiceImpl.java | 3 ++ main/manager-web/src/views/roleConfig.vue | 37 ++++++------------- 3 files changed, 26 insertions(+), 26 deletions(-) diff --git a/main/manager-api/src/main/java/xiaozhi/modules/model/dto/VoiceDTO.java b/main/manager-api/src/main/java/xiaozhi/modules/model/dto/VoiceDTO.java index 4db614ef..e69608a9 100644 --- a/main/manager-api/src/main/java/xiaozhi/modules/model/dto/VoiceDTO.java +++ b/main/manager-api/src/main/java/xiaozhi/modules/model/dto/VoiceDTO.java @@ -22,12 +22,24 @@ public class VoiceDTO implements Serializable { @Schema(description = "音频播放地址") private String voiceDemo; + + @Schema(description = "是否为克隆音色") + private Boolean isClone; // 添加双参数构造函数,保持向后兼容 public VoiceDTO(String id, String name) { this.id = id; this.name = name; this.voiceDemo = null; + this.isClone = false; // 默认不是克隆音色 + } + + // 添加三参数构造函数,用于普通音色 + public VoiceDTO(String id, String name, String voiceDemo) { + this.id = id; + this.name = name; + this.voiceDemo = voiceDemo; + this.isClone = false; } } \ No newline at end of file diff --git a/main/manager-api/src/main/java/xiaozhi/modules/timbre/service/impl/TimbreServiceImpl.java b/main/manager-api/src/main/java/xiaozhi/modules/timbre/service/impl/TimbreServiceImpl.java index feb6c449..9d6ca5c4 100644 --- a/main/manager-api/src/main/java/xiaozhi/modules/timbre/service/impl/TimbreServiceImpl.java +++ b/main/manager-api/src/main/java/xiaozhi/modules/timbre/service/impl/TimbreServiceImpl.java @@ -136,6 +136,7 @@ public class TimbreServiceImpl extends BaseServiceImpl .map(entity -> { VoiceDTO dto = new VoiceDTO(entity.getId(), entity.getName()); dto.setVoiceDemo(entity.getVoiceDemo()); + dto.setIsClone(false); // 设置为普通音色 return dto; }) .collect(Collectors.toList()); @@ -152,6 +153,7 @@ public class TimbreServiceImpl extends BaseServiceImpl voiceDTO.setName(MessageUtils.getMessage(ErrorCode.VOICE_CLONE_PREFIX) + entity.getName()); // 保留从数据库查询到的voiceDemo字段 voiceDTO.setVoiceDemo(entity.getVoiceDemo()); + voiceDTO.setIsClone(true); // 设置为克隆音色 redisUtils.set(RedisKeys.getTimbreNameById(voiceDTO.getId()), voiceDTO.getName(), RedisUtils.NOT_EXPIRE); voiceDTOs.add(0, voiceDTO); @@ -214,6 +216,7 @@ public class TimbreServiceImpl extends BaseServiceImpl TimbreEntity entity = list.get(0); VoiceDTO dto = new VoiceDTO(entity.getId(), entity.getName()); dto.setVoiceDemo(entity.getVoiceDemo()); + dto.setIsClone(false); // 设置为普通音色 return dto; } } \ No newline at end of file diff --git a/main/manager-web/src/views/roleConfig.vue b/main/manager-web/src/views/roleConfig.vue index 4203ceb9..f753b868 100644 --- a/main/manager-web/src/views/roleConfig.vue +++ b/main/manager-web/src/views/roleConfig.vue @@ -746,32 +746,17 @@ export default { }, // 检查是否有音频预览 hasAudioPreview(item) { - // 检查item中是否包含有效的音频URL字段或克隆音频字段 - // 克隆音频通过hasCloneAudio标志或ID格式判断(非TTS开头的ID) - const isCloneAudio = - item.hasCloneAudio || (item.value && !item.value.startsWith("TTS")); - - const audioFields = [ - item.voiceDemo, - item.demoUrl, - item.audioUrl, - item.voice_demo, - item.sample_voice, - item.referenceAudio, - item.cloneAudioUrl, // 克隆音频的URL - ]; - - // 检查是否有任何音频字段是有效的URL - const hasUrlAudio = audioFields.some( - (field) => - field !== undefined && - field !== null && - typeof field === "string" && - field.trim() !== "" && - field.toLowerCase().startsWith("http") - ); - - return hasUrlAudio || isCloneAudio; + // 使用新增的isClone字段来判断是否为克隆音色 + const isCloneAudio = item.isClone === true; + + // 普通音色的音频检查:同时检查voiceDemo和voice_demo两种命名格式 + const audioField = item.voice_demo || item.voiceDemo; + const hasManualAudio = audioField && + typeof audioField === "string" && + audioField.trim() !== "" && + audioField.toLowerCase().startsWith("http"); + + return isCloneAudio || hasManualAudio; }, // 播放/暂停音频切换 From 81e923b4f713f4703578830ca3ad5c388e7ba3bf Mon Sep 17 00:00:00 2001 From: LJH-rgsze <3241304429@qq.com> Date: Wed, 7 Jan 2026 16:52:36 +0800 Subject: [PATCH 2/7] =?UTF-8?q?=E8=A1=A5=E5=85=85=E9=9F=B3=E8=89=B2?= =?UTF-8?q?=E7=AE=A1=E7=90=86=E9=A1=B5=E9=9D=A2=E7=BC=BA=E5=A4=B1=E7=9A=84?= =?UTF-8?q?=E5=9B=BD=E9=99=85=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- main/manager-web/src/i18n/de.js | 4 ++++ main/manager-web/src/i18n/en.js | 4 ++++ main/manager-web/src/i18n/vi.js | 4 ++++ main/manager-web/src/i18n/zh_CN.js | 4 ++++ main/manager-web/src/i18n/zh_TW.js | 2 ++ 5 files changed, 18 insertions(+) diff --git a/main/manager-web/src/i18n/de.js b/main/manager-web/src/i18n/de.js index 22512e8c..81bb1b5d 100644 --- a/main/manager-web/src/i18n/de.js +++ b/main/manager-web/src/i18n/de.js @@ -919,6 +919,10 @@ export default { 'ttsModel.selectVoiceToDelete': 'Bitte wählen Sie Stimmen zum Löschen aus', 'ttsModel.warning': 'Warnung', 'ttsModel.confirmDeleteVoice': 'Sind Sie sicher, dass Sie {count} Stimmen löschen möchten?', + 'ttsModel.voiceCodeNameLanguageRequired': 'Stimmcode, Stimmaname und Sprache können nicht leer sein', + 'ttsModel.deleteCancelled': 'Löschvorgang abgebrochen', + 'ttsModel.updateSuccess': 'Aktualisierung erfolgreich', + 'ttsModel.saveSuccess': 'Speicherung erfolgreich', // OTA Management Page Text 'otaManagement.firmwareManagement': 'Firmware-Verwaltung', diff --git a/main/manager-web/src/i18n/en.js b/main/manager-web/src/i18n/en.js index 9bcc1f7d..3314adca 100644 --- a/main/manager-web/src/i18n/en.js +++ b/main/manager-web/src/i18n/en.js @@ -919,6 +919,10 @@ export default { 'ttsModel.selectVoiceToDelete': 'Please select voices to delete', 'ttsModel.warning': 'Warning', 'ttsModel.confirmDeleteVoice': 'Are you sure to delete {count} voices?', + 'ttsModel.voiceCodeNameLanguageRequired': 'Voice code, voice name and language type cannot be empty', + 'ttsModel.deleteCancelled': 'Deletion cancelled', + 'ttsModel.updateSuccess': 'Update successful', + 'ttsModel.saveSuccess': 'Save successful', // OTA Management Page Text 'otaManagement.firmwareManagement': 'Firmware Management', diff --git a/main/manager-web/src/i18n/vi.js b/main/manager-web/src/i18n/vi.js index c9d9e1cf..9191233a 100644 --- a/main/manager-web/src/i18n/vi.js +++ b/main/manager-web/src/i18n/vi.js @@ -919,6 +919,10 @@ export default { 'ttsModel.selectVoiceToDelete': 'Vui lòng chọn giọng nói để xóa', 'ttsModel.warning': 'Cảnh báo', 'ttsModel.confirmDeleteVoice': 'Bạn có chắc chắn muốn xóa {count} giọng nói?', + 'ttsModel.voiceCodeNameLanguageRequired': 'Mã giọng nói, tên giọng nói và loại ngôn ngữ không được để trống', + 'ttsModel.deleteCancelled': 'Xóa đã bị hủy', + 'ttsModel.updateSuccess': 'Cập nhật thành công', + 'ttsModel.saveSuccess': 'Lưu thành công', // OTA Management Page Text 'otaManagement.firmwareManagement': 'Quản lý firmware', diff --git a/main/manager-web/src/i18n/zh_CN.js b/main/manager-web/src/i18n/zh_CN.js index 44d8e400..a8439c62 100644 --- a/main/manager-web/src/i18n/zh_CN.js +++ b/main/manager-web/src/i18n/zh_CN.js @@ -919,6 +919,10 @@ export default { 'ttsModel.selectVoiceToDelete': '请选择要删除的音色', 'ttsModel.warning': '警告', 'ttsModel.confirmDeleteVoice': '确定要删除{count}个音色吗?', + 'ttsModel.voiceCodeNameLanguageRequired': '音色编码、音色名称和语言类型不能为空', + 'ttsModel.deleteCancelled': '删除已取消', + 'ttsModel.updateSuccess': '更新成功', + 'ttsModel.saveSuccess': '保存成功', // OTA管理页面文本 'otaManagement.firmwareManagement': '固件管理', diff --git a/main/manager-web/src/i18n/zh_TW.js b/main/manager-web/src/i18n/zh_TW.js index ca5a5221..b4089c09 100644 --- a/main/manager-web/src/i18n/zh_TW.js +++ b/main/manager-web/src/i18n/zh_TW.js @@ -917,6 +917,8 @@ export default { 'ttsModel.selectVoiceToDelete': '請選擇要刪除的音色', 'ttsModel.warning': '警告', 'ttsModel.confirmDeleteVoice': '確定要刪除{count}個音色嗎?', + 'ttsModel.voiceCodeNameLanguageRequired': '音色編碼、音色名稱和語言類型不能為空', + 'ttsModel.deleteCancelled': '刪除已取消', 'ttsModel.operationFailed': '操作失敗', 'ttsModel.operationClosed': '操作已關閉', From 07d5b3cd2a4676598c4f68a3d923e53f4dc650b6 Mon Sep 17 00:00:00 2001 From: LJH-rgsze <3241304429@qq.com> Date: Wed, 7 Jan 2026 16:54:08 +0800 Subject: [PATCH 3/7] =?UTF-8?q?=E8=A1=A5=E5=85=85-=E4=B8=8A=E4=B8=AA?= =?UTF-8?q?=E4=BF=AE=E6=94=B9=E4=B8=8A=E4=BC=A0=E5=B0=91=E4=BA=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- main/manager-web/src/i18n/zh_TW.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/main/manager-web/src/i18n/zh_TW.js b/main/manager-web/src/i18n/zh_TW.js index b4089c09..20c89ceb 100644 --- a/main/manager-web/src/i18n/zh_TW.js +++ b/main/manager-web/src/i18n/zh_TW.js @@ -919,6 +919,8 @@ export default { 'ttsModel.confirmDeleteVoice': '確定要刪除{count}個音色嗎?', 'ttsModel.voiceCodeNameLanguageRequired': '音色編碼、音色名稱和語言類型不能為空', 'ttsModel.deleteCancelled': '刪除已取消', + 'ttsModel.updateSuccess': '更新成功', + 'ttsModel.saveSuccess': '保存成功', 'ttsModel.operationFailed': '操作失敗', 'ttsModel.operationClosed': '操作已關閉', From c190abe4b14676dc2ae9f6a451a9d9afff82a9ac Mon Sep 17 00:00:00 2001 From: LJH-rgsze <3241304429@qq.com> Date: Wed, 7 Jan 2026 17:03:56 +0800 Subject: [PATCH 4/7] =?UTF-8?q?=E7=94=A8=E5=9B=BD=E9=99=85=E5=8C=96?= =?UTF-8?q?=E9=87=8D=E5=86=99=E7=A1=AC=E7=BC=96=E7=A0=81=E6=8F=90=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- main/manager-web/src/i18n/de.js | 10 ++++++++++ main/manager-web/src/i18n/en.js | 10 ++++++++++ main/manager-web/src/i18n/vi.js | 10 ++++++++++ main/manager-web/src/i18n/zh_CN.js | 10 ++++++++++ main/manager-web/src/i18n/zh_TW.js | 10 ++++++++++ main/manager-web/src/views/roleConfig.vue | 22 +++++++++++----------- 6 files changed, 61 insertions(+), 11 deletions(-) diff --git a/main/manager-web/src/i18n/de.js b/main/manager-web/src/i18n/de.js index 81bb1b5d..c726e497 100644 --- a/main/manager-web/src/i18n/de.js +++ b/main/manager-web/src/i18n/de.js @@ -779,6 +779,16 @@ export default { 'roleConfig.fetchConfigFailed': 'Konfiguration konnte nicht abgerufen werden', 'roleConfig.fetchModelsFailed': 'Modellliste konnte nicht abgerufen werden', 'roleConfig.fetchPluginsFailed': 'Plugin-Liste konnte nicht abgerufen werden', + 'roleConfig.cannotResumeAudio': 'Audio-Wiedergabe kann nicht fortgesetzt werden', + 'roleConfig.selectVoiceFirst': 'Bitte wählen Sie zuerst eine Stimme aus', + 'roleConfig.audioLoadTimeout': 'Audio-Laden dauert zu lange, bitte versuchen Sie es später erneut', + 'roleConfig.cloneAudioPlayFailed': 'Klon-Audio-Wiedergabe fehlgeschlagen', + 'roleConfig.cannotPlayCloneAudio': 'Klon-Audio kann nicht abgespielt werden', + 'roleConfig.getCloneAudioFailed': 'Klon-Audio konnte nicht abgerufen werden', + 'roleConfig.noPreviewAudio': 'Diese Stimme hat keine Vorschau-Audio-Datei', + 'roleConfig.audioPlayFailed': 'Audio-Wiedergabe fehlgeschlagen', + 'roleConfig.cannotPlayAudio': 'Audio kann nicht abgespielt werden', + 'roleConfig.audioPlayError': 'Fehler bei der Audio-Wiedergabe', // Function management dialog text 'functionDialog.title': 'Funktionsverwaltung', diff --git a/main/manager-web/src/i18n/en.js b/main/manager-web/src/i18n/en.js index 3314adca..dd5ab2ff 100644 --- a/main/manager-web/src/i18n/en.js +++ b/main/manager-web/src/i18n/en.js @@ -779,6 +779,16 @@ export default { 'roleConfig.fetchConfigFailed': 'Failed to fetch configuration', 'roleConfig.fetchModelsFailed': 'Failed to fetch model list', 'roleConfig.fetchPluginsFailed': 'Failed to fetch plugin list', + 'roleConfig.cannotResumeAudio': 'Cannot resume audio playback', + 'roleConfig.selectVoiceFirst': 'Please select a voice first', + 'roleConfig.audioLoadTimeout': 'Audio loading takes too long, please try again later', + 'roleConfig.cloneAudioPlayFailed': 'Clone audio playback failed', + 'roleConfig.cannotPlayCloneAudio': 'Cannot play clone audio', + 'roleConfig.getCloneAudioFailed': 'Failed to get clone audio', + 'roleConfig.noPreviewAudio': 'This voice has no preview audio available', + 'roleConfig.audioPlayFailed': 'Audio playback failed', + 'roleConfig.cannotPlayAudio': 'Cannot play audio', + 'roleConfig.audioPlayError': 'Error occurred during audio playback', // Function management dialog text 'functionDialog.title': 'Function Management', diff --git a/main/manager-web/src/i18n/vi.js b/main/manager-web/src/i18n/vi.js index 9191233a..5a73b968 100644 --- a/main/manager-web/src/i18n/vi.js +++ b/main/manager-web/src/i18n/vi.js @@ -779,6 +779,16 @@ export default { 'roleConfig.fetchConfigFailed': 'Không thể lấy cấu hình', 'roleConfig.fetchModelsFailed': 'Không thể tải danh sách mô hình', 'roleConfig.fetchPluginsFailed': 'Không thể tải danh sách plugin', + 'roleConfig.cannotResumeAudio': 'Không thể tiếp tục phát âm thanh', + 'roleConfig.selectVoiceFirst': 'Vui lòng chọn giọng nói trước', + 'roleConfig.audioLoadTimeout': 'Tải âm thanh mất quá nhiều thời gian, vui lòng thử lại sau', + 'roleConfig.cloneAudioPlayFailed': 'Phát âm thanh sao chép thất bại', + 'roleConfig.cannotPlayCloneAudio': 'Không thể phát âm thanh sao chép', + 'roleConfig.getCloneAudioFailed': 'Không thể lấy âm thanh sao chép', + 'roleConfig.noPreviewAudio': 'Giọng nói này không có âm thanh xem trước', + 'roleConfig.audioPlayFailed': 'Phát âm thanh thất bại', + 'roleConfig.cannotPlayAudio': 'Không thể phát âm thanh', + 'roleConfig.audioPlayError': 'Lỗi trong quá trình phát âm thanh', // Function management dialog text 'functionDialog.title': 'Quản lý chức năng', diff --git a/main/manager-web/src/i18n/zh_CN.js b/main/manager-web/src/i18n/zh_CN.js index a8439c62..7452808b 100644 --- a/main/manager-web/src/i18n/zh_CN.js +++ b/main/manager-web/src/i18n/zh_CN.js @@ -779,6 +779,16 @@ export default { 'roleConfig.fetchConfigFailed': '获取配置失败', 'roleConfig.fetchModelsFailed': '获取模型列表失败', 'roleConfig.fetchPluginsFailed': '获取插件列表失败', + 'roleConfig.cannotResumeAudio': '无法恢复播放音频', + 'roleConfig.selectVoiceFirst': '请先选择一个音色', + 'roleConfig.audioLoadTimeout': '音频加载时间较长,请稍后重试', + 'roleConfig.cloneAudioPlayFailed': '克隆音频播放失败', + 'roleConfig.cannotPlayCloneAudio': '无法播放克隆音频', + 'roleConfig.getCloneAudioFailed': '获取克隆音频失败', + 'roleConfig.noPreviewAudio': '该音色暂无可预览的音频', + 'roleConfig.audioPlayFailed': '音频播放失败', + 'roleConfig.cannotPlayAudio': '无法播放音频', + 'roleConfig.audioPlayError': '播放音频过程出错', // 功能管理对话框文本 'functionDialog.title': '功能管理', diff --git a/main/manager-web/src/i18n/zh_TW.js b/main/manager-web/src/i18n/zh_TW.js index 20c89ceb..729d7151 100644 --- a/main/manager-web/src/i18n/zh_TW.js +++ b/main/manager-web/src/i18n/zh_TW.js @@ -779,6 +779,16 @@ export default { 'roleConfig.fetchConfigFailed': '獲取配置失敗', 'roleConfig.fetchModelsFailed': '獲取模型列表失敗', 'roleConfig.fetchPluginsFailed': '獲取插件列表失敗', + 'roleConfig.cannotResumeAudio': '無法恢復播放音訊', + 'roleConfig.selectVoiceFirst': '請先選擇一個音色', + 'roleConfig.audioLoadTimeout': '音訊載入時間較長,請稍後重試', + 'roleConfig.cloneAudioPlayFailed': '克隆音訊播放失敗', + 'roleConfig.cannotPlayCloneAudio': '無法播放克隆音訊', + 'roleConfig.getCloneAudioFailed': '獲取克隆音訊失敗', + 'roleConfig.noPreviewAudio': '該音色暫無可預覽的音訊', + 'roleConfig.audioPlayFailed': '音訊播放失敗', + 'roleConfig.cannotPlayAudio': '無法播放音訊', + 'roleConfig.audioPlayError': '播放音訊過程出錯', // 功能管理對話框文本 'functionDialog.title': '功能管理', diff --git a/main/manager-web/src/views/roleConfig.vue b/main/manager-web/src/views/roleConfig.vue index f753b868..af5971c1 100644 --- a/main/manager-web/src/views/roleConfig.vue +++ b/main/manager-web/src/views/roleConfig.vue @@ -767,7 +767,7 @@ export default { // 从暂停状态恢复播放 this.currentAudio.play().catch((error) => { console.error("恢复播放失败:", error); - this.$message.warning("无法恢复播放音频"); + this.$message.warning(this.$t('roleConfig.cannotResumeAudio')); }); this.isPaused = false; } else { @@ -788,7 +788,7 @@ export default { const targetVoiceId = voiceId || this.form.ttsVoiceId; if (!targetVoiceId) { - this.$message.warning("请先选择一个音色"); + this.$message.warning(this.$t('roleConfig.selectVoiceFirst')); return; } @@ -874,7 +874,7 @@ export default { // 设置超时,防止加载过长时间 const timeoutId = setTimeout(() => { if (this.currentAudio && this.playingVoice) { - this.$message.warning("音频加载时间较长,请稍后重试"); + this.$message.warning(this.$t('roleConfig.audioLoadTimeout')); this.playingVoice = false; } }, 10000); // 10秒超时 @@ -883,7 +883,7 @@ export default { this.currentAudio.onerror = () => { clearTimeout(timeoutId); console.error("克隆音频播放错误"); - this.$message.warning("克隆音频播放失败"); + this.$message.warning(this.$t('roleConfig.cloneAudioPlayFailed')); this.playingVoice = false; }; @@ -905,12 +905,12 @@ export default { this.currentAudio.play().catch((error) => { clearTimeout(timeoutId); console.error("播放克隆音频失败:", error); - this.$message.warning("无法播放克隆音频"); + this.$message.warning(this.$t('roleConfig.cannotPlayCloneAudio')); this.playingVoice = false; }); } else { clearTimeout(timeoutId); - this.$message.warning("获取克隆音频失败"); + this.$message.warning(this.$t('roleConfig.getCloneAudioFailed')); this.playingVoice = false; } }); @@ -950,7 +950,7 @@ export default { if (!audioUrl) { // 如果没有音频URL,显示友好的提示 - this.$message.warning("该音色暂无可预览的音频"); + this.$message.warning(this.$t('roleConfig.noPreviewAudio')); return; } @@ -969,7 +969,7 @@ export default { // 设置超时,防止加载过长时间 const timeoutId = setTimeout(() => { if (this.currentAudio && this.playingVoice) { - this.$message.warning("音频加载时间较长,请稍后重试"); + this.$message.warning(this.$t('roleConfig.audioLoadTimeout')); this.playingVoice = false; } }, 10000); // 10秒超时 @@ -978,7 +978,7 @@ export default { this.currentAudio.onerror = () => { clearTimeout(timeoutId); console.error("音频播放错误"); - this.$message.warning("音频播放失败"); + this.$message.warning(this.$t('roleConfig.audioPlayFailed')); this.playingVoice = false; }; @@ -996,13 +996,13 @@ export default { this.currentAudio.play().catch((error) => { clearTimeout(timeoutId); console.error("播放失败:", error); - this.$message.warning("无法播放音频"); + this.$message.warning(this.$t('roleConfig.cannotPlayAudio')); this.playingVoice = false; }); } } catch (error) { console.error("播放音频过程出错:", error); - this.$message.error("播放音频过程出错"); + this.$message.error(this.$t('roleConfig.audioPlayError')); this.playingVoice = false; } }, From 40a6b7434ba644d040eb72d2cab924e66ae2dfe9 Mon Sep 17 00:00:00 2001 From: LJH-rgsze <3241304429@qq.com> Date: Wed, 7 Jan 2026 18:08:43 +0800 Subject: [PATCH 5/7] =?UTF-8?q?=E8=B0=83=E6=95=B4=E5=88=A4=E6=96=AD?= =?UTF-8?q?=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- main/manager-web/src/views/roleConfig.vue | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/main/manager-web/src/views/roleConfig.vue b/main/manager-web/src/views/roleConfig.vue index af5971c1..2da34fe3 100644 --- a/main/manager-web/src/views/roleConfig.vue +++ b/main/manager-web/src/views/roleConfig.vue @@ -746,17 +746,11 @@ export default { }, // 检查是否有音频预览 hasAudioPreview(item) { - // 使用新增的isClone字段来判断是否为克隆音色 - const isCloneAudio = item.isClone === true; - - // 普通音色的音频检查:同时检查voiceDemo和voice_demo两种命名格式 - const audioField = item.voice_demo || item.voiceDemo; - const hasManualAudio = audioField && - typeof audioField === "string" && - audioField.trim() !== "" && - audioField.toLowerCase().startsWith("http"); - - return isCloneAudio || hasManualAudio; + // 极度简化逻辑: + // 1. 如果hasCloneAudio字段存在且不为false/0,就显示播放按钮 + // 2. 否则检查是否有有效的音频URL + return (item.hasCloneAudio && item.hasCloneAudio !== 'false' && item.hasCloneAudio !== '0') || + !!((item.voice_demo || item.voiceDemo || item.demoUrl || item.audioUrl || item.sample_voice || item.referenceAudio || item.cloneAudioUrl)?.trim()); }, // 播放/暂停音频切换 From c1959e079541abf03a0a7e7a3f78fa5e686f2eb2 Mon Sep 17 00:00:00 2001 From: LJH-rgsze <3241304429@qq.com> Date: Thu, 8 Jan 2026 10:10:39 +0800 Subject: [PATCH 6/7] =?UTF-8?q?=E4=BC=98=E5=8C=96=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- main/manager-web/src/views/roleConfig.vue | 41 ++++++++++------------- 1 file changed, 17 insertions(+), 24 deletions(-) diff --git a/main/manager-web/src/views/roleConfig.vue b/main/manager-web/src/views/roleConfig.vue index 2da34fe3..2beff38a 100644 --- a/main/manager-web/src/views/roleConfig.vue +++ b/main/manager-web/src/views/roleConfig.vue @@ -599,17 +599,12 @@ export default { this.voiceOptions = data.data.map((voice) => ({ value: voice.id, label: voice.name, - // 复制音频相关字段,确保hasAudioPreview能检测到 + // 只保留后端实际返回的音频相关字段 voiceDemo: voice.voiceDemo, - demoUrl: voice.demoUrl, - audioUrl: voice.audioUrl, voice_demo: voice.voice_demo, - sample_voice: voice.sample_voice, - referenceAudio: voice.referenceAudio, - // 新增:添加克隆音频相关字段 - cloneAudioUrl: voice.cloneAudioUrl, - hasCloneAudio: voice.hasCloneAudio || false, - // 保存训练状态字段,用于判断是否为克隆音频 + // 使用后端实际返回的 isClone 字段 + isClone: Boolean(voice.isClone), + // 保存训练状态字段 train_status: voice.trainStatus, })); // 保存完整的音色信息,添加调试信息 @@ -746,11 +741,15 @@ export default { }, // 检查是否有音频预览 hasAudioPreview(item) { - // 极度简化逻辑: - // 1. 如果hasCloneAudio字段存在且不为false/0,就显示播放按钮 - // 2. 否则检查是否有有效的音频URL - return (item.hasCloneAudio && item.hasCloneAudio !== 'false' && item.hasCloneAudio !== '0') || - !!((item.voice_demo || item.voiceDemo || item.demoUrl || item.audioUrl || item.sample_voice || item.referenceAudio || item.cloneAudioUrl)?.trim()); + // 检查是否为克隆音频 + // 使用后端实际返回的 isClone 字段 + const isCloneAudio = Boolean(item.isClone); + + // 检查是否有有效的音频URL,只使用后端实际返回的字段 + const hasValidAudioUrl = !!((item.voice_demo || item.voiceDemo)?.trim()); + + // 克隆音频始终显示播放按钮,普通音频需要有有效URL才显示 + return isCloneAudio || hasValidAudioUrl; }, // 播放/暂停音频切换 @@ -809,10 +808,8 @@ export default { let isCloneAudio = false; if (voiceDetail) { - // 首先检查是否是克隆音频(通过ID格式判断,非TTS开头的ID) - isCloneAudio = - voiceDetail.hasCloneAudio || - (voiceDetail.id && !voiceDetail.id.startsWith("TTS")); + // 使用后端实际返回的 isClone 字段判断是否为克隆音频 + isCloneAudio = Boolean(voiceDetail.isClone); console.log( "克隆音频判断结果:", isCloneAudio, @@ -912,14 +909,10 @@ export default { // 返回,避免继续执行下面的普通音频播放逻辑 return; } else { - // 对于普通音频,尝试各种可能的URL字段 + // 对于普通音频,只使用后端实际返回的字段 audioUrl = voiceDetail.voiceDemo || - voiceDetail.demoUrl || - voiceDetail.audioUrl || - voiceDetail.voice_demo || - voiceDetail.sample_voice || - voiceDetail.cloneAudioUrl; // 克隆音频URL + voiceDetail.voice_demo; } // 如果没有找到,尝试检查是否有URL格式的字段 From 3a61ec84b30eed2c49dfb1f74f531736feaea044 Mon Sep 17 00:00:00 2001 From: hrz <1710360675@qq.com> Date: Thu, 8 Jan 2026 12:39:07 +0800 Subject: [PATCH 7/7] =?UTF-8?q?=E7=A7=BB=E9=99=A4console=E6=89=93=E5=8D=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- main/manager-web/src/views/roleConfig.vue | 1 - 1 file changed, 1 deletion(-) diff --git a/main/manager-web/src/views/roleConfig.vue b/main/manager-web/src/views/roleConfig.vue index 2beff38a..580b6989 100644 --- a/main/manager-web/src/views/roleConfig.vue +++ b/main/manager-web/src/views/roleConfig.vue @@ -608,7 +608,6 @@ export default { train_status: voice.trainStatus, })); // 保存完整的音色信息,添加调试信息 - console.log("获取到的音色数据:", data.data); this.voiceDetails = data.data.reduce((acc, voice) => { acc[voice.id] = voice; return acc;