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 fe71c05f..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"; + /** * 火山引擎双声道语音克隆 */ @@ -304,7 +309,7 @@ public interface Constant { /** * 版本号 */ - public static final String VERSION = "0.9.1"; + public static final String VERSION = "0.9.2"; /** * 无效固件URL 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/common/utils/Sm2DecryptUtil.java b/main/manager-api/src/main/java/xiaozhi/common/utils/Sm2DecryptUtil.java index 5dd1a312..332e9c80 100644 --- a/main/manager-api/src/main/java/xiaozhi/common/utils/Sm2DecryptUtil.java +++ b/main/manager-api/src/main/java/xiaozhi/common/utils/Sm2DecryptUtil.java @@ -12,28 +12,29 @@ import xiaozhi.modules.sys.service.SysParamsService; * 封装了重复的SM2解密、验证码提取和验证逻辑 */ public class Sm2DecryptUtil { - + /** * 验证码长度 */ private static final int CAPTCHA_LENGTH = 5; - + /** * 解密SM2加密内容,提取验证码并验证 + * * @param encryptedPassword SM2加密的密码字符串 - * @param captchaId 验证码ID - * @param captchaService 验证码服务 - * @param sysParamsService 系统参数服务 + * @param captchaId 验证码ID + * @param captchaService 验证码服务 + * @param sysParamsService 系统参数服务 * @return 解密后的实际密码 */ - public static String decryptAndValidateCaptcha(String encryptedPassword, String captchaId, - CaptchaService captchaService, SysParamsService sysParamsService) { + public static String decryptAndValidateCaptcha(String encryptedPassword, String captchaId, + CaptchaService captchaService, SysParamsService sysParamsService) { // 获取SM2私钥 String privateKeyStr = sysParamsService.getValue(Constant.SM2_PRIVATE_KEY, true); if (StringUtils.isBlank(privateKeyStr)) { throw new RenException(ErrorCode.SM2_KEY_NOT_CONFIGURED); } - + // 使用SM2私钥解密密码 String decryptedContent; try { @@ -41,19 +42,20 @@ public class Sm2DecryptUtil { } catch (Exception e) { throw new RenException(ErrorCode.SM2_DECRYPT_ERROR); } - + // 分离验证码和密码:前5位是验证码,后面是密码 if (decryptedContent.length() > CAPTCHA_LENGTH) { String embeddedCaptcha = decryptedContent.substring(0, CAPTCHA_LENGTH); String actualPassword = decryptedContent.substring(CAPTCHA_LENGTH); - - // 验证嵌入的验证码是否正确 + boolean embeddedCaptchaValid = captchaService.validate(captchaId, embeddedCaptcha, true); if (!embeddedCaptchaValid) { throw new RenException(ErrorCode.SMS_CAPTCHA_ERROR); } - + return actualPassword; + } else if (decryptedContent.length() > 0) { + throw new RenException(ErrorCode.SMS_CAPTCHA_ERROR); } else { throw new RenException(ErrorCode.SM2_DECRYPT_ERROR); } 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 diff --git a/main/manager-mobile/src/api/agent/agent.ts b/main/manager-mobile/src/api/agent/agent.ts index 936ccc9c..32b72ad7 100644 --- a/main/manager-mobile/src/api/agent/agent.ts +++ b/main/manager-mobile/src/api/agent/agent.ts @@ -131,6 +131,7 @@ export function getMcpAddress(agentId: string) { meta: { ignoreAuth: false, toast: false, + isExposeError: true, }, }) } @@ -208,11 +209,8 @@ export function updateAgentTags(agentId: string, data) { } // 获取所有语言 -export function getAllLanguage(modelId, voiceName) { - const queryParams = new URLSearchParams({ - voiceName: voiceName || '', - }).toString() - return http.Get(`/models/${modelId}/voices?${queryParams}`, { +export function getAllLanguage(modelId: string) { + return http.Get<{ id: string, name: string, languages: string }[]>(`/models/${modelId}/voices`, { meta: { ignoreAuth: false, toast: false, diff --git a/main/manager-mobile/src/api/agent/types.ts b/main/manager-mobile/src/api/agent/types.ts index 55764eb0..2c61c80f 100644 --- a/main/manager-mobile/src/api/agent/types.ts +++ b/main/manager-mobile/src/api/agent/types.ts @@ -48,6 +48,15 @@ export interface AgentDetail { ttsRate: number ttsPitch: number functions: AgentFunction[] + contextProviders: Providers[] +} + +export interface Providers { + url: string + headers: Array<{ + key: string + value: string + }> } export interface AgentFunction { diff --git a/main/manager-mobile/src/api/device/device.ts b/main/manager-mobile/src/api/device/device.ts index fc9d5f69..e5a2f9c7 100644 --- a/main/manager-mobile/src/api/device/device.ts +++ b/main/manager-mobile/src/api/device/device.ts @@ -33,6 +33,22 @@ export function bindDevice(agentId: string, code: string) { return http.Post(`/device/bind/${agentId}/${code}`, null) } +/** + * 手动添加设备 + * @param agentId 智能体ID + * @param board 设备类型 + * @param appVersion 固件版本 + * @param macAddress MAC地址 + */ +export function bindDeviceManual(data: { + agentId: string + board: string + appVersion: string + macAddress: string +}) { + return http.Post('/device/manual-add', data) +} + /** * 设置设备OTA升级开关 * @param deviceId 设备ID (MAC地址) diff --git a/main/manager-mobile/src/api/voiceprint/voiceprint.ts b/main/manager-mobile/src/api/voiceprint/voiceprint.ts index 600696dd..0726c535 100644 --- a/main/manager-mobile/src/api/voiceprint/voiceprint.ts +++ b/main/manager-mobile/src/api/voiceprint/voiceprint.ts @@ -60,3 +60,13 @@ export function updateVoicePrint(data: VoicePrint) { }, }) } + +// 获取音频下载ID +export function getAudioDownloadId(audioId: string) { + return http.Post(`/agent/audio/${audioId}`, {}, { + meta: { + ignoreAuth: false, + toast: false, + }, + }) +} diff --git a/main/manager-mobile/src/components/ContextProviderDialog.vue b/main/manager-mobile/src/components/ContextProviderDialog.vue deleted file mode 100644 index d4d75ba6..00000000 --- a/main/manager-mobile/src/components/ContextProviderDialog.vue +++ /dev/null @@ -1,467 +0,0 @@ - - - - - diff --git a/main/manager-mobile/src/components/VoiceSettingsDialog.vue b/main/manager-mobile/src/components/VoiceSettingsDialog.vue deleted file mode 100644 index b4ce25a5..00000000 --- a/main/manager-mobile/src/components/VoiceSettingsDialog.vue +++ /dev/null @@ -1,270 +0,0 @@ - - - - - diff --git a/main/manager-mobile/src/http/request/alova.ts b/main/manager-mobile/src/http/request/alova.ts index 752987b4..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', +} + /** * 创建请求实例 */ @@ -42,10 +53,26 @@ const alovaInstance = createAlova({ statesHook: VueHook, beforeRequest: onAuthRequired((method) => { + // h5动态获取最新的 baseURL,确保使用用户设置的服务器地址 + const currentBaseUrl = getEnvBaseUrl() + if (currentBaseUrl !== method.baseURL) { + method.baseURL = currentBaseUrl + } + + // 检查混合内容错误(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) + } + // 设置默认 Content-Type method.config.headers = { 'Content-Type': ContentTypeEnum.JSON, 'Accept': 'application/json, text/plain, */*', + 'Accept-language': currentLang, ...method.config.headers, } @@ -55,14 +82,14 @@ const alovaInstance = createAlova({ // 处理认证信息 if (!ignoreAuth) { - const token = uni.getStorageSync('token') - if (!token) { + const authInfo = JSON.parse(uni.getStorageSync('token') || '{}') + if (!authInfo.token) { // 跳转到登录页 uni.reLaunch({ url: '/pages/login/index' }) throw new Error('[请求错误]:未登录') } // 添加 Authorization 头 - method.config.headers.Authorization = `Bearer ${token}` + method.config.headers.Authorization = `Bearer ${authInfo.token}` } // 处理动态域名 diff --git a/main/manager-mobile/src/http/request/enum.ts b/main/manager-mobile/src/http/request/enum.ts index 1868fe08..048b5617 100644 --- a/main/manager-mobile/src/http/request/enum.ts +++ b/main/manager-mobile/src/http/request/enum.ts @@ -12,6 +12,7 @@ export enum ResultEnum { ServiceUnavailable = 503, // 服务不可用(原为serviceUnavailable) GatewayTimeout = 504, // 网关超时(原为gatewayTimeout) HttpVersionNotSupported = 505, // HTTP版本不支持(原为httpVersionNotSupported) + MixedContent = 600, // 混合内容错误(HTTPS页面请求HTTP接口) } export enum ContentTypeEnum { JSON = 'application/json;charset=UTF-8', @@ -59,6 +60,9 @@ export function ShowMessage(status: number | string): string { case 505: message = 'HTTP版本不受支持(505)' break + case 600: + message = '混合内容错误(600)' + break default: message = `连接出错(${status})!` } diff --git a/main/manager-mobile/src/i18n/de.ts b/main/manager-mobile/src/i18n/de.ts index eee1d3b8..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', @@ -30,6 +30,8 @@ export default { 'login.requiredMobile': 'Bitte gültige Handynummer eingeben', 'login.captchaError': 'Grafischer Bestätigungscode Fehler', 'login.forgotPassword': 'Passwort vergessen', + 'login.userAgreement': 'Nutzungsbedingungen', + 'login.privacyPolicy': 'Datenschutzrichtlinie', // Registrierungsseite 'register.pageTitle': 'Registrieren', @@ -67,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', @@ -83,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', @@ -114,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...', @@ -150,6 +152,25 @@ export default { 'contextProviderDialog.cancel': 'Abbrechen', 'contextProviderDialog.confirm': 'Bestätigen', + // Manual add device dialog related + 'manualAddDeviceDialog.title': 'Manuell Gerät hinzufügen', + 'manualAddDeviceDialog.deviceType': 'Gerätetyp', + 'manualAddDeviceDialog.deviceTypePlaceholder': 'Bitte Gerätetyp auswählen', + 'manualAddDeviceDialog.firmwareVersion': 'Firmware-Version', + 'manualAddDeviceDialog.firmwareVersionPlaceholder': 'Bitte Firmware-Version eingeben', + 'manualAddDeviceDialog.macAddress': 'Mac-Adresse', + 'manualAddDeviceDialog.macAddressPlaceholder': 'Bitte Mac-Adresse eingeben', + 'manualAddDeviceDialog.confirm': 'Bestätigen', + 'manualAddDeviceDialog.cancel': 'Abbrechen', + 'manualAddDeviceDialog.requiredMacAddress': 'Bitte Mac-Adresse eingeben', + 'manualAddDeviceDialog.invalidMacAddress': 'Bitte korrektes Mac-Adressformat eingeben, z.B.: 00:1A:2B:3C:4D:5E', + 'manualAddDeviceDialog.requiredDeviceType': 'Bitte Gerätetyp auswählen', + 'manualAddDeviceDialog.requiredFirmwareVersion': 'Bitte Firmware-Version eingeben', + 'manualAddDeviceDialog.getFirmwareTypeFailed': 'Firmware-Typ konnte nicht abgerufen werden', + 'manualAddDeviceDialog.addSuccess': 'Gerät erfolgreich hinzugefügt', + 'manualAddDeviceDialog.addFailed': 'Hinzufügen fehlgeschlagen', + 'manualAddDeviceDialog.bindWithCode': 'Mit 6-stelligem Code binden', + // Chat-Verlauf Seite 'chatHistory.getChatSessions': 'Chat-Sitzungsliste abrufen', 'chatHistory.noSelectedAgent': 'Kein Agent ausgewählt', @@ -335,7 +356,7 @@ export default { 'message.unbindFail': 'Entbinden fehlgeschlagen', 'message.networkError': 'Netzwerkfehler, bitte Verbindung prüfen', 'message.serverError': 'Serverfehler, bitte später erneut versuchen', - 'message.invalidAddress': 'Ungültige Adresse, bitte prüfen ob Server gestartet oder Netzwerkverbindung normal ist', + 'message.invalidAddress': 'Die Adresse kann ungültig sein. Bitte überprüfen Sie, ob der Server gestartet ist oder ob die Netzwerkverbindung funktioniert. Es kann auch sein, dass die Anfrage aufgrund eines Problems mit dem HTTPS-Protokoll nicht gesendet werden kann.', 'message.languageChanged': 'Sprache geändert', 'message.passwordError': 'Konto oder Passwort Fehler', 'message.phoneRegistered': 'Diese Handynummer wurde bereits registriert', @@ -350,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', @@ -471,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 20d42d54..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', @@ -30,6 +30,8 @@ export default { 'login.requiredMobile': 'Please enter a valid phone number', 'login.captchaError': 'Graphic verification code error', 'login.forgotPassword': 'Forgot Password', + 'login.userAgreement': 'User Agreement', + 'login.privacyPolicy': 'Privacy Policy', // Register page 'register.pageTitle': 'Register', @@ -67,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', @@ -150,6 +152,25 @@ export default { 'contextProviderDialog.cancel': 'Cancel', 'contextProviderDialog.confirm': 'Confirm', + // Manual add device dialog related + 'manualAddDeviceDialog.title': 'Manual Add Device', + 'manualAddDeviceDialog.deviceType': 'Device Type', + 'manualAddDeviceDialog.deviceTypePlaceholder': 'Please select device type', + 'manualAddDeviceDialog.firmwareVersion': 'Firmware Version', + 'manualAddDeviceDialog.firmwareVersionPlaceholder': 'Please enter firmware version', + 'manualAddDeviceDialog.macAddress': 'Mac Address', + 'manualAddDeviceDialog.macAddressPlaceholder': 'Please enter Mac address', + 'manualAddDeviceDialog.confirm': 'Confirm', + 'manualAddDeviceDialog.cancel': 'Cancel', + 'manualAddDeviceDialog.requiredMacAddress': 'Please enter Mac address', + 'manualAddDeviceDialog.invalidMacAddress': 'Please enter correct Mac address format, e.g.: 00:1A:2B:3C:4D:5E', + 'manualAddDeviceDialog.requiredDeviceType': 'Please select device type', + 'manualAddDeviceDialog.requiredFirmwareVersion': 'Please enter firmware version', + 'manualAddDeviceDialog.getFirmwareTypeFailed': 'Failed to get firmware type', + 'manualAddDeviceDialog.addSuccess': 'Device added successfully', + 'manualAddDeviceDialog.addFailed': 'Failed to add', + 'manualAddDeviceDialog.bindWithCode': 'Bind with 6-digit code', + // Chat History Page 'chatHistory.getChatSessions': 'Get chat session list', 'chatHistory.noSelectedAgent': 'No agent selected', @@ -335,7 +356,7 @@ export default { 'message.unbindFail': 'Unbinding failed', 'message.networkError': 'Network error, please check your connection', 'message.serverError': 'Server error, please try again later', - 'message.invalidAddress': 'Invalid address, please check if the server is started or network connection is normal', + 'message.invalidAddress': 'The address may be invalid. Please check if the server is started or if the network connection is normal; It is also possible that requests cannot be sent due to HTTPS protocol issues', 'message.languageChanged': 'Language changed', 'message.passwordError': 'Account or password error', 'message.phoneRegistered': 'This phone number has been registered', @@ -350,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', @@ -471,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 bd218234..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', @@ -29,7 +29,9 @@ export default { 'login.requiredCaptcha': 'O código de verificação não pode estar vazio', 'login.requiredMobile': 'Por favor, insira um número de telefone válido', 'login.captchaError': 'Erro no código de verificação gráfico', - 'login.forgotPassword': 'Esqueceu a Senha', + 'login.forgotPassword': 'Esqueceu a Senha', + 'login.userAgreement': 'Termos de Uso', + 'login.privacyPolicy': 'Política de Privacidade', // Register page 'register.pageTitle': 'Cadastro', @@ -67,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', @@ -150,6 +152,25 @@ export default { 'contextProviderDialog.cancel': 'Cancelar', 'contextProviderDialog.confirm': 'Confirmar', + // Diálogo de adição manual de dispositivo + 'manualAddDeviceDialog.title': 'Adicionar Dispositivo Manualmente', + 'manualAddDeviceDialog.deviceType': 'Tipo de Dispositivo', + 'manualAddDeviceDialog.deviceTypePlaceholder': 'Por favor, selecione o tipo de dispositivo', + 'manualAddDeviceDialog.firmwareVersion': 'Versão do Firmware', + 'manualAddDeviceDialog.firmwareVersionPlaceholder': 'Por favor, insira a versão do firmware', + 'manualAddDeviceDialog.macAddress': 'Endereço MAC', + 'manualAddDeviceDialog.macAddressPlaceholder': 'Por favor, insira o endereço MAC', + 'manualAddDeviceDialog.confirm': 'Confirmar', + 'manualAddDeviceDialog.cancel': 'Cancelar', + 'manualAddDeviceDialog.requiredMacAddress': 'Por favor, insira o endereço MAC', + 'manualAddDeviceDialog.invalidMacAddress': 'Por favor, insira o formato correto de endereço MAC, ex.: 00:1A:2B:3C:4D:5E', + 'manualAddDeviceDialog.requiredDeviceType': 'Por favor, selecione o tipo de dispositivo', + 'manualAddDeviceDialog.requiredFirmwareVersion': 'Por favor, insira a versão do firmware', + 'manualAddDeviceDialog.getFirmwareTypeFailed': 'Falha ao obter tipo de firmware', + 'manualAddDeviceDialog.addSuccess': 'Dispositivo adicionado com sucesso', + 'manualAddDeviceDialog.addFailed': 'Falha ao adicionar', + 'manualAddDeviceDialog.bindWithCode': 'Vincular com Código de 6 Dígitos', + // Chat History Page 'chatHistory.getChatSessions': 'Obter lista de sessões de conversa', 'chatHistory.noSelectedAgent': 'Nenhum agente selecionado', @@ -335,7 +356,7 @@ export default { 'message.unbindFail': 'Falha na desvinculação', 'message.networkError': 'Erro de rede, por favor verifique sua conexão', 'message.serverError': 'Erro no servidor, por favor tente novamente mais tarde', - 'message.invalidAddress': 'Endereço inválido, por favor verifique se o servidor está iniciado ou se a conexão de rede está normal', + 'message.invalidAddress': 'O endereço pode ser inválido, verifique se o servidor está iniciado ou se a conexão de rede está correta; Também pode ser impossível enviar solicitações devido a problemas com o protocolo HTTPS', 'message.languageChanged': 'Idioma alterado', 'message.passwordError': 'Conta ou senha incorretos', 'message.phoneRegistered': 'Este número de telefone já está cadastrado', @@ -350,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', @@ -471,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 3c0fd4f6..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', @@ -30,6 +30,8 @@ export default { 'login.requiredMobile': 'Vui lòng nhập số điện thoại hợp lệ', 'login.captchaError': 'Lỗi mã xác minh đồ họa', 'login.forgotPassword': 'Quên mật khẩu', + 'login.userAgreement': 'Thỏa thuận người dùng', + 'login.privacyPolicy': 'Chính sách bảo mật', // Trang đăng ký 'register.pageTitle': 'Đăng ký', @@ -67,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', @@ -150,6 +152,25 @@ export default { 'contextProviderDialog.cancel': 'Hủy bỏ', 'contextProviderDialog.confirm': 'Xác nhận', + // Manual add device dialog related + 'manualAddDeviceDialog.title': 'Thêm thiết bị thủ công', + 'manualAddDeviceDialog.deviceType': 'Loại thiết bị', + 'manualAddDeviceDialog.deviceTypePlaceholder': 'Vui lòng chọn loại thiết bị', + 'manualAddDeviceDialog.firmwareVersion': 'Phiên bản firmware', + 'manualAddDeviceDialog.firmwareVersionPlaceholder': 'Vui lòng nhập phiên bản firmware', + 'manualAddDeviceDialog.macAddress': 'Địa chỉ Mac', + 'manualAddDeviceDialog.macAddressPlaceholder': 'Vui lòng nhập địa chỉ Mac', + 'manualAddDeviceDialog.confirm': 'Xác nhận', + 'manualAddDeviceDialog.cancel': 'Hủy bỏ', + 'manualAddDeviceDialog.requiredMacAddress': 'Vui lòng nhập địa chỉ Mac', + 'manualAddDeviceDialog.invalidMacAddress': 'Vui lòng nhập đúng định dạng địa chỉ Mac, ví dụ: 00:1A:2B:3C:4D:5E', + 'manualAddDeviceDialog.requiredDeviceType': 'Vui lòng chọn loại thiết bị', + 'manualAddDeviceDialog.requiredFirmwareVersion': 'Vui lòng nhập phiên bản firmware', + 'manualAddDeviceDialog.getFirmwareTypeFailed': 'Không thể lấy loại firmware', + 'manualAddDeviceDialog.addSuccess': 'Đã thêm thiết bị thành công', + 'manualAddDeviceDialog.addFailed': 'Thêm thất bại', + 'manualAddDeviceDialog.bindWithCode': 'Liên kết bằng mã xác minh 6 chữ số', + // Trang lịch sử trò chuyện 'chatHistory.getChatSessions': 'Lấy danh sách phiên trò chuyện', 'chatHistory.noSelectedAgent': 'Chưa chọn đại lý', @@ -335,7 +356,7 @@ export default { 'message.unbindFail': 'Hủy liên kết thất bại', 'message.networkError': 'Lỗi mạng, vui lòng kiểm tra kết nối', 'message.serverError': 'Lỗi máy chủ, vui lòng thử lại sau', - 'message.invalidAddress': 'Địa chỉ không hợp lệ, vui lòng kiểm tra máy chủ đã khởi động hoặc kết nối mạng bình thường', + 'message.invalidAddress': 'Địa chỉ có thể không hợp lệ. Vui lòng kiểm tra xem máy chủ đã khởi động hay kết nối mạng chưa; Có thể không gửi được yêu cầu do lỗi giao thức HTTPS', 'message.languageChanged': 'Đã thay đổi ngôn ngữ', 'message.passwordError': 'Lỗi tài khoản hoặc mật khẩu', 'message.phoneRegistered': 'Số điện thoại này đã được đăng ký', @@ -350,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', @@ -471,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 aef7d223..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': '请输入用户名', @@ -30,6 +30,8 @@ export default { 'login.requiredMobile': '请输入正确的手机号码', 'login.captchaError': '图形验证码错误', 'login.forgotPassword': '忘记密码', + 'login.userAgreement': '用户协议', + 'login.privacyPolicy': '隐私政策', // 注册页面 'register.pageTitle': '注册', @@ -67,7 +69,7 @@ export default { 'home.createFirstAgent': '点击右下角 + 号创建您的第一个智能体', 'home.dialogTitle': '创建智能体', 'home.inputPlaceholder': '例如:客服助手、语音助理、知识问答', - 'home.createError': '请输入智能体名称', + 'home.createError': '名称长度必须在 1 到 64 个字符之间', 'home.createNow': '立即创建', 'home.justNow': '刚刚', 'home.minutesAgo': '分钟前', @@ -150,6 +152,25 @@ export default { 'contextProviderDialog.cancel': '取消', 'contextProviderDialog.confirm': '确定', + // 手動添加設備對話框相關 + 'manualAddDeviceDialog.title': '手动添加设备', + 'manualAddDeviceDialog.deviceType': '设备型号', + 'manualAddDeviceDialog.deviceTypePlaceholder': '请选择设备型号', + 'manualAddDeviceDialog.firmwareVersion': '固件版本', + 'manualAddDeviceDialog.firmwareVersionPlaceholder': '请输入固件版本', + 'manualAddDeviceDialog.macAddress': 'Mac地址', + 'manualAddDeviceDialog.macAddressPlaceholder': '请输入Mac地址', + 'manualAddDeviceDialog.confirm': '确定', + 'manualAddDeviceDialog.cancel': '取消', + 'manualAddDeviceDialog.requiredMacAddress': '请输入Mac地址', + 'manualAddDeviceDialog.invalidMacAddress': '请输入正确的Mac地址格式,例如:00:1A:2B:3C:4D:5E', + 'manualAddDeviceDialog.requiredDeviceType': '请选择设备型号', + 'manualAddDeviceDialog.requiredFirmwareVersion': '请输入固件版本', + 'manualAddDeviceDialog.getFirmwareTypeFailed': '获取固件类型失败', + 'manualAddDeviceDialog.addSuccess': '设备添加成功', + 'manualAddDeviceDialog.addFailed': '添加失败', + 'manualAddDeviceDialog.bindWithCode': '6位验证码绑定', + // 聊天历史页面 'chatHistory.getChatSessions': '获取聊天会话列表', 'chatHistory.noSelectedAgent': '没有选中的智能体', @@ -335,7 +356,7 @@ export default { 'message.unbindFail': '解绑失败', 'message.networkError': '网络错误,请检查网络连接', 'message.serverError': '服务器错误,请稍后再试', - 'message.invalidAddress': '无效地址,请检查服务端是否启动或网络连接是否正常', + 'message.invalidAddress': '地址可能无效,请检查服务端是否启动或网络连接是否正常;也可能因 HTTPS 协议问题导致无法发送请求', 'message.languageChanged': '语言已切换', 'message.passwordError': '账号或密码错误', 'message.phoneRegistered': '此手机号码已经注册过', @@ -471,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 5fd942b0..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': '請輸入用戶名', @@ -29,7 +29,9 @@ export default { 'login.requiredCaptcha': '驗證碼不能為空', 'login.requiredMobile': '請輸入正確的手機號碼', 'login.captchaError': '圖形驗證碼錯誤', - 'login.forgotPassword': '忘記密碼', + 'login.forgotPassword': '忘記密碼', + 'login.userAgreement': '用戶協議', + 'login.privacyPolicy': '隱私政策', // 忘記密碼頁面 'retrievePassword.title': '重置密碼', @@ -88,7 +90,7 @@ export default { 'home.createFirstAgent': '點擊右下角 + 號創建您的第一個智能體', 'home.dialogTitle': '創建智能體', 'home.inputPlaceholder': '例如:客服助手、語音助理、知識問答', - 'home.createError': '請輸入智能體暱稱', + 'home.createError': '暱稱長度必須在 1 到 64 個字元之間。', 'home.createNow': '立即創建', 'home.justNow': '剛剛', 'home.minutesAgo': '分鐘前', @@ -171,6 +173,25 @@ export default { 'contextProviderDialog.cancel': '取消', 'contextProviderDialog.confirm': '確定', + // 手動添加設備對話框相關 + 'manualAddDeviceDialog.title': '手動添加設備', + 'manualAddDeviceDialog.deviceType': '設備型號', + 'manualAddDeviceDialog.deviceTypePlaceholder': '請選擇設備型號', + 'manualAddDeviceDialog.firmwareVersion': '固件版本', + 'manualAddDeviceDialog.firmwareVersionPlaceholder': '請輸入固件版本', + 'manualAddDeviceDialog.macAddress': 'Mac地址', + 'manualAddDeviceDialog.macAddressPlaceholder': '請輸入Mac地址', + 'manualAddDeviceDialog.confirm': '確定', + 'manualAddDeviceDialog.cancel': '取消', + 'manualAddDeviceDialog.requiredMacAddress': '請輸入Mac地址', + 'manualAddDeviceDialog.invalidMacAddress': '請輸入正確的Mac地址格式,例如:00:1A:2B:3C:4D:5E', + 'manualAddDeviceDialog.requiredDeviceType': '請選擇設備型號', + 'manualAddDeviceDialog.requiredFirmwareVersion': '請輸入固件版本', + 'manualAddDeviceDialog.getFirmwareTypeFailed': '獲取固件類型失敗', + 'manualAddDeviceDialog.addSuccess': '設備添加成功', + 'manualAddDeviceDialog.addFailed': '添加失敗', + 'manualAddDeviceDialog.bindWithCode': '6位驗證碼綁定', + // 聊天歷史頁面 'chatHistory.getChatSessions': '獲取聊天會話列表', 'chatHistory.noSelectedAgent': '沒有選中的智能體', @@ -335,7 +356,7 @@ export default { 'message.unbindFail': '解除綁定失敗', 'message.networkError': '網絡錯誤,請檢查網絡連接', 'message.serverError': '服務器錯誤,請稍後再試', - 'message.invalidAddress': '無效地址,請檢查服務端是否啟動或網絡連接是否正常', + 'message.invalidAddress': '地址可能無效,請檢查服務端是否啟動或網絡連接是否正常; 也可能因HTTPS協定問題導致無法發送請求常', 'message.languageChanged': '語言已切換', 'message.passwordError': '帳號或密碼錯誤', 'message.phoneRegistered': '此手機號已經註冊過', @@ -471,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 107fe7b8..0f56db88 100644 --- a/main/manager-mobile/src/pages/agent/edit.vue +++ b/main/manager-mobile/src/pages/agent/edit.vue @@ -2,10 +2,8 @@ import type { AgentDetail, ModelOption, PluginDefinition, RoleTemplate } from '@/api/agent/types' import { computed, nextTick, onMounted, ref, watch } from 'vue' 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 { usePluginStore, useProvider, useSpeedPitch } from '@/store' import { toast } from '@/utils/toast' defineOptions({ @@ -105,29 +103,21 @@ const pickerShow = ref<{ report: false, }) -const ttsSettings = ref({ - volume: 0, - speed: 0, - pitch: 0, -}) - const allFunctions = ref([]) 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) +// 音频播放相关 +const audioRef = ref(null) +const playingVoiceId = ref('') + // 使用插件store const pluginStore = usePluginStore() +const speedPitchStore = useSpeedPitch() +const providerStore = useProvider() // tabs const tabList = [ @@ -172,29 +162,20 @@ function handleInputConfirm() { inputVisible.value = false } +// 是否禁用历史记忆输入框 +const isMemoryDisabled = computed(() => formData.value.memModelId !== 'Memory_mem_local_short') + // 打开上下文源编辑弹窗 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 + uni.navigateTo({ + url: '/pages/agent/provider', + }) } function handleRegulate() { - openVoiceSettingsDialog() + uni.navigateTo({ + url: '/pages/agent/speedPitch', + }) } // 加载智能体详情 @@ -211,14 +192,15 @@ async function loadAgentDetail() { pluginStore.setCurrentAgentId(agentId.value) pluginStore.setCurrentFunctions(detail.functions || []) + // 更新语速音调 + speedPitchStore.updateSpeedPitch({ + ttsVolume: detail.ttsVolume || 0, + ttsRate: detail.ttsRate || 0, + ttsPitch: detail.ttsPitch || 0, + }) + // 加载上下文配置 - 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, - } + providerStore.updateProviders(detail.contextProviders || []) // 如果有TTS模型,加载对应的音色选项 if (detail.ttsModelId) { @@ -373,17 +355,17 @@ function filterVoicesByLanguage() { } // 同步到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, - } + speedPitchStore.updateSpeedPitch({ + ttsVolume: formData.value.ttsVolume !== null && formData.value.ttsVolume !== undefined ? formData.value.ttsVolume : 0, + ttsRate: formData.value.ttsRate !== null && formData.value.ttsRate !== undefined ? formData.value.ttsRate : 0, + ttsPitch: 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[] + const res = await getAllLanguage(ttsModelId) // 保存完整的音色信息 voiceDetails.value = res.reduce((acc, voice) => { acc[voice.id] = voice @@ -447,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() } } @@ -518,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 = '' } // 获取模型显示名称 @@ -564,8 +606,9 @@ async function saveAgent() { // 构建保存数据,包含上下文配置和语音设置 const saveData = { ...formData.value, + ...speedPitchStore.speedPitch, ttsLanguage: formData.value.language, - contextProviders: currentContextProviders.value, + contextProviders: providerStore.providers, } await updateAgent(agentId.value, saveData) loadAgentDetail() @@ -611,15 +654,6 @@ function handleTools() { }) } -// 监听插件配置更新 -function watchPluginUpdates() { - // 监听store中的插件配置变化 - watch(() => pluginStore.currentFunctions, (newFunctions) => { - console.log('插件配置已更新:', newFunctions) - formData.value.functions = newFunctions - }, { deep: true }) -} - // 获取智能体标签 async function loadAgentTags() { try { @@ -635,9 +669,12 @@ async function handleUpdateAgentTags() { await updateAgentTags(agentId.value, { tagNames }) } +// 监听store中的插件配置变化 +watch(() => pluginStore.currentFunctions, (newFunctions) => { + formData.value.functions = newFunctions +}, { deep: true }) + onMounted(async () => { - // 初始化插件配置监听 - watchPluginUpdates() loadAgentTags() // 先加载模型选项和角色模板 @@ -726,7 +763,7 @@ onMounted(async () => { - {{ t('agent.contextProviderSuccess', { count: currentContextProviders.length }) }} + {{ t('agent.contextProviderSuccess', { count: providerStore.providers.length }) }} {{ t('agent.contextProviderDocLink') }} @@ -908,8 +945,9 @@ onMounted(async () => {