mirror of
https://github.com/xinnan-tech/xiaozhi-esp32-server.git
synced 2026-07-22 07:03:53 +08:00
update:区分本地化部署和非本地化部署tts的配置字段
This commit is contained in:
@@ -1,88 +1,63 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
:visible.sync="localVisible"
|
||||
width="85%"
|
||||
@close="handleClose"
|
||||
:show-close="false"
|
||||
:append-to-body="true"
|
||||
:close-on-click-modal="true">
|
||||
<el-dialog :visible.sync="localVisible" width="90%" @close="handleClose" :show-close="false" :append-to-body="true"
|
||||
:close-on-click-modal="true">
|
||||
<button class="custom-close-btn" @click="handleClose">
|
||||
×
|
||||
</button>
|
||||
<div class="scroll-wrapper">
|
||||
<div
|
||||
class="table-container"
|
||||
ref="tableContainer"
|
||||
@scroll="handleScroll">
|
||||
<el-table
|
||||
v-loading="loading"
|
||||
:data="filteredTtsModels"
|
||||
style="width: 100%;"
|
||||
class="data-table"
|
||||
header-row-class-name="table-header"
|
||||
:fit="true"
|
||||
element-loading-text="拼命加载中"
|
||||
element-loading-spinner="el-icon-loading"
|
||||
element-loading-background="rgba(0, 0, 0, 0.8)">
|
||||
<div class="table-container" ref="tableContainer" @scroll="handleScroll">
|
||||
<el-table v-loading="loading" :data="filteredTtsModels" style="width: 100%;" class="data-table"
|
||||
header-row-class-name="table-header" :fit="true" element-loading-text="拼命加载中"
|
||||
element-loading-spinner="el-icon-loading" element-loading-background="rgba(0, 0, 0, 0.8)">
|
||||
<el-table-column label="选择" width="50" align="center">
|
||||
<template slot-scope="scope">
|
||||
<el-checkbox v-model="scope.row.selected"></el-checkbox>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="音色编码" align="center" min-width="50">
|
||||
<el-table-column label="音色编码" align="center">
|
||||
<template slot-scope="scope">
|
||||
<el-input v-if="scope.row.editing" v-model="scope.row.voiceCode"></el-input>
|
||||
<span v-else>{{ scope.row.voiceCode }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="音色名称" align="center" min-width="50">
|
||||
<el-table-column label="音色名称" align="center">
|
||||
<template slot-scope="scope">
|
||||
<el-input v-if="scope.row.editing" v-model="scope.row.voiceName"></el-input>
|
||||
<span v-else>{{ scope.row.voiceName }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="语言类型" align="center" min-width="50">
|
||||
<el-table-column label="语言类型" align="center">
|
||||
<template slot-scope="scope">
|
||||
<el-input v-if="scope.row.editing" v-model="scope.row.languageType"></el-input>
|
||||
<span v-else>{{ scope.row.languageType }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="试听" align="center" min-width="100px" class-name="audio-column">
|
||||
<el-table-column v-if="!showReferenceColumns" label="试听" align="center" class-name="audio-column">
|
||||
<template slot-scope="scope">
|
||||
<div class="custom-audio-container">
|
||||
<el-input
|
||||
v-if="scope.row.editing"
|
||||
v-model="scope.row.voiceDemo"
|
||||
placeholder="请输入MP3地址"
|
||||
size="mini"
|
||||
class="audio-input">
|
||||
<el-input v-if="scope.row.editing" v-model="scope.row.voiceDemo" placeholder="请输入MP3地址"
|
||||
class="audio-input">
|
||||
</el-input>
|
||||
<AudioPlayer v-else-if="isValidAudioUrl(scope.row.voiceDemo)" :audioUrl="scope.row.voiceDemo"/>
|
||||
<AudioPlayer v-else-if="isValidAudioUrl(scope.row.voiceDemo)" :audioUrl="scope.row.voiceDemo" />
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="备注" align="center">
|
||||
<el-table-column v-if="!showReferenceColumns" label="备注" align="center">
|
||||
<template slot-scope="scope">
|
||||
<el-input
|
||||
v-if="scope.row.editing"
|
||||
type="textarea"
|
||||
:rows="1"
|
||||
autosize
|
||||
v-model="scope.row.remark"
|
||||
placeholder="这里是备注"
|
||||
class="remark-input"></el-input>
|
||||
<el-input v-if="scope.row.editing" type="textarea" :rows="1" autosize v-model="scope.row.remark"
|
||||
placeholder="这里是备注" class="remark-input"></el-input>
|
||||
<span v-else>{{ scope.row.remark }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="音频路径" align="center">
|
||||
<el-table-column v-if="showReferenceColumns" label="克隆音频路径" align="center">
|
||||
<template slot-scope="scope">
|
||||
<el-input v-if="scope.row.editing" v-model="scope.row.referenceAudio" placeholder="这里是参考音频路径 (本地模型用)"></el-input>
|
||||
<el-input v-if="scope.row.editing" v-model="scope.row.referenceAudio" placeholder="这里是克隆音频路径"></el-input>
|
||||
<span v-else>{{ scope.row.referenceAudio }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="音频文本" align="center">
|
||||
<el-table-column v-if="showReferenceColumns" label="克隆音频文本" align="center">
|
||||
<template slot-scope="scope">
|
||||
<el-input v-if="scope.row.editing" v-model="scope.row.referenceText" placeholder="这里是参考音频文本 (本地模型用)"></el-input>
|
||||
<el-input v-if="scope.row.editing" v-model="scope.row.referenceText" placeholder="这里是克隆音频对应文本"></el-input>
|
||||
<span v-else>{{ scope.row.referenceText }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
@@ -96,12 +71,7 @@
|
||||
删除
|
||||
</el-button>
|
||||
</template>
|
||||
<el-button
|
||||
v-else
|
||||
type="success"
|
||||
size="mini"
|
||||
@click="saveEdit(scope.row)"
|
||||
class="save-Tts">保存
|
||||
<el-button v-else type="success" size="mini" @click="saveEdit(scope.row)" class="save-Tts">保存
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
@@ -122,21 +92,19 @@
|
||||
<el-button type="primary" size="mini" @click="addNew" style="background: #5bc98c;border: None;">
|
||||
新增
|
||||
</el-button>
|
||||
<el-button type="primary"
|
||||
size="mini"
|
||||
@click="deleteRow(filteredTtsModels.filter(row => row.selected))"
|
||||
style="background: red;border:None">删除
|
||||
<el-button type="primary" size="mini" @click="deleteRow(filteredTtsModels.filter(row => row.selected))"
|
||||
style="background: red;border:None">删除
|
||||
</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import AudioPlayer from './AudioPlayer.vue'
|
||||
import Api from "@/apis/api";
|
||||
import AudioPlayer from './AudioPlayer.vue';
|
||||
|
||||
export default {
|
||||
components: {AudioPlayer},
|
||||
components: { AudioPlayer },
|
||||
props: {
|
||||
visible: {
|
||||
type: Boolean,
|
||||
@@ -145,6 +113,10 @@ export default {
|
||||
ttsModelId: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
modelConfig: {
|
||||
type: Object,
|
||||
default: null
|
||||
}
|
||||
},
|
||||
data() {
|
||||
@@ -163,6 +135,7 @@ export default {
|
||||
selectAll: false,
|
||||
selectedRows: [],
|
||||
loading: false,
|
||||
showReferenceColumns: false, // 控制是否显示参考列
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
@@ -170,12 +143,19 @@ export default {
|
||||
this.localVisible = newVal;
|
||||
if (newVal) {
|
||||
this.currentPage = 1;
|
||||
this.updateShowReferenceColumns(); // 更新显示状态
|
||||
this.loadData(); // 对话框显示时加载数据
|
||||
this.$nextTick(() => {
|
||||
this.updateScrollbar();
|
||||
});
|
||||
}
|
||||
},
|
||||
modelConfig: {
|
||||
handler(newVal) {
|
||||
this.updateShowReferenceColumns();
|
||||
},
|
||||
immediate: true
|
||||
},
|
||||
filteredTtsModels() {
|
||||
this.$nextTick(() => {
|
||||
this.updateScrollbar();
|
||||
@@ -185,7 +165,7 @@ export default {
|
||||
computed: {
|
||||
filteredTtsModels() {
|
||||
return this.ttsModels.filter(model =>
|
||||
model.voiceName.toLowerCase().includes(this.searchQuery.toLowerCase())
|
||||
model.voiceName.toLowerCase().includes(this.searchQuery.toLowerCase())
|
||||
);
|
||||
}
|
||||
},
|
||||
@@ -201,6 +181,16 @@ export default {
|
||||
window.removeEventListener('mousemove', this.handleDrag);
|
||||
},
|
||||
methods: {
|
||||
// 更新是否显示参考列
|
||||
updateShowReferenceColumns() {
|
||||
if (this.modelConfig && this.modelConfig.configJson) {
|
||||
const providerType = this.modelConfig.configJson.type;
|
||||
this.showReferenceColumns = ['fishspeech', 'gpt_sovits_v2', 'gpt_sovits_v3'].includes(providerType);
|
||||
} else {
|
||||
this.showReferenceColumns = false;
|
||||
}
|
||||
},
|
||||
|
||||
loadData() {
|
||||
this.loading = true;
|
||||
const params = {
|
||||
@@ -251,6 +241,7 @@ export default {
|
||||
this.total = 0;
|
||||
this.selectAll = false;
|
||||
this.searchQuery = '';
|
||||
this.showReferenceColumns = false;
|
||||
|
||||
this.localVisible = false;
|
||||
this.$emit('update:visible', false);
|
||||
@@ -263,7 +254,7 @@ export default {
|
||||
|
||||
if (!container || !scrollbarThumb || !scrollbarTrack) return;
|
||||
|
||||
const {scrollHeight, clientHeight} = container;
|
||||
const { scrollHeight, clientHeight } = container;
|
||||
const trackHeight = scrollbarTrack.clientHeight;
|
||||
const thumbHeight = Math.max((clientHeight / scrollHeight) * trackHeight, 20);
|
||||
|
||||
@@ -278,7 +269,7 @@ export default {
|
||||
|
||||
if (!container || !scrollbarThumb || !scrollbarTrack) return;
|
||||
|
||||
const {scrollHeight, clientHeight, scrollTop} = container;
|
||||
const { scrollHeight, clientHeight, scrollTop } = container;
|
||||
const trackHeight = scrollbarTrack.clientHeight;
|
||||
const thumbHeight = scrollbarThumb.clientHeight;
|
||||
const maxTop = trackHeight - thumbHeight;
|
||||
@@ -346,7 +337,7 @@ export default {
|
||||
|
||||
startEdit(row) {
|
||||
row.editing = true;
|
||||
this.$set(row, 'originalData', {...row});
|
||||
this.$set(row, 'originalData', { ...row });
|
||||
},
|
||||
|
||||
saveEdit(row) {
|
||||
@@ -365,13 +356,17 @@ export default {
|
||||
voiceName: row.voiceName,
|
||||
languageType: row.languageType,
|
||||
remark: row.remark,
|
||||
referenceAudio: row.referenceAudio,
|
||||
referenceText: row.referenceText,
|
||||
ttsModelId: this.ttsModelId,
|
||||
voiceDemo: row.voiceDemo || '',
|
||||
sort: row.sort
|
||||
};
|
||||
|
||||
// 只有在显示参考列的情况下才添加参考字段
|
||||
if (this.showReferenceColumns) {
|
||||
params.referenceAudio = row.referenceAudio;
|
||||
params.referenceText = row.referenceText;
|
||||
}
|
||||
|
||||
let res;
|
||||
if (row.id) {
|
||||
// 已有ID,执行更新操作
|
||||
@@ -439,8 +434,8 @@ export default {
|
||||
}
|
||||
|
||||
const maxSort = this.ttsModels.length > 0
|
||||
? Math.max(...this.ttsModels.map(item => Number(item.sort) || 0))
|
||||
: 0;
|
||||
? Math.max(...this.ttsModels.map(item => Number(item.sort) || 0))
|
||||
: 0;
|
||||
|
||||
const newRow = {
|
||||
voiceCode: '',
|
||||
@@ -459,56 +454,56 @@ export default {
|
||||
},
|
||||
|
||||
deleteRow(row) {
|
||||
// 处理单个音色或音色数组
|
||||
const voices = Array.isArray(row) ? row : [row];
|
||||
// 处理单个音色或音色数组
|
||||
const voices = Array.isArray(row) ? row : [row];
|
||||
|
||||
if (Array.isArray(row) && row.length === 0) {
|
||||
this.$message.warning("请先选择需要删除的音色");
|
||||
return;
|
||||
if (Array.isArray(row) && row.length === 0) {
|
||||
this.$message.warning("请先选择需要删除的音色");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
const voiceCount = voices.length;
|
||||
this.$confirm(`确定要删除选中的${voiceCount}个音色吗?`, "警告", {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning",
|
||||
distinguishCancelAndClose: true
|
||||
}).then(() => {
|
||||
const ids = voices.map(voice => voice.id);
|
||||
if (ids.some(id => !id)) {
|
||||
this.$message.error("存在无效的音色ID");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
const voiceCount = voices.length;
|
||||
this.$confirm(`确定要删除选中的${voiceCount}个音色吗?`, "警告", {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning",
|
||||
distinguishCancelAndClose: true
|
||||
}).then(() => {
|
||||
const ids = voices.map(voice => voice.id);
|
||||
if (ids.some(id => !id)) {
|
||||
this.$message.error("存在无效的音色ID");
|
||||
return;
|
||||
}
|
||||
|
||||
Api.timbre.deleteVoice(ids, ({data}) => {
|
||||
if (data.code === 0) {
|
||||
this.$message.success({
|
||||
message: `成功删除${voiceCount}个参数`,
|
||||
showClose: true
|
||||
});
|
||||
this.loadData(); // 刷新参数列表
|
||||
} else {
|
||||
this.$message.error({
|
||||
message: data.msg || '删除失败,请重试',
|
||||
showClose: true
|
||||
});
|
||||
}
|
||||
Api.timbre.deleteVoice(ids, ({ data }) => {
|
||||
if (data.code === 0) {
|
||||
this.$message.success({
|
||||
message: `成功删除${voiceCount}个参数`,
|
||||
showClose: true
|
||||
});
|
||||
this.loadData(); // 刷新参数列表
|
||||
} else {
|
||||
this.$message.error({
|
||||
message: data.msg || '删除失败,请重试',
|
||||
showClose: true
|
||||
});
|
||||
}
|
||||
});
|
||||
}).catch(action => {
|
||||
if (action === 'cancel') {
|
||||
this.$message({
|
||||
type: 'info',
|
||||
message: '已取消删除操作',
|
||||
duration: 1000
|
||||
});
|
||||
} else {
|
||||
this.$message({
|
||||
type: 'info',
|
||||
message: '操作已关闭',
|
||||
duration: 1000
|
||||
});
|
||||
}
|
||||
if (action === 'cancel') {
|
||||
this.$message({
|
||||
type: 'info',
|
||||
message: '已取消删除操作',
|
||||
duration: 1000
|
||||
});
|
||||
} else {
|
||||
this.$message({
|
||||
type: 'info',
|
||||
message: '操作已关闭',
|
||||
duration: 1000
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
@@ -520,7 +515,6 @@ export default {
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
::v-deep .el-dialog {
|
||||
border-radius: 8px !important;
|
||||
overflow: hidden;
|
||||
@@ -713,6 +707,7 @@ export default {
|
||||
white-space: pre-wrap !important;
|
||||
word-break: break-all !important;
|
||||
}
|
||||
|
||||
/* 按钮组定位调整 */
|
||||
.action-buttons {
|
||||
position: static;
|
||||
@@ -737,5 +732,4 @@ export default {
|
||||
flex-shrink: 0;
|
||||
margin: 2px !important;
|
||||
}
|
||||
|
||||
</style>
|
||||
@@ -128,7 +128,7 @@
|
||||
|
||||
<ModelEditDialog :modelType="activeTab" :visible.sync="editDialogVisible" :modelData="editModelData"
|
||||
@save="handleModelSave" />
|
||||
<TtsModel :visible.sync="ttsDialogVisible" :ttsModelId="selectedTtsModelId" />
|
||||
<TtsModel :visible.sync="ttsDialogVisible" :ttsModelId="selectedTtsModelId" :modelConfig="selectedModelConfig" />
|
||||
<AddModelDialog :modelType="activeTab" :visible.sync="addDialogVisible" @confirm="handleAddConfirm" />
|
||||
</div>
|
||||
<el-footer>
|
||||
@@ -162,7 +162,8 @@ export default {
|
||||
total: 0,
|
||||
selectedModels: [],
|
||||
isAllSelected: false,
|
||||
loading: false
|
||||
loading: false,
|
||||
selectedModelConfig: {}
|
||||
};
|
||||
},
|
||||
|
||||
@@ -211,6 +212,7 @@ export default {
|
||||
},
|
||||
openTtsDialog(row) {
|
||||
this.selectedTtsModelId = row.id;
|
||||
this.selectedModelConfig = row;
|
||||
this.ttsDialogVisible = true;
|
||||
},
|
||||
headerCellClassName({ column, columnIndex }) {
|
||||
|
||||
Reference in New Issue
Block a user