mirror of
https://github.com/xinnan-tech/xiaozhi-esp32-server.git
synced 2026-07-22 07:03:53 +08:00
Merge pull request #2988 from xinnan-tech/update-manager-mobile
web端功能同步更新到mobile端
This commit is contained in:
@@ -183,3 +183,42 @@ export function createVoicePrint(data: { agentId: string, audioId: string, sourc
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// 获取智能体标签
|
||||
export function getAgentTags(agentId: string) {
|
||||
return http.Get<any[]>(`/agent/${agentId}/tags`, {
|
||||
meta: {
|
||||
ignoreAuth: false,
|
||||
toast: false,
|
||||
},
|
||||
cacheFor: {
|
||||
expire: 0,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// 更新智能体标签
|
||||
export function updateAgentTags(agentId: string, data) {
|
||||
return http.Put(`/agent/${agentId}/tags`, data, {
|
||||
meta: {
|
||||
ignoreAuth: false,
|
||||
isExposeError: true,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// 获取所有语言
|
||||
export function getAllLanguage(modelId, voiceName) {
|
||||
const queryParams = new URLSearchParams({
|
||||
voiceName: voiceName || '',
|
||||
}).toString()
|
||||
return http.Get(`/models/${modelId}/voices?${queryParams}`, {
|
||||
meta: {
|
||||
ignoreAuth: false,
|
||||
toast: false,
|
||||
},
|
||||
cacheFor: {
|
||||
expire: 0,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ export interface Agent {
|
||||
summaryMemory: string | null
|
||||
lastConnectedAt: string | null
|
||||
deviceCount: number
|
||||
tags: Record<string, string>[]
|
||||
}
|
||||
|
||||
// 智能体创建数据类型
|
||||
@@ -42,6 +43,10 @@ export interface AgentDetail {
|
||||
createdAt: string
|
||||
updater: string
|
||||
updatedAt: string
|
||||
ttsLanguage: string
|
||||
ttsVolume: number
|
||||
ttsRate: number
|
||||
ttsPitch: number
|
||||
functions: AgentFunction[]
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,467 @@
|
||||
<script lang="ts" setup>
|
||||
import { ref, watch } from 'vue'
|
||||
import { t } from '@/i18n'
|
||||
|
||||
interface Props {
|
||||
visible?: boolean
|
||||
providers?: Array<{
|
||||
url: string
|
||||
headers: Record<string, string>
|
||||
}>
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
visible: false,
|
||||
providers: () => [],
|
||||
})
|
||||
|
||||
const emit = defineEmits<{
|
||||
'update:visible': [value: boolean]
|
||||
'confirm': [value: Array<{
|
||||
url: string
|
||||
headers: Record<string, string>
|
||||
}>]
|
||||
}>()
|
||||
|
||||
const localProviders = ref<Array<{
|
||||
url: string
|
||||
headers: Array<{
|
||||
key: string
|
||||
value: string
|
||||
}>
|
||||
}>>([])
|
||||
|
||||
function initLocalData() {
|
||||
localProviders.value = props.providers.map((p) => {
|
||||
const headers = p.headers || {}
|
||||
return {
|
||||
url: p.url || '',
|
||||
headers: Object.entries(headers).map(([key, value]) => ({ key, value })),
|
||||
}
|
||||
})
|
||||
|
||||
if (localProviders.value.length === 0) {
|
||||
localProviders.value.push({ url: '', headers: [{ key: '', value: '' }] })
|
||||
}
|
||||
}
|
||||
|
||||
function addProvider(index: number) {
|
||||
localProviders.value.splice(index, 0, {
|
||||
url: '',
|
||||
headers: [{ key: '', value: '' }],
|
||||
})
|
||||
}
|
||||
|
||||
function removeProvider(index: number) {
|
||||
localProviders.value.splice(index, 1)
|
||||
}
|
||||
|
||||
function addHeader(pIndex: number, hIndex: number) {
|
||||
localProviders.value[pIndex].headers.splice(hIndex, 0, { key: '', value: '' })
|
||||
}
|
||||
|
||||
function removeHeader(pIndex: number, hIndex: number) {
|
||||
localProviders.value[pIndex].headers.splice(hIndex, 1)
|
||||
}
|
||||
|
||||
function handleConfirm() {
|
||||
const result = localProviders.value
|
||||
.filter(p => p.url.trim() !== '')
|
||||
.map((p) => {
|
||||
const headersObj: Record<string, string> = {}
|
||||
p.headers.forEach((h) => {
|
||||
if (h.key.trim()) {
|
||||
headersObj[h.key.trim()] = h.value
|
||||
}
|
||||
})
|
||||
return {
|
||||
url: p.url.trim(),
|
||||
headers: headersObj,
|
||||
}
|
||||
})
|
||||
|
||||
emit('confirm', result)
|
||||
emit('update:visible', false)
|
||||
}
|
||||
|
||||
function handleClose() {
|
||||
emit('update:visible', false)
|
||||
}
|
||||
|
||||
watch(() => props.visible, (val) => {
|
||||
if (val) {
|
||||
initLocalData()
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view v-if="visible" class="context-provider-dialog-mask" @click="handleClose">
|
||||
<view class="context-provider-dialog" @click.stop>
|
||||
<view class="dialog-header">
|
||||
<text class="dialog-title">
|
||||
{{ t('contextProviderDialog.title') }}
|
||||
</text>
|
||||
</view>
|
||||
|
||||
<view class="dialog-content">
|
||||
<view v-if="localProviders.length === 0" class="empty-container">
|
||||
<text class="empty-text">
|
||||
{{ t('contextProviderDialog.noContextApi') }}
|
||||
</text>
|
||||
<wd-button type="primary" size="small" @click="addProvider(0)">
|
||||
{{ t('contextProviderDialog.add') }}
|
||||
</wd-button>
|
||||
</view>
|
||||
|
||||
<view v-else class="providers-list">
|
||||
<view v-for="(provider, pIndex) in localProviders" :key="pIndex" class="provider-item">
|
||||
<view class="provider-card">
|
||||
<view class="card-header">
|
||||
<view class="card-controls">
|
||||
<wd-button
|
||||
type="icon"
|
||||
icon="add"
|
||||
size="small"
|
||||
class="!h-[60rpx] !w-[60rpx] !bg-[#66b1ff] !text-[#fff]"
|
||||
@click="addProvider(pIndex + 1)"
|
||||
/>
|
||||
<wd-button
|
||||
type="icon"
|
||||
icon="decrease"
|
||||
size="small"
|
||||
class="!h-[60rpx] !w-[60rpx] !bg-[#F56C6C] !text-[#fff]"
|
||||
@click="removeProvider(pIndex)"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
<view class="input-row">
|
||||
<text class="label-text">
|
||||
{{ t('contextProviderDialog.apiUrl') }}
|
||||
</text>
|
||||
<wd-input
|
||||
v-model="provider.url"
|
||||
class="flex-1"
|
||||
:placeholder="t('contextProviderDialog.apiUrlPlaceholder')"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<view class="headers-section">
|
||||
<view class="label-text" style="margin-top: 6px;">
|
||||
{{ t('contextProviderDialog.requestHeaders') }}
|
||||
</view>
|
||||
<view class="headers-list">
|
||||
<view
|
||||
v-for="(header, hIndex) in provider.headers"
|
||||
:key="hIndex"
|
||||
class="header-row-vertical"
|
||||
>
|
||||
<view class="header-input-group">
|
||||
<wd-input
|
||||
v-model="header.key"
|
||||
placeholder="key"
|
||||
class="header-input-full"
|
||||
/>
|
||||
</view>
|
||||
<view class="header-input-group">
|
||||
<wd-input
|
||||
v-model="header.value"
|
||||
placeholder="value"
|
||||
class="header-input-full"
|
||||
/>
|
||||
</view>
|
||||
<view class="header-controls">
|
||||
<wd-button
|
||||
type="icon"
|
||||
icon="add"
|
||||
size="small"
|
||||
class="!h-[50rpx] !w-[50rpx] !border-[1rpx] !border-solid !bg-[#ecf5ff] !text-[#b3d8ff]"
|
||||
@click="addHeader(pIndex, hIndex + 1)"
|
||||
/>
|
||||
<wd-button
|
||||
type="icon"
|
||||
icon="decrease"
|
||||
size="small"
|
||||
class="!h-[50rpx] !w-[50rpx] !border-[1rpx] !border-solid !bg-[#fef0f0] !text-[#F56C6C]"
|
||||
@click="removeHeader(pIndex, hIndex)"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="provider.headers.length === 0" class="header-row empty-header">
|
||||
<text class="no-header-text">
|
||||
{{ t('contextProviderDialog.noHeaders') }}
|
||||
</text>
|
||||
<wd-button type="text" size="small" @click="addHeader(pIndex, 0)">
|
||||
{{ t('contextProviderDialog.addHeader') }}
|
||||
</wd-button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="dialog-footer">
|
||||
<wd-button class="cancel-btn" @click="handleClose">
|
||||
{{ t('contextProviderDialog.cancel') }}
|
||||
</wd-button>
|
||||
<wd-button type="primary" class="confirm-btn" @click="handleConfirm">
|
||||
{{ t('contextProviderDialog.confirm') }}
|
||||
</wd-button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.context-provider-dialog-mask {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
z-index: 9999;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.context-provider-dialog {
|
||||
background: #fff;
|
||||
// border-radius: 20rpx;
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.dialog-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 20rpx;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
.dialog-title {
|
||||
font-size: 32rpx;
|
||||
font-weight: 600;
|
||||
color: #232338;
|
||||
}
|
||||
|
||||
.close-icon {
|
||||
font-size: 40rpx;
|
||||
color: #9d9ea3;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.dialog-content {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding: 20rpx;
|
||||
}
|
||||
|
||||
.empty-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 100rpx 0;
|
||||
gap: 30rpx;
|
||||
}
|
||||
|
||||
.empty-text {
|
||||
font-size: 28rpx;
|
||||
color: #9d9ea3;
|
||||
}
|
||||
|
||||
.providers-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.provider-item {
|
||||
margin-bottom: 30rpx;
|
||||
}
|
||||
|
||||
.provider-card {
|
||||
flex: 1;
|
||||
background: #fff;
|
||||
border-radius: 16rpx;
|
||||
border: 1px solid #eee;
|
||||
border-left: 6rpx solid #336cff;
|
||||
padding: 20rpx;
|
||||
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.card-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 30rpx;
|
||||
}
|
||||
|
||||
.card-title {
|
||||
font-size: 30rpx;
|
||||
font-weight: 600;
|
||||
color: #232338;
|
||||
}
|
||||
|
||||
.card-controls {
|
||||
display: flex;
|
||||
gap: 16rpx;
|
||||
}
|
||||
|
||||
.input-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 20rpx;
|
||||
margin-bottom: 40rpx;
|
||||
}
|
||||
|
||||
.headers-section {
|
||||
display: flex;
|
||||
gap: 20rpx;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.headers-list {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 20rpx;
|
||||
background: #fcfcfc;
|
||||
padding: 4rpx;
|
||||
border-radius: 12rpx;
|
||||
border: 1px dashed #dcdfe6;
|
||||
}
|
||||
|
||||
.header-row-vertical {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16rpx;
|
||||
background: #fff;
|
||||
// padding: 20rpx;
|
||||
border-radius: 12rpx;
|
||||
// border: 1px solid #e8e8e8;
|
||||
}
|
||||
|
||||
.header-input-group {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8rpx;
|
||||
}
|
||||
|
||||
.header-key-label,
|
||||
.header-value-label {
|
||||
font-size: 24rpx;
|
||||
font-weight: 500;
|
||||
color: #606266;
|
||||
}
|
||||
|
||||
.header-input-full {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.header-controls {
|
||||
display: flex;
|
||||
gap: 12rpx;
|
||||
// margin-top: 8rpx;
|
||||
align-self: flex-start;
|
||||
}
|
||||
|
||||
.block-controls {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16rpx;
|
||||
padding-top: 10rpx;
|
||||
}
|
||||
|
||||
.input-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 20rpx;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.label-text {
|
||||
font-size: 28rpx;
|
||||
font-weight: 600;
|
||||
color: #606266;
|
||||
width: 140rpx;
|
||||
}
|
||||
|
||||
.headers-section {
|
||||
display: flex;
|
||||
gap: 20rpx;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.headers-list {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 20rpx;
|
||||
background: #fcfcfc;
|
||||
padding: 16rpx;
|
||||
border-radius: 12rpx;
|
||||
border: 1px dashed #dcdfe6;
|
||||
}
|
||||
|
||||
.header-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16rpx;
|
||||
}
|
||||
|
||||
.header-input {
|
||||
width: 200rpx;
|
||||
}
|
||||
|
||||
.separator {
|
||||
color: #909399;
|
||||
font-weight: bold;
|
||||
font-size: 32rpx;
|
||||
}
|
||||
|
||||
.row-controls {
|
||||
display: flex;
|
||||
gap: 12rpx;
|
||||
margin-left: 8rpx;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.empty-header {
|
||||
justify-content: center;
|
||||
padding: 20rpx;
|
||||
color: #909399;
|
||||
font-size: 26rpx;
|
||||
}
|
||||
|
||||
.no-header-text {
|
||||
margin-right: 16rpx;
|
||||
}
|
||||
|
||||
.flex-1 {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.dialog-footer {
|
||||
display: flex;
|
||||
gap: 20rpx;
|
||||
padding: 30rpx;
|
||||
border-top: 1px solid #eee;
|
||||
}
|
||||
|
||||
.cancel-btn,
|
||||
.confirm-btn {
|
||||
flex: 1;
|
||||
height: 80rpx;
|
||||
border-radius: 12rpx;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,270 @@
|
||||
<script lang="ts" setup>
|
||||
import { ref, watch } from 'vue'
|
||||
import { t } from '@/i18n'
|
||||
|
||||
interface Props {
|
||||
visible?: boolean
|
||||
settings?: {
|
||||
volume: number
|
||||
speed: number
|
||||
pitch: number
|
||||
}
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
visible: false,
|
||||
settings: () => ({
|
||||
volume: 0,
|
||||
speed: 0,
|
||||
pitch: 0,
|
||||
}),
|
||||
})
|
||||
|
||||
const emit = defineEmits<{
|
||||
'update:visible': [value: boolean]
|
||||
'confirm': [value: {
|
||||
volume: number
|
||||
speed: number
|
||||
pitch: number
|
||||
}]
|
||||
}>()
|
||||
|
||||
const localSettings = ref({
|
||||
volume: 0,
|
||||
speed: 0,
|
||||
pitch: 0,
|
||||
})
|
||||
|
||||
function initLocalData() {
|
||||
localSettings.value = {
|
||||
volume: props.settings.volume || 0,
|
||||
speed: props.settings.speed || 0,
|
||||
pitch: props.settings.pitch || 0,
|
||||
}
|
||||
}
|
||||
|
||||
function handleConfirm() {
|
||||
emit('confirm', localSettings.value)
|
||||
emit('update:visible', false)
|
||||
}
|
||||
|
||||
function handleClose() {
|
||||
emit('update:visible', false)
|
||||
}
|
||||
|
||||
watch(() => props.visible, (val) => {
|
||||
if (val) {
|
||||
initLocalData()
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view v-if="visible" class="voice-settings-dialog-mask" @click="handleClose">
|
||||
<view class="voice-settings-dialog" @click.stop>
|
||||
<view class="dialog-header">
|
||||
<text class="dialog-title">
|
||||
{{ t('agent.languageConfig') }}
|
||||
</text>
|
||||
</view>
|
||||
|
||||
<view class="dialog-content">
|
||||
<!-- 音量调节 -->
|
||||
<view class="setting-item">
|
||||
<text class="setting-label">
|
||||
{{ t('agent.ttsVolume') }}
|
||||
</text>
|
||||
<view class="slider-container">
|
||||
<wd-slider
|
||||
v-model="localSettings.volume"
|
||||
:min="-100"
|
||||
:max="100"
|
||||
:step="1"
|
||||
:show-value="false"
|
||||
custom-class="voice-slider"
|
||||
/>
|
||||
<text class="slider-value">
|
||||
{{ localSettings.volume }}
|
||||
</text>
|
||||
</view>
|
||||
<text class="setting-desc">
|
||||
{{ t('agent.volumeHint') }}
|
||||
</text>
|
||||
</view>
|
||||
|
||||
<!-- 语速调节 -->
|
||||
<view class="setting-item">
|
||||
<text class="setting-label">
|
||||
{{ t('agent.ttsRate') }}
|
||||
</text>
|
||||
<view class="slider-container">
|
||||
<wd-slider
|
||||
v-model="localSettings.speed"
|
||||
:min="-100"
|
||||
:max="100"
|
||||
:step="1"
|
||||
:show-value="false"
|
||||
custom-class="voice-slider"
|
||||
/>
|
||||
<text class="slider-value">
|
||||
{{ localSettings.speed }}
|
||||
</text>
|
||||
</view>
|
||||
<text class="setting-desc">
|
||||
{{ t('agent.speedHint') }}
|
||||
</text>
|
||||
</view>
|
||||
|
||||
<!-- 音调调节 -->
|
||||
<view class="setting-item">
|
||||
<text class="setting-label">
|
||||
{{ t('agent.ttsPitch') }}
|
||||
</text>
|
||||
<view class="slider-container">
|
||||
<wd-slider
|
||||
v-model="localSettings.pitch"
|
||||
:min="-100"
|
||||
:max="100"
|
||||
:step="1"
|
||||
:show-value="false"
|
||||
custom-class="voice-slider"
|
||||
/>
|
||||
<text class="slider-value">
|
||||
{{ localSettings.pitch }}
|
||||
</text>
|
||||
</view>
|
||||
<text class="setting-desc">
|
||||
{{ t('agent.pitchHint') }}
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="dialog-footer">
|
||||
<wd-button class="cancel-btn" @click="handleClose">
|
||||
{{ t('agent.cancel') }}
|
||||
</wd-button>
|
||||
<wd-button type="primary" class="confirm-btn" @click="handleConfirm">
|
||||
{{ t('agent.save') }}
|
||||
</wd-button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.voice-settings-dialog-mask {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
z-index: 9999;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.voice-settings-dialog {
|
||||
background: #fff;
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.dialog-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 30rpx;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
.dialog-title {
|
||||
font-size: 32rpx;
|
||||
font-weight: 600;
|
||||
color: #232338;
|
||||
}
|
||||
|
||||
.close-icon {
|
||||
font-size: 40rpx;
|
||||
color: #9d9ea3;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.dialog-content {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding: 40rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 50rpx;
|
||||
}
|
||||
|
||||
.setting-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 20rpx;
|
||||
}
|
||||
|
||||
.setting-label {
|
||||
font-size: 30rpx;
|
||||
font-weight: 600;
|
||||
color: #232338;
|
||||
}
|
||||
|
||||
.slider-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 20rpx;
|
||||
}
|
||||
|
||||
.voice-slider {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.slider-value {
|
||||
font-size: 28rpx;
|
||||
color: #336cff;
|
||||
font-weight: 500;
|
||||
min-width: 80rpx;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.setting-desc {
|
||||
font-size: 24rpx;
|
||||
color: #9d9ea3;
|
||||
margin-top: 10rpx;
|
||||
}
|
||||
|
||||
.dialog-footer {
|
||||
display: flex;
|
||||
gap: 20rpx;
|
||||
padding: 30rpx;
|
||||
border-top: 1px solid #eee;
|
||||
}
|
||||
|
||||
.cancel-btn,
|
||||
.confirm-btn {
|
||||
flex: 1;
|
||||
height: 80rpx;
|
||||
border-radius: 12rpx;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
.confirm-btn {
|
||||
background-color: #336cff !important;
|
||||
}
|
||||
|
||||
/* 自定义滑块样式 */
|
||||
:deep(.wd-slider) {
|
||||
--wd-slider-bar-background: #e6ebff;
|
||||
--wd-slider-bar-active-background: #336cff;
|
||||
--wd-slider-thumb-border-color: #336cff;
|
||||
--wd-slider-thumb-background: #336cff;
|
||||
--wd-slider-thumb-size: 32rpx;
|
||||
}
|
||||
</style>
|
||||
@@ -107,6 +107,10 @@ const alovaInstance = createAlova({
|
||||
throw new Error(`请求错误[${code}]:${msg}`)
|
||||
}
|
||||
|
||||
if (config.meta?.isExposeError) {
|
||||
return Promise.reject(msg)
|
||||
}
|
||||
|
||||
if (config.meta?.toast !== false) {
|
||||
toast.warning(msg)
|
||||
}
|
||||
|
||||
@@ -73,6 +73,8 @@ export default {
|
||||
'home.minutesAgo': 'Minuten her',
|
||||
'home.hoursAgo': 'Stunden her',
|
||||
'home.daysAgo': 'Tage her',
|
||||
'home.languageModel': 'LLM',
|
||||
'home.voiceModel': 'TTS',
|
||||
|
||||
// Agentenseite
|
||||
'agent.pageTitle': 'Agent',
|
||||
@@ -92,6 +94,13 @@ export default {
|
||||
'agent.agentName': 'Agentenname',
|
||||
'agent.inputAgentName': 'Bitte Agenten-Namen eingeben',
|
||||
'agent.roleMode': 'Rollenmodus',
|
||||
'agent.agentTag': 'Smart Body-Etiketten',
|
||||
'agent.addAgentTag': 'Tags hinzufügen',
|
||||
'agent.inputAgentTag': 'Bitte Smart Body-Etiketten eingeben',
|
||||
'agent.contextProvider': 'Kontext',
|
||||
'agent.contextProviderSuccess': '{count} Quellen erfolgreich hinzugefügt.',
|
||||
'agent.contextProviderDocLink': 'Wie man Kontextquellen bereitstellt',
|
||||
'agent.editContextProvider': 'Quelle bearbeiten',
|
||||
'agent.roleDescription': 'Rollenbeschreibung',
|
||||
'agent.inputRoleDescription': 'Bitte Rollenbeschreibung eingeben',
|
||||
'agent.modelConfig': 'Modellkonfiguration',
|
||||
@@ -115,6 +124,31 @@ export default {
|
||||
'agent.pleaseInputAgentName': 'Bitte Agenten-Namen eingeben',
|
||||
'agent.pleaseInputRoleDescription': 'Bitte Rollenbeschreibung eingeben',
|
||||
'agent.pleaseSelect': 'Bitte auswählen',
|
||||
'agent.reportText': 'Text melden',
|
||||
'agent.reportTextVoice': 'Text + Sprache melden',
|
||||
'agent.reportMode': 'Meldemodus',
|
||||
'agent.language': 'Unterhaltungssprache',
|
||||
'agent.languageConfig': 'Sprachgeschwindigkeit & Tonhöhe',
|
||||
'agent.ttsVolume': 'Lautstärke',
|
||||
'agent.ttsRate': 'Sprechtempo',
|
||||
'agent.ttsPitch': 'Tonhöhe',
|
||||
'agent.volumeHint': '-100=min, 0=Standard, 100=max',
|
||||
'agent.speedHint': '-100=langsamst, 0=Standard, 100=schnellst',
|
||||
'agent.pitchHint': '-100=tiefst, 0=Standard, 100=höchst',
|
||||
|
||||
// Context provider dialog related
|
||||
'contextProviderDialog.title': 'Quelle bearbeiten',
|
||||
'contextProviderDialog.noContextApi': 'Keine Kontext-API',
|
||||
'contextProviderDialog.add': 'Hinzufügen',
|
||||
'contextProviderDialog.apiUrl': 'API-URL',
|
||||
'contextProviderDialog.apiUrlPlaceholder': 'http://api.example.com/data',
|
||||
'contextProviderDialog.requestHeaders': 'Anfrage-Header',
|
||||
'contextProviderDialog.headerKeyPlaceholder': 'Schlüssel',
|
||||
'contextProviderDialog.headerValuePlaceholder': 'Wert',
|
||||
'contextProviderDialog.noHeaders': 'Keine Headers',
|
||||
'contextProviderDialog.addHeader': 'Header hinzufügen',
|
||||
'contextProviderDialog.cancel': 'Abbrechen',
|
||||
'contextProviderDialog.confirm': 'Bestätigen',
|
||||
|
||||
// Chat-Verlauf Seite
|
||||
'chatHistory.getChatSessions': 'Chat-Sitzungsliste abrufen',
|
||||
|
||||
@@ -73,6 +73,8 @@ export default {
|
||||
'home.minutesAgo': 'minutes ago',
|
||||
'home.hoursAgo': 'hours ago',
|
||||
'home.daysAgo': 'days ago',
|
||||
'home.languageModel': 'LLM',
|
||||
'home.voiceModel': 'TTS',
|
||||
|
||||
// Agent page
|
||||
'agent.pageTitle': 'Agent',
|
||||
@@ -92,6 +94,13 @@ export default {
|
||||
'agent.agentName': 'Agent Name',
|
||||
'agent.inputAgentName': 'Please input agent name',
|
||||
'agent.roleMode': 'Role Mode',
|
||||
'agent.agentTag': 'Intelligent agent label',
|
||||
'agent.addAgentTag': 'Add label',
|
||||
'agent.inputAgentTag': 'Please input agent label',
|
||||
'agent.contextProvider': 'Context',
|
||||
'agent.contextProviderSuccess': 'Successfully added {count} sources.',
|
||||
'agent.contextProviderDocLink': 'How to deploy context provider',
|
||||
'agent.editContextProvider': 'Edit Source',
|
||||
'agent.roleDescription': 'Role Description',
|
||||
'agent.inputRoleDescription': 'Please input role description',
|
||||
'agent.modelConfig': 'Model Configuration',
|
||||
@@ -115,6 +124,31 @@ export default {
|
||||
'agent.pleaseInputAgentName': 'Please input agent name',
|
||||
'agent.pleaseInputRoleDescription': 'Please input role description',
|
||||
'agent.pleaseSelect': 'Please select',
|
||||
'agent.reportText': 'Report Text',
|
||||
'agent.reportTextVoice': 'Report Text+Voice',
|
||||
'agent.reportMode': 'Report Mode',
|
||||
'agent.language': 'Conversation Language',
|
||||
'agent.languageConfig': 'Speech Rate&Tone',
|
||||
'agent.ttsVolume': 'Volume',
|
||||
'agent.ttsRate': 'Speech Rate',
|
||||
'agent.ttsPitch': 'Tone',
|
||||
'agent.volumeHint': '-100=Minimum, 0=Standard, 100=Maximum',
|
||||
'agent.speedHint': '-100=Slower, 0=Standard, 100=Faster',
|
||||
'agent.pitchHint': '-100=Lowest, 0=Standard, 100=Highest',
|
||||
|
||||
// Context provider dialog related
|
||||
'contextProviderDialog.title': 'Edit Source',
|
||||
'contextProviderDialog.noContextApi': 'No Context API',
|
||||
'contextProviderDialog.add': 'Add',
|
||||
'contextProviderDialog.apiUrl': 'API URL',
|
||||
'contextProviderDialog.apiUrlPlaceholder': 'http://api.example.com/data',
|
||||
'contextProviderDialog.requestHeaders': 'Request Headers',
|
||||
'contextProviderDialog.headerKeyPlaceholder': 'Key',
|
||||
'contextProviderDialog.headerValuePlaceholder': 'Value',
|
||||
'contextProviderDialog.noHeaders': 'No Headers',
|
||||
'contextProviderDialog.addHeader': 'Add Header',
|
||||
'contextProviderDialog.cancel': 'Cancel',
|
||||
'contextProviderDialog.confirm': 'Confirm',
|
||||
|
||||
// Chat History Page
|
||||
'chatHistory.getChatSessions': 'Get chat session list',
|
||||
|
||||
@@ -73,6 +73,8 @@ export default {
|
||||
'home.minutesAgo': 'minutos atrás',
|
||||
'home.hoursAgo': 'horas atrás',
|
||||
'home.daysAgo': 'dias atrás',
|
||||
'home.languageModel': 'LLM',
|
||||
'home.voiceModel': 'TTS',
|
||||
|
||||
// Agent page
|
||||
'agent.pageTitle': 'Agente',
|
||||
@@ -92,6 +94,13 @@ export default {
|
||||
'agent.agentName': 'Nome do Agente',
|
||||
'agent.inputAgentName': 'Por favor, insira o nome do agente',
|
||||
'agent.roleMode': 'Modo de Papel',
|
||||
'agent.agentTag': 'Etiquetas de corpo inteligente',
|
||||
'agent.addAgentTag': 'Adicionar etiqueta',
|
||||
'agent.inputAgentTag': 'Por favor, insira o rótulo do corpo inteligente',
|
||||
'agent.contextProvider': 'Contexto',
|
||||
'agent.contextProviderSuccess': '{count} fontes adicionadas com sucesso.',
|
||||
'agent.contextProviderDocLink': 'Como implantar provedor de contexto',
|
||||
'agent.editContextProvider': 'Editar Fonte',
|
||||
'agent.roleDescription': 'Descrição do Papel',
|
||||
'agent.inputRoleDescription': 'Por favor, insira a descrição do papel',
|
||||
'agent.modelConfig': 'Configuração do Modelo',
|
||||
@@ -115,6 +124,31 @@ export default {
|
||||
'agent.pleaseInputAgentName': 'Por favor, insira o nome do agente',
|
||||
'agent.pleaseInputRoleDescription': 'Por favor, insira a descrição do papel',
|
||||
'agent.pleaseSelect': 'Por favor, selecione',
|
||||
'agent.reportText': 'Enviar Texto',
|
||||
'agent.reportTextVoice': 'Enviar Texto+Voz',
|
||||
'agent.reportMode': 'Modo de Envio',
|
||||
'agent.language': 'Idioma de Conversa',
|
||||
'agent.languageConfig': 'Configuração de Voz',
|
||||
'agent.ttsVolume': 'Volume',
|
||||
'agent.ttsRate': 'Taxa de Fala',
|
||||
'agent.ttsPitch': 'Tonalidade',
|
||||
'agent.volumeHint': '-100=Mínimo, 0=Padrão, 100=Máximo',
|
||||
'agent.speedHint': '-100=Slower, 0=Standard, 100=Faster',
|
||||
'agent.pitchHint': '-100=Lowest, 0=Standard, 100=Highest',
|
||||
|
||||
// Diálogo de provedor de contexto
|
||||
'contextProviderDialog.title': 'Editar Fonte',
|
||||
'contextProviderDialog.noContextApi': 'Sem API de Contexto',
|
||||
'contextProviderDialog.add': 'Adicionar',
|
||||
'contextProviderDialog.apiUrl': 'URL da API',
|
||||
'contextProviderDialog.apiUrlPlaceholder': 'http://api.example.com/data',
|
||||
'contextProviderDialog.requestHeaders': 'Cabeçalhos da Requisição',
|
||||
'contextProviderDialog.headerKeyPlaceholder': 'Chave',
|
||||
'contextProviderDialog.headerValuePlaceholder': 'Valor',
|
||||
'contextProviderDialog.noHeaders': 'Sem Cabeçalhos',
|
||||
'contextProviderDialog.addHeader': 'Adicionar Cabeçalho',
|
||||
'contextProviderDialog.cancel': 'Cancelar',
|
||||
'contextProviderDialog.confirm': 'Confirmar',
|
||||
|
||||
// Chat History Page
|
||||
'chatHistory.getChatSessions': 'Obter lista de sessões de conversa',
|
||||
|
||||
@@ -73,6 +73,8 @@ export default {
|
||||
'home.minutesAgo': 'phút trước',
|
||||
'home.hoursAgo': 'giờ trước',
|
||||
'home.daysAgo': 'ngày trước',
|
||||
'home.languageModel': 'LLM',
|
||||
'home.voiceModel': 'TTS',
|
||||
|
||||
// Trang đại lý
|
||||
'agent.pageTitle': 'Đại lý',
|
||||
@@ -92,6 +94,13 @@ export default {
|
||||
'agent.agentName': 'Tên đại lý',
|
||||
'agent.inputAgentName': 'Vui lòng nhập tên đại lý',
|
||||
'agent.roleMode': 'Chế độ vai trò',
|
||||
'agent.agentTag': 'Nhãn cơ thể thông minh',
|
||||
'agent.addAgentTag': 'Thêm thẻ',
|
||||
'agent.inputAgentTag': 'Vui lòng nhập thẻ cơ thể thông minh',
|
||||
'agent.contextProvider': 'Bối cảnh',
|
||||
'agent.contextProviderSuccess': 'Đã thêm thành công {count} nguồn.',
|
||||
'agent.contextProviderDocLink': 'Cách triển khai nguồn ngữ cảnh',
|
||||
'agent.editContextProvider': 'Chỉnh sửa nguồn',
|
||||
'agent.roleDescription': 'Mô tả vai trò',
|
||||
'agent.inputRoleDescription': 'Vui lòng nhập mô tả vai trò',
|
||||
'agent.modelConfig': 'Cấu hình mô hình',
|
||||
@@ -115,6 +124,31 @@ export default {
|
||||
'agent.pleaseInputAgentName': 'Vui lòng nhập tên đại lý',
|
||||
'agent.pleaseInputRoleDescription': 'Vui lòng nhập mô tả vai trò',
|
||||
'agent.pleaseSelect': 'Vui lòng chọn',
|
||||
'agent.reportText': 'Gửi văn bản',
|
||||
'agent.reportTextVoice': 'Gửi văn bản+giọng nói',
|
||||
'agent.reportMode': 'Chế độ gửi',
|
||||
'agent.language': 'Ngôn ngữ',
|
||||
'agent.languageConfig': 'Giọng nói',
|
||||
'agent.ttsVolume': 'Âm lượng',
|
||||
'agent.ttsRate': 'Tốc độ',
|
||||
'agent.ttsPitch': 'Tone',
|
||||
'agent.volumeHint': '-100=Minimum, 0=Standard, 100=Maximum',
|
||||
'agent.speedHint': '-100=Slowest, 0=Standard, 100=Fastest',
|
||||
'agent.pitchHint': '-100=Lowest, 0=Standard, 100=Highest',
|
||||
|
||||
// Context provider dialog related
|
||||
'contextProviderDialog.title': 'Chỉnh sửa nguồn',
|
||||
'contextProviderDialog.noContextApi': 'Không có API ngữ cảnh',
|
||||
'contextProviderDialog.add': 'Thêm',
|
||||
'contextProviderDialog.apiUrl': 'Địa chỉ API',
|
||||
'contextProviderDialog.apiUrlPlaceholder': 'http://api.example.com/data',
|
||||
'contextProviderDialog.requestHeaders': 'Header yêu cầu',
|
||||
'contextProviderDialog.headerKeyPlaceholder': 'Khóa',
|
||||
'contextProviderDialog.headerValuePlaceholder': 'Giá trị',
|
||||
'contextProviderDialog.noHeaders': 'Không có Headers',
|
||||
'contextProviderDialog.addHeader': 'Thêm Header',
|
||||
'contextProviderDialog.cancel': 'Hủy bỏ',
|
||||
'contextProviderDialog.confirm': 'Xác nhận',
|
||||
|
||||
// Trang lịch sử trò chuyện
|
||||
'chatHistory.getChatSessions': 'Lấy danh sách phiên trò chuyện',
|
||||
|
||||
@@ -73,6 +73,8 @@ export default {
|
||||
'home.minutesAgo': '分钟前',
|
||||
'home.hoursAgo': '小时前',
|
||||
'home.daysAgo': '天前',
|
||||
'home.languageModel': '语言模型',
|
||||
'home.voiceModel': '音色模型',
|
||||
|
||||
// Agent页面
|
||||
'agent.pageTitle': '智能体',
|
||||
@@ -92,6 +94,13 @@ export default {
|
||||
'agent.agentName': '助手昵称',
|
||||
'agent.inputAgentName': '请输入助手昵称',
|
||||
'agent.roleMode': '角色模式',
|
||||
'agent.agentTag': '智能体标签',
|
||||
'agent.addAgentTag': '添加标签',
|
||||
'agent.inputAgentTag': '请输入智能体标签',
|
||||
'agent.contextProvider': '上下文源',
|
||||
'agent.contextProviderSuccess': '已成功添加 {count} 个源。',
|
||||
'agent.contextProviderDocLink': '如何部署上下文源',
|
||||
'agent.editContextProvider': '编辑源',
|
||||
'agent.roleDescription': '角色介绍',
|
||||
'agent.inputRoleDescription': '请输入角色介绍',
|
||||
'agent.modelConfig': '模型配置',
|
||||
@@ -115,6 +124,31 @@ export default {
|
||||
'agent.pleaseInputAgentName': '请输入智能体名称',
|
||||
'agent.pleaseInputRoleDescription': '请输入角色介绍',
|
||||
'agent.pleaseSelect': '请选择',
|
||||
'agent.reportText': '上报文字',
|
||||
'agent.reportTextVoice': '上报文字+语音',
|
||||
'agent.reportMode': '上报模式',
|
||||
'agent.language': '对话语言',
|
||||
'agent.languageConfig': '语速音调',
|
||||
'agent.ttsVolume': '音量',
|
||||
'agent.ttsRate': '语速',
|
||||
'agent.ttsPitch': '音调',
|
||||
'agent.volumeHint': '-100=最小, 0=标准, 100=最大',
|
||||
'agent.speedHint': '-100=最慢, 0=标准, 100=最快',
|
||||
'agent.pitchHint': '-100=最低, 0=标准, 100=最高',
|
||||
|
||||
// 上下文源对话框相关
|
||||
'contextProviderDialog.title': '编辑源',
|
||||
'contextProviderDialog.noContextApi': '暂无上下文API',
|
||||
'contextProviderDialog.add': '添加',
|
||||
'contextProviderDialog.apiUrl': '接口地址',
|
||||
'contextProviderDialog.apiUrlPlaceholder': 'http://api.example.com/data',
|
||||
'contextProviderDialog.requestHeaders': '请求头',
|
||||
'contextProviderDialog.headerKeyPlaceholder': 'Key',
|
||||
'contextProviderDialog.headerValuePlaceholder': 'Value',
|
||||
'contextProviderDialog.noHeaders': '暂无 Headers',
|
||||
'contextProviderDialog.addHeader': '添加 Header',
|
||||
'contextProviderDialog.cancel': '取消',
|
||||
'contextProviderDialog.confirm': '确定',
|
||||
|
||||
// 聊天历史页面
|
||||
'chatHistory.getChatSessions': '获取聊天会话列表',
|
||||
|
||||
@@ -94,6 +94,8 @@ export default {
|
||||
'home.minutesAgo': '分鐘前',
|
||||
'home.hoursAgo': '小時前',
|
||||
'home.daysAgo': '天前',
|
||||
'home.languageModel': '語言模型',
|
||||
'home.voiceModel': '音色模型',
|
||||
|
||||
// Agent頁面
|
||||
'agent.pageTitle': '智能體',
|
||||
@@ -113,6 +115,13 @@ export default {
|
||||
'agent.agentName': '助手暱稱',
|
||||
'agent.inputAgentName': '請輸入助手暱稱',
|
||||
'agent.roleMode': '角色模式',
|
||||
'agent.agentTag': '智慧體標籤',
|
||||
'agent.addAgentTag': '添加標籤',
|
||||
'agent.inputAgentTag': '請輸入智慧體標籤',
|
||||
'agent.contextProvider': '上下文源',
|
||||
'agent.contextProviderSuccess': '已成功添加 {count} 個源。',
|
||||
'agent.contextProviderDocLink': '如何部署上下文源',
|
||||
'agent.editContextProvider': '編輯源',
|
||||
'agent.roleDescription': '角色介紹',
|
||||
'agent.inputRoleDescription': '請輸入角色介紹',
|
||||
'agent.modelConfig': '模型配置',
|
||||
@@ -136,6 +145,31 @@ export default {
|
||||
'agent.pleaseInputAgentName': '請輸入助手暱稱',
|
||||
'agent.pleaseInputRoleDescription': '請輸入角色介紹',
|
||||
'agent.pleaseSelect': '請選擇',
|
||||
'agent.reportText': '上报文字',
|
||||
'agent.reportTextVoice': '上报文字+语音',
|
||||
'agent.reportMode': '上報模式',
|
||||
'agent.language': '對話語言',
|
||||
'agent.languageConfig': '語速音調',
|
||||
'agent.ttsVolume': '音量',
|
||||
'agent.ttsRate': '語速',
|
||||
'agent.ttsPitch': '音調',
|
||||
'agent.volumeHint': '-100=最小, 0=標準, 100=最大',
|
||||
'agent.speedHint': '-100=最慢, 0=標準, 100=最快',
|
||||
'agent.pitchHint': '-100=最低, 0=標準, 100=最高',
|
||||
|
||||
// 上下文源对话框相关
|
||||
'contextProviderDialog.title': '編輯源',
|
||||
'contextProviderDialog.noContextApi': '暫無上下文API',
|
||||
'contextProviderDialog.add': '添加',
|
||||
'contextProviderDialog.apiUrl': '介面地址',
|
||||
'contextProviderDialog.apiUrlPlaceholder': 'http://api.example.com/data',
|
||||
'contextProviderDialog.requestHeaders': '請求頭',
|
||||
'contextProviderDialog.headerKeyPlaceholder': 'Key',
|
||||
'contextProviderDialog.headerValuePlaceholder': 'Value',
|
||||
'contextProviderDialog.noHeaders': '暫無 Headers',
|
||||
'contextProviderDialog.addHeader': '添加 Header',
|
||||
'contextProviderDialog.cancel': '取消',
|
||||
'contextProviderDialog.confirm': '確定',
|
||||
|
||||
// 聊天歷史頁面
|
||||
'chatHistory.getChatSessions': '獲取聊天會話列表',
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
<script lang="ts" setup>
|
||||
import type { AgentDetail, ModelOption, PluginDefinition, RoleTemplate } from '@/api/agent/types'
|
||||
import { computed, nextTick, onMounted, ref, watch } from 'vue'
|
||||
import { getAgentDetail, getModelOptions, getPluginFunctions, getRoleTemplates, getTTSVoices, updateAgent } from '@/api/agent/agent'
|
||||
import { getAgentDetail, getAgentTags, getAllLanguage, getModelOptions, getPluginFunctions, getRoleTemplates, updateAgent, updateAgentTags } from '@/api/agent/agent'
|
||||
import ContextProviderDialog from '@/components/ContextProviderDialog.vue'
|
||||
import VoiceSettingsDialog from '@/components/VoiceSettingsDialog.vue'
|
||||
import { t } from '@/i18n'
|
||||
import { usePluginStore } from '@/store'
|
||||
import { toast } from '@/utils/toast'
|
||||
import { t } from '@/i18n'
|
||||
|
||||
defineOptions({
|
||||
name: 'AgentEdit',
|
||||
@@ -34,6 +36,10 @@ const formData = ref<Partial<AgentDetail>>({
|
||||
memModelId: '',
|
||||
ttsModelId: '',
|
||||
ttsVoiceId: '',
|
||||
ttsLanguage: '',
|
||||
ttsVolume: 0,
|
||||
ttsRate: 0,
|
||||
ttsPitch: 0,
|
||||
})
|
||||
|
||||
// 显示名称数据
|
||||
@@ -47,6 +53,8 @@ const displayNames = ref({
|
||||
memory: t('agent.pleaseSelect'),
|
||||
tts: t('agent.pleaseSelect'),
|
||||
voiceprint: t('agent.pleaseSelect'),
|
||||
report: t('agent.pleaseSelect'),
|
||||
language: t('agent.pleaseSelect'),
|
||||
})
|
||||
|
||||
// 角色模板数据
|
||||
@@ -71,7 +79,15 @@ const modelOptions = ref<{
|
||||
})
|
||||
|
||||
// 音色选项数据
|
||||
const voiceOptions = ref<{ id: string, name: string }[]>([])
|
||||
const voiceOptions = ref([])
|
||||
// 保存完整的音色信息
|
||||
const voiceDetails = ref({})
|
||||
|
||||
// 上报模式选项数据
|
||||
const reportOptions = [
|
||||
{ name: t('agent.reportText'), value: 1 },
|
||||
{ name: t('agent.reportTextVoice'), value: 2 },
|
||||
]
|
||||
|
||||
// 选择器显示状态
|
||||
const pickerShow = ref<{
|
||||
@@ -85,9 +101,30 @@ const pickerShow = ref<{
|
||||
memory: false,
|
||||
tts: false,
|
||||
voiceprint: false,
|
||||
language: false,
|
||||
report: false,
|
||||
})
|
||||
|
||||
const ttsSettings = ref({
|
||||
volume: 0,
|
||||
speed: 0,
|
||||
pitch: 0,
|
||||
})
|
||||
|
||||
const allFunctions = ref<PluginDefinition[]>([])
|
||||
const dynamicTags = ref([])
|
||||
const inputValue = ref('')
|
||||
const inputVisible = ref(false)
|
||||
const showContextProviderDialog = ref(false)
|
||||
const currentContextProviders = ref([])
|
||||
const showVoiceSettingsDialog = ref(false)
|
||||
const voiceSettings = ref({
|
||||
volume: 0,
|
||||
speed: 0,
|
||||
pitch: 0,
|
||||
})
|
||||
const languageOptions = ref([])
|
||||
const isVisibleReport = ref(false)
|
||||
|
||||
// 使用插件store
|
||||
const pluginStore = usePluginStore()
|
||||
@@ -119,6 +156,46 @@ const tabList = [
|
||||
activeIcon: '/static/tabbar/voiceprint_activate.png',
|
||||
},
|
||||
]
|
||||
function handleCloseTag(id: string) {
|
||||
dynamicTags.value = dynamicTags.value.filter(tag => tag.id !== id)
|
||||
}
|
||||
|
||||
function showInput() {
|
||||
inputVisible.value = true
|
||||
}
|
||||
|
||||
function handleInputConfirm() {
|
||||
if (inputValue.value) {
|
||||
dynamicTags.value.push({ id: new Date().getTime(), tagName: inputValue.value.trim() })
|
||||
inputValue.value = ''
|
||||
}
|
||||
inputVisible.value = false
|
||||
}
|
||||
|
||||
// 打开上下文源编辑弹窗
|
||||
function openContextProviderDialog() {
|
||||
showContextProviderDialog.value = true
|
||||
}
|
||||
|
||||
// 处理上下文源更新
|
||||
function handleUpdateContext(providers: any[]) {
|
||||
currentContextProviders.value = providers
|
||||
}
|
||||
|
||||
function openVoiceSettingsDialog() {
|
||||
showVoiceSettingsDialog.value = true
|
||||
}
|
||||
|
||||
function handleUpdateVoiceSettings(settings: any) {
|
||||
ttsSettings.value = settings
|
||||
formData.value.ttsVolume = settings.volume
|
||||
formData.value.ttsRate = settings.speed
|
||||
formData.value.ttsPitch = settings.pitch
|
||||
}
|
||||
|
||||
function handleRegulate() {
|
||||
openVoiceSettingsDialog()
|
||||
}
|
||||
|
||||
// 加载智能体详情
|
||||
async function loadAgentDetail() {
|
||||
@@ -134,9 +211,18 @@ async function loadAgentDetail() {
|
||||
pluginStore.setCurrentAgentId(agentId.value)
|
||||
pluginStore.setCurrentFunctions(detail.functions || [])
|
||||
|
||||
// 加载上下文配置
|
||||
currentContextProviders.value = (detail as any).contextProviders || []
|
||||
// 加载语音设置
|
||||
voiceSettings.value = {
|
||||
volume: (detail as any).volume || 0,
|
||||
speed: (detail as any).speed || 0,
|
||||
pitch: (detail as any).pitch || 0,
|
||||
}
|
||||
|
||||
// 如果有TTS模型,加载对应的音色选项
|
||||
if (detail.ttsModelId) {
|
||||
await loadVoiceOptions(detail.ttsModelId)
|
||||
await fetchAllLanguag(detail.ttsModelId)
|
||||
}
|
||||
|
||||
// 等待模型选项加载完成后再更新显示名称
|
||||
@@ -208,7 +294,10 @@ function updateDisplayNames() {
|
||||
displayNames.value.tts = getModelDisplayName('TTS', formData.value.ttsModelId)
|
||||
|
||||
// 角色音色特殊处理
|
||||
displayNames.value.voiceprint = getVoiceDisplayName(formData.value.ttsVoiceId || '')
|
||||
displayNames.value.report = reportOptions.find(item => item.value === formData.value.chatHistoryConf)?.name
|
||||
displayNames.value.language = formData.value.ttsLanguage
|
||||
|
||||
isVisibleReport.value = formData.value.memModelId !== 'Memory_nomem'
|
||||
|
||||
console.log('最终音色显示名称:', displayNames.value.voiceprint)
|
||||
}
|
||||
@@ -244,23 +333,110 @@ async function loadModelOptions() {
|
||||
}
|
||||
}
|
||||
|
||||
// 加载TTS音色选项
|
||||
async function loadVoiceOptions(ttsModelId?: string) {
|
||||
if (!ttsModelId)
|
||||
return
|
||||
|
||||
try {
|
||||
console.log(`加载音色选项: ${ttsModelId}`)
|
||||
const voices = await getTTSVoices(ttsModelId)
|
||||
voiceOptions.value = voices
|
||||
console.log('音色选项:', voices)
|
||||
}
|
||||
catch (error) {
|
||||
console.error('加载音色选项失败:', error)
|
||||
// 根据语言筛选音色
|
||||
function filterVoicesByLanguage() {
|
||||
if (!voiceDetails.value || Object.keys(voiceDetails.value).length === 0) {
|
||||
voiceOptions.value = []
|
||||
return
|
||||
}
|
||||
|
||||
const allVoices = Object.values(voiceDetails.value) as any[]
|
||||
|
||||
// 根据选中的语言筛选音色
|
||||
const filteredVoices = allVoices.filter((voice) => {
|
||||
if (!voice.languages) {
|
||||
return false
|
||||
}
|
||||
const languagesArray = voice.languages.split(/[、;;,,]/).map(lang => lang.trim()).filter(lang => lang)
|
||||
return languagesArray.includes(formData.value.language)
|
||||
})
|
||||
|
||||
voiceOptions.value = filteredVoices.map(voice => ({
|
||||
value: voice.id,
|
||||
name: voice.name,
|
||||
voiceDemo: voice.voiceDemo,
|
||||
voice_demo: voice.voice_demo,
|
||||
isClone: Boolean(voice.isClone),
|
||||
train_status: voice.trainStatus,
|
||||
}))
|
||||
|
||||
// 检查当前选中的音色是否支持当前语言,如果不支持则选择第一个
|
||||
const currentVoiceSupportsLanguage = formData.value.ttsVoiceId
|
||||
&& filteredVoices.some(voice => voice.id === formData.value.ttsVoiceId)
|
||||
|
||||
if (!currentVoiceSupportsLanguage) {
|
||||
formData.value.ttsVoiceId = filteredVoices.length > 0 ? filteredVoices[0].id : ''
|
||||
displayNames.value.voiceprint = filteredVoices.length > 0 ? filteredVoices[0].name : ''
|
||||
}
|
||||
else {
|
||||
displayNames.value.voiceprint = filteredVoices.find(item => item.id === formData.value.ttsVoiceId)?.name
|
||||
}
|
||||
|
||||
// 同步到ttsSettings(如果值为null,使用0作为显示默认值,但不修改form中的值)
|
||||
ttsSettings.value = {
|
||||
volume: formData.value.ttsVolume !== null && formData.value.ttsVolume !== undefined ? formData.value.ttsVolume : 0,
|
||||
speed: formData.value.ttsRate !== null && formData.value.ttsRate !== undefined ? formData.value.ttsRate : 0,
|
||||
pitch: formData.value.ttsPitch !== null && formData.value.ttsPitch !== undefined ? formData.value.ttsPitch : 0,
|
||||
}
|
||||
}
|
||||
|
||||
// 根据语音合成模型加载语言
|
||||
async function fetchAllLanguag(ttsModelId: string) {
|
||||
try {
|
||||
const res = await getAllLanguage(ttsModelId, '') as any[]
|
||||
// 保存完整的音色信息
|
||||
voiceDetails.value = res.reduce((acc, voice) => {
|
||||
acc[voice.id] = voice
|
||||
return acc
|
||||
}, {})
|
||||
// 提取所有语言选项并去重
|
||||
const allLanguages = new Set()
|
||||
res.forEach((voice) => {
|
||||
if (voice.languages) {
|
||||
const languagesArray = voice.languages.split(/[、;;,,]/).map(lang => lang.trim()).filter(lang => lang)
|
||||
languagesArray.forEach(lang => allLanguages.add(lang))
|
||||
}
|
||||
})
|
||||
languageOptions.value = Array.from(allLanguages).map(lang => ({
|
||||
value: lang,
|
||||
name: lang,
|
||||
}))
|
||||
|
||||
// 使用后端返回的用户选择的语言,如果没有则使用第一个语言选项
|
||||
if (formData.value.ttsLanguage && languageOptions.value.some(option => option.value === formData.value.ttsLanguage)) {
|
||||
formData.value.language = formData.value.ttsLanguage
|
||||
displayNames.value.language = formData.value.ttsLanguage
|
||||
}
|
||||
else if (languageOptions.value.length > 0) {
|
||||
formData.value.language = languageOptions.value[0].value
|
||||
displayNames.value.language = languageOptions.value[0].value
|
||||
}
|
||||
|
||||
// 根据选中的语言筛选音色
|
||||
filterVoicesByLanguage()
|
||||
}
|
||||
catch {
|
||||
languageOptions.value = []
|
||||
}
|
||||
}
|
||||
|
||||
// 加载TTS音色选项
|
||||
// async function loadVoiceOptions(ttsModelId?: string) {
|
||||
// if (!ttsModelId)
|
||||
// return
|
||||
|
||||
// try {
|
||||
// console.log(`加载音色选项: ${ttsModelId}`)
|
||||
// const voices = await getTTSVoices(ttsModelId)
|
||||
// voiceOptions.value = voices
|
||||
// console.log('音色选项:', voices)
|
||||
// }
|
||||
// catch (error) {
|
||||
// console.error('加载音色选项失败:', error)
|
||||
// voiceOptions.value = []
|
||||
// }
|
||||
// }
|
||||
|
||||
// 选择角色模板
|
||||
function selectRoleTemplate(templateId: string) {
|
||||
if (selectedTemplateId.value === templateId) {
|
||||
@@ -314,20 +490,26 @@ async function onPickerConfirm(type: string, value: any, name: string) {
|
||||
break
|
||||
case 'memory':
|
||||
formData.value.memModelId = value
|
||||
formData.value.chatHistoryConf = value === 'Memory_nomem' ? 0 : 2
|
||||
displayNames.value.memory = name // 确保显示名称正确更新
|
||||
displayNames.value.report = reportOptions[1].name
|
||||
isVisibleReport.value = value !== 'Memory_nomem'
|
||||
break
|
||||
case 'tts':
|
||||
formData.value.ttsModelId = value
|
||||
// 当选择TTS模型时,自动加载对应的音色选项
|
||||
await loadVoiceOptions(value)
|
||||
// 重置音色选择
|
||||
formData.value.ttsVoiceId = ''
|
||||
displayNames.value.voiceprint = '请选择'
|
||||
await fetchAllLanguag(value)
|
||||
break
|
||||
case 'language':
|
||||
formData.value.language = value
|
||||
filterVoicesByLanguage()
|
||||
break
|
||||
case 'voiceprint':
|
||||
formData.value.ttsVoiceId = value
|
||||
displayNames.value.voiceprint = name // 确保显示名称正确更新
|
||||
break
|
||||
case 'report':
|
||||
formData.value.chatHistoryConf = value
|
||||
break
|
||||
}
|
||||
|
||||
pickerShow.value[type] = false
|
||||
@@ -369,9 +551,24 @@ async function saveAgent() {
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
await handleUpdateAgentTags()
|
||||
}
|
||||
catch (err) {
|
||||
toast.error(err)
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
saving.value = true
|
||||
await updateAgent(agentId.value, formData.value)
|
||||
// 构建保存数据,包含上下文配置和语音设置
|
||||
const saveData = {
|
||||
...formData.value,
|
||||
ttsLanguage: formData.value.language,
|
||||
contextProviders: currentContextProviders.value,
|
||||
}
|
||||
await updateAgent(agentId.value, saveData)
|
||||
loadAgentDetail()
|
||||
|
||||
toast.success(t('agent.saveSuccess'))
|
||||
}
|
||||
@@ -423,9 +620,25 @@ function watchPluginUpdates() {
|
||||
}, { deep: true })
|
||||
}
|
||||
|
||||
// 获取智能体标签
|
||||
async function loadAgentTags() {
|
||||
try {
|
||||
const res = await getAgentTags(agentId.value)
|
||||
dynamicTags.value = res || []
|
||||
}
|
||||
catch (error) {}
|
||||
}
|
||||
|
||||
// 更新智能体标签
|
||||
async function handleUpdateAgentTags() {
|
||||
const tagNames = dynamicTags.value.map(tag => tag.tagName)
|
||||
await updateAgentTags(agentId.value, { tagNames })
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
// 初始化插件配置监听
|
||||
watchPluginUpdates()
|
||||
loadAgentTags()
|
||||
|
||||
// 先加载模型选项和角色模板
|
||||
await Promise.all([
|
||||
@@ -443,19 +656,19 @@ onMounted(async () => {
|
||||
|
||||
<template>
|
||||
<view class="bg-[#f5f7fb] px-[20rpx]">
|
||||
<!--// 基础信息标题
|
||||
<!-- 基础信息标题
|
||||
<view class="pb-[20rpx] first:pt-[20rpx]">
|
||||
<text class="text-[32rpx] text-[#232338] font-bold">
|
||||
{{ t('agent.basicInfo') }}
|
||||
</text>
|
||||
</view>
|
||||
</view -->
|
||||
|
||||
<!-- 基础信息卡片 -->
|
||||
<view class="mb-[24rpx] border border-[#eeeeee] rounded-[20rpx] bg-[#fbfbfb] p-[24rpx]" style="box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.04);">
|
||||
<view class="mb-[24rpx] last:mb-0">
|
||||
<text class="mb-[12rpx] block text-[28rpx] text-[#232338] font-medium">
|
||||
{{ t('agent.agentName') }}
|
||||
</text>
|
||||
{{ t('agent.agentName') }}
|
||||
</text>
|
||||
<input
|
||||
v-model="formData.agentName"
|
||||
class="box-border h-[80rpx] w-full border border-[#eeeeee] rounded-[12rpx] bg-[#f5f7fb] p-[16rpx_20rpx] text-[28rpx] text-[#232338] leading-[1.4] outline-none focus:border-[#336cff] focus:bg-white placeholder:text-[#9d9ea3]"
|
||||
@@ -466,8 +679,32 @@ onMounted(async () => {
|
||||
|
||||
<view class="mb-[24rpx] last:mb-0">
|
||||
<text class="mb-[12rpx] block text-[28rpx] text-[#232338] font-medium">
|
||||
{{ t('agent.roleMode') }}
|
||||
</text>
|
||||
{{ t('agent.agentTag') }}
|
||||
</text>
|
||||
<input
|
||||
v-if="inputVisible"
|
||||
v-model="inputValue"
|
||||
class="mb-[10rpx] box-border h-[80rpx] w-full border border-[#eeeeee] rounded-[12rpx] bg-[#f5f7fb] p-[16rpx_20rpx] text-[28rpx] text-[#232338] leading-[1.4] outline-none focus:border-[#336cff] focus:bg-white placeholder:text-[#9d9ea3]"
|
||||
type="text"
|
||||
:maxlength="20"
|
||||
:placeholder="t('agent.inputAgentTag')"
|
||||
@keyup.enter="handleInputConfirm"
|
||||
@blur="handleInputConfirm"
|
||||
>
|
||||
<view class="flex flex-wrap gap-[10rpx_10rpx]">
|
||||
<wd-tag v-for="tag in dynamicTags" :key="tag.id" class="items-center border !flex !border-[rgba(51,108,255,0.2)] !bg-[rgba(51,108,255,0.1)] !text-[#336cff]" round closable @close="handleCloseTag(tag.id)">
|
||||
{{ tag.tagName }}
|
||||
</wd-tag>
|
||||
<wd-button v-if="!inputVisible" class="!bg-[rgba(51,108,255,0.1)] !text-[#336cff]" size="small" icon="add" @click="showInput">
|
||||
{{ t('agent.addAgentTag') }}
|
||||
</wd-button>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="mb-[24rpx] last:mb-0">
|
||||
<text class="mb-[12rpx] block text-[28rpx] text-[#232338] font-medium">
|
||||
{{ t('agent.roleMode') }}
|
||||
</text>
|
||||
<view class="mt-0 flex flex-wrap gap-[12rpx]">
|
||||
<view
|
||||
v-for="template in roleTemplates"
|
||||
@@ -485,8 +722,25 @@ onMounted(async () => {
|
||||
|
||||
<view class="mb-[24rpx] last:mb-0">
|
||||
<text class="mb-[12rpx] block text-[28rpx] text-[#232338] font-medium">
|
||||
{{ t('agent.roleDescription') }}
|
||||
{{ t('agent.contextProvider') }}
|
||||
</text>
|
||||
<view class="mt-0 flex flex-wrap items-center gap-[12rpx]">
|
||||
<text class="text-[26rpx] text-[#65686f]">
|
||||
{{ t('agent.contextProviderSuccess', { count: currentContextProviders.length }) }}
|
||||
</text>
|
||||
<a class="text-[26rpx] text-[#5778ff] no-underline" href="https://github.com/xinnan-tech/xiaozhi-esp32-server/blob/main/docs/context-provider-integration.md" target="_blank">
|
||||
{{ t('agent.contextProviderDocLink') }}
|
||||
</a>
|
||||
<wd-button class="!bg-[rgba(51,108,255,0.1)] !text-[#336cff]" size="small" @click="openContextProviderDialog">
|
||||
{{ t('agent.editContextProvider') }}
|
||||
</wd-button>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="mb-[24rpx] last:mb-0">
|
||||
<text class="mb-[12rpx] block text-[28rpx] text-[#232338] font-medium">
|
||||
{{ t('agent.roleDescription') }}
|
||||
</text>
|
||||
<textarea
|
||||
v-model="formData.systemPrompt"
|
||||
:maxlength="2000"
|
||||
@@ -568,6 +822,16 @@ onMounted(async () => {
|
||||
</text>
|
||||
<wd-icon name="arrow-right" custom-class="text-[20rpx] text-[#9d9ea3]" />
|
||||
</view>
|
||||
|
||||
<view v-show="isVisibleReport" class="flex cursor-pointer items-center justify-between border border-[#eeeeee] rounded-[12rpx] bg-[#f5f7fb] p-[20rpx] transition-all duration-300 active:bg-[#eef3ff]" @click="openPicker('report')">
|
||||
<text class="text-[28rpx] text-[#232338] font-medium">
|
||||
{{ t('agent.reportMode') }}
|
||||
</text>
|
||||
<text class="mx-[16rpx] flex-1 text-right text-[26rpx] text-[#65686f]">
|
||||
{{ displayNames.report }}
|
||||
</text>
|
||||
<wd-icon name="arrow-right" custom-class="text-[20rpx] text-[#9d9ea3]" />
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
@@ -591,6 +855,16 @@ onMounted(async () => {
|
||||
<wd-icon name="arrow-right" custom-class="text-[20rpx] text-[#9d9ea3]" />
|
||||
</view>
|
||||
|
||||
<view class="flex cursor-pointer items-center justify-between border border-[#eeeeee] rounded-[12rpx] bg-[#f5f7fb] p-[20rpx] transition-all duration-300 active:bg-[#eef3ff]" @click="openPicker('language')">
|
||||
<text class="text-[28rpx] text-[#232338] font-medium">
|
||||
{{ t('agent.language') }}
|
||||
</text>
|
||||
<text class="mx-[16rpx] flex-1 text-right text-[26rpx] text-[#65686f]">
|
||||
{{ displayNames.language }}
|
||||
</text>
|
||||
<wd-icon name="arrow-right" custom-class="text-[20rpx] text-[#9d9ea3]" />
|
||||
</view>
|
||||
|
||||
<view class="flex cursor-pointer items-center justify-between border border-[#eeeeee] rounded-[12rpx] bg-[#f5f7fb] p-[20rpx] transition-all duration-300 active:bg-[#eef3ff]" @click="openPicker('voiceprint')">
|
||||
<text class="text-[28rpx] text-[#232338] font-medium">
|
||||
{{ t('agent.voiceprint') }}
|
||||
@@ -601,6 +875,15 @@ onMounted(async () => {
|
||||
<wd-icon name="arrow-right" custom-class="text-[20rpx] text-[#9d9ea3]" />
|
||||
</view>
|
||||
|
||||
<view class="flex items-center justify-between border border-[#eeeeee] rounded-[12rpx] bg-[#f5f7fb] p-[20rpx]">
|
||||
<view class="text-[28rpx] text-[#232338] font-medium">
|
||||
{{ t('agent.languageConfig') }}
|
||||
</view>
|
||||
<view class="cursor-pointer rounded-[20rpx] bg-[rgba(51,108,255,0.1)] px-[24rpx] py-[12rpx] text-[24rpx] text-[#336cff] transition-all duration-300 active:bg-[#336cff] active:text-white" @click="handleRegulate">
|
||||
<text>{{ t('agent.editFunctions') }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="flex items-center justify-between border border-[#eeeeee] rounded-[12rpx] bg-[#f5f7fb] p-[20rpx]">
|
||||
<view class="text-[28rpx] text-[#232338] font-medium">
|
||||
{{ t('agent.plugins') }}
|
||||
@@ -695,9 +978,37 @@ onMounted(async () => {
|
||||
|
||||
<wd-action-sheet
|
||||
v-model="pickerShow.voiceprint"
|
||||
:actions="voiceOptions && voiceOptions.map(item => ({ name: item.name, value: item.id }))"
|
||||
:actions="voiceOptions"
|
||||
@close="onPickerCancel('voiceprint')"
|
||||
@select="({ item }) => onPickerConfirm('voiceprint', item.value, item.name)"
|
||||
/>
|
||||
<wd-action-sheet
|
||||
v-model="pickerShow.language"
|
||||
:actions="languageOptions"
|
||||
@close="onPickerCancel('language')"
|
||||
@select="({ item }) => onPickerConfirm('language', item.value, item.name)"
|
||||
/>
|
||||
<wd-action-sheet
|
||||
v-model="pickerShow.report"
|
||||
:actions="reportOptions"
|
||||
@close="onPickerCancel('report')"
|
||||
@select="({ item }) => onPickerConfirm('report', item.value, item.name)"
|
||||
/>
|
||||
<ContextProviderDialog
|
||||
v-model:visible="showContextProviderDialog"
|
||||
:providers="currentContextProviders"
|
||||
@confirm="handleUpdateContext"
|
||||
/>
|
||||
<VoiceSettingsDialog
|
||||
v-model:visible="showVoiceSettingsDialog"
|
||||
:settings="ttsSettings"
|
||||
@confirm="handleUpdateVoiceSettings"
|
||||
/>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
::v-deep .wd-tag__close {
|
||||
color: #336cff !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -11,8 +11,8 @@
|
||||
<script lang="ts" setup>
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import { computed, onMounted, ref } from 'vue'
|
||||
import { t } from '@/i18n'
|
||||
import CustomTabs from '@/components/custom-tabs/index.vue'
|
||||
import { t } from '@/i18n'
|
||||
import ChatHistory from '@/pages/chat-history/index.vue'
|
||||
import DeviceManagement from '@/pages/device/index.vue'
|
||||
import VoiceprintManagement from '@/pages/voiceprint/index.vue'
|
||||
|
||||
@@ -12,12 +12,13 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import type { Agent } from '@/api/agent/types'
|
||||
import { ref } from 'vue'
|
||||
import { onMounted, ref } from 'vue'
|
||||
// 在组件挂载后设置导航栏标题
|
||||
import { useMessage } from 'wot-design-uni'
|
||||
import useZPaging from 'z-paging/components/z-paging/js/hooks/useZPaging.js'
|
||||
import { createAgent, deleteAgent, getAgentList } from '@/api/agent/agent'
|
||||
import { toast } from '@/utils/toast'
|
||||
import { t } from '@/i18n'
|
||||
import { toast } from '@/utils/toast'
|
||||
|
||||
defineOptions({
|
||||
name: 'Home',
|
||||
@@ -162,11 +163,9 @@ onShow(() => {
|
||||
}
|
||||
})
|
||||
|
||||
// 在组件挂载后设置导航栏标题
|
||||
import { onMounted } from 'vue'
|
||||
onMounted(() => {
|
||||
uni.setNavigationBarTitle({
|
||||
title: t('home.pageTitle')
|
||||
title: t('home.pageTitle'),
|
||||
})
|
||||
})
|
||||
</script>
|
||||
@@ -223,10 +222,10 @@ onMounted(() => {
|
||||
|
||||
<view class="model-info">
|
||||
<text class="model-text">
|
||||
语言模型: {{ agent.llmModelName }}
|
||||
{{ t('home.languageModel') }}: {{ agent.llmModelName }}
|
||||
</text>
|
||||
<text class="model-text">
|
||||
音色模型: {{ agent.ttsModelName }} ({{ agent.ttsVoiceName }})
|
||||
{{ t('home.voiceModel') }}: {{ agent.ttsModelName }} ({{ agent.ttsVoiceName }})
|
||||
</text>
|
||||
</view>
|
||||
|
||||
@@ -243,6 +242,9 @@ onMounted(() => {
|
||||
{{ t('home.lastConversation') }}{{ formatTime(agent.lastConnectedAt) }}
|
||||
</text>
|
||||
</view>
|
||||
<text v-if="agent.tags" class="flex-1 truncate text-right text-[22rpx] text-[#666]">
|
||||
{{ agent.tags.map(tag => tag.tagName).join(',') }}
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
@@ -433,6 +435,7 @@ onMounted(() => {
|
||||
|
||||
.card-main {
|
||||
flex: 1;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.agent-title {
|
||||
@@ -465,7 +468,9 @@ onMounted(() => {
|
||||
}
|
||||
|
||||
.stats-row {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12rpx;
|
||||
flex-wrap: wrap;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user