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 - select id, name, voice_id as voiceDemo + select id, name, voice_id as voiceDemo, languages from ai_voice_clone where model_id = #{modelId} and user_id = #{userId} and train_status = 2 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 @@ - - - - - - - - {{ t('contextProviderDialog.title') }} - - - - - - - {{ t('contextProviderDialog.noContextApi') }} - - - {{ t('contextProviderDialog.add') }} - - - - - - - - - - - - - - - {{ t('contextProviderDialog.apiUrl') }} - - - - - - - {{ t('contextProviderDialog.requestHeaders') }} - - - - - - - - - - - - - - - - - {{ t('contextProviderDialog.noHeaders') }} - - - {{ t('contextProviderDialog.addHeader') }} - - - - - - - - - - - - {{ t('contextProviderDialog.cancel') }} - - - {{ t('contextProviderDialog.confirm') }} - - - - - - - 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 @@ - - - - - - - - {{ t('agent.languageConfig') }} - - - - - - - - {{ t('agent.ttsVolume') }} - - - - - {{ localSettings.volume }} - - - - {{ t('agent.volumeHint') }} - - - - - - - {{ t('agent.ttsRate') }} - - - - - {{ localSettings.speed }} - - - - {{ t('agent.speedHint') }} - - - - - - - {{ t('agent.ttsPitch') }} - - - - - {{ localSettings.pitch }} - - - - {{ t('agent.pitchHint') }} - - - - - - - {{ t('agent.cancel') }} - - - {{ t('agent.save') }} - - - - - - - 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 () => { @@ -972,16 +1010,35 @@ onMounted(async () => { onPickerConfirm('tts', item.value, item.name)" /> - onPickerConfirm('voiceprint', item.value, item.name)" - /> + + + + + + + {{ voice.name }} + + + + + + + + { @close="onPickerCancel('report')" @select="({ item }) => onPickerConfirm('report', item.value, item.name)" /> - - @@ -1011,4 +1058,19 @@ onMounted(async () => { ::v-deep .wd-tag__close { color: #336cff !important; } +::v-deep .custom-popup { + .wd-popup { + padding: 20rpx !important; + background: transparent !important; + } +} +::v-deep .custom-sheet-tts { + .wd-action-sheet { + padding: 8px 0 !important; + overflow: hidden; + } + .wd-action-sheet__actions { + padding: 0 !important; + } +} diff --git a/main/manager-mobile/src/pages/agent/index.vue b/main/manager-mobile/src/pages/agent/index.vue index 49f11e57..c6befce0 100644 --- a/main/manager-mobile/src/pages/agent/index.vue +++ b/main/manager-mobile/src/pages/agent/index.vue @@ -51,17 +51,18 @@ const currentTab = ref('agent-config') // 刷新和加载状态 const refreshing = ref(false) - -// 计算是否启用下拉刷新(角色编辑页面不启用) -const refresherEnabled = computed(() => { - return currentTab.value !== 'agent-config' -}) +const refresherEnabled = ref(false) // 子组件引用 const deviceRef = ref() const chatRef = ref() const voiceprintRef = ref() +// 更新刷新器状态 +function updateRefresherEnabled(value: boolean) { + refresherEnabled.value = value +} + // Tab 配置 const tabList = [ { @@ -144,6 +145,10 @@ async function onLoadMore() { } } +watch(() => currentTab.value, (newTab) => { + updateRefresherEnabled(newTab !== 'agent-config') +}) + // 接收页面参数 onLoad((options) => { if (options?.agentId) { @@ -204,6 +209,7 @@ onMounted(async () => { v-else-if="currentTab === 'voiceprint-management'" ref="voiceprintRef" :agent-id="currentAgentId" + @update-refresher-enabled="updateRefresherEnabled" /> diff --git a/main/manager-mobile/src/pages/agent/provider.vue b/main/manager-mobile/src/pages/agent/provider.vue new file mode 100644 index 00000000..47bd56e0 --- /dev/null +++ b/main/manager-mobile/src/pages/agent/provider.vue @@ -0,0 +1,208 @@ + +{ + "layout": "default", + "style": { + "navigationBarTitleText": "编辑源", + "navigationStyle": "custom" + } +} + + + + + + + + + + + + + + + + {{ t('contextProviderDialog.noContextApi') }} + + + {{ t('contextProviderDialog.add') }} + + + + + + + + + + + + + + + {{ t('contextProviderDialog.apiUrl') }} + + + + + + + {{ t('contextProviderDialog.requestHeaders') }} + + + + + + + + + + + + + + + + + {{ t('contextProviderDialog.noHeaders') }} + + + {{ t('contextProviderDialog.addHeader') }} + + + + + + + + + + + + {{ t('contextProviderDialog.confirm') }} + + + + + + diff --git a/main/manager-mobile/src/pages/agent/speedPitch.vue b/main/manager-mobile/src/pages/agent/speedPitch.vue new file mode 100644 index 00000000..c8b7514a --- /dev/null +++ b/main/manager-mobile/src/pages/agent/speedPitch.vue @@ -0,0 +1,153 @@ + +{ + "layout": "default", + "style": { + "navigationBarTitleText": "语音设置", + "navigationStyle": "custom" + } +} + + + + + + + + + + + + + + + + + + {{ t('agent.ttsVolume') }} + + + + + {{ localSettings.ttsVolume }} + + + + {{ t('agent.volumeHint') }} + + + + + + + {{ t('agent.ttsRate') }} + + + + + {{ localSettings.ttsRate }} + + + + {{ t('agent.speedHint') }} + + + + + + + {{ t('agent.ttsPitch') }} + + + + + {{ localSettings.ttsPitch }} + + + + {{ t('agent.pitchHint') }} + + + + + + + {{ t('agent.save') }} + + + + + + + diff --git a/main/manager-mobile/src/pages/agent/tools.vue b/main/manager-mobile/src/pages/agent/tools.vue index deeda0c5..fb47deae 100644 --- a/main/manager-mobile/src/pages/agent/tools.vue +++ b/main/manager-mobile/src/pages/agent/tools.vue @@ -11,8 +11,8 @@ + + + + + + + + + + + + + Privacy Policy + + + + + Last Updated: March 10, 2026 + + + + + Introduction + + + + + Welcome to use the XiaoZhi Backend Service (hereinafter referred to as "the Service"). The operator of this Service is the actual deployer and administrator of the Service (hereinafter referred to as "Operator" or "we"). We fully understand the importance of your personal information and will do our best to protect your personal information security. + + + + + Please carefully read and fully understand all contents of this Privacy Policy before using the Service. Once you start using the Service, it signifies that you have read and agreed to this Privacy Policy. + + + + + This Privacy Policy applies to our collection, storage, use, sharing, and protection of your personal information when you use the Service through the Admin Console (management backend), API interfaces, and other means. + + + + + I. Information We Collect + + + + + To provide services to you, we may need to collect the following information: + + + + + 1.1 Account Registration Information: When you register an account, we collect your phone number or username, password, and other information to create and verify your account. + + + + + 1.2 Device Information: When you bind hardware devices, we collect device identification information (such as device code, MAC address), device model, firmware version, etc., for device management and service provision. + + + + + 1.3 Agent Configuration Information: When you create and configure Agents, we collect role templates, language model selections, voice parameter configurations, etc., to provide personalized AI interaction services. + + + + + 1.4 Voice Interaction Data: When you use the voice interaction function, the Service uses Voice Activity Detection (VAD) to determine the start and end of your voice, processes your voice input data, and transmits it to third-party Automatic Speech Recognition (ASR) and Large Language Model (LLM) services for processing to achieve voice interaction capabilities. + + + + + 1.5 Image Data: When you use the vision model function, we may process image data captured through the device camera and transmit it to third-party vision model services for analysis and understanding to achieve image recognition, scene understanding, and other functions. + + + + + 1.6 Conversation Memory Data: When you enable the memory function, the Service stores summaries of your interaction history with the Agent to provide more coherent and personalized interaction experiences in subsequent conversations. + + + + + 1.7 Knowledge Base Data: When you use the knowledge base function, we collect and store documents, texts, and other knowledge base content you upload for Agents to perform knowledge retrieval and Q&A during conversations. + + + + + 1.8 Voice Print Data: When you use the voice print recognition function, we collect and store your voice print characteristic samples for speaker identity verification and personalized services. + + + + + 1.9 Chat History Data: We store conversation history records between you and the Agents, including text conversation content, conversation time, interaction context, etc., to provide continuous conversation experience and history query functions. + + + + + 1.10 Conversation Audio Data: When you use the voice interaction function, we may store audio data of your interactions with the Agents to improve voice interaction quality and enable retrieval queries. + + + + + 1.11 Agent Configuration Data: When you configure Agents, we collect tags, plugin configurations, context provider settings, etc., to provide Agent customization services. + + + + + 1.12 Device Firmware Data: When you use the OTA upgrade function, we record device firmware version, upgrade history, etc., for device management and firmware traceability. + + + + + 1.13 Log Information: When you use the Service, we automatically collect service log information, including but not limited to access time, IP address, browser type, operation records, etc., for service operation and security assurance. + + + + + 1.14 Verification Code Information: When you use phone number login, we send verification codes via SMS service for identity verification. + + + + + II. How We Use the Collected Information + + + + + The information we collect will be used for the following purposes: + + + + + (1) Providing, maintaining, and improving the Service, including core functions such as account management, device management, and Agent configuration. + + + + + (2) Processing your voice interaction requests, using Voice Activity Detection (VAD) to identify voice input, calling third-party AI model services to complete speech recognition, intent recognition, semantic understanding, and speech synthesis. + + + + + (3) Processing your image data, calling third-party vision model services to complete image recognition and scene understanding. + + + + + (4) Storing and managing your conversation memory data to provide more coherent service experiences in subsequent interactions. + + + + + (5) Storing and retrieving knowledge base content you upload so that Agents can provide more accurate knowledge Q&A during conversations. + + + + + (6) Ensuring service security and stability, including identity verification, security protection, troubleshooting, etc. + + + + + (7) Complying with applicable laws, regulations, and regulatory requirements. + + + + + We will not use your personal information for purposes unrelated to the above. If we need to use information for other purposes not stated in this Privacy Policy, we will obtain your consent in advance. + + + + + III. Sharing and Disclosure of Information + + + + + We will not sell your personal information to third parties. Only in the following circumstances may we share or disclose your information: + + + + + 3.1 Third-party Service Calls: To achieve voice interaction, visual understanding, and other functions, your voice data, image data, and text content may be transmitted to third-party AI service providers for processing. + + + + + 3.2 Legal Requirements: According to applicable laws, regulations, legal procedures, or requirements from government authorities, we may need to disclose your personal information. + + + + + 3.3 Security Assurance: To protect the Operator, other users, or the public from damage, we may use or disclose personal information within a reasonably necessary scope. + + + + + 3.4 With Consent: We may share your personal information with third parties if we obtain your explicit consent. + + + + + IV. Storage and Protection of Information + + + + + 4.1 Storage Location: Your personal information will be stored on the server where the Operator deploys the Service, including but not limited to databases (MySQL/PostgreSQL) and cache services (Redis). + + + + + 4.2 Storage Period: We will retain your personal information for the period necessary to provide you with services. After you cancel your account, we will delete or anonymize your personal information within a reasonable time. + + + + + 4.3 Security Measures: We take reasonable technical and management measures to protect the security of your personal information, including but not limited to data encryption, access control, security auditing, etc. + + + + + 4.4 Security Incident Handling: If a personal information security incident occurs, we will promptly inform you of the basic situation of the security incident, possible impacts, and measures taken or to be taken. + + + + + 4.5 Special Note for Open-source Projects: The Service is an open-source project with two operation modes: + + + + + (1) Self-deployment: If you self-deploy the Service, the Operator is only the code provider, and actual data storage and processing are your responsibility. + + + + + (2) Test Platform: If you use the test platform deployed by the Operator, your data will be managed and protected by the Operator. + + + + + 4.6 Cross-border Data Transfer: When providing intelligent interaction functions, the Service may need to call interfaces from third-party AI service providers outside mainland China. + + + + + V. Your Rights + + + + + 5.1 Query and Access: You can view and manage your personal information such as account information, device information, and Agent configuration through the Admin Console. + + + + + 5.2 Correction and Modification: When you find that your personal information is incorrect, you can correct it through the Admin Console or contact the Operator for assistance. + + + + + 5.3 Deletion: Under certain circumstances, you may request us to delete your personal information. + + + + + 5.4 Account Cancellation: You can cancel your account through the account settings in the Admin Console or contact the Operator for processing. + + + + + 5.5 Withdrawal of Consent: You may withdraw your consent granted to us at any time. + + + + + VI. Protection of Minor Information + + + + + 6.1 We attach great importance to the protection of minors' personal information. If you are a minor under 18 years of age, please use the Service under the guidance and consent of your guardian. + + + + + 6.2 If a guardian discovers that a minor has provided personal information to us without consent, please contact the Operator. We will delete the relevant information as soon as possible. + + + + + 6.3 For minors who use the Service with guardian consent, we will provide stricter protection for their personal information in accordance with laws and regulations. + + + + + VII. Third-party Services Description + + + + + 7.1 When providing intelligent interaction functions, the Service needs to call third-party services, including but not limited to: Voice Activity Detection Service (VAD), Automatic Speech Recognition Service (ASR), Large Language Model Service (LLM), Text-to-Speech Service (TTS), Vision Model Service, SMS Verification Code Service, MQTT Message Broker Service, Database Service. + + + + + 7.2 The above third-party service providers will process data according to their respective privacy policies. We recommend that you understand the privacy policies of relevant third-party service providers before using the Service. + + + + + VIII. Use of Cookies and Similar Technologies + + + + + 8.1 The Service may use Cookies and similar technologies to save your login status, record your preference settings, etc., to provide you with a better user experience. + + + + + 8.2 You can manage Cookies through browser settings. However, please note that disabling Cookies may affect some functions of the Service. + + + + + IX. Changes to the Privacy Policy + + + + + 9.1 We may revise this Privacy Policy based on business adjustments, changes in laws and regulations, and other reasons. The revised Privacy Policy will be published through the Service's announcement mechanisms. + + + + + 9.2 If you continue to use the Service after the Privacy Policy revision, it shall be deemed that you have accepted the revised Privacy Policy. + + + + + X. Information Security Warning + + + + + 10.1 Please do not disclose sensitive personal information such as your property account numbers, bank card numbers, credit card numbers, passwords, ID card numbers, etc., in voice or text interactions with AI. Any losses resulting from this shall be borne by you. + + + + + 10.2 Please properly keep your account and password secure, and do not share your account information with others or share accounts with others. + + + + + 10.3 If you discover that personal information may have been leaked, please contact the Operator promptly to take measures. + + + + + XI. Applicable Law + + + + + 11.1 The formulation, interpretation, execution, and dispute resolution of this Privacy Policy shall be governed by the laws of the People's Republic of China (excluding the laws of Hong Kong, Macau, and Taiwan for the purposes of this Privacy Policy). + + + + + 11.2 If any provision of this Privacy Policy conflicts with the current laws and regulations of the People's Republic of China, the provisions of laws and regulations shall prevail, and the remaining provisions shall remain valid. + + + + + + diff --git a/main/manager-mobile/src/pages/login/privacy-policy-zh.vue b/main/manager-mobile/src/pages/login/privacy-policy-zh.vue new file mode 100644 index 00000000..3fffa070 --- /dev/null +++ b/main/manager-mobile/src/pages/login/privacy-policy-zh.vue @@ -0,0 +1,402 @@ + +{ + "layout": "default", + "style": { + "navigationStyle": "custom", + "navigationBarTitleText": "隐私政策" + } +} + + + + + + + + + + + + + + + + {{ t('login.privacyPolicy') }} + + + + + 更新日期:2026年3月10日 + + + + + 引言 + + + + + 欢迎您使用小智后端服务(以下简称"本服务")。本服务的运营方为本服务的实际部署者和管理者(以下简称"运营者"或"我们")。我们深知个人信息对您的重要性,将尽全力保护您的个人信息安全。 + + + + + 请您在使用本服务前,仔细阅读并充分理解本隐私政策的全部内容。一旦您开始使用本服务,即表示您已阅读并同意本隐私政策。 + + + + + 本隐私政策适用于您通过智控台(管理后台)、API接口及其他方式使用本服务时,我们对您个人信息的收集、存储、使用、共享、保护等行为。 + + + + + 一、我们收集的信息 + + + + + 为向您提供服务,我们可能需要收集以下信息: + + + + + 1.1 账号注册信息:当您注册账号时,我们会收集您的手机号码或用户名、密码等信息,用于创建和验证您的账号。 + + + + + 1.2 设备信息:当您绑定硬件设备时,我们会收集设备的标识信息(如设备编码、MAC地址等)、设备型号、固件版本等,用于设备管理和服务提供。 + + + + + 1.3 智能体配置信息:当您创建和配置智能体时,我们会收集您设定的角色模板、语言模型选择、语音参数配置等信息,用于提供个性化的AI交互服务。 + + + + + 1.4 语音交互数据:在您使用语音交互功能时,本服务会通过语音活动检测(VAD)判断您的语音起止状态,并处理您的语音输入数据,将其传输至第三方语音识别(ASR)和语言模型(LLM)服务进行处理,以实现语音交互功能。 + + + + + 1.5 图像数据:当您使用视觉模型功能时,我们可能会处理您通过设备摄像头采集的图像数据,并将其传输至第三方视觉模型服务进行分析和理解,用于实现图像识别、场景理解等功能。 + + + + + 1.6 对话记忆数据:当您开启记忆功能时,本服务会存储您与智能体的交互历史摘要,用于在后续对话中提供更连贯、个性化的交互体验。 + + + + + 1.7 知识库数据:当您使用知识库功能时,我们会收集和存储您上传的文档、文本等知识库内容,用于智能体在对话中进行知识检索和问答。 + + + + + 1.8 声纹数据:当您使用声纹识别功能时,我们会收集和存储您的声纹特征样本,用于说话人身份验证和个性化服务。 + + + + + 1.9 聊天历史数据:我们会存储您与智能体的对话历史记录,包括文本对话内容、对话时间、交互上下文等信息,用于提供连续性对话体验和历史查询功能。 + + + + + 1.10 对话音频数据:在您使用语音交互功能时,我们可能会存储您与智能体交互的音频数据,用于优化语音交互质量和回溯查询。 + + + + + 1.11 智能体配置数据:当您配置智能体时,我们会收集您设定的标签、插件配置、上下文提供者设置等信息,用于提供智能体定制化服务。 + + + + + 1.12 设备固件数据:当您使用OTA升级功能时,我们会记录设备固件版本、升级历史等信息,用于设备管理和固件追溯。 + + + + + 1.13 日志信息:当您使用本服务时,我们会自动收集服务日志信息,包括但不限于访问时间、IP地址、浏览器类型、操作记录等,用于服务运维和安全保障。 + + + + + 1.14 验证码信息:当您使用手机号登录时,我们会通过短信服务向您发送验证码,用于身份验证。 + + + + + 二、我们如何使用收集的信息 + + + + + 我们收集的信息将用于以下目的: + + + + + (1)提供、维护和改进本服务,包括账号管理、设备管理、智能体配置等核心功能。 + + + + + (2)处理您的语音交互请求,通过语音活动检测(VAD)识别语音输入,调用第三方AI模型服务完成语音识别、意图识别、语义理解和语音合成。 + + + + + (3)处理您的图像数据,调用第三方视觉模型服务完成图像识别和场景理解。 + + + + + (4)存储和管理您的对话记忆数据,以便在后续交互中提供更连贯的服务体验。 + + + + + (5)存储和检索您上传的知识库内容,以便智能体在对话中为您提供更准确的知识问答。 + + + + + (6)保障服务的安全性和稳定性,包括身份验证、安全防护、故障排查等。 + + + + + (7)遵守适用的法律法规和监管要求。 + + + + + 我们不会将您的个人信息用于与上述目的无关的其他用途。如需将信息用于本隐私政策未载明的其他目的,我们会事先征得您的同意。 + + + + + 三、信息的共享与披露 + + + + + 我们不会向第三方出售您的个人信息。仅在以下情形下,我们可能会共享或披露您的信息: + + + + + 3.1 第三方服务调用:为实现语音交互、视觉理解等功能,您的语音数据、图像数据和文本内容可能会被传输至第三方AI服务提供商(如语言模型、语音识别、语音合成、视觉模型服务商)进行处理。我们会选择具备合理安全保障能力的服务商,但请您知悉第三方服务商将按照其自身的隐私政策处理相关数据。 + + + + + 3.2 法律要求:根据适用的法律法规、法律程序或政府主管部门的要求,我们可能需要披露您的个人信息。 + + + + + 3.3 安全保障:为保护运营者、其他用户或公众的权益、财产或安全免遭损害,在合理必要的范围内使用或披露个人信息。 + + + + + 3.4 征得同意:在获得您明确同意的前提下,我们可能会与第三方共享您的个人信息。 + + + + + 四、信息的存储与保护 + + + + + 4.1 存储地点:您的个人信息将存储在运营者部署本服务的服务器上,包括但不限于数据库(MySQL/PostgreSQL)和缓存服务(Redis)。 + + + + + 4.2 存储期限:我们将在为您提供服务所必需的期限内保留您的个人信息。当您注销账号后,我们将在合理时间内删除或匿名化处理您的个人信息,法律法规另有规定的除外。 + + + + + 4.3 安全措施:我们采取合理的技术和管理措施保护您的个人信息安全,包括但不限于数据加密、访问控制、安全审计等。但请您理解,互联网并非绝对安全的环境,我们无法保证信息传输和存储的绝对安全性。 + + + + + 4.4 安全事件处理:如发生个人信息安全事件,我们将按照法律法规的要求,及时向您告知安全事件的基本情况、可能的影响、已采取或将要采取的处置措施等。 + + + + + 4.5 开源项目特别说明:本服务为开源项目,存在两种运营模式: + + + + + (1)自行部署:如您自行部署本服务,运营者仅为代码提供方,实际的数据存储和处理由您自行负责。 + + + + + (2)测试平台:如您使用运营者部署的测试平台,您的数据将由运营人员负责管理和保护。 + + + + + 4.6 数据跨境传输:本服务在提供智能交互功能时,可能需要调用境外第三方AI服务提供商的接口。 + + + + + 五、您的权利 + + + + + 5.1 查询与访问:您可通过智控台查看和管理您的账号信息、设备信息、智能体配置等个人信息。 + + + + + 5.2 更正与修改:当您发现个人信息有误时,您可通过智控台自行更正,或联系运营者协助处理。 + + + + + 5.3 删除:在以下情形下,您可请求我们删除您的个人信息:(1)处理目的已实现、无法实现或不再必要;(2)我们违反法律法规或与您的约定收集、使用个人信息;(3)注销账号。 + + + + + 5.4 账号注销:您可通过智控台的账号设置功能注销账号,或联系运营者进行处理。 + + + + + 5.5 撤回同意:您可随时撤回您此前向我们作出的同意授权。 + + + + + 六、未成年人信息保护 + + + + + 6.1 我们高度重视未成年人个人信息的保护。若您是未满18周岁的未成年人,请在监护人的指导和同意下使用本服务。 + + + + + 6.2 如果监护人发现未成年人未经其同意向我们提供了个人信息,请联系运营者,我们将尽快删除相关信息。 + + + + + 6.3 对于经监护人同意使用本服务的未成年人,我们将按照法律法规的规定,给予其个人信息更严格的保护。 + + + + + 七、第三方服务说明 + + + + + 7.1 本服务在提供智能交互功能时,需要调用第三方服务,包括但不限于:语音活动检测服务(VAD)、语音识别服务(ASR)、大语言模型服务(LLM)、语音合成服务(TTS)、视觉模型服务、短信验证码服务、MQTT消息代理服务、数据库服务。 + + + + + 7.2 上述第三方服务提供商将按照其各自的隐私政策对数据进行处理。我们建议您在使用本服务前,了解相关第三方服务商的隐私政策。 + + + + + 八、Cookie及类似技术的使用 + + + + + 8.1 本服务可能使用Cookie及类似技术来保存您的登录状态、记录您的偏好设置等,以便为您提供更好的使用体验。 + + + + + 8.2 您可以通过浏览器设置管理Cookie。但请注意,如果禁用Cookie,可能会影响本服务的部分功能。 + + + + + 九、隐私政策的变更 + + + + + 9.1 我们可能会根据业务调整、法律法规变化等原因对本隐私政策进行修订。修订后的隐私政策将通过本平台公告等方式予以发布。 + + + + + 9.2 如您在隐私政策修订后继续使用本服务,则视为您已接受修订后的隐私政策。 + + + + + 十、信息安全提示 + + + + + 10.1 请勿在与AI的语音或文字交互中透露您的财产账户、银行卡号、信用卡号、密码、身份证号等敏感个人信息,否则由此带来的损失由您自行承担。 + + + + + 10.2 请妥善保管您的账号和密码,不要将账号信息告知他人或与他人共享账号。 + + + + + 10.3 如您发现个人信息可能被泄露,请及时联系运营者采取措施。 + + + + + 十一、适用法律 + + + + + 11.1 本隐私政策的制定、解释、执行及争议解决均适用中华人民共和国法律法规(为本隐私政策之目的,不包括港澳台地区法律)。 + + + + + 11.2 如本隐私政策的任何条款与中华人民共和国现行法律法规相抵触,以法律法规的规定为准,其余条款仍然有效。 + + + + + + diff --git a/main/manager-mobile/src/pages/login/user-agreement-en.vue b/main/manager-mobile/src/pages/login/user-agreement-en.vue new file mode 100644 index 00000000..be9369a1 --- /dev/null +++ b/main/manager-mobile/src/pages/login/user-agreement-en.vue @@ -0,0 +1,539 @@ + +{ + "layout": "default", + "style": { + "navigationStyle": "custom", + "navigationBarTitleText": "User Agreement" + } +} + + + + + + + + + + + + + + + + User Agreement + + + + + Last Updated: March 10, 2026 + + + + + Important Notice + + + + + Welcome to use the XiaoZhi Backend Service (hereinafter referred to as "the Service"). The Service is designed to provide backend service support for XiaoZhi AI hardware devices, including but not limited to intelligent voice interaction, visual understanding, intent recognition, conversation memory, knowledge base Q&A, device management, and agent management. The operator of this Service is the actual deployer and administrator of the Service (hereinafter referred to as "Operator" or "we"). + + + + + Before registering, logging in, or using the Service, please carefully read and fully understand all terms of this Agreement, especially the terms that are highlighted in bold and may have significant impact on your interests, including but not limited to disclaimers and liability limitations. + + + + + When you complete registration, login, or otherwise use the Service following the on-screen instructions, it signifies that you have fully read, understood, and accepted all contents of this Agreement. If you disagree with this Agreement or any of its terms, please stop using the Service immediately. + + + + + This Agreement may be updated and revised based on actual circumstances. The revised Agreement will be published through the Service's announcement mechanisms. The revised Agreement shall take effect from the date of publication. If you continue to use the Service after the Agreement revision, it shall be deemed that you have accepted the revised Agreement. + + + + + + I. Definitions + + + + + XiaoZhi Backend Service: refers to the XiaoZhi Backend Service and its backend service system, including but not limited to the Admin Console (management backend), API interfaces, WebSocket communication services, etc. + + + + + Admin Console: refers to the web management interface provided by the Service for device management, agent configuration, user management, and other functions. + + + + + User: refers to natural persons, legal persons, or other organizations who register or otherwise use the Service, hereinafter referred to as "you". + + + + + Intelligent Agent (Agent): refers to an AI character created and configured within the Service, containing a collection of capabilities such as language models, speech recognition, speech synthesis, visual understanding, intent recognition, conversation memory, and knowledge base. + + + + + Device: refers to ESP32 and other hardware devices connected and managed through the Service. + + + + + + II. Scope of Agreement + + + + + This Agreement is a legal agreement between you and the Operator regarding your use of the Service. This Agreement applies to all your actions when using the Service through the Admin Console or other means. + + + + + The source code of the Service follows the corresponding open-source license. This Agreement governs your use of the Service and does not affect the rights granted to you by the open-source license itself. + + + + + + III. Account Registration and Use + + + + + 3.1 User Eligibility: You confirm that before using the Service, you should have the capacity for civil conduct as required by the laws of the People's Republic of China. If you are a minor, you should use the Service under the company and guidance of your legal guardian. + + + + + 3.2 Account Registration: You may register and log in to the Service through mobile phone verification code, username/password, or other methods. You shall provide true, accurate, and complete registration information and update it promptly. + + + + + 3.3 Account Security: You shall properly keep your account and password safe. All consequences arising from account leakage or unauthorized use by others due to your reasons shall be borne by you. If you discover any security risks with your account, please contact the Operator immediately. + + + + + 3.4 Account Usage Restrictions: Your account is for your personal use only. Without the Operator's consent, you shall not transfer, rent, or lend your account to any third party in any way. + + + + + 3.5 Account Cancellation: If you need to cancel your account, you may do so through the account settings in the Admin Console or contact the Operator for processing. After account cancellation, related data will be deleted and cannot be recovered. Please proceed with caution. + + + + + + IV. Service Content + + + + + 4.1 Service Overview: Relying on artificial intelligence technology, the Service provides intelligent interaction services for connected hardware devices through API calls to third-party generative AI models, including but not limited to Voice Activity Detection (VAD), Automatic Speech Recognition (ASR), Large Language Model (LLM), Text-to-Speech (TTS), Vision Large Language Model (VLLM), Intent Recognition, Conversation Memory, and Retrieval-Augmented Generation (RAG). + + + + + 4.2 Agent Management: You can create and configure Agents through the Admin Console, including setting role templates, selecting language models, configuring voice parameters, setting intent recognition rules, managing knowledge bases, enabling conversation memory, configuring Agent plugins, etc. The Agent settings shall not violate national laws and regulations. + + + + + 4.3 Device Management: You can bind and manage your hardware devices through the Admin Console, perform device configuration, firmware updates, OTA remote upgrades, etc. You shall ensure that the devices you manage are lawfully owned or authorized by you. + + + + + 4.4 Visual Understanding: The Service supports image capture through device cameras and uses third-party vision models for image recognition and scene understanding. You shall ensure that image capture complies with relevant laws and regulations and does not infringe upon others' privacy. + + + + + 4.5 Intent Recognition: The Service can understand the intent of user commands through intent recognition and trigger corresponding operations or services, such as controlling smart devices, querying information, etc. + + + + + 4.6 Conversation Memory: The Service can record and store summaries of your interaction history with the Agent to provide more coherent and personalized interaction experiences in subsequent conversations. You can manage or clear memory data in the Admin Console. + + + + + 4.7 Knowledge Base: The Service supports uploading documents, texts, and other content to build knowledge bases. Agents can retrieve knowledge base content during conversations to provide Q&A services. You shall ensure that uploaded knowledge base content does not infringe upon third-party intellectual property rights and does not contain content that violates laws and regulations. + + + + + 4.8 Voice Print Recognition: The Service supports voice print recognition. You can register voice print samples to achieve speaker identity verification and personalized services. Voice print data will be used for identity verification purposes. + + + + + 4.9 Voice Cloning: The Service supports voice cloning. You can clone custom voice timbres by providing audio samples. Cloned voices are for your personal use only and shall not be used to impersonate others or engage in illegal activities. + + + + + 4.10 MCP Endpoints: the Service supports MCP (Model Context Protocol) and can serve as an MCP Server to provide tool calling capabilities to external systems, or as an MCP Client to call external MCP services, achieving standardized integration with external systems. + + + + + 4.11 Context Providers: The Service supports Context Provider functionality, which can obtain real-time information from external data sources, such as weather, news, stocks, etc., providing Agents with richer knowledge sources. + + + + + 4.12 MQTT Protocol: The Service supports MQTT (Message Queuing Telemetry Transport) protocol for message communication between IoT devices. You can use the MQTT protocol to send device control commands, monitor device status, etc. + + + + + 4.13 Service Disclaimer: The conversations and responses generated by third-party AI models that the Service depends on are for reference only and do not constitute professional advice in any field. You shall not use the output content as professional advice in medical, legal, financial, or other professional fields. Any judgments or decisions you make based on the output content shall be entirely at your own responsibility. + + + + + 4.14 Service Fees: The Service is a free open-source project and does not charge any usage fees from users. It only provides platform capabilities for calling third-party services and does not involve any paid functions or value-added services. + + + + + The Service supports multiple AI service providers with different billing models as follows: + + + + + (1) Free Services: Some service providers offer free quotas or completely free services, such as Zhipu AI (free models like glm-4-flash), Microsoft EdgeTTS voice synthesis, etc. + + + + + (2) Pay-as-you-go: Some service providers charge based on API usage, such as OpenAI, Alibaba Cloud Intelligent Speech, Baidu Wenxin, iFlytek, etc. You need to pay the corresponding fees to third-party service providers yourself. Such fees are unrelated to this Service. + + + + + (3) Local Deployment: The Service supports fully local AI deployment solutions, such as FunASR speech recognition, FishSpeech voice synthesis, Ollama local large models, etc. Local deployment does not require network fees or API usage fees but requires sufficient local computing resources. + + + + + 4.15 Service Changes: The Operator reserves the right to adjust, upgrade, or terminate the Service content as actual circumstances require, and will provide notice as far in advance as possible. + + + + + + V. User Conduct Standards + + + + + 5.1 Legal Use: When using the Service, you shall comply with the laws and regulations of the People's Republic of China and relevant international treaties, and shall not use the Service for any illegal activities. + + + + + 5.2 Prohibited Conduct: You promise not to engage in the following behaviors when using the Service: + + + + + (1) Publishing, transmitting, or storing content that endangers national security or social stability, including but not limited to content involving subverting state power, damaging national honor and interests, or inciting ethnic hatred. + + + + + (2) Publishing, transmitting, or storing content that infringes upon the legitimate rights and interests of others, including but not limited to infringing upon intellectual property rights, privacy rights, reputation rights, etc. + + + + + (3) Publishing, transmitting, or storing obscene, pornographic, violent, terrorist, or crime-inciting content. + + + + + (4) Publishing false information, spreading rumors, or engaging in fraudulent activities. + + + + + (5) Interfering with the normal operation of the Service in any way, including but not limited to attacking servers, spreading malicious programs, or malicious consuming system resources. + + + + + (6) Unauthorized reverse engineering, decompiling, or attempting to obtain system source code of the Service (this clause does not limit your lawful use of open-source code according to the open-source license). + + + + + (7) Using the Service for automated batch operations, malicious consuming API call quotas or other system resources. + + + + + (8) Entering content that violates laws, regulations, or public order and good customs in Agent settings. + + + + + (9) Using the Service to harm or attempt to harm minors. + + + + + (10) Other behaviors that violate laws, regulations, this Agreement, or may harm the legitimate rights and interests of the Operator or third parties. + + + + + 5.3 Handling of Violations: If you violate the above conduct standards, the Operator has the right to take measures such as warnings, feature restrictions, service suspension, or account banning based on the severity of the situation, and reserves the right to pursue legal liability. + + + + + + VI. Intellectual Property + + + + + 6.1 Open-source License: The Service is an open-source project, and its source code follows the corresponding open-source license. You may use the relevant source code in compliance with the license terms. + + + + + 6.2 Service Content Ownership: Except for open-source code, the intellectual property rights of interface designs, icons, copy, and other independently created content in the Service belong to the Operator. + + + + + 6.3 User Content: The intellectual property rights of content you input, upload, or generate through the Service shall be determined according to relevant laws and regulations. You grant the Operator the right to store and process your input content for the purpose of maintaining and improving the Service. + + + + + 6.4 Third-party Rights: When using the Service, you should respect the intellectual property rights and other legitimate rights of third parties. You shall bear all responsibilities for any disputes arising from your infringement of third-party rights. + + + + + + VII. Privacy Protection + + + + + 7.1 Information Collection: To provide the Service, the Operator may collect your registration information (such as phone number, username), device information, usage logs, etc. For specific personal information collection and usage rules, please refer to the Privacy Policy. + + + + + 7.2 Information Protection: The Operator will take reasonable technical and management measures to protect the security of your personal information. However, due to the openness of the Internet, the Operator cannot absolutely guarantee information security. Please pay attention to protecting your personal sensitive information. + + + + + 7.3 Information Security Warning: Please do not disclose your sensitive personal information such as property accounts, bank card numbers, passwords, etc. to AI during your use of the Service. Any losses resulting from this shall be borne by you. + + + + + + VIII. Disclaimer + + + + + 8.1 AI-Generated Content: The Service relies on third-party AI models to provide intelligent interaction capabilities. The content generated by AI may be inaccurate, incomplete, or inappropriate. The Operator does not make any guarantees regarding the authenticity, accuracy, or completeness of AI-generated content. + + + + + 8.2 Service Interruption: The Operator shall not be responsible for service interruptions or abnormalities caused by the following reasons: + + + + + (1) Force majeure factors, such as natural disasters, pandemics, wars, etc. + + + + + (2) Public service factors such as power supply failures or communication network failures. + + + + + (3) Service failures or policy adjustments of third-party AI model service providers. + + + + + (4) Temporary service interruptions caused by system maintenance or upgrades. + + + + + (5) Network security incidents such as hacker attacks or computer viruses. + + + + + (6) Service adjustments due to laws, regulations, or government controls. + + + + + (7) Other situations not caused by the Operator's fault. + + + + + 8.3 Third-party Services: The Service may involve third-party provided language models, speech recognition, speech synthesis, vision models, intent recognition, and other services. You should also comply with the terms of service of third parties when using them. For issues arising from third-party services, please contact the third party directly. + + + + + 8.4 Open-source Statement: The Service is an open-source project provided "as is". To the maximum extent permitted by law, the Operator does not make any express or implied guarantees regarding the merchantability, fitness for a particular purpose, or non-infringement of the Service. + + + + + 8.5 Special Open-source Software Statement: This project is open-source software. This Service has no commercial cooperation relationship with any third-party API service providers it connects to (including but not limited to platforms such as speech recognition, large language models, speech synthesis, etc.) and does not provide any form of guarantee for their service quality and capital security. This software does not host any account keys, does not participate in capital flow, and does not bear the risk of recharge capital losses. + + + + + 8.6 Security Warning: This project functions are not fully developed and have not passed network security assessment. Please do not use it in production environments. If you deploy this project for learning in a public network environment, you must take necessary protective measures, including but not limited to setting strong passwords, restricting access permissions, enabling HTTPS encrypted transmission, etc. + + + + + + IX. Protection of Minors + + + + + 9.1 If you are a minor under 18 years of age, you should use the Service under the guidance and consent of your guardian. + + + + + 9.2 Guardians should strengthen supervision of minors using the Service, guide minors to use it reasonably, and avoid excessive reliance. + + + + + 9.3 Minors should pay attention to personal information protection when using the Service and avoid uploading or disclosing personal sensitive information. + + + + + + X. Agreement Termination + + + + + 10.1 User Termination: You have the right to stop using the Service and cancel your account at any time. + + + + + 10.2 Operator Termination: The Operator has the right to terminate providing services to you under the following circumstances: + + + + + (1) You violate the terms of this Agreement. + + + + + (2) You use the Service for illegal activities. + + + + + (3) As required by laws, regulations, or policies. + + + + + (4) The Operator decides to stop operating the Service. + + + + + 10.3 Post-termination Handling: After the Agreement is terminated, the Operator is not obligated to retain your account information and related data. The Operator still has the right to pursue your breach of contract liability during the validity period of the Agreement. + + + + + + XI. Governing Law and Dispute Resolution + + + + + 11.1 The formation, effectiveness, interpretation, revision, termination, and dispute resolution of this Agreement are governed by the laws of the People's Republic of China. + + + + + 11.2 Any disputes arising from this Agreement or the Service shall be resolved through friendly negotiation between both parties; if negotiation fails, either party has the right to bring a lawsuit to the people's court with jurisdiction at the Operator's location. + + + + + 11.3 If any provision of this Agreement is determined to be invalid or unenforceable, it does not affect the validity of the remaining provisions. + + + + + + XII. Miscellaneous + + + + + 12.1 This Agreement constitutes the complete agreement between you and the Operator regarding your use of the Service. + + + + + 12.2 The Operator's failure to exercise or delay in exercising any rights under this Agreement does not constitute a waiver of such rights. + + + + + + diff --git a/main/manager-mobile/src/pages/login/user-agreement-zh.vue b/main/manager-mobile/src/pages/login/user-agreement-zh.vue new file mode 100644 index 00000000..e612a187 --- /dev/null +++ b/main/manager-mobile/src/pages/login/user-agreement-zh.vue @@ -0,0 +1,542 @@ + +{ + "layout": "default", + "style": { + "navigationStyle": "custom", + "navigationBarTitleText": "用户协议" + } +} + + + + + + + + + + + + + + + + {{ t('login.userAgreement') }} + + + + + 更新日期:2026年3月10日 + + + + + 提示条款 + + + + + 欢迎您使用小智后端服务(以下简称"本服务")。本服务旨在为小智AI硬件设备提供后端服务支持,包括但不限于智能语音交互、视觉理解、意图识别、对话记忆、知识库问答、设备管理、智能体管理等功能。本服务的运营方为本服务的实际部署者和管理者(以下简称"运营者"或"我们")。 + + + + + 在您注册、登录或使用本服务之前,请您务必审慎阅读、充分理解本协议各条款内容,特别是以加粗形式提示您注意的可能与您利益有重大关系的条款,包括但不限于免责声明、责任限制等条款。 + + + + + 当您按照页面提示完成注册、登录或以其他方式使用本服务时,即表示您已充分阅读、理解并接受本协议的全部内容。如果您不同意本协议或其中任何条款,请立即停止使用本服务。 + + + + + 本协议可能根据实际情况进行更新和修订,修订后的协议将通过本平台公告等方式予以公示。修订后的协议自公示之日起生效,如您在协议修订后继续使用本服务,则视为您已接受修订后的协议。 + + + + + + 一、定义 + + + + + 小智后端服务:指小智后端服务及其部署运行的后端服务系统,包括但不限于智控台(管理后台)、API接口、WebSocket通信服务等。 + + + + + 智控台:指本服务提供的Web管理界面,用于设备管理、智能体配置、用户管理等功能。 + + + + + 用户:指通过注册或其他方式使用本服务的自然人、法人或其他组织,以下简称"您"。 + + + + + 智能体:指在本服务中创建和配置的AI角色,包含语言模型、语音识别、语音合成、视觉理解、意图识别、对话记忆、知识库等能力的集合。 + + + + + 设备:指通过本服务进行连接和管理的ESP32等硬件设备。 + + + + + + 二、协议范围 + + + + + 本协议是您与运营者之间关于使用本服务的法律协议。本协议适用于您通过智控台或其他方式使用本服务的全部行为。 + + + + + 本服务的源代码遵循相应的开源许可证。本协议约束您对本服务的使用行为,不影响开源许可证本身赋予您的权利。 + + + + + + 三、账号注册与使用 + + + + + 3.1 用户资格:您确认,在使用本服务前,您应当具备中华人民共和国法律规定的与您行为相适应的民事行为能力。若您为未成年人,应在法定监护人的陪同和指导下使用本服务。 + + + + + 3.2 账号注册:您可通过手机号验证码或用户名密码等方式注册和登录本服务。您应当提供真实、准确、完整的注册信息,并及时更新。 + + + + + 3.3 账号安全:您应妥善保管您的账号和密码,因您的原因导致账号泄露或被他人冒用所产生的一切后果,由您自行承担。如发现账号存在安全隐患,请立即联系运营者。 + + + + + 3.4 账号使用限制:您的账号仅限您本人使用,未经运营者同意,不得以任何方式将账号转让、出租或借给第三方使用。 + + + + + 3.5 账号注销:如您需要注销账号,可通过智控台的账号设置功能进行操作,或联系运营者进行处理。账号注销后,相关数据将被删除且无法恢复,请谨慎操作。 + + + + + + 四、服务内容 + + + + + 4.1 服务概述:本服务依托人工智能技术,通过API接口调用第三方生成式人工智能模型,为连接的硬件设备提供智能交互服务,包括但不限于语音活动检测(VAD)、语音识别(ASR)、语义理解(LLM)、语音合成(TTS)、视觉理解(VLLM)、意图识别(Intent)、对话记忆(Memory)、知识库(RAG)等。 + + + + + 4.2 智能体管理:您可通过智控台创建和配置智能体,包括设定角色模板、选择语言模型、配置语音参数、设置意图识别规则、管理知识库、开启对话记忆、配置智能体插件等。智能体的设定内容不得违反国家法律法规。 + + + + + 4.3 设备管理:您可通过智控台绑定和管理您的硬件设备,进行设备配置、固件更新、OTA远程升级等操作。您应确保所管理的设备为您合法拥有或已获得授权。 + + + + + 4.4 视觉理解:本服务支持通过设备摄像头采集图像,调用第三方视觉模型进行图像识别和场景理解。您应确保采集图像的行为符合相关法律法规,不得侵犯他人隐私。 + + + + + 4.5 意图识别:本服务可通过意图识别功能理解用户指令的意图,并据此触发相应的操作或服务,如控制智能设备、查询信息等。 + + + + + 4.6 对话记忆:本服务可记录和存储您与智能体的交互历史摘要,以便在后续对话中提供更连贯、个性化的交互体验。您可在智控台管理或清除记忆数据。 + + + + + 4.7 知识库:本服务支持您上传文档、文本等内容构建知识库,智能体可在对话中检索知识库内容为您提供问答服务。您应确保上传的知识库内容不侵犯第三方知识产权,且不包含违反法律法规的内容。 + + + + + 4.8 声纹识别:本服务支持声纹识别功能,您可注册声纹样本以实现说话人身份验证和个性化服务。声纹数据将用于身份验证目的。 + + + + + 4.9 语音克隆:本服务支持语音克隆功能,您可通过提供音频样本克隆自定义音色。克隆音色仅供您本人使用,不得用于仿冒他人或从事违法违规活动。 + + + + + 4.10 MCP接入点:本服务支持MCP(Model Context Protocol)协议,可作为MCP Server向外部提供工具调用能力,也可作为MCP Client调用外部MCP服务,实现与外部系统的标准化集成。 + + + + + 4.11 上下文提供者:本服务支持上下文提供者(Context Provider)功能,可从外部数据源获取实时信息,如天气、新闻、股票等,为智能体提供更丰富的知识来源。 + + + + + 4.12 MQTT协议:本服务支持MQTT(Message Queuing Telemetry Transport)协议,用于与物联网设备之间的消息通信。您可通过MQTT协议实现设备控制指令下发、设备状态监控等功能。 + + + + + 4.13 服务说明:本服务所依赖的第三方AI模型生成的对话、答复内容仅供参考,不构成任何专业建议。您不得将输出内容作为医疗、法律、金融等领域的专业建议。您根据输出内容所作的任何判断或决策,由您自行承担全部责任。 + + + + + 4.14 服务费用:本服务为免费开源项目,不向用户收取任何使用费用,仅提供调用第三方服务的平台能力,不涉及任何付费功能或增值服务。 + + + + + 本服务支持多种AI服务提供商,不同提供商的收费模式如下: + + + + + (1)免费服务:部分服务商提供免费额度或完全免费的服务,如智谱AI(glm-4-flash等免费模型)、微软EdgeTTS语音合成等。 + + + + + (2)按量付费服务:部分服务商按API调用量计费,如OpenAI、阿里云智能语音、百度文心、讯飞等。您需要自行向第三方服务商支付相应费用,该等费用与本服务无关。 + + + + + (3)本地部署方案:本服务支持完全本地部署的AI方案,如FunASR语音识别、FishSpeech语音合成、Ollama本地大模型等。本地部署无需网络费用和API调用费用,但需要本地具备足够的计算资源。 + + + + + 4.15 服务变更:运营者保留根据实际情况对服务内容进行调整、升级或终止的权利,并将尽可能提前予以通知。 + + + + + + 五、用户行为规范 + + + + + 5.1 合法使用:您在使用本服务时,应遵守中华人民共和国的法律法规及相关国际条约,不得利用本服务从事任何违法违规活动。 + + + + + 5.2 禁止行为:您承诺在使用本服务时不得实施以下行为: + + + + + (1)发布、传输、存储危害国家安全、社会稳定的内容,包括但不限于涉及颠覆国家政权、损害国家荣誉和利益、煽动民族仇恨等内容。 + + + + + (2)发布、传输、存储侵犯他人合法权益的内容,包括但不限于侵犯知识产权、隐私权、名誉权等。 + + + + + (3)发布、传输、存储淫秽、色情、暴力、恐怖或教唆犯罪的内容。 + + + + + (4)发布虚假信息、散布谣言或从事欺诈行为。 + + + + + (5)以任何方式干扰本服务的正常运行,包括但不限于攻击服务器、传播恶意程序、恶意消耗系统资源等。 + + + + + (6)未经授权对本服务进行反向工程、反编译或其他试图获取系统源代码的行为(本条不限制您依据开源许可证对开源代码的合法使用)。 + + + + + (7)利用本服务进行自动化批量操作,恶意消耗API调用配额或其他系统资源。 + + + + + (8)在智能体设定中输入违反法律法规或社会公序良俗的内容。 + + + + + (9)利用本服务伤害或企图伤害未成年人。 + + + + + (10)其他违反法律法规、本协议约定或可能损害运营者及第三方合法权益的行为。 + + + + + 5.3 违规处理:如您违反上述行为规范,运营者有权视情节严重程度采取警告、限制功能、暂停服务、封禁账号等措施,并保留追究法律责任的权利。 + + + + + + 六、知识产权 + + + + + 6.1 开源许可:本服务为开源项目,其源代码遵循相应的开源许可证。您可以在遵守该许可证条款的前提下使用相关源代码。 + + + + + 6.2 服务内容权属:除开源代码外,本服务中的界面设计、图标、文案及其他运营者独立创作的内容,其知识产权归运营者所有。 + + + + + 6.3 用户内容:您通过本服务输入、上传或生成的内容,其知识产权归属依照相关法律法规确定。您授予运营者为维护和改进服务之目的,对您输入内容进行存储和必要处理的权利。 + + + + + 6.4 第三方权益:您在使用本服务时,应尊重第三方的知识产权及其他合法权益。因您侵犯第三方权益而引发的纠纷,由您自行承担全部责任。 + + + + + + 七、隐私保护 + + + + + 7.1 信息收集:为提供本服务,运营者可能会收集您的注册信息(如手机号、用户名)、设备信息、使用日志等。具体的个人信息收集和使用规则请参阅《隐私政策》。 + + + + + 7.2 信息保护:运营者将采取合理的技术和管理措施保护您的个人信息安全。但由于互联网的开放性,运营者不能绝对保证信息安全,请您注意保护个人敏感信息。 + + + + + 7.3 信息安全提示:请勿在使用本服务过程中向AI透露您的财产账户、银行卡、密码等敏感个人信息,否则由此带来的损失由您自行承担。 + + + + + + 八、免责声明 + + + + + 8.1 AI生成内容:本服务依赖第三方AI模型提供智能交互能力,AI生成的内容可能存在不准确、不完整或不恰当之处。运营者不对AI生成内容的真实性、准确性、完整性作任何保证。 + + + + + 8.2 服务中断:因以下原因导致服务中断或异常,运营者不承担责任: + + + + + (1)不可抗力因素,如自然灾害、疫情、战争等。 + + + + + (2)电力供应故障、通信网络故障等公共服务因素。 + + + + + (3)第三方AI模型服务商的服务故障或政策调整。 + + + + + (4)系统维护、升级导致的临时性服务中断。 + + + + + (5)黑客攻击、计算机病毒等网络安全事件。 + + + + + (6)法律法规或政府管制导致的服务调整。 + + + + + (7)其他非运营者过错导致的情形。 + + + + + 8.3 第三方服务:本服务可能涉及第三方提供的语言模型、语音识别、语音合成、视觉模型、意图识别等服务。您在使用时应同时遵守第三方的服务条款。因第三方服务引发的问题,请直接与第三方联系。 + + + + + 8.4 开源声明:本服务为开源项目,按"现状"提供。在法律允许的最大范围内,运营者不就本服务的适销性、特定用途适用性或不侵权性作任何明示或暗示的保证。 + + + + + 8.5 开源软件特别声明:本项目为开源软件,本服务与对接的任何第三方API服务商(包括但不限于语音识别、大模型、语音合成等平台)均不存在商业合作关系,不为其服务质量及资金安全提供任何形式的担保。本软件不托管任何账户密钥、不参与资金流转、不承担充值资金损失风险。 + + + + + 8.6 安全警告:本项目功能未完善,且未通过网络安全测评,请勿在生产环境中使用。如果您在公网环境中部署学习本项目,请务必做好必要的防护措施,包括但不限于设置强密码、限制访问权限、启用HTTPS加密传输等。 + + + + + + 九、未成年人保护 + + + + + 9.1 若您是未满18周岁的未成年人,应在监护人的指导和同意下使用本服务。 + + + + + 9.2 监护人应加强对未成年人使用本服务的监督,引导未成年人合理使用,避免过度依赖。 + + + + + 9.3 未成年人在使用本服务时应注意个人信息保护,避免上传或透露个人敏感信息。 + + + + + + 十、协议终止 + + + + + 10.1 用户终止:您有权随时停止使用本服务并注销账号。 + + + + + 10.2 运营者终止:出现以下情形时,运营者有权终止向您提供服务: + + + + + (1)您违反本协议的约定。 + + + + + (2)您利用本服务从事违法违规活动。 + + + + + (3)根据法律法规或政策要求。 + + + + + (4)运营者决定停止运营本服务。 + + + + + 10.3 终止后处理:协议终止后,运营者无义务保留您的账号信息及相关数据。运营者仍有权依据本协议追究您在协议有效期内的违约责任。 + + + + + + 十一、法律适用与争议解决 + + + + + 11.1 本协议的订立、生效、解释、修订、终止及争议解决均适用中华人民共和国法律。 + + + + + 11.2 因本协议或本服务引发的争议,双方应友好协商解决;协商不成的,任何一方有权向运营者所在地有管辖权的人民法院提起诉讼。 + + + + + 11.3 本协议的任何条款被认定为无效或不可执行,不影响其余条款的效力。 + + + + + + 十二、其他 + + + + + 12.1 本协议构成您与运营者之间关于使用本服务的完整协议。 + + + + + 12.2 运营者未行使或延迟行使本协议项下的任何权利,不构成对该权利的放弃。 + + + + + + + + diff --git a/main/manager-mobile/src/pages/settings/index.vue b/main/manager-mobile/src/pages/settings/index.vue index 02436948..9aa52927 100644 --- a/main/manager-mobile/src/pages/settings/index.vue +++ b/main/manager-mobile/src/pages/settings/index.vue @@ -1,18 +1,21 @@ -{ + +{ "layout": "default", "style": { "navigationBarTitleText": "设置", "navigationStyle": "custom" } -} +} + @@ -269,8 +299,10 @@ onMounted(async () => { - + {{ t('settings.serverApiUrl') }} @@ -281,11 +313,13 @@ onMounted(async () => { - - + + input-class="text-[28rpx] text-[#232338]" @input="validateUrl" @blur="validateUrl" + /> {{ urlError }} @@ -293,14 +327,18 @@ onMounted(async () => { - + @click="saveServerBaseUrl" + > {{ t('settings.saveSettings') }} - + @click="resetServerBaseUrl" + > {{ t('settings.resetDefault') }} @@ -315,12 +353,15 @@ onMounted(async () => { - + + class="flex items-center justify-between border border-[#eeeeee] rounded-[16rpx] bg-[#f5f7fb] p-[24rpx] transition-all active:bg-[#eef3ff]" + > {{ t('settings.totalCacheSize') }} @@ -336,7 +377,8 @@ onMounted(async () => { + class="flex items-center justify-between border border-[#eeeeee] rounded-[16rpx] bg-[#f5f7fb] p-[24rpx]" + > {{ t('settings.cacheClear') }} @@ -347,7 +389,8 @@ onMounted(async () => { + @click="clearCache" + > {{ t('settings.clearCache') }} @@ -363,11 +406,14 @@ onMounted(async () => { - + + @click="showAbout" + > {{ t('settings.aboutUs') }} @@ -389,11 +435,14 @@ onMounted(async () => { - + + @click="showLanguageSheet = true" + > {{ t('settings.language') }} @@ -403,8 +452,8 @@ onMounted(async () => { - - {{supportedLanguages.find(lang => lang.code === currentLanguage)?.name}} + + {{ supportedLanguages.find(lang => lang.code === currentLanguage)?.name }} @@ -416,8 +465,10 @@ onMounted(async () => { - + {{ lang.name }} diff --git a/main/manager-mobile/src/pages/voiceprint/index.vue b/main/manager-mobile/src/pages/voiceprint/index.vue index 3cca4442..e6ba2ccc 100644 --- a/main/manager-mobile/src/pages/voiceprint/index.vue +++ b/main/manager-mobile/src/pages/voiceprint/index.vue @@ -3,22 +3,25 @@ import type { ChatHistory, CreateSpeakerData, VoicePrint } from '@/api/voiceprin import { computed, onMounted, ref } from 'vue' import { useMessage } from 'wot-design-uni' import { useToast } from 'wot-design-uni/components/wd-toast' -import { createVoicePrint, deleteVoicePrint, getChatHistory, getVoicePrintList, updateVoicePrint } from '@/api/voiceprint' +import { createVoicePrint, deleteVoicePrint, getAudioDownloadId, getChatHistory, getVoicePrintList, updateVoicePrint } from '@/api/voiceprint' import { t } from '@/i18n' +import { getEnvBaseUrl } from '@/utils' defineOptions({ name: 'VoicePrintManage', }) +const props = withDefaults(defineProps(), { + agentId: 'default', +}) + +const emits = defineEmits(['update-refresher-enabled']) + // 接收props interface Props { agentId?: string } -const props = withDefaults(defineProps(), { - agentId: 'default' -}) - // 获取屏幕边界到安全区域距离 let safeAreaInsets: any let systemInfo: any @@ -50,6 +53,10 @@ const chatHistoryActions = ref([]) const swipeStates = ref>({}) const loading = ref(false) +// 音频播放相关 +const audioRef = ref(null) +const playingAudioId = ref('') + // 使用传入的智能体ID const currentAgentId = computed(() => { return props.agentId @@ -130,7 +137,6 @@ async function loadChatHistory() { audioId: item.audioId, index, })) - showChatHistoryDialog.value = true } catch (error) { console.error('获取对话记录失败:', error) @@ -157,11 +163,13 @@ function openAddDialog() { introduce: '', } showAddDialog.value = true - } catch (error: any) { + } + catch (error: any) { // 捕捉声纹接口未配置错误 if (error.message && error.message.includes('请求错误[10054]')) { toast.error(t('voiceprint.voiceprintInterfaceNotConfigured')) - } else { + } + else { // 其他错误,继续打开弹窗 addForm.value = { agentId: currentAgentId.value, @@ -202,6 +210,11 @@ function selectAudioId({ item }: { item: any }) { showChatHistoryDialog.value = false } +// 点击选择 +function handleItemClick(item: any) { + selectAudioId({ item }) +} + // 提交添加说话人 async function submitAdd() { if (!addForm.value.sourceName.trim()) { @@ -274,14 +287,93 @@ async function handleDelete(id: string) { }) } +// 播放音频 +async function playAudio(audioId: string, event: Event) { + event.stopPropagation() // 阻止事件冒泡,防止关闭下拉框 + + if (!audioId) { + toast.warning(t('voiceprint.audioNotExist')) + return + } + + // 如果正在播放同一个音频,则停止 + if (playingAudioId.value === audioId) { + stopAudio() + return + } + + // 停止之前的音频 + stopAudio() + + try { + // 先获取音频下载ID + playingAudioId.value = audioId + const downloadId = await getAudioDownloadId(audioId) + + if (!downloadId) { + toast.error(t('voiceprint.getAudioFailed')) + playingAudioId.value = '' + return + } + + // 获取baseURL + const baseURL = getEnvBaseUrl() + const audioUrl = `${baseURL}/agent/play/${downloadId}` + + // 创建新的音频实例 + audioRef.value = uni.createInnerAudioContext() + audioRef.value.src = audioUrl + audioRef.value.autoplay = true + + // 监听播放结束 + audioRef.value.onEnded(() => { + playingAudioId.value = '' + }) + + // 监听播放错误 + audioRef.value.onError((error) => { + console.error('音频播放错误:', error) + toast.error(t('voiceprint.audioPlayFailed')) + playingAudioId.value = '' + }) + } + catch (error) { + console.error('播放音频失败:', error) + toast.error(t('voiceprint.audioPlayFailed')) + playingAudioId.value = '' + } +} + +// 停止音频 +function stopAudio() { + if (audioRef.value) { + audioRef.value.stop() + audioRef.value.destroy() + audioRef.value = null + } + playingAudioId.value = '' +} + +watch(() => [showAddDialog.value, showEditDialog.value], (newValues) => { + if (newValues.some((value: boolean) => value)) { + emits('update-refresher-enabled', false) + } + else { + emits('update-refresher-enabled', true) + } +}) + onMounted(async () => { // 智能体已简化为默认 loadVoicePrintList() + loadChatHistory() }) // 暴露方法给父组件 defineExpose({ + showAddDialog, + showEditDialog, refresh, }) @@ -349,7 +441,7 @@ defineExpose({ - + @@ -359,25 +451,24 @@ defineExpose({ - - - {{ t('voiceprint.addSpeaker') }} - - - - * {{ t('voiceprint.voiceVector') }} + + * + + {{ t('voiceprint.voiceVector') }} - * {{ t('voiceprint.name') }} + + * + + {{ t('voiceprint.name') }} - * {{ t('voiceprint.description') }} + + * + + {{ t('voiceprint.description') }} - {{ t('voiceprint.cancel') }} - - - {{ t('voiceprint.save') }} - + {{ t('voiceprint.cancel') }} + + + {{ t('voiceprint.save') }} + @@ -433,7 +530,7 @@ defineExpose({ safe-area-inset-bottom > - + {{ t('voiceprint.editSpeaker') }} @@ -443,11 +540,14 @@ defineExpose({ - * {{ t('voiceprint.voiceVector') }} + + * + + {{ t('voiceprint.voiceVector') }} - * {{ t('voiceprint.name') }} + + * + + {{ t('voiceprint.name') }} - * {{ t('voiceprint.description') }} + + * + + {{ t('voiceprint.description') }} - {{ t('voiceprint.cancel') }} - - - {{ t('voiceprint.save') }} - + {{ t('voiceprint.cancel') }} + + + {{ t('voiceprint.save') }} + - - + + + + + + + {{ item.name }} + + + + + + + + - diff --git a/main/manager-mobile/src/store/index.ts b/main/manager-mobile/src/store/index.ts index d960c0a4..51d14e0e 100644 --- a/main/manager-mobile/src/store/index.ts +++ b/main/manager-mobile/src/store/index.ts @@ -15,5 +15,7 @@ export default store export * from './config' export * from './plugin' +export * from './provider' +export * from './speedPitch' // 模块统一导出 export * from './user' diff --git a/main/manager-mobile/src/store/provider.ts b/main/manager-mobile/src/store/provider.ts new file mode 100644 index 00000000..76a0171c --- /dev/null +++ b/main/manager-mobile/src/store/provider.ts @@ -0,0 +1,23 @@ +import type { Providers } from '@/api/agent/types' +import { defineStore } from 'pinia' + +export const useProvider = defineStore('provider', () => { + const providers = ref([]) + + const updateProviders = (val: Providers[]) => { + providers.value = val + } + + return { + providers, + updateProviders, + } +}, { + persist: { + key: 'providers', + serializer: { + serialize: state => JSON.stringify(state.providers), + deserialize: value => ({ providers: JSON.parse(value) }), + }, + }, +}) diff --git a/main/manager-mobile/src/store/speedPitch.ts b/main/manager-mobile/src/store/speedPitch.ts new file mode 100644 index 00000000..0b9af69f --- /dev/null +++ b/main/manager-mobile/src/store/speedPitch.ts @@ -0,0 +1,26 @@ +import { defineStore } from 'pinia' + +export const useSpeedPitch = defineStore('speedPitch', () => { + const speedPitch = ref({ + ttsVolume: 0, + ttsRate: 0, + ttsPitch: 0, + }) + + const updateSpeedPitch = (val: typeof speedPitch.value) => { + speedPitch.value = val + } + + return { + speedPitch, + updateSpeedPitch, + } +}, { + persist: { + key: 'speedPitch', + serializer: { + serialize: state => JSON.stringify(state.speedPitch), + deserialize: value => ({ speedPitch: JSON.parse(value) }), + }, + }, +}) diff --git a/main/manager-mobile/src/store/user.ts b/main/manager-mobile/src/store/user.ts index 47f6d80c..a062fcc5 100644 --- a/main/manager-mobile/src/store/user.ts +++ b/main/manager-mobile/src/store/user.ts @@ -19,7 +19,7 @@ const userInfoState: UserInfo & { avatar?: string, token?: string } = { } export const useUserStore = defineStore( - 'user', + 'userInfo', () => { // 定义用户信息 const userInfo = ref({ ...userInfoState }) @@ -51,15 +51,8 @@ export const useUserStore = defineStore( */ const getUserInfo = async () => { const userData = await _getUserInfo() - const userInfoWithExtras = { - ...userData, - avatar: userInfoState.avatar, - token: uni.getStorageSync('token') || '', - } - setUserInfo(userInfoWithExtras) - uni.setStorageSync('userInfo', userInfoWithExtras) - // TODO 这里可以增加获取用户路由的方法 根据用户的角色动态生成路由 - return userInfoWithExtras + setUserInfo(userData) + return userData } /** * 退出登录 并 删除用户信息 @@ -78,6 +71,12 @@ export const useUserStore = defineStore( } }, { - persist: true, + persist: { + key: 'userInfo', + serializer: { + serialize: state => JSON.stringify(state.userInfo), + deserialize: value => ({ userInfo: JSON.parse(value) }), + }, + }, }, ) diff --git a/main/manager-mobile/src/utils/index.ts b/main/manager-mobile/src/utils/index.ts index 0d9070b4..8ac842c8 100644 --- a/main/manager-mobile/src/utils/index.ts +++ b/main/manager-mobile/src/utils/index.ts @@ -1,4 +1,6 @@ +import smCrypto from 'sm-crypto' import { pages, subPackages } from '@/pages.json' + import { isMpWeixin } from './platform' /** @@ -197,23 +199,21 @@ export function getEnvBaseUploadUrl() { return baseUploadUrl } -import smCrypto from 'sm-crypto' - /** * 生成SM2密钥对(十六进制格式) * @returns {Object} 包含公钥和私钥的对象 */ export function generateSm2KeyPairHex() { - // 使用sm-crypto库生成SM2密钥对 - const sm2 = smCrypto.sm2; - const keypair = sm2.generateKeyPairHex(); - - return { - publicKey: keypair.publicKey, - privateKey: keypair.privateKey, - clientPublicKey: keypair.publicKey, // 客户端公钥 - clientPrivateKey: keypair.privateKey // 客户端私钥 - }; + // 使用sm-crypto库生成SM2密钥对 + const sm2 = smCrypto.sm2 + const keypair = sm2.generateKeyPairHex() + + return { + publicKey: keypair.publicKey, + privateKey: keypair.privateKey, + clientPublicKey: keypair.publicKey, // 客户端公钥 + clientPrivateKey: keypair.privateKey, // 客户端私钥 + } } /** @@ -223,21 +223,21 @@ export function generateSm2KeyPairHex() { * @returns {string} 加密后的密文(十六进制格式) */ export function sm2Encrypt(publicKey: string, plainText: string): string { - if (!publicKey) { - throw new Error('公钥不能为null或undefined'); - } - - if (!plainText) { - throw new Error('明文不能为空'); - } - - const sm2 = smCrypto.sm2; - // SM2加密,添加04前缀表示未压缩公钥 - const encrypted = sm2.doEncrypt(plainText, publicKey, 1); - // 转换为十六进制格式(与后端保持一致,添加04前缀) - const result = "04" + encrypted; - - return result; + if (!publicKey) { + throw new Error('公钥不能为null或undefined') + } + + if (!plainText) { + throw new Error('明文不能为空') + } + + const sm2 = smCrypto.sm2 + // SM2加密,添加04前缀表示未压缩公钥 + const encrypted = sm2.doEncrypt(plainText, publicKey, 1) + // 转换为十六进制格式(与后端保持一致,添加04前缀) + const result = `04${encrypted}` + + return result } /** @@ -247,9 +247,56 @@ export function sm2Encrypt(publicKey: string, plainText: string): string { * @returns {string} 解密后的明文 */ export function sm2Decrypt(privateKey: string, cipherText: string): string { - const sm2 = smCrypto.sm2; - // 移除04前缀(与后端保持一致) - const dataWithoutPrefix = cipherText.startsWith("04") ? cipherText.substring(2) : cipherText; - // SM2解密 - return sm2.doDecrypt(dataWithoutPrefix, privateKey, 1); + const sm2 = smCrypto.sm2 + // 移除04前缀(与后端保持一致) + const dataWithoutPrefix = cipherText.startsWith('04') ? cipherText.substring(2) : cipherText + // SM2解密 + return sm2.doDecrypt(dataWithoutPrefix, privateKey, 1) +} + +type AnyFunction = (...args: any[]) => any + +interface DebouncedFunction extends AnyFunction { + cancel: () => void +} + +/** + * 防抖函数 + * @param fn 要防抖的函数 + * @param delay 延迟时间(毫秒),默认500ms + * @param immediate 是否立即执行,默认false + * @returns 防抖处理后的函数 + */ +export function debounce( + fn: T, + delay = 500, + immediate = false, +): DebouncedFunction { + let timer: ReturnType | null = null + + const debounced = function (this: any, ...args: Parameters) { + if (timer) { + clearTimeout(timer) + } + + if (immediate && !timer) { + fn.apply(this, args) + } + + timer = setTimeout(() => { + if (!immediate) { + fn.apply(this, args) + } + timer = null + }, delay) + } as DebouncedFunction + + debounced.cancel = () => { + if (timer) { + clearTimeout(timer) + timer = null + } + } + + return debounced } diff --git a/main/manager-web/.env b/main/manager-web/.env index 1b5f8138..d234c067 100644 --- a/main/manager-web/.env +++ b/main/manager-web/.env @@ -1 +1,3 @@ -VUE_APP_TITLE=智控台 \ No newline at end of file +VUE_APP_TITLE=智控台 +VUE_APP_DESCRIPTION=小智后端服务(xiaozhi-server)是由华南理工大学刘思源教授团队主导研发的智能终端软硬件体系后端服务系统,专为xiaozhi-esp32开源硬件打造,具备多协议兼容、声纹识别、知识库管理等核心能力。 +VUE_APP_KEYWORDS=xiaozhi-server,小智服务端,智控台,AI硬件,智能硬件,AI玩具,情感陪伴,聊天机器人,智能家居,车载机器人 diff --git a/main/manager-web/public/index.html b/main/manager-web/public/index.html index e3ae5a53..3cd3bb73 100644 --- a/main/manager-web/public/index.html +++ b/main/manager-web/public/index.html @@ -5,6 +5,8 @@ + + <%= process.env.VUE_APP_TITLE %> @@ -17,10 +19,6 @@ - - We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. - Please enable it to continue. - <% if (htmlWebpackPlugin.options.cdn && htmlWebpackPlugin.options.cdn.js) { %> diff --git a/main/manager-web/src/App.vue b/main/manager-web/src/App.vue index 180f8f0d..f101e155 100644 --- a/main/manager-web/src/App.vue +++ b/main/manager-web/src/App.vue @@ -28,17 +28,16 @@ nav { } .copyright { - text-align: center; + padding: 0 !important; color: rgb(0, 0, 0); font-size: 12px; font-weight: 400; margin-top: auto; - padding: 30px 0 20px; - position: absolute; - bottom: 0; - left: 50%; - transform: translateX(-50%); width: 100%; + height: 100%; + display: flex; + justify-content: center; + align-items: center; } .el-message { @@ -60,6 +59,11 @@ export default { isCDNEnabled: process.env.VUE_APP_USE_CDN === 'true' }; }, + created() { + // 挂载 store 状态 + this.$store.commit('setUserInfo', JSON.parse(localStorage.getItem('userInfo') || '{}')); + this.$store.commit('setPubConfig', JSON.parse(localStorage.getItem('pubConfig') || '{}')); + }, mounted() { // 检测是否为移动设备且VUE_APP_H5_URL不为空,如果两个条件都满足则跳转到H5页面 if (this.isMobileDevice() && process.env.VUE_APP_H5_URL) { diff --git a/main/manager-web/src/apis/module/agent.js b/main/manager-web/src/apis/module/agent.js index 5cbd60cb..d79f8da4 100644 --- a/main/manager-web/src/apis/module/agent.js +++ b/main/manager-web/src/apis/module/agent.js @@ -170,6 +170,9 @@ export default { RequestService.clearRequestTime(); callback(res); }) + .fail((err) => { + callback(err); + }) .networkFail(() => { RequestService.reAjaxFun(() => { this.getAgentMcpAccessAddress(agentId, callback); diff --git a/main/manager-web/src/components/ChatHistoryDialog.vue b/main/manager-web/src/components/ChatHistoryDialog.vue index 12c06621..7821ba2d 100644 --- a/main/manager-web/src/components/ChatHistoryDialog.vue +++ b/main/manager-web/src/components/ChatHistoryDialog.vue @@ -21,11 +21,35 @@ {{ message.content }} - + - {{ extractContentFromString(message.content) }} + + + + {{ item.text }} + {{ item.text }} + + + + {{ getFirstLineText(item.text) }} + + + {{ item.text }} + + + + + + {{ item.text }} + + + + + + {{ extractContentFromString(message.content) }} + @@ -49,6 +73,7 @@ -