diff --git a/docs/FAQ.md b/docs/FAQ.md index b6bec471..a5dc0b08 100644 --- a/docs/FAQ.md +++ b/docs/FAQ.md @@ -83,6 +83,7 @@ VAD: 9、[知识库ragflow集成指南](./ragflow-integration.md)
10、[如何部署上下文源](./context-provider-integration.md)
11、[如何集成PowerMem智能记忆](./powermem-integration.md)
+12、[如何配置天气插件查询天气](./weather-integration.md)
### 11、语音克隆、本地语音部署相关教程 1、[如何在智控台克隆音色](./huoshan-streamTTS-voice-cloning.md)
diff --git a/main/manager-api/src/main/java/xiaozhi/common/constant/Constant.java b/main/manager-api/src/main/java/xiaozhi/common/constant/Constant.java index 8a9e4fba..b438fec1 100644 --- a/main/manager-api/src/main/java/xiaozhi/common/constant/Constant.java +++ b/main/manager-api/src/main/java/xiaozhi/common/constant/Constant.java @@ -151,6 +151,11 @@ public interface Constant { */ String MEMORY_NO_MEM = "Memory_nomem"; + /** + * 仅上报聊天记录(不总结记忆) + */ + String MEMORY_MEM_REPORT_ONLY = "Memory_mem_report_only"; + /** * 火山引擎双声道语音克隆 */ diff --git a/main/manager-api/src/main/java/xiaozhi/common/exception/ErrorCode.java b/main/manager-api/src/main/java/xiaozhi/common/exception/ErrorCode.java index 5681ec9e..820f4089 100644 --- a/main/manager-api/src/main/java/xiaozhi/common/exception/ErrorCode.java +++ b/main/manager-api/src/main/java/xiaozhi/common/exception/ErrorCode.java @@ -251,4 +251,9 @@ public interface ErrorCode { int AGENT_TAG_NOT_EXIST = 10198; // 标签不存在 int RAG_DOCUMENT_PARSING_DELETE_ERROR = 10199; // 文档解析中,禁止删除 + + // 智能体MCP相关错误码 + int MCP_ACCESS_POINT_ADDRESS_NO_PERMISSION = 10200; // 没有权限查看该智能体的MCP接入点地址 + int MCP_ACCESS_POINT_ADDRESS_NOT_CONFIGURED = 10201; // 请联系管理员进入参数管理配置mcp接入点地址 + int MCP_ACCESS_POINT_TOOLS_LIST_NO_PERMISSION = 10202; // 没有权限查看该智能体的MCP工具列表 } diff --git a/main/manager-api/src/main/java/xiaozhi/modules/agent/controller/AgentMcpAccessPointController.java b/main/manager-api/src/main/java/xiaozhi/modules/agent/controller/AgentMcpAccessPointController.java index bee728f5..c805a4e7 100644 --- a/main/manager-api/src/main/java/xiaozhi/modules/agent/controller/AgentMcpAccessPointController.java +++ b/main/manager-api/src/main/java/xiaozhi/modules/agent/controller/AgentMcpAccessPointController.java @@ -11,6 +11,7 @@ import org.springframework.web.bind.annotation.RestController; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; +import xiaozhi.common.exception.ErrorCode; import xiaozhi.common.user.UserDetail; import xiaozhi.common.utils.Result; import xiaozhi.modules.agent.service.AgentMcpAccessPointService; @@ -40,11 +41,11 @@ public class AgentMcpAccessPointController { // 检查权限 if (!agentService.checkAgentPermission(agentId, user.getId())) { - return new Result().error("没有权限查看该智能体的MCP接入点地址"); + return new Result().error(ErrorCode.MCP_ACCESS_POINT_ADDRESS_NO_PERMISSION); } String agentMcpAccessAddress = agentMcpAccessPointService.getAgentMcpAccessAddress(agentId); if (agentMcpAccessAddress == null) { - return new Result().ok("请联系管理员进入参数管理配置mcp接入点地址"); + return new Result().error(ErrorCode.MCP_ACCESS_POINT_ADDRESS_NOT_CONFIGURED); } return new Result().ok(agentMcpAccessAddress); } @@ -58,7 +59,7 @@ public class AgentMcpAccessPointController { // 检查权限 if (!agentService.checkAgentPermission(agentId, user.getId())) { - return new Result>().error("没有权限查看该智能体的MCP工具列表"); + return new Result>().error(ErrorCode.MCP_ACCESS_POINT_TOOLS_LIST_NO_PERMISSION); } List agentMcpToolsList = agentMcpAccessPointService.getAgentMcpToolsList(agentId); return new Result>().ok(agentMcpToolsList); diff --git a/main/manager-api/src/main/java/xiaozhi/modules/agent/service/impl/AgentChatSummaryServiceImpl.java b/main/manager-api/src/main/java/xiaozhi/modules/agent/service/impl/AgentChatSummaryServiceImpl.java index 38fef94b..26e601ec 100644 --- a/main/manager-api/src/main/java/xiaozhi/modules/agent/service/impl/AgentChatSummaryServiceImpl.java +++ b/main/manager-api/src/main/java/xiaozhi/modules/agent/service/impl/AgentChatSummaryServiceImpl.java @@ -14,6 +14,7 @@ import org.springframework.stereotype.Service; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import lombok.RequiredArgsConstructor; +import xiaozhi.common.constant.Constant; import xiaozhi.modules.agent.dto.AgentChatHistoryDTO; import xiaozhi.modules.agent.dto.AgentChatSummaryDTO; import xiaozhi.modules.agent.dto.AgentMemoryDTO; @@ -90,21 +91,28 @@ public class AgentChatSummaryServiceImpl implements AgentChatSummaryService { @Override public boolean generateAndSaveChatSummary(String sessionId) { try { - // 1. 生成总结 - AgentChatSummaryDTO summaryDTO = generateChatSummary(sessionId); - if (!summaryDTO.isSuccess()) { - log.info("生成总结失败: {}", summaryDTO.getErrorMessage()); - return false; - } - - // 2. 获取设备信息(通过会话关联的设备) + // 1. 获取设备信息(通过会话关联的设备) DeviceEntity device = getDeviceBySessionId(sessionId); if (device == null) { log.info("未找到与会话 {} 关联的设备", sessionId); return false; } - // 3. 更新智能体记忆 + // 2. 检查记忆模型类型,如果是仅上报聊天记录模式则跳过总结 + String memModelId = agentService.getAgentById(device.getAgentId()).getMemModelId(); + if (memModelId != null && memModelId.equals(Constant.MEMORY_MEM_REPORT_ONLY)) { + log.info("会话 {} 使用仅上报聊天记录模式,跳过记忆总结", sessionId); + return true; + } + + // 3. 生成总结 + AgentChatSummaryDTO summaryDTO = generateChatSummary(sessionId); + if (!summaryDTO.isSuccess()) { + log.info("生成总结失败: {}", summaryDTO.getErrorMessage()); + return false; + } + + // 4. 更新智能体记忆 AgentMemoryDTO memoryDTO = new AgentMemoryDTO(); memoryDTO.setSummaryMemory(summaryDTO.getSummary()); diff --git a/main/manager-api/src/main/java/xiaozhi/modules/model/service/impl/ModelConfigServiceImpl.java b/main/manager-api/src/main/java/xiaozhi/modules/model/service/impl/ModelConfigServiceImpl.java index 24bdb751..a49ce69c 100644 --- a/main/manager-api/src/main/java/xiaozhi/modules/model/service/impl/ModelConfigServiceImpl.java +++ b/main/manager-api/src/main/java/xiaozhi/modules/model/service/impl/ModelConfigServiceImpl.java @@ -57,7 +57,8 @@ public class ModelConfigServiceImpl extends BaseServiceImpl queryWrapper = new QueryWrapper<>(); queryWrapper.eq("model_type", StringUtils.isBlank(modelType) ? "" : modelType); + queryWrapper.orderByAsc("sort"); List providerEntities = modelProviderDao.selectList(queryWrapper); return ConvertUtils.sourceToTarget(providerEntities, ModelProviderDTO.class); } @@ -147,7 +148,8 @@ public class ModelProviderServiceImpl extends BaseServiceImpl(`/agent/audio/${audioId}`, {}, { + meta: { + ignoreAuth: false, + toast: false, + }, + }) +} diff --git a/main/manager-mobile/src/http/request/alova.ts b/main/manager-mobile/src/http/request/alova.ts index e7887120..42243bc1 100644 --- a/main/manager-mobile/src/http/request/alova.ts +++ b/main/manager-mobile/src/http/request/alova.ts @@ -1,5 +1,6 @@ import type { uniappRequestAdapter } from '@alova/adapter-uniapp' import type { IResponse } from './types' +import type { Language } from '@/store/lang' import AdapterUniapp from '@alova/adapter-uniapp' import { createAlova } from 'alova' import { createServerTokenAuthentication } from 'alova/client' @@ -8,6 +9,16 @@ import { getEnvBaseUrl } from '@/utils' import { toast } from '@/utils/toast' import { ContentTypeEnum, ResultEnum, ShowMessage } from './enum' +// 语言映射, 用于设置 Accept-language 头 +const langMap: Record = { + zh_CN: 'zh-CN', + en: 'en-US', + zh_TW: 'zh-TW', + de: 'de', + vi: 'vi', + pt_BR: 'pt-BR', +} + /** * 创建请求实例 */ @@ -51,6 +62,7 @@ const alovaInstance = createAlova({ // 检查混合内容错误(HTTPS页面请求HTTP接口) const currentProtocol = typeof window !== 'undefined' && window.location.protocol const requestProtocol = method.baseURL?.split(':')[0] + const currentLang = langMap[uni.getStorageSync('app_language') as Language || 'zh_CN'] if (currentProtocol === 'https:' && requestProtocol === 'http') { const errorMessage = '无法配置http协议地址,请检查接口地址' throw new Error(errorMessage) @@ -60,6 +72,7 @@ const alovaInstance = createAlova({ method.config.headers = { 'Content-Type': ContentTypeEnum.JSON, 'Accept': 'application/json, text/plain, */*', + 'Accept-language': currentLang, ...method.config.headers, } diff --git a/main/manager-mobile/src/i18n/de.ts b/main/manager-mobile/src/i18n/de.ts index 9d0711ea..d76a4093 100644 --- a/main/manager-mobile/src/i18n/de.ts +++ b/main/manager-mobile/src/i18n/de.ts @@ -11,7 +11,7 @@ export default { 'login.navigationTitle': 'Anmelden', 'login.fetchConfigError': 'Konfiguration konnte nicht abgerufen werden:', 'login.selectLanguage': 'Sprache auswählen', - 'login.selectLanguageTip': 'Vi', + 'login.selectLanguageTip': 'De', 'login.welcomeBack': 'Willkommen zurück', 'login.pleaseLogin': 'Bitte melden Sie sich an', 'login.enterUsername': 'Bitte Benutzernamen eingeben', @@ -69,7 +69,7 @@ export default { 'home.createFirstAgent': 'Klicken Sie auf die + Schaltfläche unten rechts, um Ihren ersten Agenten zu erstellen', 'home.dialogTitle': 'Agent erstellen', 'home.inputPlaceholder': 'z.B. Kundenservice-Assistent, Sprachassistent, Wissens-F&A', - 'home.createError': 'Bitte Agenten-Namen eingeben', + 'home.createError': 'Der Name muss zwischen 1 und 64 Zeichen lang sein.', 'home.createNow': 'Jetzt erstellen', 'home.justNow': 'Gerade eben', 'home.minutesAgo': 'Minuten her', @@ -85,7 +85,7 @@ export default { 'agent.chatHistory': 'Chat-Verlauf', 'agent.voiceprintManagement': 'Stimmabdruckverwaltung', 'agent.editTitle': 'Agent bearbeiten', - 'agent.toolsTitle': 'Funktionen bearbeiten', + 'agent.toolsTitle': 'Bearbeiten', 'agent.voiceActivityDetection': 'Sprachaktivitätserkennung', 'agent.speechRecognition': 'Spracherkennung', 'agent.largeLanguageModel': 'Großes Sprachmodell', @@ -116,7 +116,7 @@ export default { 'agent.tts': 'Text-zu-Sprache', 'agent.voiceprint': 'Agenten-Stimme', 'agent.plugins': 'Plugins', - 'agent.editFunctions': 'Funktionen bearbeiten', + 'agent.editFunctions': 'Bearbeiten', 'agent.historyMemory': 'Verlaufsspeicher', 'agent.memoryContent': 'Speicherinhalt', 'agent.saving': 'Wird gespeichert...', @@ -371,7 +371,7 @@ export default { 'agent.tools.mcpAccessPoint': 'MCP-Zugangspunkt', 'agent.tools.copy': 'Kopieren', 'agent.tools.noTools': 'Keine Werkzeuge verfügbar', - 'agent.tools.parameterConfig': 'Parameterkonfiguration', + 'agent.tools.parameterConfig': 'Konfig', 'agent.tools.noParamsNeeded': 'Keine Parameter benötigt', 'agent.tools.pleaseInput': 'Bitte eingeben', 'agent.tools.inputOneItemPerLine': 'Ein Element pro Zeile eingeben', @@ -492,4 +492,9 @@ export default { 'deviceConfig.afterConfigSuccessDeviceWillRestart': 'Nach erfolgreicher Konfiguration startet Gerät automatisch neu', 'deviceConfig.audioPlaybackError': 'Audio-Wiedergabe-Fehler', 'deviceConfig.playbackFailed': 'Wiedergabe fehlgeschlagen', + + // Voiceprint page + 'voiceprint.audioNotExist': 'Audio existiert nicht', + 'voiceprint.getAudioFailed': 'Audio konnte nicht abgerufen werden', + 'voiceprint.audioPlayFailed': 'Audio-Wiedergabe fehlgeschlagen', } diff --git a/main/manager-mobile/src/i18n/en.ts b/main/manager-mobile/src/i18n/en.ts index ea232160..0066b0fd 100644 --- a/main/manager-mobile/src/i18n/en.ts +++ b/main/manager-mobile/src/i18n/en.ts @@ -11,7 +11,7 @@ export default { 'login.navigationTitle': 'Login', 'login.fetchConfigError': 'Failed to fetch configuration:', 'login.selectLanguage': 'Select Language', - 'login.selectLanguageTip': '中文', + 'login.selectLanguageTip': 'En', 'login.welcomeBack': 'Welcome Back', 'login.pleaseLogin': 'Please log in to your account', 'login.enterUsername': 'Please enter username', @@ -69,7 +69,7 @@ export default { 'home.createFirstAgent': 'Click the + button in the lower right corner to create your first agent', 'home.dialogTitle': 'Create Agent', 'home.inputPlaceholder': 'e.g. Customer Service Assistant, Voice Assistant, Knowledge Q&A', - 'home.createError': 'Please input agent name', + 'home.createError': 'The name length must be between 1 and 64 characters', 'home.createNow': 'Create Now', 'home.justNow': 'Just now', 'home.minutesAgo': 'minutes ago', @@ -371,7 +371,7 @@ export default { 'agent.tools.mcpAccessPoint': 'MCP Access Point', 'agent.tools.copy': 'Copy', 'agent.tools.noTools': 'No tools available', - 'agent.tools.parameterConfig': 'Parameter Configuration', + 'agent.tools.parameterConfig': 'Param Config', 'agent.tools.noParamsNeeded': 'No parameters needed', 'agent.tools.pleaseInput': 'Please input', 'agent.tools.inputOneItemPerLine': 'Input one item per line', @@ -492,4 +492,9 @@ export default { 'deviceConfig.afterConfigSuccessDeviceWillRestart': 'After successful configuration, device will automatically restart', 'deviceConfig.audioPlaybackError': 'Audio playback error', 'deviceConfig.playbackFailed': 'Playback failed', + + // Voiceprint page + 'voiceprint.audioNotExist': 'Audio does not exist', + 'voiceprint.getAudioFailed': 'Failed to get audio', + 'voiceprint.audioPlayFailed': 'Audio playback failed', } diff --git a/main/manager-mobile/src/i18n/pt_BR.ts b/main/manager-mobile/src/i18n/pt_BR.ts index 7d91096a..416b1f8f 100644 --- a/main/manager-mobile/src/i18n/pt_BR.ts +++ b/main/manager-mobile/src/i18n/pt_BR.ts @@ -11,7 +11,7 @@ export default { 'login.navigationTitle': 'Entrar', 'login.fetchConfigError': 'Falha ao buscar configuração:', 'login.selectLanguage': 'Selecionar Idioma', - 'login.selectLanguageTip': '中文', + 'login.selectLanguageTip': 'Pt', 'login.welcomeBack': 'Bem-vindo de Volta', 'login.pleaseLogin': 'Por favor, entre na sua conta', 'login.enterUsername': 'Por favor, insira o nome de usuário', @@ -69,7 +69,7 @@ export default { 'home.createFirstAgent': 'Clique no botão + no canto inferior direito para criar seu primeiro agente', 'home.dialogTitle': 'Criar Agente', 'home.inputPlaceholder': 'ex: Assistente de Atendimento, Assistente de Voz, Perguntas e Respostas', - 'home.createError': 'Por favor, insira o nome do agente', + 'home.createError': 'O comprimento do nome deve estar entre 1 e 64 caracteres', 'home.createNow': 'Criar Agora', 'home.justNow': 'Agora mesmo', 'home.minutesAgo': 'minutos atrás', @@ -371,7 +371,7 @@ export default { 'agent.tools.mcpAccessPoint': 'Ponto de Acesso MCP', 'agent.tools.copy': 'Copiar', 'agent.tools.noTools': 'Nenhuma ferramenta disponível', - 'agent.tools.parameterConfig': 'Configuração de Parâmetros', + 'agent.tools.parameterConfig': 'Configuração', 'agent.tools.noParamsNeeded': 'Nenhum parâmetro necessário', 'agent.tools.pleaseInput': 'Por favor, insira', 'agent.tools.inputOneItemPerLine': 'Insira um item por linha', @@ -492,4 +492,9 @@ export default { 'deviceConfig.afterConfigSuccessDeviceWillRestart': 'Após a configuração bem-sucedida, o dispositivo reiniciará automaticamente', 'deviceConfig.audioPlaybackError': 'Erro na reprodução de áudio', 'deviceConfig.playbackFailed': 'Falha na reprodução', + + // Voiceprint page + 'voiceprint.audioNotExist': 'O áudio não existe', + 'voiceprint.getAudioFailed': 'Falha ao obter áudio', + 'voiceprint.audioPlayFailed': 'Falha na reprodução de áudio', } diff --git a/main/manager-mobile/src/i18n/vi.ts b/main/manager-mobile/src/i18n/vi.ts index 2deab9d9..8ee1a35e 100644 --- a/main/manager-mobile/src/i18n/vi.ts +++ b/main/manager-mobile/src/i18n/vi.ts @@ -11,7 +11,7 @@ export default { 'login.navigationTitle': 'Đăng nhập', 'login.fetchConfigError': 'Không thể tải cấu hình:', 'login.selectLanguage': 'Chọn ngôn ngữ', - 'login.selectLanguageTip': 'de', + 'login.selectLanguageTip': 'Vi', 'login.welcomeBack': 'Chào mừng trở lại', 'login.pleaseLogin': 'Vui lòng đăng nhập vào tài khoản của bạn', 'login.enterUsername': 'Vui lòng nhập tên đăng nhập', @@ -69,7 +69,7 @@ export default { 'home.createFirstAgent': 'Nhấp vào nút + ở góc dưới bên phải để tạo đại lý đầu tiên của bạn', 'home.dialogTitle': 'Tạo đại lý', 'home.inputPlaceholder': 'ví dụ: Trợ lý chăm sóc khách hàng, Trợ lý giọng nói, Hỏi đáp kiến thức', - 'home.createError': 'Vui lòng nhập tên đại lý', + 'home.createError': 'Độ dài tên phải từ 1 đến 64 ký tự', 'home.createNow': 'Tạo ngay', 'home.justNow': 'Vừa xong', 'home.minutesAgo': 'phút trước', @@ -371,7 +371,7 @@ export default { 'agent.tools.mcpAccessPoint': 'Điểm truy cập MCP', 'agent.tools.copy': 'Sao chép', 'agent.tools.noTools': 'Không có công cụ nào', - 'agent.tools.parameterConfig': 'Cấu hình tham số', + 'agent.tools.parameterConfig': 'Cấu hình', 'agent.tools.noParamsNeeded': 'Không cần tham số', 'agent.tools.pleaseInput': 'Vui lòng nhập', 'agent.tools.inputOneItemPerLine': 'Nhập một mục mỗi dòng', @@ -492,4 +492,9 @@ export default { 'deviceConfig.afterConfigSuccessDeviceWillRestart': 'Sau khi cấu hình thành công, thiết bị sẽ tự động khởi động lại', 'deviceConfig.audioPlaybackError': 'Lỗi phát âm thanh', 'deviceConfig.playbackFailed': 'Phát thất bại', + + // Voiceprint page + 'voiceprint.audioNotExist': 'Âm thanh không tồn tại', + 'voiceprint.getAudioFailed': 'Không thể lấy âm thanh', + 'voiceprint.audioPlayFailed': 'Phát âm thanh thất bại', } \ No newline at end of file diff --git a/main/manager-mobile/src/i18n/zh_CN.ts b/main/manager-mobile/src/i18n/zh_CN.ts index dbe3980c..a5dec898 100644 --- a/main/manager-mobile/src/i18n/zh_CN.ts +++ b/main/manager-mobile/src/i18n/zh_CN.ts @@ -11,7 +11,7 @@ export default { 'login.navigationTitle': '登录', 'login.fetchConfigError': '获取配置失败:', 'login.selectLanguage': '选择语言', - 'login.selectLanguageTip': 'En', + 'login.selectLanguageTip': '中文', 'login.welcomeBack': '欢迎回来', 'login.pleaseLogin': '请登录您的账户', 'login.enterUsername': '请输入用户名', @@ -69,7 +69,7 @@ export default { 'home.createFirstAgent': '点击右下角 + 号创建您的第一个智能体', 'home.dialogTitle': '创建智能体', 'home.inputPlaceholder': '例如:客服助手、语音助理、知识问答', - 'home.createError': '请输入智能体名称', + 'home.createError': '名称长度必须在 1 到 64 个字符之间', 'home.createNow': '立即创建', 'home.justNow': '刚刚', 'home.minutesAgo': '分钟前', @@ -492,4 +492,9 @@ export default { 'deviceConfig.afterConfigSuccessDeviceWillRestart': '配网成功后设备将自动重启', 'deviceConfig.audioPlaybackError': '音频播放错误', 'deviceConfig.playbackFailed': '播放失败', + + // Voiceprint page + 'voiceprint.audioNotExist': '该音频不存在', + 'voiceprint.getAudioFailed': '获取音频失败', + 'voiceprint.audioPlayFailed': '音频播放失败', } diff --git a/main/manager-mobile/src/i18n/zh_TW.ts b/main/manager-mobile/src/i18n/zh_TW.ts index d290a118..9125e296 100644 --- a/main/manager-mobile/src/i18n/zh_TW.ts +++ b/main/manager-mobile/src/i18n/zh_TW.ts @@ -11,7 +11,7 @@ export default { 'login.navigationTitle': '登錄', 'login.fetchConfigError': '獲取配置失敗:', 'login.selectLanguage': '選擇語言', - 'login.selectLanguageTip': '简体', + 'login.selectLanguageTip': '繁體', 'login.welcomeBack': '歡迎回來', 'login.pleaseLogin': '請登錄您的賬戶', 'login.enterUsername': '請輸入用戶名', @@ -90,7 +90,7 @@ export default { 'home.createFirstAgent': '點擊右下角 + 號創建您的第一個智能體', 'home.dialogTitle': '創建智能體', 'home.inputPlaceholder': '例如:客服助手、語音助理、知識問答', - 'home.createError': '請輸入智能體暱稱', + 'home.createError': '暱稱長度必須在 1 到 64 個字元之間。', 'home.createNow': '立即創建', 'home.justNow': '剛剛', 'home.minutesAgo': '分鐘前', @@ -492,4 +492,9 @@ export default { 'deviceConfig.afterConfigSuccessDeviceWillRestart': '配網成功後設備將自動重啟', 'deviceConfig.audioPlaybackError': '音頻播放錯誤', 'deviceConfig.playbackFailed': '播放失敗', + + // Voiceprint page + 'voiceprint.audioNotExist': '該音頻不存在', + 'voiceprint.getAudioFailed': '獲取音頻失敗', + 'voiceprint.audioPlayFailed': '音頻播放失敗', } diff --git a/main/manager-mobile/src/pages/agent/edit.vue b/main/manager-mobile/src/pages/agent/edit.vue index 734c2722..0f56db88 100644 --- a/main/manager-mobile/src/pages/agent/edit.vue +++ b/main/manager-mobile/src/pages/agent/edit.vue @@ -110,6 +110,10 @@ const inputVisible = ref(false) const languageOptions = ref([]) const isVisibleReport = ref(false) +// 音频播放相关 +const audioRef = ref(null) +const playingVoiceId = ref('') + // 使用插件store const pluginStore = usePluginStore() const speedPitchStore = useSpeedPitch() @@ -158,6 +162,9 @@ function handleInputConfirm() { inputVisible.value = false } +// 是否禁用历史记忆输入框 +const isMemoryDisabled = computed(() => formData.value.memModelId !== 'Memory_mem_local_short') + // 打开上下文源编辑弹窗 function openContextProviderDialog() { uni.navigateTo({ @@ -422,15 +429,24 @@ function selectRoleTemplate(templateId: string) { selectedTemplateId.value = templateId const template = roleTemplates.value.find(t => t.id === templateId) if (template) { - formData.value.systemPrompt = template.systemPrompt - formData.value.vadModelId = template.vadModelId - formData.value.asrModelId = template.asrModelId - formData.value.llmModelId = template.llmModelId - formData.value.vllmModelId = template.vllmModelId - formData.value.intentModelId = template.intentModelId - formData.value.memModelId = template.memModelId - formData.value.ttsModelId = template.ttsModelId - formData.value.ttsVoiceId = template.ttsVoiceId + formData.value = { + ...formData.value, + systemPrompt: template.systemPrompt || formData.value.systemPrompt, + vadModelId: template.vadModelId || formData.value.vadModelId, + asrModelId: template.asrModelId || formData.value.asrModelId, + llmModelId: template.llmModelId || formData.value.llmModelId, + vllmModelId: template.vllmModelId || formData.value.vllmModelId, + intentModelId: template.intentModelId || formData.value.intentModelId, + memModelId: template.memModelId || formData.value.memModelId, + ttsModelId: template.ttsModelId || formData.value.ttsModelId, + ttsVoiceId: template.ttsVoiceId || formData.value.ttsVoiceId, + agentName: template.agentName || formData.value.agentName, + chatHistoryConf: template.chatHistoryConf || formData.value.chatHistoryConf, + summaryMemory: template.summaryMemory || formData.value.summaryMemory, + langCode: template.langCode || formData.value.langCode, + } + fetchAllLanguag(template.ttsModelId || formData.value.ttsModelId) + updateDisplayNames() } } @@ -493,6 +509,57 @@ async function onPickerConfirm(type: string, value: any, name: string) { // 选择器取消 function onPickerCancel(type: string) { pickerShow.value[type] = false + // 关闭时停止播放 + if (type === 'voiceprint') { + stopAudio() + } +} + +// 播放音频 +function playAudio(voiceDemo: string, voiceId: string, event: Event) { + event.stopPropagation() // 阻止事件冒泡,防止关闭下拉框 + + if (!voiceDemo) { + return + } + + // 如果正在播放同一个音频,则停止 + if (playingVoiceId.value === voiceId) { + stopAudio() + return + } + + // 停止之前的音频 + stopAudio() + + // 创建新的音频实例 + audioRef.value = uni.createInnerAudioContext() + audioRef.value.src = voiceDemo + playingVoiceId.value = voiceId + + // 监听播放结束 + audioRef.value.onEnded(() => { + playingVoiceId.value = '' + }) + + // 监听播放错误 + audioRef.value.onError(() => { + toast.error('音频播放失败') + playingVoiceId.value = '' + }) + + // 播放音频 + audioRef.value.play() +} + +// 停止音频 +function stopAudio() { + if (audioRef.value) { + audioRef.value.stop() + audioRef.value.destroy() + audioRef.value = null + } + playingVoiceId.value = '' } // 获取模型显示名称 @@ -878,8 +945,9 @@ onMounted(async () => {