From fdb050f6ed48b3ef7a2559ecee97e3ddae26744c Mon Sep 17 00:00:00 2001 From: hrz <1710360675@qq.com> Date: Wed, 21 Jan 2026 22:58:58 +0800 Subject: [PATCH 1/2] =?UTF-8?q?add:=E8=8E=B7=E5=8F=96=E8=AE=BE=E5=A4=87?= =?UTF-8?q?=E7=9A=84mcp=E5=B7=A5=E5=85=B7=E5=88=97=E8=A1=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../xiaozhi/common/exception/ErrorCode.java | 4 + .../device/controller/DeviceController.java | 22 +- .../modules/device/service/DeviceService.java | 10 +- .../service/impl/DeviceServiceImpl.java | 98 ++++- .../main/resources/i18n/messages.properties | 4 +- .../resources/i18n/messages_de_DE.properties | 132 +++--- .../resources/i18n/messages_en_US.properties | 4 +- .../resources/i18n/messages_vi_VN.properties | 386 +++++++++--------- .../resources/i18n/messages_zh_CN.properties | 4 +- .../resources/i18n/messages_zh_TW.properties | 32 +- 10 files changed, 404 insertions(+), 292 deletions(-) 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 c0f49754..172505a3 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 @@ -240,4 +240,8 @@ public interface ErrorCode { int RAG_ADAPTER_CACHE_ERROR = 10191; // 适配器缓存错误 int RAG_ADAPTER_TYPE_NOT_FOUND = 10192; // 适配器类型未找到 + // 设备工具相关错误码 + int DEVICE_ID_NOT_NULL = 10193; // 设备ID不能为空 + int DEVICE_NOT_EXIST = 10194; // 设备不存在 + } diff --git a/main/manager-api/src/main/java/xiaozhi/modules/device/controller/DeviceController.java b/main/manager-api/src/main/java/xiaozhi/modules/device/controller/DeviceController.java index b562542b..ff593528 100644 --- a/main/manager-api/src/main/java/xiaozhi/modules/device/controller/DeviceController.java +++ b/main/manager-api/src/main/java/xiaozhi/modules/device/controller/DeviceController.java @@ -1,6 +1,8 @@ package xiaozhi.modules.device.controller; -import java.util.*; +import java.util.List; +import java.util.Map; + import org.apache.commons.lang3.StringUtils; import org.apache.shiro.authz.annotation.RequiresPermissions; import org.springframework.beans.BeanUtils; @@ -11,6 +13,7 @@ import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; + import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; @@ -125,4 +128,21 @@ public class DeviceController { deviceService.manualAddDevice(user.getId(), dto); return new Result<>(); } + + @PostMapping("/tools/list") + @Operation(summary = "获取设备工具列表") + @RequiresPermissions("sys:role:normal") + public Result getDeviceTools(@RequestBody Map requestBody) { + String deviceId = requestBody.get("deviceId"); + if (StringUtils.isBlank(deviceId)) { + return new Result().error(ErrorCode.DEVICE_ID_NOT_NULL); + } + + Object toolsData = deviceService.getDeviceTools(deviceId); + if (toolsData == null) { + return new Result().error(ErrorCode.DEVICE_NOT_EXIST); + } + + return new Result().ok(toolsData); + } } \ No newline at end of file diff --git a/main/manager-api/src/main/java/xiaozhi/modules/device/service/DeviceService.java b/main/manager-api/src/main/java/xiaozhi/modules/device/service/DeviceService.java index c37f69f5..b34a0c4a 100644 --- a/main/manager-api/src/main/java/xiaozhi/modules/device/service/DeviceService.java +++ b/main/manager-api/src/main/java/xiaozhi/modules/device/service/DeviceService.java @@ -5,10 +5,10 @@ import java.util.List; import xiaozhi.common.page.PageData; import xiaozhi.common.service.BaseService; +import xiaozhi.modules.device.dto.DeviceManualAddDTO; import xiaozhi.modules.device.dto.DevicePageUserDTO; import xiaozhi.modules.device.dto.DeviceReportReqDTO; import xiaozhi.modules.device.dto.DeviceReportRespDTO; -import xiaozhi.modules.device.dto.DeviceManualAddDTO; import xiaozhi.modules.device.entity.DeviceEntity; import xiaozhi.modules.device.vo.UserShowDeviceListVO; @@ -87,6 +87,7 @@ public interface DeviceService extends BaseService { /** * 获取这个智能体设备理的最近的最后连接时间 + * * @param agentId 智能体id * @return 返回设备最近的最后连接时间 */ @@ -116,9 +117,14 @@ public interface DeviceService extends BaseService { * 根据MAC地址搜索设备 * * @param macAddress MAC地址关键词 - * @param userId 用户ID + * @param userId 用户ID * @return 设备列表 */ List searchDevicesByMacAddress(String macAddress, Long userId); + /** + * 获取设备工具列表 + */ + Object getDeviceTools(String deviceId); + } \ No newline at end of file diff --git a/main/manager-api/src/main/java/xiaozhi/modules/device/service/impl/DeviceServiceImpl.java b/main/manager-api/src/main/java/xiaozhi/modules/device/service/impl/DeviceServiceImpl.java index 8c9d6232..856b627b 100644 --- a/main/manager-api/src/main/java/xiaozhi/modules/device/service/impl/DeviceServiceImpl.java +++ b/main/manager-api/src/main/java/xiaozhi/modules/device/service/impl/DeviceServiceImpl.java @@ -4,21 +4,20 @@ import java.nio.charset.StandardCharsets; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.time.Instant; -import java.util.*; +import java.util.Base64; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.TimeZone; +import java.util.UUID; import java.util.stream.Collectors; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; -import cn.hutool.core.date.DatePattern; -import cn.hutool.core.date.DateUtil; -import cn.hutool.core.map.MapUtil; -import cn.hutool.core.util.StrUtil; -import cn.hutool.crypto.digest.DigestUtil; -import cn.hutool.http.ContentType; -import cn.hutool.http.Header; -import cn.hutool.http.HttpRequest; -import cn.hutool.json.JSONUtil; import org.apache.commons.lang3.StringUtils; import org.springframework.aop.framework.AopContext; import org.springframework.scheduling.annotation.Async; @@ -30,7 +29,16 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.map.MapUtil; import cn.hutool.core.util.RandomUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.crypto.digest.DigestUtil; +import cn.hutool.http.ContentType; +import cn.hutool.http.Header; +import cn.hutool.http.HttpRequest; +import cn.hutool.json.JSONUtil; import jakarta.servlet.http.HttpServletRequest; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -44,7 +52,6 @@ import xiaozhi.common.service.impl.BaseServiceImpl; import xiaozhi.common.user.UserDetail; import xiaozhi.common.utils.ConvertUtils; import xiaozhi.common.utils.DateUtils; -import xiaozhi.common.utils.Result; import xiaozhi.common.utils.ToolUtil; import xiaozhi.modules.device.dao.DeviceDao; import xiaozhi.modules.device.dto.DeviceManualAddDTO; @@ -179,7 +186,7 @@ public class DeviceServiceImpl extends BaseServiceImpl .header(Header.CONTENT_TYPE, ContentType.JSON.getValue()) .header(Header.AUTHORIZATION, "Bearer " + generateBearerToken()) .body(JSONUtil.toJsonStr(params)) - .timeout(10000) //超时,毫秒 + .timeout(10000) // 超时,毫秒 .execute().body(); return resultMessage; } @@ -649,14 +656,13 @@ public class DeviceServiceImpl extends BaseServiceImpl return mqtt; } - /** * 生成BearerToken */ private String generateBearerToken() { try { String dateStr = DateUtil.format(new Date(), DatePattern.NORM_DATE_PATTERN); - String signatureKey = sysParamsService.getValue(Constant.SERVER_MQTT_SECRET,false); + String signatureKey = sysParamsService.getValue(Constant.SERVER_MQTT_SECRET, false); if (ToolUtil.isEmpty(signatureKey)) { return null; } @@ -665,4 +671,68 @@ public class DeviceServiceImpl extends BaseServiceImpl return null; } } + + @Override + public Object getDeviceTools(String deviceId) { + // 从系统参数中获取MQTT网关地址 + String mqttGatewayUrl = sysParamsService.getValue("server.mqtt_manager_api", true); + if (StringUtils.isBlank(mqttGatewayUrl) || "null".equals(mqttGatewayUrl)) { + return null; + } + + // 获取设备信息 + DeviceEntity device = baseDao.selectById(deviceId); + if (device == null) { + return null; + } + + // 检查设备是否属于当前用户 + UserDetail user = SecurityUser.getUser(); + if (!device.getUserId().equals(user.getId())) { + return null; + } + + // 构建clientId + String macAddress = Optional.ofNullable(device.getMacAddress()).orElse("unknown").replace(":", "_"); + String groupId = Optional.ofNullable(device.getBoard()).orElse("GID_default").replace(":", "_"); + String clientId = StrUtil.format("{}@@@{}@@@{}", groupId, macAddress, macAddress); + + // 构建完整的URL + String url = StrUtil.format("http://{}/api/commands/{}", mqttGatewayUrl, clientId); + + // 构建请求体 + Map payload = MapUtil + .builder(new HashMap()) + .put("jsonrpc", "2.0") + .put("id", 2) + .put("method", "tools/list") + .put("params", MapUtil.builder(new HashMap()) + .put("withUserTools", true) + .build()) + .build(); + + Map requestBody = MapUtil + .builder(new HashMap()) + .put("type", "mcp") + .put("payload", payload) + .build(); + + // 发送请求 + String resultMessage = HttpRequest.post(url) + .header(Header.CONTENT_TYPE, ContentType.JSON.getValue()) + .header(Header.AUTHORIZATION, "Bearer " + generateBearerToken()) + .body(JSONUtil.toJsonStr(requestBody)) + .timeout(10000) // 超时,毫秒 + .execute().body(); + + // 解析响应 + if (StringUtils.isNotBlank(resultMessage)) { + cn.hutool.json.JSONObject jsonObject = JSONUtil.parseObj(resultMessage); + if (jsonObject.getBool("success", false)) { + return jsonObject.get("data"); + } + } + + return null; + } } diff --git a/main/manager-api/src/main/resources/i18n/messages.properties b/main/manager-api/src/main/resources/i18n/messages.properties index 187c0ccb..324fc4fd 100644 --- a/main/manager-api/src/main/resources/i18n/messages.properties +++ b/main/manager-api/src/main/resources/i18n/messages.properties @@ -198,4 +198,6 @@ 10189=\u9002\u914D\u5668\u64CD\u4F5C\u5931\u8D25 10190=\u9002\u914D\u5668\u672A\u627E\u5230 10191=\u9002\u914D\u5668\u7F13\u5B58\u9519\u8BEF -10192=\u9002\u914D\u5668\u7C7B\u578B\u672A\u627E\u5230 \ No newline at end of file +10192=\u9002\u914D\u5668\u7C7B\u578B\u672A\u627E\u5230 +10193=\u8BBE\u5907ID\u4E0D\u80FD\u4E3A\u7A7A +10194=\u8BBE\u5907\u4E0D\u5B58\u5728 \ No newline at end of file diff --git a/main/manager-api/src/main/resources/i18n/messages_de_DE.properties b/main/manager-api/src/main/resources/i18n/messages_de_DE.properties index abde16e5..1e3b1f44 100644 --- a/main/manager-api/src/main/resources/i18n/messages_de_DE.properties +++ b/main/manager-api/src/main/resources/i18n/messages_de_DE.properties @@ -8,23 +8,23 @@ 10004=Die Kontonummer oder das Passwort ist falsch 10005=Konto wurde deaktiviert 10006=Eindeutige ID darf nicht leer sein -10007=Der Bestätigungscode ist falsch -10008=Zuerst Untermenü oder Schaltfläche löschen -10009=Das ursprüngliche Passwort ist falsch -10010=Das Konto oder Passwort ist falsch, Sie können es noch {0} Mal versuchen +10007=Der Best\u00E4tigungscode ist falsch +10008=Zuerst Untermen\u00FC oder Schaltfl\u00E4che l\u00F6schen +10009=Das urspr\u00FCngliche Passwort ist falsch +10010=Das Konto oder Passwort ist falsch, Sie k\u00F6nnen es noch {0} Mal versuchen -10011=Die übergeordnete Abteilung hat eine falsche Wahl getroffen -10012=Oberes Menü kann nicht sich selbst sein +10011=Die \u00FCbergeordnete Abteilung hat eine falsche Wahl getroffen +10012=Oberes Men\u00FC kann nicht sich selbst sein 10013=Datenberechtigungsschnittstelle, die nur ein Map-Typ-Parameter sein kann -10014=Bitte löschen Sie zuerst die untergeordnete Abteilung -10015=Bitte löschen Sie zuerst den Benutzer unter der Abteilung +10014=Bitte l\u00F6schen Sie zuerst die untergeordnete Abteilung +10015=Bitte l\u00F6schen Sie zuerst den Benutzer unter der Abteilung 10016=Bereitstellung fehlgeschlagen, kein Prozess -10017=Das ModellDiagramm ist falsch, bitte überprüfen +10017=Das ModellDiagramm ist falsch, bitte \u00FCberpr\u00FCfen 10018=Export fehlgeschlagen, Modell-ID ist {0} 10019=Bitte laden Sie eine Datei hoch 10020=Token darf nicht leer sein -10021=Token ist ungültig, bitte melden Sie sich erneut an +10021=Token ist ung\u00FCltig, bitte melden Sie sich erneut an 10022=Das Konto wurde gesperrt 10023=Bitte laden Sie Dateien im Format zip, bar, bpmn, bpmn20.xml hoch @@ -37,25 +37,25 @@ 10029=Darf keine illegalen Zeichen enthalten 10030=Das Passwort hat weniger als {0} Ziffern -10031=Das Passwort muss gleichzeitig aus Zahlen, Groß- und Kleinbuchstaben sowie Sonderzeichen bestehen -10032=Ausnahme beim Löschen dieser Daten -10033=Gerätebestätigungscode Fehler +10031=Das Passwort muss gleichzeitig aus Zahlen, Gro\u00DF- und Kleinbuchstaben sowie Sonderzeichen bestehen +10032=Ausnahme beim L\u00F6schen dieser Daten +10033=Ger\u00E4tebest\u00E4tigungscode Fehler 10034=Parameterwert darf nicht leer sein 10035=Parametertyp darf nicht leer sein -10036=Nicht unterstützter Parametertyp -10037=Parameterwert muss eine gültige Zahl sein +10036=Nicht unterst\u00FCtzter Parametertyp +10037=Parameterwert muss eine g\u00FCltige Zahl sein 10038=Parameterwert muss true oder false sein -10039=Parameterwert muss ein gültiges JSON-Array-Format sein -10040=Parameterwert muss ein gültiges JSON-Format sein +10039=Parameterwert muss ein g\u00FCltiges JSON-Array-Format sein +10040=Parameterwert muss ein g\u00FCltiges JSON-Format sein -10041=Gerät nicht gefunden +10041=Ger\u00E4t nicht gefunden 10042={0} -10043=Löschen der Daten fehlgeschlagen +10043=L\u00F6schen der Daten fehlgeschlagen 10044=Benutzer nicht angemeldet -10045=WebSocket-Verbindung fehlgeschlagen oder Zeitüberschreitung +10045=WebSocket-Verbindung fehlgeschlagen oder Zeit\u00FCberschreitung 10046=Stimmabdruck speichern fehlgeschlagen, bitte Administrator kontaktieren -10047=Tägliches SendeLimit erreicht +10047=T\u00E4gliches SendeLimit erreicht 10048=Altes Passwort ist falsch 10049=Das eingestellte LLM ist nicht openai oder ollama 10050=Token-Generierung fehlgeschlagen @@ -65,45 +65,45 @@ 10054=Stimmabdruck-Schnittstelle nicht konfiguriert, bitte konfigurieren Sie zuerst die Stimmabdruck-Schnittstellenadresse (server.voice_print) in der Parameterkonfiguration 10055=SMS-Sendung fehlgeschlagen 10056=SMS-Verbindung konnte nicht hergestellt werden -10057=Stimmabdruck für Agent konnte nicht erstellt werden -10058=Stimmabdruck für Agent konnte nicht aktualisiert werden -10059=Stimmabdruck für Agent konnte nicht gelöscht werden -10060=Sendung zu häufig, bitte versuchen Sie es nach {0} Sekunden erneut +10057=Stimmabdruck f\u00FCr Agent konnte nicht erstellt werden +10058=Stimmabdruck f\u00FCr Agent konnte nicht aktualisiert werden +10059=Stimmabdruck f\u00FCr Agent konnte nicht gel\u00F6scht werden +10060=Sendung zu h\u00E4ufig, bitte versuchen Sie es nach {0} Sekunden erneut 10061=Aktivierungscode darf nicht leer sein 10062=Aktivierungscode Fehler -10063=Gerät bereits aktiviert +10063=Ger\u00E4t bereits aktiviert 10064=Dieses Modell ist das Standardmodell, bitte setzen Sie zuerst ein anderes Modell als Standard -10065=Hinzufügen der Daten fehlgeschlagen +10065=Hinzuf\u00FCgen der Daten fehlgeschlagen 10066=Aktualisieren der Daten fehlgeschlagen -10067=Grafischer Bestätigungscode Fehler -10068=Mobilregistrierung nicht aktiviert, SMS-Bestätigungscode-Funktion kann nicht verwendet werden +10067=Grafischer Best\u00E4tigungscode Fehler +10068=Mobilregistrierung nicht aktiviert, SMS-Best\u00E4tigungscode-Funktion kann nicht verwendet werden 10069=Benutzername ist keine Handynummer, bitte erneut eingeben 10070=Diese Handynummer wurde bereits registriert 10071=Die eingegebene Handynummer ist nicht registriert 10072=Normale Benutzerregistrierung derzeit nicht erlaubt 10073=Mobilregistrierung nicht aktiviert, Passwort-Wiederherstellungsfunktion kann nicht verwendet werden 10074=Das Format der eingegebenen Handynummer ist falsch -10075=Der eingegebene SMS-Bestätigungscode ist falsch -10076=Wörterbuchtyp existiert nicht -10077=Wörterbuchtypcode ist dupliziert +10075=Der eingegebene SMS-Best\u00E4tigungscode ist falsch +10076=W\u00F6rterbuchtyp existiert nicht +10077=W\u00F6rterbuchtypcode ist dupliziert 10078=Lesen der Ressource fehlgeschlagen -10079=LLM-Modell und Absichtserkennung, Parameterauswahl stimmt nicht überein -10080=Dieser Stimmabdruck gehört zu {0}, der bereits registriert ist, bitte wählen Sie eine andere Stimme -10081=Fehler beim Löschen des Stimmabdrucks aufgetreten -10082=Änderung nicht erlaubt, diese Stimme wurde bereits als Stimmabdruck registriert ({0}) -10083=Fehler beim Ändern des Stimmabdrucks, bitte Administrator kontaktieren -10084=Stimmabdruck-Schnittstellenadresse Fehler, bitte gehen Sie zur Parameterverwaltung, um die Stimmabdruck-Schnittstellenadresse zu ändern -10085=Audiodaten gehören nicht zu diesem Agent -10086=Audiodaten sind leer, bitte überprüfen Sie hochgeladene Daten +10079=LLM-Modell und Absichtserkennung, Parameterauswahl stimmt nicht \u00FCberein +10080=Dieser Stimmabdruck geh\u00F6rt zu {0}, der bereits registriert ist, bitte w\u00E4hlen Sie eine andere Stimme +10081=Fehler beim L\u00F6schen des Stimmabdrucks aufgetreten +10082=\u00C4nderung nicht erlaubt, diese Stimme wurde bereits als Stimmabdruck registriert ({0}) +10083=Fehler beim \u00C4ndern des Stimmabdrucks, bitte Administrator kontaktieren +10084=Stimmabdruck-Schnittstellenadresse Fehler, bitte gehen Sie zur Parameterverwaltung, um die Stimmabdruck-Schnittstellenadresse zu \u00E4ndern +10085=Audiodaten geh\u00F6ren nicht zu diesem Agent +10086=Audiodaten sind leer, bitte \u00FCberpr\u00FCfen Sie hochgeladene Daten 10087=Stimmabdruck-Registrierung fehlgeschlagen, Anfrage nicht erfolgreich 10088=Stimmabdruck-Registrierung fehlgeschlagen, Anfrageverarbeitung fehlgeschlagen 10089=Stimmabdruck-Stornierung fehlgeschlagen, Anfrage nicht erfolgreich 10090=Stimmabdruck-Stornierung fehlgeschlagen, Anfrageverarbeitung fehlgeschlagen 10091=Modellanbieter existiert nicht 10092=Das konfigurierte LLM existiert nicht -10093=Diese Modellkonfiguration wird von Agent {0} referenziert und kann nicht gelöscht werden -10094=Dieses LLM-Modell wird von der Absichtserkennungskonfiguration referenziert und kann nicht gelöscht werden -10095=Ungültige Serveroperation +10093=Diese Modellkonfiguration wird von Agent {0} referenziert und kann nicht gel\u00F6scht werden +10094=Dieses LLM-Modell wird von der Absichtserkennungskonfiguration referenziert und kann nicht gel\u00F6scht werden +10095=Ung\u00FCltige Serveroperation 10096=Server WebSocket-Adresse nicht konfiguriert 10097=Ziel-WebSocket-Adresse existiert nicht 10098=WebSocket-Adressliste darf nicht leer sein @@ -115,47 +115,47 @@ 10104=OTA-Adresse muss mit http oder https beginnen 10105=OTA-Adresse muss mit /ota/ enden 10106=OTA-Schnittstellenzugriff fehlgeschlagen -10107=OTA-Schnittstelle Rückgabeinhaltformat ist falsch +10107=OTA-Schnittstelle R\u00FCckgabeinhaltformat ist falsch 10108=OTA-Schnittstellenvalidierung fehlgeschlagen 10109=MCP-Adresse darf nicht leer sein 10110=MCP-Adresse darf nicht localhost oder 127.0.0.1 verwenden -10111=Keine gültige MCP-Adresse +10111=Keine g\u00FCltige MCP-Adresse 10112=MCP-Schnittstellenzugriff fehlgeschlagen -10113=MCP-Schnittstelle Rückgabeinhaltformat ist falsch +10113=MCP-Schnittstelle R\u00FCckgabeinhaltformat ist falsch 10114=MCP-Schnittstellenvalidierung fehlgeschlagen 10115=Stimmabdruck-Schnittstellenadresse darf nicht leer sein 10116=Stimmabdruck-Schnittstellenadresse darf nicht localhost oder 127.0.0.1 verwenden -10117=Keine gültige Stimmabdruck-Schnittstellenadresse +10117=Keine g\u00FCltige Stimmabdruck-Schnittstellenadresse 10118=Stimmabdruck-Schnittstellenadresse muss mit http oder https beginnen 10119=Stimmabdruck-Schnittstellenzugriff fehlgeschlagen -10120=Stimmabdruck-Schnittstelle Rückgabeinhaltformat ist falsch +10120=Stimmabdruck-Schnittstelle R\u00FCckgabeinhaltformat ist falsch 10121=Stimmabdruck-Schnittstellenvalidierung fehlgeschlagen 10122=MQTT-Geheimnis darf nicht leer sein -10123=Ihr MQTT-Geheimnis ist nicht sicher, es muss mindestens 8 Zeichen lang sein und muss sowohl Groß- als auch Kleinbuchstaben enthalten -10124=Ihr MQTT-Geheimnis ist nicht sicher, MQTT-Geheimnis muss sowohl Groß- als auch Kleinbuchstaben enthalten -10125=Ihr MQTT-Geheimnis enthält schwaches Passwort -10128=Wörterbuchlabel ist dupliziert -10129=SM2-Schlüssel nicht konfiguriert -10130=SM2-Entschlüsselung fehlgeschlagen -10131=modelType und provideCode dürfen nicht leer sein +10123=Ihr MQTT-Geheimnis ist nicht sicher, es muss mindestens 8 Zeichen lang sein und muss sowohl Gro\u00DF- als auch Kleinbuchstaben enthalten +10124=Ihr MQTT-Geheimnis ist nicht sicher, MQTT-Geheimnis muss sowohl Gro\u00DF- als auch Kleinbuchstaben enthalten +10125=Ihr MQTT-Geheimnis enth\u00E4lt schwaches Passwort +10128=W\u00F6rterbuchlabel ist dupliziert +10129=SM2-Schl\u00FCssel nicht konfiguriert +10130=SM2-Entschl\u00FCsselung fehlgeschlagen +10131=modelType und provideCode d\u00FCrfen nicht leer sein 10132=Keine Berechtigung, den Chat-Verlauf dieses Agents anzuzeigen 10133=Sitzungs-ID darf nicht leer sein 10134=Agent-ID darf nicht leer sein 10135=Chat-Verlauf-Download fehlgeschlagen -10136=Download-Link abgelaufen oder ungültig -10137=Download-Link ungültig +10136=Download-Link abgelaufen oder ung\u00FCltig +10137=Download-Link ung\u00FCltig 10138=Benutzer 10139=Agent 10140=Audio-Datei darf nicht leer sein -10141=Nur Audio-Dateien werden unterstützt -10142=Audio-Dateigröße darf 10MB nicht überschreiten +10141=Nur Audio-Dateien werden unterst\u00FCtzt +10142=Audio-Dateigr\u00F6\u00DFe darf 10MB nicht \u00FCberschreiten 10143=Upload fehlgeschlagen 10144=Stimmenklon-Datensatz existiert nicht -10145=Stimmressourceninformationen dürfen nicht leer sein +10145=Stimmressourceninformationen d\u00FCrfen nicht leer sein 10146=TTS-Plattformname darf nicht leer sein 10147=Stimmen-ID darf nicht leer sein 10148=Kontoinhaber darf nicht leer sein -10149=Zu löschende Stimmressourcen-ID darf nicht leer sein +10149=Zu l\u00F6schende Stimmressourcen-ID darf nicht leer sein 10150=Sie haben keine Berechtigung, diesen Datensatz zu bearbeiten 10151=Bitte laden Sie zuerst eine Audio-Datei hoch 10152=Modellkonfiguration nicht gefunden @@ -179,18 +179,18 @@ 10170=Wissensbasis-Name existiert bereits 10171=RAG-Konfiguration base_url darf nicht leer sein 10172=RAG-Konfiguration api_key darf nicht leer sein -10173=RAG-Konfiguration api_key darf keinen Platzhalter enthalten, bitte ersetzen Sie mit tatsächlichem API-Schlüssel +10173=RAG-Konfiguration api_key darf keinen Platzhalter enthalten, bitte ersetzen Sie mit tats\u00E4chlichem API-Schl\u00FCssel 10174=RAG-Konfiguration base_url-Formatfehler, muss mit http oder https beginnen 10175=Mac-Adresse darf nicht leer sein 10176=RAG-Konfiguration dataset_id darf nicht leer sein 10177=RAG-Konfiguration model_id darf nicht leer sein -10178=RAG-Konfiguration dataset_id und model_id dürfen nicht leer sein +10178=RAG-Konfiguration dataset_id und model_id d\u00FCrfen nicht leer sein 10179=Dateiname darf nicht leer sein 10180=Dateiinhalt darf nicht leer sein 10181=Stimmenklon-Name darf nicht leer sein 10182=Stimmenklon-Audio nicht gefunden 10183=Standard-Agent-Vorlage nicht gefunden -10184=Nicht unterstützter Adaptertyp +10184=Nicht unterst\u00FCtzter Adaptertyp 10185=RAG-Konfigurationsvalidierung fehlgeschlagen 10186=Adapter-Erstellung fehlgeschlagen 10187=Adapter-Initialisierung fehlgeschlagen @@ -198,4 +198,6 @@ 10189=Adapter-Operation fehlgeschlagen 10190=Adapter nicht gefunden 10191=Adapter-Cache-Fehler -10192=Adaptertyp nicht gefunden \ No newline at end of file +10192=Adaptertyp nicht gefunden +10193=Adapter-ID darf nicht leer sein +10194=Adapter nicht gefunden \ No newline at end of file diff --git a/main/manager-api/src/main/resources/i18n/messages_en_US.properties b/main/manager-api/src/main/resources/i18n/messages_en_US.properties index ea4fca51..71f98a76 100644 --- a/main/manager-api/src/main/resources/i18n/messages_en_US.properties +++ b/main/manager-api/src/main/resources/i18n/messages_en_US.properties @@ -198,4 +198,6 @@ 10189=Adapter operation failed 10190=Adapter not found 10191=Adapter cache error -10192=Adapter type not found \ No newline at end of file +10192=Adapter type not found +10193=Device ID cannot be empty +10194=Device not found \ No newline at end of file diff --git a/main/manager-api/src/main/resources/i18n/messages_vi_VN.properties b/main/manager-api/src/main/resources/i18n/messages_vi_VN.properties index eafe1827..91e5cfff 100644 --- a/main/manager-api/src/main/resources/i18n/messages_vi_VN.properties +++ b/main/manager-api/src/main/resources/i18n/messages_vi_VN.properties @@ -1,201 +1,203 @@ -#Tiếng Việt -500=Ngoại lệ nội bộ máy chủ -401=Không được ủy quyền -403=Truy cập bị từ chối, không có quyền -10001={0} không thể để trống -10002=Bản ghi đã tồn tại trong cơ sở dữ liệu -10003=Không thể lấy tham số -10004=Số tài khoản hoặc mật khẩu không chính xác -10005=Tài khoản đã bị vô hiệu hóa -10006=ID duy nhất không thể để trống -10007=Mã xác minh không chính xác -10008=Trước tiên hãy xóa menu con hoặc nút -10009=Mật khẩu gốc không chính xác -10010=Tài khoản hoặc mật khẩu không chính xác, bạn có thể thử thêm {0} lần nữa +#Ti\u1EBFng Vi\u1EC7t +500=Ngo\u1EA1i l\u1EC7 n\u1ED9i b\u1ED9 m\u00E1y ch\u1EE7 +401=Kh\u00F4ng \u0111\u01B0\u1EE3c \u1EE7y quy\u1EC1n +403=Truy c\u1EADp b\u1ECB t\u1EEB ch\u1ED1i, kh\u00F4ng c\u00F3 quy\u1EC1n +10001={0} kh\u00F4ng th\u1EC3 \u0111\u1EC3 tr\u1ED1ng +10002=B\u1EA3n ghi \u0111\u00E3 t\u1ED3n t\u1EA1i trong c\u01A1 s\u1EDF d\u1EEF li\u1EC7u +10003=Kh\u00F4ng th\u1EC3 l\u1EA5y tham s\u1ED1 +10004=S\u1ED1 t\u00E0i kho\u1EA3n ho\u1EB7c m\u1EADt kh\u1EA9u kh\u00F4ng ch\u00EDnh x\u00E1c +10005=T\u00E0i kho\u1EA3n \u0111\u00E3 b\u1ECB v\u00F4 hi\u1EC7u h\u00F3a +10006=ID duy nh\u1EA5t kh\u00F4ng th\u1EC3 \u0111\u1EC3 tr\u1ED1ng +10007=M\u00E3 x\u00E1c minh kh\u00F4ng ch\u00EDnh x\u00E1c +10008=Tr\u01B0\u1EDBc ti\u00EAn h\u00E3y x\u00F3a menu con ho\u1EB7c n\u00FAt +10009=M\u1EADt kh\u1EA9u g\u1ED1c kh\u00F4ng ch\u00EDnh x\u00E1c +10010=T\u00E0i kho\u1EA3n ho\u1EB7c m\u1EADt kh\u1EA9u kh\u00F4ng ch\u00EDnh x\u00E1c, b\u1EA1n c\u00F3 th\u1EC3 th\u1EED th\u00EAm {0} l\u1EA7n n\u1EEFa -10011=Phòng ban cấp trên đã lựa chọn sai -10012=Menu trên không thể là chính nó -10013=Giao diện quyền dữ liệu, chỉ có thể là tham số kiểu Map -10014=Vui lòng xóa phòng ban cấp dưới trước -10015=Vui lòng xóa người dùng thuộc phòng ban trước -10016=Triển khai thất bại, không có quy trình -10017=Biểu đồ mô hình không chính xác, vui lòng kiểm tra -10018=Xuất thất bại, ID mô hình là {0} +10011=Ph\u00F2ng ban c\u1EA5p tr\u00EAn \u0111\u00E3 l\u1EF1a ch\u1ECDn sai +10012=Menu tr\u00EAn kh\u00F4ng th\u1EC3 l\u00E0 ch\u00EDnh n\u00F3 +10013=Giao di\u1EC7n quy\u1EC1n d\u1EEF li\u1EC7u, ch\u1EC9 c\u00F3 th\u1EC3 l\u00E0 tham s\u1ED1 ki\u1EC3u Map +10014=Vui l\u00F2ng x\u00F3a ph\u00F2ng ban c\u1EA5p d\u01B0\u1EDBi tr\u01B0\u1EDBc +10015=Vui l\u00F2ng x\u00F3a ng\u01B0\u1EDDi d\u00F9ng thu\u1ED9c ph\u00F2ng ban tr\u01B0\u1EDBc +10016=Tri\u1EC3n khai th\u1EA5t b\u1EA1i, kh\u00F4ng c\u00F3 quy tr\u00ECnh +10017=Bi\u1EC3u \u0111\u1ED3 m\u00F4 h\u00ECnh kh\u00F4ng ch\u00EDnh x\u00E1c, vui l\u00F2ng ki\u1EC3m tra +10018=Xu\u1EA5t th\u1EA5t b\u1EA1i, ID m\u00F4 h\u00ECnh l\u00E0 {0} -10019=Vui lòng tải lên tệp -10020=Token không thể để trống -10021=Token không hợp lệ, vui lòng đăng nhập lại -10022=Tài khoản đã bị khóa -10023=Vui lòng tải lên tệp ở định dạng zip, bar, bpmn, bpmn20.xml +10019=Vui l\u00F2ng t\u1EA3i l\u00EAn t\u1EC7p +10020=Token kh\u00F4ng th\u1EC3 \u0111\u1EC3 tr\u1ED1ng +10021=Token kh\u00F4ng h\u1EE3p l\u1EC7, vui l\u00F2ng \u0111\u0103ng nh\u1EADp l\u1EA1i +10022=T\u00E0i kho\u1EA3n \u0111\u00E3 b\u1ECB kh\u00F3a +10023=Vui l\u00F2ng t\u1EA3i l\u00EAn t\u1EC7p \u1EDF \u0111\u1ECBnh d\u1EA1ng zip, bar, bpmn, bpmn20.xml -10024=Tải lên tệp {0} thất bại -10025=Gửi SMS {0} thất bại -10026=Mẫu email không tồn tại +10024=T\u1EA3i l\u00EAn t\u1EC7p {0} th\u1EA5t b\u1EA1i +10025=G\u1EEDi SMS {0} th\u1EA5t b\u1EA1i +10026=M\u1EABu email kh\u00F4ng t\u1ED3n t\u1EA1i -10027=Ngoại lệ dịch vụ Redis -10028=Tác vụ hẹn giờ thất bại -10029=Không thể chứa ký tự không hợp lệ +10027=Ngo\u1EA1i l\u1EC7 d\u1ECBch v\u1EE5 Redis +10028=T\u00E1c v\u1EE5 h\u1EB9n gi\u1EDD th\u1EA5t b\u1EA1i +10029=Kh\u00F4ng th\u1EC3 ch\u1EE9a k\u00FD t\u1EF1 kh\u00F4ng h\u1EE3p l\u1EC7 -10030=Mật khẩu ít hơn {0} chữ số -10031=Mật khẩu phải bao gồm số, chữ hoa, chữ thường và ký tự đặc biệt cùng một lúc -10032=Ngoại lệ khi xóa dữ liệu này -10033=Lỗi mã xác minh thiết bị +10030=M\u1EADt kh\u1EA9u \u00EDt h\u01A1n {0} ch\u1EEF s\u1ED1 +10031=M\u1EADt kh\u1EA9u ph\u1EA3i bao g\u1ED3m s\u1ED1, ch\u1EEF hoa, ch\u1EEF th\u01B0\u1EDDng v\u00E0 k\u00FD t\u1EF1 \u0111\u1EB7c bi\u1EC7t c\u00F9ng m\u1ED9t l\u00FAc +10032=Ngo\u1EA1i l\u1EC7 khi x\u00F3a d\u1EEF li\u1EC7u n\u00E0y +10033=L\u1ED7i m\u00E3 x\u00E1c minh thi\u1EBFt b\u1ECB -10034=Giá trị tham số không thể để trống -10035=Loại tham số không thể để trống -10036=Loại tham số không được hỗ trợ -10037=Giá trị tham số phải là số hợp lệ -10038=Giá trị tham số phải là true hoặc false -10039=Giá trị tham số phải là định dạng mảng JSON hợp lệ -10040=Giá trị tham số phải là định dạng JSON hợp lệ +10034=Gi\u00E1 tr\u1ECB tham s\u1ED1 kh\u00F4ng th\u1EC3 \u0111\u1EC3 tr\u1ED1ng +10035=Lo\u1EA1i tham s\u1ED1 kh\u00F4ng th\u1EC3 \u0111\u1EC3 tr\u1ED1ng +10036=Lo\u1EA1i tham s\u1ED1 kh\u00F4ng \u0111\u01B0\u1EE3c h\u1ED7 tr\u1EE3 +10037=Gi\u00E1 tr\u1ECB tham s\u1ED1 ph\u1EA3i l\u00E0 s\u1ED1 h\u1EE3p l\u1EC7 +10038=Gi\u00E1 tr\u1ECB tham s\u1ED1 ph\u1EA3i l\u00E0 true ho\u1EB7c false +10039=Gi\u00E1 tr\u1ECB tham s\u1ED1 ph\u1EA3i l\u00E0 \u0111\u1ECBnh d\u1EA1ng m\u1EA3ng JSON h\u1EE3p l\u1EC7 +10040=Gi\u00E1 tr\u1ECB tham s\u1ED1 ph\u1EA3i l\u00E0 \u0111\u1ECBnh d\u1EA1ng JSON h\u1EE3p l\u1EC7 -10041=Không tìm thấy thiết bị +10041=Kh\u00F4ng t\u00ECm th\u1EA5y thi\u1EBFt b\u1ECB 10042={0} -10043=Xóa dữ liệu thất bại -10044=Người dùng chưa đăng nhập -10045=Kết nối WebSocket thất bại hoặc hết thời gian chờ -10046=Không thể lưu dấu giọng nói, vui lòng liên hệ quản trị viên -10047=Đạt đến giới hạn gửi hàng ngày -10048=Mật khẩu cũ không chính xác -10049=LLM được đặt không phải là openai hoặc ollama -10050=Không thể tạo token -10051=Không tìm thấy tài nguyên -10052=Không tìm thấy agent mặc định -10053=Không tìm thấy agent -10054=Giao diện dấu giọng nói chưa được cấu hình, vui lòng cấu hình địa chỉ giao diện dấu giọng nói (server.voice_print) trong cấu hình tham số trước -10055=Gửi SMS thất bại -10056=Không thể thiết lập kết nối SMS -10057=Không thể tạo dấu giọng nói cho agent -10058=Không thể cập nhật dấu giọng nói cho agent -10059=Không thể xóa dấu giọng nói cho agent -10060=Gửi quá thường xuyên, vui lòng thử lại sau {0} giây -10061=Mã kích hoạt không thể để trống -10062=Lỗi mã kích hoạt -10063=Thiết bị đã được kích hoạt -10064=Mô hình này là mô hình mặc định, vui lòng đặt mô hình khác làm mặc định trước -10065=Thêm dữ liệu thất bại -10066=Cập nhật dữ liệu thất bại -10067=Lỗi mã xác minh đồ họa -10068=Đăng ký di động không được bật, không thể sử dụng chức năng mã xác minh SMS -10069=Tên người dùng không phải là số điện thoại di động, vui lòng nhập lại -10070=Số điện thoại di động này đã được đăng ký -10071=Số điện thoại di động đã nhập không được đăng ký -10072=Hiện không cho phép đăng ký người dùng thông thường -10073=Đăng ký di động không được bật, không thể sử dụng chức năng truy xuất mật khẩu -10074=Định dạng số điện thoại di động đã nhập không chính xác -10075=Mã xác minh SMS đã nhập không chính xác -10076=Loại từ điển không tồn tại -10077=Mã loại từ điển bị trùng lặp -10078=Đọc tài nguyên thất bại -10079=Mô hình LLM và nhận dạng ý định, lựa chọn tham số không khớp -10080=Dấu giọng nói này thuộc về {0} đã đăng ký, vui lòng chọn giọng nói khác -10081=Đã xảy ra lỗi khi xóa dấu giọng nói -10082=Không cho phép sửa đổi, giọng nói này đã được đăng ký làm dấu giọng nói ({0}) -10083=Lỗi sửa đổi dấu giọng nói, vui lòng liên hệ quản trị viên -10084=Lỗi địa chỉ giao diện dấu giọng nói, vui lòng vào quản lý tham số để sửa đổi địa chỉ giao diện dấu giọng nói -10085=Dữ liệu âm thanh không thuộc về agent này -10086=Dữ liệu âm thanh trống, vui lòng kiểm tra dữ liệu đã tải lên -10087=Đăng ký dấu giọng nói thất bại, yêu cầu không thành công -10088=Đăng ký dấu giọng nói thất bại, xử lý yêu cầu thất bại -10089=Hủy dấu giọng nói thất bại, yêu cầu không thành công -10090=Hủy dấu giọng nói thất bại, xử lý yêu cầu thất bại -10091=Nhà cung cấp mô hình không tồn tại -10092=LLM được cấu hình không tồn tại -10093=Cấu hình mô hình này được tham chiếu bởi agent {0} và không thể xóa -10094=Mô hình LLM này được tham chiếu bởi cấu hình nhận dạng ý định và không thể xóa -10095=Thao tác máy chủ không hợp lệ -10096=Địa chỉ WebSocket máy chủ chưa được cấu hình -10097=Địa chỉ WebSocket mục tiêu không tồn tại -10098=Danh sách địa chỉ WebSocket không thể để trống -10099=Địa chỉ WebSocket không thể sử dụng localhost hoặc 127.0.0.1 -10100=Định dạng địa chỉ WebSocket không chính xác -10101=Kiểm tra kết nối WebSocket thất bại -10102=Địa chỉ OTA không thể để trống -10103=Địa chỉ OTA không thể sử dụng localhost hoặc 127.0.0.1 -10104=Địa chỉ OTA phải bắt đầu bằng http hoặc https -10105=Địa chỉ OTA phải kết thúc bằng /ota/ -10106=Truy cập giao diện OTA thất bại -10107=Định dạng nội dung trả về giao diện OTA không chính xác -10108=Xác thực giao diện OTA thất bại -10109=Địa chỉ MCP không thể để trống -10110=Địa chỉ MCP không thể sử dụng localhost hoặc 127.0.0.1 -10111=Không phải địa chỉ MCP hợp lệ -10112=Truy cập giao diện MCP thất bại -10113=Định dạng nội dung trả về giao diện MCP không chính xác -10114=Xác thực giao diện MCP thất bại -10115=Địa chỉ giao diện dấu giọng nói không thể để trống -10116=Địa chỉ giao diện dấu giọng nói không thể sử dụng localhost hoặc 127.0.0.1 -10117=Không phải địa chỉ giao diện dấu giọng nói hợp lệ -10118=Địa chỉ giao diện dấu giọng nói phải bắt đầu bằng http hoặc https -10119=Truy cập giao diện dấu giọng nói thất bại -10120=Định dạng nội dung trả về giao diện dấu giọng nói không chính xác -10121=Xác thực giao diện dấu giọng nói thất bại -10122=Bí mật MQTT không thể để trống -10123=Bí mật MQTT của bạn không an toàn, cần ít nhất 8 ký tự và phải chứa cả chữ hoa và chữ thường -10124=Bí mật MQTT của bạn không an toàn, bí mật MQTT phải chứa cả chữ hoa và chữ thường -10125=Bí mật MQTT của bạn chứa mật khẩu yếu -10128=Nhãn từ điển bị trùng lặp -10129=Khóa SM2 chưa được cấu hình -10130=Giải mã SM2 thất bại -10131=modelType và provideCode không thể để trống -10132=Không có quyền xem lịch sử trò chuyện của agent này -10133=ID phiên không thể để trống -10134=ID agent không thể để trống -10135=Tải xuống lịch sử trò chuyện thất bại -10136=Liên kết tải xuống đã hết hạn hoặc không hợp lệ -10137=Liên kết tải xuống không hợp lệ -10138=Người dùng +10043=X\u00F3a d\u1EEF li\u1EC7u th\u1EA5t b\u1EA1i +10044=Ng\u01B0\u1EDDi d\u00F9ng ch\u01B0a \u0111\u0103ng nh\u1EADp +10045=K\u1EBFt n\u1ED1i WebSocket th\u1EA5t b\u1EA1i ho\u1EB7c h\u1EBFt th\u1EDDi gian ch\u1EDD +10046=Kh\u00F4ng th\u1EC3 l\u01B0u d\u1EA5u gi\u1ECDng n\u00F3i, vui l\u00F2ng li\u00EAn h\u1EC7 qu\u1EA3n tr\u1ECB vi\u00EAn +10047=\u0110\u1EA1t \u0111\u1EBFn gi\u1EDBi h\u1EA1n g\u1EEDi h\u00E0ng ng\u00E0y +10048=M\u1EADt kh\u1EA9u c\u0169 kh\u00F4ng ch\u00EDnh x\u00E1c +10049=LLM \u0111\u01B0\u1EE3c \u0111\u1EB7t kh\u00F4ng ph\u1EA3i l\u00E0 openai ho\u1EB7c ollama +10050=Kh\u00F4ng th\u1EC3 t\u1EA1o token +10051=Kh\u00F4ng t\u00ECm th\u1EA5y t\u00E0i nguy\u00EAn +10052=Kh\u00F4ng t\u00ECm th\u1EA5y agent m\u1EB7c \u0111\u1ECBnh +10053=Kh\u00F4ng t\u00ECm th\u1EA5y agent +10054=Giao di\u1EC7n d\u1EA5u gi\u1ECDng n\u00F3i ch\u01B0a \u0111\u01B0\u1EE3c c\u1EA5u h\u00ECnh, vui l\u00F2ng c\u1EA5u h\u00ECnh \u0111\u1ECBa ch\u1EC9 giao di\u1EC7n d\u1EA5u gi\u1ECDng n\u00F3i (server.voice_print) trong c\u1EA5u h\u00ECnh tham s\u1ED1 tr\u01B0\u1EDBc +10055=G\u1EEDi SMS th\u1EA5t b\u1EA1i +10056=Kh\u00F4ng th\u1EC3 thi\u1EBFt l\u1EADp k\u1EBFt n\u1ED1i SMS +10057=Kh\u00F4ng th\u1EC3 t\u1EA1o d\u1EA5u gi\u1ECDng n\u00F3i cho agent +10058=Kh\u00F4ng th\u1EC3 c\u1EADp nh\u1EADt d\u1EA5u gi\u1ECDng n\u00F3i cho agent +10059=Kh\u00F4ng th\u1EC3 x\u00F3a d\u1EA5u gi\u1ECDng n\u00F3i cho agent +10060=G\u1EEDi qu\u00E1 th\u01B0\u1EDDng xuy\u00EAn, vui l\u00F2ng th\u1EED l\u1EA1i sau {0} gi\u00E2y +10061=M\u00E3 k\u00EDch ho\u1EA1t kh\u00F4ng th\u1EC3 \u0111\u1EC3 tr\u1ED1ng +10062=L\u1ED7i m\u00E3 k\u00EDch ho\u1EA1t +10063=Thi\u1EBFt b\u1ECB \u0111\u00E3 \u0111\u01B0\u1EE3c k\u00EDch ho\u1EA1t +10064=M\u00F4 h\u00ECnh n\u00E0y l\u00E0 m\u00F4 h\u00ECnh m\u1EB7c \u0111\u1ECBnh, vui l\u00F2ng \u0111\u1EB7t m\u00F4 h\u00ECnh kh\u00E1c l\u00E0m m\u1EB7c \u0111\u1ECBnh tr\u01B0\u1EDBc +10065=Th\u00EAm d\u1EEF li\u1EC7u th\u1EA5t b\u1EA1i +10066=C\u1EADp nh\u1EADt d\u1EEF li\u1EC7u th\u1EA5t b\u1EA1i +10067=L\u1ED7i m\u00E3 x\u00E1c minh \u0111\u1ED3 h\u1ECDa +10068=\u0110\u0103ng k\u00FD di \u0111\u1ED9ng kh\u00F4ng \u0111\u01B0\u1EE3c b\u1EADt, kh\u00F4ng th\u1EC3 s\u1EED d\u1EE5ng ch\u1EE9c n\u0103ng m\u00E3 x\u00E1c minh SMS +10069=T\u00EAn ng\u01B0\u1EDDi d\u00F9ng kh\u00F4ng ph\u1EA3i l\u00E0 s\u1ED1 \u0111i\u1EC7n tho\u1EA1i di \u0111\u1ED9ng, vui l\u00F2ng nh\u1EADp l\u1EA1i +10070=S\u1ED1 \u0111i\u1EC7n tho\u1EA1i di \u0111\u1ED9ng n\u00E0y \u0111\u00E3 \u0111\u01B0\u1EE3c \u0111\u0103ng k\u00FD +10071=S\u1ED1 \u0111i\u1EC7n tho\u1EA1i di \u0111\u1ED9ng \u0111\u00E3 nh\u1EADp kh\u00F4ng \u0111\u01B0\u1EE3c \u0111\u0103ng k\u00FD +10072=Hi\u1EC7n kh\u00F4ng cho ph\u00E9p \u0111\u0103ng k\u00FD ng\u01B0\u1EDDi d\u00F9ng th\u00F4ng th\u01B0\u1EDDng +10073=\u0110\u0103ng k\u00FD di \u0111\u1ED9ng kh\u00F4ng \u0111\u01B0\u1EE3c b\u1EADt, kh\u00F4ng th\u1EC3 s\u1EED d\u1EE5ng ch\u1EE9c n\u0103ng truy xu\u1EA5t m\u1EADt kh\u1EA9u +10074=\u0110\u1ECBnh d\u1EA1ng s\u1ED1 \u0111i\u1EC7n tho\u1EA1i di \u0111\u1ED9ng \u0111\u00E3 nh\u1EADp kh\u00F4ng ch\u00EDnh x\u00E1c +10075=M\u00E3 x\u00E1c minh SMS \u0111\u00E3 nh\u1EADp kh\u00F4ng ch\u00EDnh x\u00E1c +10076=Lo\u1EA1i t\u1EEB \u0111i\u1EC3n kh\u00F4ng t\u1ED3n t\u1EA1i +10077=M\u00E3 lo\u1EA1i t\u1EEB \u0111i\u1EC3n b\u1ECB tr\u00F9ng l\u1EB7p +10078=\u0110\u1ECDc t\u00E0i nguy\u00EAn th\u1EA5t b\u1EA1i +10079=M\u00F4 h\u00ECnh LLM v\u00E0 nh\u1EADn d\u1EA1ng \u00FD \u0111\u1ECBnh, l\u1EF1a ch\u1ECDn tham s\u1ED1 kh\u00F4ng kh\u1EDBp +10080=D\u1EA5u gi\u1ECDng n\u00F3i n\u00E0y thu\u1ED9c v\u1EC1 {0} \u0111\u00E3 \u0111\u0103ng k\u00FD, vui l\u00F2ng ch\u1ECDn gi\u1ECDng n\u00F3i kh\u00E1c +10081=\u0110\u00E3 x\u1EA3y ra l\u1ED7i khi x\u00F3a d\u1EA5u gi\u1ECDng n\u00F3i +10082=Kh\u00F4ng cho ph\u00E9p s\u1EEDa \u0111\u1ED5i, gi\u1ECDng n\u00F3i n\u00E0y \u0111\u00E3 \u0111\u01B0\u1EE3c \u0111\u0103ng k\u00FD l\u00E0m d\u1EA5u gi\u1ECDng n\u00F3i ({0}) +10083=L\u1ED7i s\u1EEDa \u0111\u1ED5i d\u1EA5u gi\u1ECDng n\u00F3i, vui l\u00F2ng li\u00EAn h\u1EC7 qu\u1EA3n tr\u1ECB vi\u00EAn +10084=L\u1ED7i \u0111\u1ECBa ch\u1EC9 giao di\u1EC7n d\u1EA5u gi\u1ECDng n\u00F3i, vui l\u00F2ng v\u00E0o qu\u1EA3n l\u00FD tham s\u1ED1 \u0111\u1EC3 s\u1EEDa \u0111\u1ED5i \u0111\u1ECBa ch\u1EC9 giao di\u1EC7n d\u1EA5u gi\u1ECDng n\u00F3i +10085=D\u1EEF li\u1EC7u \u00E2m thanh kh\u00F4ng thu\u1ED9c v\u1EC1 agent n\u00E0y +10086=D\u1EEF li\u1EC7u \u00E2m thanh tr\u1ED1ng, vui l\u00F2ng ki\u1EC3m tra d\u1EEF li\u1EC7u \u0111\u00E3 t\u1EA3i l\u00EAn +10087=\u0110\u0103ng k\u00FD d\u1EA5u gi\u1ECDng n\u00F3i th\u1EA5t b\u1EA1i, y\u00EAu c\u1EA7u kh\u00F4ng th\u00E0nh c\u00F4ng +10088=\u0110\u0103ng k\u00FD d\u1EA5u gi\u1ECDng n\u00F3i th\u1EA5t b\u1EA1i, x\u1EED l\u00FD y\u00EAu c\u1EA7u th\u1EA5t b\u1EA1i +10089=H\u1EE7y d\u1EA5u gi\u1ECDng n\u00F3i th\u1EA5t b\u1EA1i, y\u00EAu c\u1EA7u kh\u00F4ng th\u00E0nh c\u00F4ng +10090=H\u1EE7y d\u1EA5u gi\u1ECDng n\u00F3i th\u1EA5t b\u1EA1i, x\u1EED l\u00FD y\u00EAu c\u1EA7u th\u1EA5t b\u1EA1i +10091=Nh\u00E0 cung c\u1EA5p m\u00F4 h\u00ECnh kh\u00F4ng t\u1ED3n t\u1EA1i +10092=LLM \u0111\u01B0\u1EE3c c\u1EA5u h\u00ECnh kh\u00F4ng t\u1ED3n t\u1EA1i +10093=C\u1EA5u h\u00ECnh m\u00F4 h\u00ECnh n\u00E0y \u0111\u01B0\u1EE3c tham chi\u1EBFu b\u1EDFi agent {0} v\u00E0 kh\u00F4ng th\u1EC3 x\u00F3a +10094=M\u00F4 h\u00ECnh LLM n\u00E0y \u0111\u01B0\u1EE3c tham chi\u1EBFu b\u1EDFi c\u1EA5u h\u00ECnh nh\u1EADn d\u1EA1ng \u00FD \u0111\u1ECBnh v\u00E0 kh\u00F4ng th\u1EC3 x\u00F3a +10095=Thao t\u00E1c m\u00E1y ch\u1EE7 kh\u00F4ng h\u1EE3p l\u1EC7 +10096=\u0110\u1ECBa ch\u1EC9 WebSocket m\u00E1y ch\u1EE7 ch\u01B0a \u0111\u01B0\u1EE3c c\u1EA5u h\u00ECnh +10097=\u0110\u1ECBa ch\u1EC9 WebSocket m\u1EE5c ti\u00EAu kh\u00F4ng t\u1ED3n t\u1EA1i +10098=Danh s\u00E1ch \u0111\u1ECBa ch\u1EC9 WebSocket kh\u00F4ng th\u1EC3 \u0111\u1EC3 tr\u1ED1ng +10099=\u0110\u1ECBa ch\u1EC9 WebSocket kh\u00F4ng th\u1EC3 s\u1EED d\u1EE5ng localhost ho\u1EB7c 127.0.0.1 +10100=\u0110\u1ECBnh d\u1EA1ng \u0111\u1ECBa ch\u1EC9 WebSocket kh\u00F4ng ch\u00EDnh x\u00E1c +10101=Ki\u1EC3m tra k\u1EBFt n\u1ED1i WebSocket th\u1EA5t b\u1EA1i +10102=\u0110\u1ECBa ch\u1EC9 OTA kh\u00F4ng th\u1EC3 \u0111\u1EC3 tr\u1ED1ng +10103=\u0110\u1ECBa ch\u1EC9 OTA kh\u00F4ng th\u1EC3 s\u1EED d\u1EE5ng localhost ho\u1EB7c 127.0.0.1 +10104=\u0110\u1ECBa ch\u1EC9 OTA ph\u1EA3i b\u1EAFt \u0111\u1EA7u b\u1EB1ng http ho\u1EB7c https +10105=\u0110\u1ECBa ch\u1EC9 OTA ph\u1EA3i k\u1EBFt th\u00FAc b\u1EB1ng /ota/ +10106=Truy c\u1EADp giao di\u1EC7n OTA th\u1EA5t b\u1EA1i +10107=\u0110\u1ECBnh d\u1EA1ng n\u1ED9i dung tr\u1EA3 v\u1EC1 giao di\u1EC7n OTA kh\u00F4ng ch\u00EDnh x\u00E1c +10108=X\u00E1c th\u1EF1c giao di\u1EC7n OTA th\u1EA5t b\u1EA1i +10109=\u0110\u1ECBa ch\u1EC9 MCP kh\u00F4ng th\u1EC3 \u0111\u1EC3 tr\u1ED1ng +10110=\u0110\u1ECBa ch\u1EC9 MCP kh\u00F4ng th\u1EC3 s\u1EED d\u1EE5ng localhost ho\u1EB7c 127.0.0.1 +10111=Kh\u00F4ng ph\u1EA3i \u0111\u1ECBa ch\u1EC9 MCP h\u1EE3p l\u1EC7 +10112=Truy c\u1EADp giao di\u1EC7n MCP th\u1EA5t b\u1EA1i +10113=\u0110\u1ECBnh d\u1EA1ng n\u1ED9i dung tr\u1EA3 v\u1EC1 giao di\u1EC7n MCP kh\u00F4ng ch\u00EDnh x\u00E1c +10114=X\u00E1c th\u1EF1c giao di\u1EC7n MCP th\u1EA5t b\u1EA1i +10115=\u0110\u1ECBa ch\u1EC9 giao di\u1EC7n d\u1EA5u gi\u1ECDng n\u00F3i kh\u00F4ng th\u1EC3 \u0111\u1EC3 tr\u1ED1ng +10116=\u0110\u1ECBa ch\u1EC9 giao di\u1EC7n d\u1EA5u gi\u1ECDng n\u00F3i kh\u00F4ng th\u1EC3 s\u1EED d\u1EE5ng localhost ho\u1EB7c 127.0.0.1 +10117=Kh\u00F4ng ph\u1EA3i \u0111\u1ECBa ch\u1EC9 giao di\u1EC7n d\u1EA5u gi\u1ECDng n\u00F3i h\u1EE3p l\u1EC7 +10118=\u0110\u1ECBa ch\u1EC9 giao di\u1EC7n d\u1EA5u gi\u1ECDng n\u00F3i ph\u1EA3i b\u1EAFt \u0111\u1EA7u b\u1EB1ng http ho\u1EB7c https +10119=Truy c\u1EADp giao di\u1EC7n d\u1EA5u gi\u1ECDng n\u00F3i th\u1EA5t b\u1EA1i +10120=\u0110\u1ECBnh d\u1EA1ng n\u1ED9i dung tr\u1EA3 v\u1EC1 giao di\u1EC7n d\u1EA5u gi\u1ECDng n\u00F3i kh\u00F4ng ch\u00EDnh x\u00E1c +10121=X\u00E1c th\u1EF1c giao di\u1EC7n d\u1EA5u gi\u1ECDng n\u00F3i th\u1EA5t b\u1EA1i +10122=B\u00ED m\u1EADt MQTT kh\u00F4ng th\u1EC3 \u0111\u1EC3 tr\u1ED1ng +10123=B\u00ED m\u1EADt MQTT c\u1EE7a b\u1EA1n kh\u00F4ng an to\u00E0n, c\u1EA7n \u00EDt nh\u1EA5t 8 k\u00FD t\u1EF1 v\u00E0 ph\u1EA3i ch\u1EE9a c\u1EA3 ch\u1EEF hoa v\u00E0 ch\u1EEF th\u01B0\u1EDDng +10124=B\u00ED m\u1EADt MQTT c\u1EE7a b\u1EA1n kh\u00F4ng an to\u00E0n, b\u00ED m\u1EADt MQTT ph\u1EA3i ch\u1EE9a c\u1EA3 ch\u1EEF hoa v\u00E0 ch\u1EEF th\u01B0\u1EDDng +10125=B\u00ED m\u1EADt MQTT c\u1EE7a b\u1EA1n ch\u1EE9a m\u1EADt kh\u1EA9u y\u1EBFu +10128=Nh\u00E3n t\u1EEB \u0111i\u1EC3n b\u1ECB tr\u00F9ng l\u1EB7p +10129=Kh\u00F3a SM2 ch\u01B0a \u0111\u01B0\u1EE3c c\u1EA5u h\u00ECnh +10130=Gi\u1EA3i m\u00E3 SM2 th\u1EA5t b\u1EA1i +10131=modelType v\u00E0 provideCode kh\u00F4ng th\u1EC3 \u0111\u1EC3 tr\u1ED1ng +10132=Kh\u00F4ng c\u00F3 quy\u1EC1n xem l\u1ECBch s\u1EED tr\u00F2 chuy\u1EC7n c\u1EE7a agent n\u00E0y +10133=ID phi\u00EAn kh\u00F4ng th\u1EC3 \u0111\u1EC3 tr\u1ED1ng +10134=ID agent kh\u00F4ng th\u1EC3 \u0111\u1EC3 tr\u1ED1ng +10135=T\u1EA3i xu\u1ED1ng l\u1ECBch s\u1EED tr\u00F2 chuy\u1EC7n th\u1EA5t b\u1EA1i +10136=Li\u00EAn k\u1EBFt t\u1EA3i xu\u1ED1ng \u0111\u00E3 h\u1EBFt h\u1EA1n ho\u1EB7c kh\u00F4ng h\u1EE3p l\u1EC7 +10137=Li\u00EAn k\u1EBFt t\u1EA3i xu\u1ED1ng kh\u00F4ng h\u1EE3p l\u1EC7 +10138=Ng\u01B0\u1EDDi d\u00F9ng 10139=Agent -10140=Tệp âm thanh không thể để trống -10141=Chỉ hỗ trợ tệp âm thanh -10142=Kích thước tệp âm thanh không thể vượt quá 10MB -10143=Tải lên thất bại -10144=Bản ghi nhân bản giọng nói không tồn tại -10145=Thông tin tài nguyên giọng nói không thể để trống -10146=Tên nền tảng TTS không thể để trống -10147=ID giọng nói không thể để trống -10148=Tài khoản chủ sở hữu không thể để trống -10149=ID tài nguyên giọng nói cần xóa không thể để trống -10150=Bạn không có quyền thao tác bản ghi này -10151=Vui lòng tải lên tệp âm thanh trước -10152=Không tìm thấy cấu hình mô hình -10153=Không tìm thấy loại mô hình -10154=Đào tạo thất bại: {0} -10155=Thiếu cấu hình Huoshan Engine -10156=Lỗi định dạng phản hồi, thiếu trường BaseResp -10157=Yêu cầu thất bại -10158=Nhân bản âm sắc: -10159=ID giọng nói đã tồn tại -10160=Lỗi định dạng ID giọng nói Huoshan Engine, phải bắt đầu bằng S_ -10161=Địa chỉ Mac đã tồn tại -10162=Nhà cung cấp mô hình không tồn tại -10163=Bản ghi cơ sở kiến thức không tồn tại -10164=Không tìm thấy cấu hình RAG -10165=Lỗi loại cấu hình RAG -10166=Không tìm thấy cấu hình RAG mặc định -10167=Gọi API RAG thất bại: {0} -10168=Tải lên tệp thất bại -10169=Không có quyền thao tác cơ sở kiến thức này -10170=Tên cơ sở kiến thức đã tồn tại -10171=Cấu hình RAG base_url không thể để trống -10172=Cấu hình RAG api_key không thể để trống -10173=Cấu hình RAG api_key không thể chứa trình giữ chỗ, vui lòng thay thế bằng khóa API thực tế -10174=Lỗi định dạng cấu hình RAG base_url, phải bắt đầu bằng http hoặc https -10175=Địa chỉ Mac không thể để trống -10176=Cấu hình RAG dataset_id không thể để trống -10177=Cấu hình RAG model_id không thể để trống -10178=Cấu hình RAG dataset_id và model_id không thể để trống -10179=Tên tệp không thể để trống -10180=Nội dung tệp không thể để trống -10181=Tên nhân bản giọng nói không thể để trống -10182=Không tìm thấy âm thanh nhân bản giọng nói -10183=Không tìm thấy mẫu agent mặc định -10184=Loại bộ chuyển đổi không được hỗ trợ -10185=Kiểm tra cấu hình RAG thất bại -10186=Tạo bộ chuyển đổi thất bại -10187=Khởi tạo bộ chuyển đổi thất bại -10188=Kiểm tra kết nối bộ chuyển đổi thất bại -10189=Thao tác bộ chuyển đổi thất bại -10190=Không tìm thấy bộ chuyển đổi -10191=Lỗi bộ nhớ đệm bộ chuyển đổi -10192=Không tìm thấy loại bộ chuyển đổi \ No newline at end of file +10140=T\u1EC7p \u00E2m thanh kh\u00F4ng th\u1EC3 \u0111\u1EC3 tr\u1ED1ng +10141=Ch\u1EC9 h\u1ED7 tr\u1EE3 t\u1EC7p \u00E2m thanh +10142=K\u00EDch th\u01B0\u1EDBc t\u1EC7p \u00E2m thanh kh\u00F4ng th\u1EC3 v\u01B0\u1EE3t qu\u00E1 10MB +10143=T\u1EA3i l\u00EAn th\u1EA5t b\u1EA1i +10144=B\u1EA3n ghi nh\u00E2n b\u1EA3n gi\u1ECDng n\u00F3i kh\u00F4ng t\u1ED3n t\u1EA1i +10145=Th\u00F4ng tin t\u00E0i nguy\u00EAn gi\u1ECDng n\u00F3i kh\u00F4ng th\u1EC3 \u0111\u1EC3 tr\u1ED1ng +10146=T\u00EAn n\u1EC1n t\u1EA3ng TTS kh\u00F4ng th\u1EC3 \u0111\u1EC3 tr\u1ED1ng +10147=ID gi\u1ECDng n\u00F3i kh\u00F4ng th\u1EC3 \u0111\u1EC3 tr\u1ED1ng +10148=T\u00E0i kho\u1EA3n ch\u1EE7 s\u1EDF h\u1EEFu kh\u00F4ng th\u1EC3 \u0111\u1EC3 tr\u1ED1ng +10149=ID t\u00E0i nguy\u00EAn gi\u1ECDng n\u00F3i c\u1EA7n x\u00F3a kh\u00F4ng th\u1EC3 \u0111\u1EC3 tr\u1ED1ng +10150=B\u1EA1n kh\u00F4ng c\u00F3 quy\u1EC1n thao t\u00E1c b\u1EA3n ghi n\u00E0y +10151=Vui l\u00F2ng t\u1EA3i l\u00EAn t\u1EC7p \u00E2m thanh tr\u01B0\u1EDBc +10152=Kh\u00F4ng t\u00ECm th\u1EA5y c\u1EA5u h\u00ECnh m\u00F4 h\u00ECnh +10153=Kh\u00F4ng t\u00ECm th\u1EA5y lo\u1EA1i m\u00F4 h\u00ECnh +10154=\u0110\u00E0o t\u1EA1o th\u1EA5t b\u1EA1i: {0} +10155=Thi\u1EBFu c\u1EA5u h\u00ECnh Huoshan Engine +10156=L\u1ED7i \u0111\u1ECBnh d\u1EA1ng ph\u1EA3n h\u1ED3i, thi\u1EBFu tr\u01B0\u1EDDng BaseResp +10157=Y\u00EAu c\u1EA7u th\u1EA5t b\u1EA1i +10158=Nh\u00E2n b\u1EA3n \u00E2m s\u1EAFc: +10159=ID gi\u1ECDng n\u00F3i \u0111\u00E3 t\u1ED3n t\u1EA1i +10160=L\u1ED7i \u0111\u1ECBnh d\u1EA1ng ID gi\u1ECDng n\u00F3i Huoshan Engine, ph\u1EA3i b\u1EAFt \u0111\u1EA7u b\u1EB1ng S_ +10161=\u0110\u1ECBa ch\u1EC9 Mac \u0111\u00E3 t\u1ED3n t\u1EA1i +10162=Nh\u00E0 cung c\u1EA5p m\u00F4 h\u00ECnh kh\u00F4ng t\u1ED3n t\u1EA1i +10163=B\u1EA3n ghi c\u01A1 s\u1EDF ki\u1EBFn th\u1EE9c kh\u00F4ng t\u1ED3n t\u1EA1i +10164=Kh\u00F4ng t\u00ECm th\u1EA5y c\u1EA5u h\u00ECnh RAG +10165=L\u1ED7i lo\u1EA1i c\u1EA5u h\u00ECnh RAG +10166=Kh\u00F4ng t\u00ECm th\u1EA5y c\u1EA5u h\u00ECnh RAG m\u1EB7c \u0111\u1ECBnh +10167=G\u1ECDi API RAG th\u1EA5t b\u1EA1i: {0} +10168=T\u1EA3i l\u00EAn t\u1EC7p th\u1EA5t b\u1EA1i +10169=Kh\u00F4ng c\u00F3 quy\u1EC1n thao t\u00E1c c\u01A1 s\u1EDF ki\u1EBFn th\u1EE9c n\u00E0y +10170=T\u00EAn c\u01A1 s\u1EDF ki\u1EBFn th\u1EE9c \u0111\u00E3 t\u1ED3n t\u1EA1i +10171=C\u1EA5u h\u00ECnh RAG base_url kh\u00F4ng th\u1EC3 \u0111\u1EC3 tr\u1ED1ng +10172=C\u1EA5u h\u00ECnh RAG api_key kh\u00F4ng th\u1EC3 \u0111\u1EC3 tr\u1ED1ng +10173=C\u1EA5u h\u00ECnh RAG api_key kh\u00F4ng th\u1EC3 ch\u1EE9a tr\u00ECnh gi\u1EEF ch\u1ED7, vui l\u00F2ng thay th\u1EBF b\u1EB1ng kh\u00F3a API th\u1EF1c t\u1EBF +10174=L\u1ED7i \u0111\u1ECBnh d\u1EA1ng c\u1EA5u h\u00ECnh RAG base_url, ph\u1EA3i b\u1EAFt \u0111\u1EA7u b\u1EB1ng http ho\u1EB7c https +10175=\u0110\u1ECBa ch\u1EC9 Mac kh\u00F4ng th\u1EC3 \u0111\u1EC3 tr\u1ED1ng +10176=C\u1EA5u h\u00ECnh RAG dataset_id kh\u00F4ng th\u1EC3 \u0111\u1EC3 tr\u1ED1ng +10177=C\u1EA5u h\u00ECnh RAG model_id kh\u00F4ng th\u1EC3 \u0111\u1EC3 tr\u1ED1ng +10178=C\u1EA5u h\u00ECnh RAG dataset_id v\u00E0 model_id kh\u00F4ng th\u1EC3 \u0111\u1EC3 tr\u1ED1ng +10179=T\u00EAn t\u1EC7p kh\u00F4ng th\u1EC3 \u0111\u1EC3 tr\u1ED1ng +10180=N\u1ED9i dung t\u1EC7p kh\u00F4ng th\u1EC3 \u0111\u1EC3 tr\u1ED1ng +10181=T\u00EAn nh\u00E2n b\u1EA3n gi\u1ECDng n\u00F3i kh\u00F4ng th\u1EC3 \u0111\u1EC3 tr\u1ED1ng +10182=Kh\u00F4ng t\u00ECm th\u1EA5y \u00E2m thanh nh\u00E2n b\u1EA3n gi\u1ECDng n\u00F3i +10183=Kh\u00F4ng t\u00ECm th\u1EA5y m\u1EABu agent m\u1EB7c \u0111\u1ECBnh +10184=Lo\u1EA1i b\u1ED9 chuy\u1EC3n \u0111\u1ED5i kh\u00F4ng \u0111\u01B0\u1EE3c h\u1ED7 tr\u1EE3 +10185=Ki\u1EC3m tra c\u1EA5u h\u00ECnh RAG th\u1EA5t b\u1EA1i +10186=T\u1EA1o b\u1ED9 chuy\u1EC3n \u0111\u1ED5i th\u1EA5t b\u1EA1i +10187=Kh\u1EDFi t\u1EA1o b\u1ED9 chuy\u1EC3n \u0111\u1ED5i th\u1EA5t b\u1EA1i +10188=Ki\u1EC3m tra k\u1EBFt n\u1ED1i b\u1ED9 chuy\u1EC3n \u0111\u1ED5i th\u1EA5t b\u1EA1i +10189=Thao t\u00E1c b\u1ED9 chuy\u1EC3n \u0111\u1ED5i th\u1EA5t b\u1EA1i +10190=Kh\u00F4ng t\u00ECm th\u1EA5y b\u1ED9 chuy\u1EC3n \u0111\u1ED5i +10191=L\u1ED7i b\u1ED9 nh\u1EDB \u0111\u1EC7m b\u1ED9 chuy\u1EC3n \u0111\u1ED5i +10192=Kh\u00F4ng t\u00ECm th\u1EA5y lo\u1EA1i b\u1ED9 chuy\u1EC3n \u0111\u1ED5i +10193=ID thi\u1EBFt b\u1ECB kh\u00F4ng th\u1EC3 tr\u1ED1ng +10194=Kh\u00F4ng t\u00ECm th\u1EA5y thi\u1EBFt b\u1ECB \ No newline at end of file diff --git a/main/manager-api/src/main/resources/i18n/messages_zh_CN.properties b/main/manager-api/src/main/resources/i18n/messages_zh_CN.properties index 187c0ccb..324fc4fd 100644 --- a/main/manager-api/src/main/resources/i18n/messages_zh_CN.properties +++ b/main/manager-api/src/main/resources/i18n/messages_zh_CN.properties @@ -198,4 +198,6 @@ 10189=\u9002\u914D\u5668\u64CD\u4F5C\u5931\u8D25 10190=\u9002\u914D\u5668\u672A\u627E\u5230 10191=\u9002\u914D\u5668\u7F13\u5B58\u9519\u8BEF -10192=\u9002\u914D\u5668\u7C7B\u578B\u672A\u627E\u5230 \ No newline at end of file +10192=\u9002\u914D\u5668\u7C7B\u578B\u672A\u627E\u5230 +10193=\u8BBE\u5907ID\u4E0D\u80FD\u4E3A\u7A7A +10194=\u8BBE\u5907\u4E0D\u5B58\u5728 \ No newline at end of file diff --git a/main/manager-api/src/main/resources/i18n/messages_zh_TW.properties b/main/manager-api/src/main/resources/i18n/messages_zh_TW.properties index ce1d9ef4..4c4f9b48 100644 --- a/main/manager-api/src/main/resources/i18n/messages_zh_TW.properties +++ b/main/manager-api/src/main/resources/i18n/messages_zh_TW.properties @@ -164,7 +164,7 @@ 10155=\u706B\u5C71\u5F15\u64CE\u7F3A\u5C11appid\u6216access_token 10156=\u97FF\u61C9\u683C\u5F0F\u932F\u8AA4\uFF0C\u7F3A\u5C11BaseResp\u5B57\u6BB5 10157=\u8ACB\u6C42\u5931\u6557 -10158=\u514b\u9686\u97f3\u8272: +10158=\u514B\u9686\u97F3\u8272: 10159=\u97F3\u8272ID\u5DF2\u5B58\u5728 10160=\u706B\u5C71\u5F15\u64CE\u97F3\u8272ID\u683C\u5F0F\u932F\u8AA4\uFF0C\u5FC5\u9808\u4EE5S_\u958B\u982D 10161=Mac\u5730\u5740\u5DF2\u5B58\u5728 @@ -173,23 +173,23 @@ 10164=RAG\u914D\u7F6E\u672A\u627E\u5230 10165=RAG\u914D\u7F6E\u985E\u578B\u932F\u8AA4 10166=\u9810\u8A2DRAG\u914D\u7F6E\u672A\u627E\u5230 -10167=\u0052\u0041\u0047\u8abf\u7528\u5931\u6557\uFF0C{0} +10167=RAG\u8ABF\u7528\u5931\u6557\uFF0C{0} 10168=\u4E0A\u50B3\u6587\u4EF6\u5931\u6557 10169=\u60A8\u6C92\u6709\u6B0A\u9650\u64CD\u4F5C\u8A72\u8A18\u9304 10170=\u77E5\u8B58\u5EAB\u540D\u7A31\u91CD\u8907 -10171=\u0052\u0041\u0047\u914D\u7F6E\u4F53\u7684base_url\u4E0D\u80FD\u4E3A\u7A7A -10172=\u0052\u0041\u0047\u914D\u7F6E\u4F53\u7684api_key\u4E0D\u80FD\u4E3A\u7A7A -10173=\u0052\u0041\u0047\u914D\u7F6E\u4F53\u7684api_key\u4E0D\u80FD\u4E3A\u7A7A\uFF0C\u8BF7\u66F4\u6362\u4E3A\u5728\u53D6\u7684API\u53C2\u6570 -10174=\u0052\u0041\u0047\u914D\u7F6E\u4F53\u7684base_url\u683C\u5F0F\u9519\u8BEF\uFF0C\u5FC5\u987B\u4EE5http\u6216https\u5F00\u5934 +10171=RAG\u914D\u7F6E\u4F53\u7684base_url\u4E0D\u80FD\u4E3A\u7A7A +10172=RAG\u914D\u7F6E\u4F53\u7684api_key\u4E0D\u80FD\u4E3A\u7A7A +10173=RAG\u914D\u7F6E\u4F53\u7684api_key\u4E0D\u80FD\u4E3A\u7A7A\uFF0C\u8BF7\u66F4\u6362\u4E3A\u5728\u53D6\u7684API\u53C2\u6570 +10174=RAG\u914D\u7F6E\u4F53\u7684base_url\u683C\u5F0F\u9519\u8BEF\uFF0C\u5FC5\u987B\u4EE5http\u6216https\u5F00\u5934 10175=mac\u5730\u5740\u4E0D\u80FD\u4E3A\u7A7A -10176=\u0052\u0041\u0047\u914D\u7F6E\u4F53\u7684dataset_id\u4E0D\u80FD\u4E3A\u7A7A -10177=\u0052\u0041\u0047\u914D\u7F6E\u4F53\u7684model_id\u4E0D\u80FD\u4E3A\u7A7A -10178=\u0052\u0041\u0047\u914D\u7F6E\u4F53\u7684dataset_id\u548Cmodel_id\u4E0D\u80FD\u4E3A\u7A7A -10179=\u6587\u4ef6\u540d\u7a31\u4e0d\u80fd\u70ba\u7a7a -10180=\u6587\u4ef6\u5185\u5bb9\u4e0d\u80fd\u70ba\u7a7a -10181=\u97f3\u8272\u514b\u9686\u540d\u7a31\u4e0d\u80fd\u70ba\u7a7a -10182=\u97f3\u8272\u514b\u9686\u97f3\u983b\u4e0d\u5b58\u5728 -10183=\u9ed8\u8ba4\u667a\u80fd\u4f53\u672a\u627e\u5230 +10176=RAG\u914D\u7F6E\u4F53\u7684dataset_id\u4E0D\u80FD\u4E3A\u7A7A +10177=RAG\u914D\u7F6E\u4F53\u7684model_id\u4E0D\u80FD\u4E3A\u7A7A +10178=RAG\u914D\u7F6E\u4F53\u7684dataset_id\u548Cmodel_id\u4E0D\u80FD\u4E3A\u7A7A +10179=\u6587\u4EF6\u540D\u7A31\u4E0D\u80FD\u70BA\u7A7A +10180=\u6587\u4EF6\u5185\u5BB9\u4E0D\u80FD\u70BA\u7A7A +10181=\u97F3\u8272\u514B\u9686\u540D\u7A31\u4E0D\u80FD\u70BA\u7A7A +10182=\u97F3\u8272\u514B\u9686\u97F3\u983B\u4E0D\u5B58\u5728 +10183=\u9ED8\u8BA4\u667A\u80FD\u4F53\u672A\u627E\u5230 10184=\u4E0D\u652F\u6301\u7684\u9002\u914D\u5668\u985E\u578B 10185=RAG\u914D\u7F6E\u9A57\u8B49\u5931\u6557 10186=\u9002\u914D\u5668\u5275\u5EFA\u5931\u6557 @@ -198,4 +198,6 @@ 10189=\u9002\u914D\u5668\u64CD\u4F5C\u5931\u6557 10190=\u9002\u914D\u5668\u672A\u627E\u5230 10191=\u9002\u914D\u5668\u7F13\u5B58\u932F\u8AA4 -10192=\u9002\u914D\u5668\u985E\u578B\u672A\u627E\u5230 \ No newline at end of file +10192=\u9002\u914D\u5668\u985E\u578B\u672A\u627E\u5230 +10193=\u8A2D\u5099ID\u4E0D\u80FD\u4E3A\u7A7A +10194=\u8A2D\u5099\u4E0D\u5B58\u5728 From cbb293e7fa15ccc7c37dc7d9ab5e527c980387d0 Mon Sep 17 00:00:00 2001 From: hrz <1710360675@qq.com> Date: Thu, 22 Jan 2026 13:27:10 +0800 Subject: [PATCH 2/2] =?UTF-8?q?add:=E4=B8=8A=E4=BC=A0=E8=87=AA=E5=AE=9A?= =?UTF-8?q?=E4=B9=89=E8=A1=A8=E6=83=85=E5=9B=BA=E4=BB=B6=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../xiaozhi/common/config/SwaggerConfig.java | 2 +- .../xiaozhi/common/exception/ErrorCode.java | 1 + .../java/xiaozhi/common/redis/RedisKeys.java | 15 +++- .../device/controller/DeviceController.java | 28 +++++-- .../device/controller/OTAMagController.java | 58 +++++++++++++- .../device/dto/DeviceToolsCallReqDTO.java | 15 ++++ .../modules/device/service/DeviceService.java | 6 ++ .../service/impl/DeviceServiceImpl.java | 79 +++++++++++++++++++ .../controller/VoiceCloneController.java | 7 ++ .../main/resources/i18n/messages.properties | 3 +- .../resources/i18n/messages_de_DE.properties | 3 +- .../resources/i18n/messages_en_US.properties | 3 +- .../resources/i18n/messages_vi_VN.properties | 3 +- .../resources/i18n/messages_zh_CN.properties | 3 +- .../resources/i18n/messages_zh_TW.properties | 3 +- 15 files changed, 210 insertions(+), 19 deletions(-) create mode 100644 main/manager-api/src/main/java/xiaozhi/modules/device/dto/DeviceToolsCallReqDTO.java diff --git a/main/manager-api/src/main/java/xiaozhi/common/config/SwaggerConfig.java b/main/manager-api/src/main/java/xiaozhi/common/config/SwaggerConfig.java index 8fb31641..25d1ad45 100644 --- a/main/manager-api/src/main/java/xiaozhi/common/config/SwaggerConfig.java +++ b/main/manager-api/src/main/java/xiaozhi/common/config/SwaggerConfig.java @@ -43,7 +43,7 @@ public class SwaggerConfig { public GroupedOpenApi oatApi() { return GroupedOpenApi.builder() .group("ota") - .pathsToMatch("/ota/**") + .pathsToMatch("/ota/**", "/otaMag/**") .build(); } 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 172505a3..3f914e4c 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 @@ -243,5 +243,6 @@ public interface ErrorCode { // 设备工具相关错误码 int DEVICE_ID_NOT_NULL = 10193; // 设备ID不能为空 int DEVICE_NOT_EXIST = 10194; // 设备不存在 + int OTA_UPLOAD_COUNT_EXCEED = 10195; // OTA上传次数超过限制 } diff --git a/main/manager-api/src/main/java/xiaozhi/common/redis/RedisKeys.java b/main/manager-api/src/main/java/xiaozhi/common/redis/RedisKeys.java index 527b9330..6b143930 100644 --- a/main/manager-api/src/main/java/xiaozhi/common/redis/RedisKeys.java +++ b/main/manager-api/src/main/java/xiaozhi/common/redis/RedisKeys.java @@ -170,10 +170,21 @@ public class RedisKeys { /** * OTA绑定设备 */ - public static String getOtaActivationCode(String activationCode) {return "ota:activation:code:" + activationCode;} + public static String getOtaActivationCode(String activationCode) { + return "ota:activation:code:" + activationCode; + } /** * OTA获取设备mac相关信息 */ - public static String getOtaDeviceActivationInfo(String deviceId) {return "ota:activation:data:" + deviceId;} + public static String getOtaDeviceActivationInfo(String deviceId) { + return "ota:activation:data:" + deviceId; + } + + /** + * OTA上传次数 + */ + public static String getOtaUploadCountKey(Long username) { + return "ota:upload:count:" + username; + } } diff --git a/main/manager-api/src/main/java/xiaozhi/modules/device/controller/DeviceController.java b/main/manager-api/src/main/java/xiaozhi/modules/device/controller/DeviceController.java index ff593528..629ba80f 100644 --- a/main/manager-api/src/main/java/xiaozhi/modules/device/controller/DeviceController.java +++ b/main/manager-api/src/main/java/xiaozhi/modules/device/controller/DeviceController.java @@ -24,6 +24,7 @@ import xiaozhi.common.user.UserDetail; import xiaozhi.common.utils.Result; import xiaozhi.modules.device.dto.DeviceManualAddDTO; import xiaozhi.modules.device.dto.DeviceRegisterDTO; +import xiaozhi.modules.device.dto.DeviceToolsCallReqDTO; import xiaozhi.modules.device.dto.DeviceUnBindDTO; import xiaozhi.modules.device.dto.DeviceUpdateDTO; import xiaozhi.modules.device.entity.DeviceEntity; @@ -129,15 +130,10 @@ public class DeviceController { return new Result<>(); } - @PostMapping("/tools/list") + @PostMapping("/tools/list/{deviceId}") @Operation(summary = "获取设备工具列表") @RequiresPermissions("sys:role:normal") - public Result getDeviceTools(@RequestBody Map requestBody) { - String deviceId = requestBody.get("deviceId"); - if (StringUtils.isBlank(deviceId)) { - return new Result().error(ErrorCode.DEVICE_ID_NOT_NULL); - } - + public Result getDeviceTools(@PathVariable String deviceId) { Object toolsData = deviceService.getDeviceTools(deviceId); if (toolsData == null) { return new Result().error(ErrorCode.DEVICE_NOT_EXIST); @@ -145,4 +141,22 @@ public class DeviceController { return new Result().ok(toolsData); } + + @PostMapping("/tools/call/{deviceId}") + @Operation(summary = "调用设备工具") + @RequiresPermissions("sys:role:normal") + public Result callDeviceTool(@PathVariable String deviceId, + @Valid @RequestBody DeviceToolsCallReqDTO request) { + String toolName = request.getName(); + Map arguments = request.getArguments(); + + Object result = deviceService.callDeviceTool(deviceId, toolName, arguments); + if (result == null) { + return new Result().error(ErrorCode.DEVICE_NOT_EXIST); + } + + Result response = new Result(); + response.setMsg("Tools called successfully"); + return response.ok(result); + } } \ No newline at end of file diff --git a/main/manager-api/src/main/java/xiaozhi/modules/device/controller/OTAMagController.java b/main/manager-api/src/main/java/xiaozhi/modules/device/controller/OTAMagController.java index 128ba195..cfdf3913 100644 --- a/main/manager-api/src/main/java/xiaozhi/modules/device/controller/OTAMagController.java +++ b/main/manager-api/src/main/java/xiaozhi/modules/device/controller/OTAMagController.java @@ -38,6 +38,7 @@ import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import xiaozhi.common.constant.Constant; +import xiaozhi.common.exception.ErrorCode; import xiaozhi.common.page.PageData; import xiaozhi.common.redis.RedisKeys; import xiaozhi.common.redis.RedisUtils; @@ -45,8 +46,11 @@ import xiaozhi.common.utils.Result; import xiaozhi.common.validator.ValidatorUtils; import xiaozhi.modules.device.entity.OtaEntity; import xiaozhi.modules.device.service.OtaService; +import xiaozhi.modules.security.user.SecurityUser; +import xiaozhi.modules.sys.enums.SuperAdminEnum; +import xiaozhi.modules.sys.service.SysParamsService; -@Tag(name = "设备管理", description = "OTA 相关接口") +@Tag(name = "固件升级管理", description = "OTA 相关接口") @Slf4j @RestController @RequiredArgsConstructor @@ -55,6 +59,7 @@ public class OTAMagController { private static final Logger logger = LoggerFactory.getLogger(OTAController.class); private final OtaService otaService; private final RedisUtils redisUtils; + private final SysParamsService sysParamsService; @GetMapping @Operation(summary = "分页查询 OTA 固件信息") @@ -160,7 +165,17 @@ public class OTAMagController { try { // 获取固件信息 - OtaEntity otaEntity = otaService.selectById(id); + OtaEntity otaEntity = null; + if (id.indexOf("file:") == 0) { + id = id.substring(5); + otaEntity = new OtaEntity(); + otaEntity.setFirmwarePath(id); + otaEntity.setType("assets"); + otaEntity.setVersion("1.0.0"); + } else { + otaEntity = otaService.selectById(id); + } + if (otaEntity == null || StringUtils.isBlank(otaEntity.getFirmwarePath())) { logger.warn("Firmware not found or path is empty for ID: {}", id); return ResponseEntity.notFound().build(); @@ -168,6 +183,7 @@ public class OTAMagController { // 获取文件路径 - 确保路径是绝对路径或正确的相对路径 String firmwarePath = otaEntity.getFirmwarePath(); + String originalFilename = otaEntity.getType() + "_" + otaEntity.getVersion(); Path path; // 检查是否是绝对路径 @@ -201,7 +217,7 @@ public class OTAMagController { byte[] fileContent = Files.readAllBytes(path); // 设置响应头 - String originalFilename = otaEntity.getType() + "_" + otaEntity.getVersion(); + if (firmwarePath.contains(".")) { String extension = firmwarePath.substring(firmwarePath.lastIndexOf(".")); originalFilename += extension; @@ -277,6 +293,42 @@ public class OTAMagController { } } + @PostMapping("/uploadAssetsBin") + @Operation(summary = "上传资源固件文件") + @RequiresPermissions("sys:role:normal") + public Result uploadAssetsBin(@RequestParam("file") MultipartFile file) { + String otaUrl = sysParamsService.getValue(Constant.SERVER_OTA, true); + if (StringUtils.isBlank(otaUrl) || otaUrl.equals("null")) { + return new Result().error(ErrorCode.OTA_URL_EMPTY); + } + logger.info("username:{},uploadAssetsBin size: {}", SecurityUser.getUser().getUsername(), file.getSize()); + // 验证文件大小 (资源固件最大20MB) + if (file.getSize() > 20 * 1024 * 1024) { + return new Result().error(ErrorCode.VOICE_CLONE_AUDIO_TOO_LARGE); + } + // 普通用户只能每天上传50次 + if (SecurityUser.getUser().getSuperAdmin() == SuperAdminEnum.NO.value()) { + String uploadCountKey = RedisKeys.getOtaUploadCountKey(SecurityUser.getUser().getId()); + Integer uploadCount = (Integer) Optional.ofNullable(redisUtils.get(uploadCountKey)).orElse(0); + if (uploadCount >= 50) { + return new Result().error(ErrorCode.OTA_UPLOAD_COUNT_EXCEED); + } + // 增加上传次数 + redisUtils.increment(RedisKeys.getOtaUploadCountKey(SecurityUser.getUser().getId()), + RedisUtils.DEFAULT_EXPIRE); + } + Result result = uploadFirmware(file); + + // 生成资源文件路径 + if (StringUtils.isNotBlank(result.getData())) { + String uuid = UUID.randomUUID().toString(); + redisUtils.set(RedisKeys.getOtaIdKey(uuid), "file:" + result.getData()); + String downloadUrl = otaUrl.replace("/ota/", "/otaMag/download/") + uuid; + result.setData(downloadUrl); + } + return result; + } + private String calculateMD5(MultipartFile file) throws IOException, NoSuchAlgorithmException { MessageDigest md = MessageDigest.getInstance("MD5"); byte[] digest = md.digest(file.getBytes()); diff --git a/main/manager-api/src/main/java/xiaozhi/modules/device/dto/DeviceToolsCallReqDTO.java b/main/manager-api/src/main/java/xiaozhi/modules/device/dto/DeviceToolsCallReqDTO.java new file mode 100644 index 00000000..777bee03 --- /dev/null +++ b/main/manager-api/src/main/java/xiaozhi/modules/device/dto/DeviceToolsCallReqDTO.java @@ -0,0 +1,15 @@ +package xiaozhi.modules.device.dto; + +import java.util.Map; + +import jakarta.validation.constraints.NotBlank; +import lombok.Data; + +@Data +public class DeviceToolsCallReqDTO { + + @NotBlank(message = "工具名称不能为空") + private String name; + + private Map arguments; +} \ No newline at end of file diff --git a/main/manager-api/src/main/java/xiaozhi/modules/device/service/DeviceService.java b/main/manager-api/src/main/java/xiaozhi/modules/device/service/DeviceService.java index b34a0c4a..ecbf719c 100644 --- a/main/manager-api/src/main/java/xiaozhi/modules/device/service/DeviceService.java +++ b/main/manager-api/src/main/java/xiaozhi/modules/device/service/DeviceService.java @@ -2,6 +2,7 @@ package xiaozhi.modules.device.service; import java.util.Date; import java.util.List; +import java.util.Map; import xiaozhi.common.page.PageData; import xiaozhi.common.service.BaseService; @@ -127,4 +128,9 @@ public interface DeviceService extends BaseService { */ Object getDeviceTools(String deviceId); + /** + * 调用设备工具 + */ + Object callDeviceTool(String deviceId, String toolName, Map arguments); + } \ No newline at end of file diff --git a/main/manager-api/src/main/java/xiaozhi/modules/device/service/impl/DeviceServiceImpl.java b/main/manager-api/src/main/java/xiaozhi/modules/device/service/impl/DeviceServiceImpl.java index 856b627b..09ab63bd 100644 --- a/main/manager-api/src/main/java/xiaozhi/modules/device/service/impl/DeviceServiceImpl.java +++ b/main/manager-api/src/main/java/xiaozhi/modules/device/service/impl/DeviceServiceImpl.java @@ -735,4 +735,83 @@ public class DeviceServiceImpl extends BaseServiceImpl return null; } + + @Override + public Object callDeviceTool(String deviceId, String toolName, Map arguments) { + // 从系统参数中获取MQTT网关地址 + String mqttGatewayUrl = sysParamsService.getValue("server.mqtt_manager_api", true); + if (StringUtils.isBlank(mqttGatewayUrl) || "null".equals(mqttGatewayUrl)) { + return null; + } + + // 获取设备信息 + DeviceEntity device = baseDao.selectById(deviceId); + if (device == null) { + return null; + } + + // 检查设备是否属于当前用户 + UserDetail user = SecurityUser.getUser(); + if (!device.getUserId().equals(user.getId())) { + return null; + } + + // 构建clientId + String macAddress = Optional.ofNullable(device.getMacAddress()).orElse("unknown").replace(":", "_"); + String groupId = Optional.ofNullable(device.getBoard()).orElse("GID_default").replace(":", "_"); + String clientId = StrUtil.format("{}@@@{}@@@{}", groupId, macAddress, macAddress); + + // 构建完整的URL + String url = StrUtil.format("http://{}/api/commands/{}", mqttGatewayUrl, clientId); + + // 构建请求体 + Map params = MapUtil + .builder(new HashMap()) + .put("name", toolName) + .put("arguments", arguments) + .build(); + + Map payload = MapUtil + .builder(new HashMap()) + .put("jsonrpc", "2.0") + .put("id", 2) + .put("method", "tools/call") + .put("params", params) + .build(); + + Map requestBody = MapUtil + .builder(new HashMap()) + .put("type", "mcp") + .put("payload", payload) + .build(); + + // 发送请求 + String resultMessage = HttpRequest.post(url) + .header(Header.CONTENT_TYPE, ContentType.JSON.getValue()) + .header(Header.AUTHORIZATION, "Bearer " + generateBearerToken()) + .body(JSONUtil.toJsonStr(requestBody)) + .timeout(10000) // 超时,毫秒 + .execute().body(); + + // 解析响应 + if (StringUtils.isNotBlank(resultMessage)) { + cn.hutool.json.JSONObject jsonObject = JSONUtil.parseObj(resultMessage); + if (jsonObject.getBool("success", false)) { + cn.hutool.json.JSONObject data = jsonObject.getJSONObject("data"); + if (data != null) { + cn.hutool.json.JSONArray content = data.getJSONArray("content"); + if (content != null && content.size() > 0) { + cn.hutool.json.JSONObject firstContent = content.getJSONObject(0); + if (firstContent != null && "text".equals(firstContent.getStr("type"))) { + String text = firstContent.getStr("text"); + if (StringUtils.isNotBlank(text)) { + return JSONUtil.parseObj(text); + } + } + } + } + } + } + return null; + } } diff --git a/main/manager-api/src/main/java/xiaozhi/modules/voiceclone/controller/VoiceCloneController.java b/main/manager-api/src/main/java/xiaozhi/modules/voiceclone/controller/VoiceCloneController.java index a85dd34a..21370a46 100644 --- a/main/manager-api/src/main/java/xiaozhi/modules/voiceclone/controller/VoiceCloneController.java +++ b/main/manager-api/src/main/java/xiaozhi/modules/voiceclone/controller/VoiceCloneController.java @@ -83,6 +83,13 @@ public class VoiceCloneController { return new Result().error(ErrorCode.VOICE_CLONE_NOT_AUDIO_FILE); } + // 加强验证文件扩展名 + String originalFilename = voiceFile.getOriginalFilename(); + String extension = originalFilename.substring(originalFilename.lastIndexOf(".")).toLowerCase(); + if (!extension.equals(".mp3") && !extension.equals(".wav")) { + return new Result().error("只允许上传.mp3和.wav格式的文件"); + } + // 验证文件大小 (最大10MB) if (voiceFile.getSize() > 10 * 1024 * 1024) { return new Result().error(ErrorCode.VOICE_CLONE_AUDIO_TOO_LARGE); diff --git a/main/manager-api/src/main/resources/i18n/messages.properties b/main/manager-api/src/main/resources/i18n/messages.properties index 324fc4fd..25cd7021 100644 --- a/main/manager-api/src/main/resources/i18n/messages.properties +++ b/main/manager-api/src/main/resources/i18n/messages.properties @@ -200,4 +200,5 @@ 10191=\u9002\u914D\u5668\u7F13\u5B58\u9519\u8BEF 10192=\u9002\u914D\u5668\u7C7B\u578B\u672A\u627E\u5230 10193=\u8BBE\u5907ID\u4E0D\u80FD\u4E3A\u7A7A -10194=\u8BBE\u5907\u4E0D\u5B58\u5728 \ No newline at end of file +10194=\u8BBE\u5907\u4E0D\u5B58\u5728\u6216\u4E0D\u5728\u7EBF +10195=OTA\u4E0A\u4F20\u6B21\u6570\u8D85\u8FC7\u9650\u5236 \ No newline at end of file diff --git a/main/manager-api/src/main/resources/i18n/messages_de_DE.properties b/main/manager-api/src/main/resources/i18n/messages_de_DE.properties index 1e3b1f44..0b9ed96d 100644 --- a/main/manager-api/src/main/resources/i18n/messages_de_DE.properties +++ b/main/manager-api/src/main/resources/i18n/messages_de_DE.properties @@ -200,4 +200,5 @@ 10191=Adapter-Cache-Fehler 10192=Adaptertyp nicht gefunden 10193=Adapter-ID darf nicht leer sein -10194=Adapter nicht gefunden \ No newline at end of file +10194=Adapter nicht gefunden oder nicht online +10195=OTA-Upload-Anzahl \u00FCberschreitet das Limit \ No newline at end of file diff --git a/main/manager-api/src/main/resources/i18n/messages_en_US.properties b/main/manager-api/src/main/resources/i18n/messages_en_US.properties index 71f98a76..17b1b961 100644 --- a/main/manager-api/src/main/resources/i18n/messages_en_US.properties +++ b/main/manager-api/src/main/resources/i18n/messages_en_US.properties @@ -200,4 +200,5 @@ 10191=Adapter cache error 10192=Adapter type not found 10193=Device ID cannot be empty -10194=Device not found \ No newline at end of file +10194=Device not found or not online +10195=OTA upload times exceed the limit \ No newline at end of file diff --git a/main/manager-api/src/main/resources/i18n/messages_vi_VN.properties b/main/manager-api/src/main/resources/i18n/messages_vi_VN.properties index 91e5cfff..3b80a6dc 100644 --- a/main/manager-api/src/main/resources/i18n/messages_vi_VN.properties +++ b/main/manager-api/src/main/resources/i18n/messages_vi_VN.properties @@ -200,4 +200,5 @@ 10191=L\u1ED7i b\u1ED9 nh\u1EDB \u0111\u1EC7m b\u1ED9 chuy\u1EC3n \u0111\u1ED5i 10192=Kh\u00F4ng t\u00ECm th\u1EA5y lo\u1EA1i b\u1ED9 chuy\u1EC3n \u0111\u1ED5i 10193=ID thi\u1EBFt b\u1ECB kh\u00F4ng th\u1EC3 tr\u1ED1ng -10194=Kh\u00F4ng t\u00ECm th\u1EA5y thi\u1EBFt b\u1ECB \ No newline at end of file +10194=Kh\u00F4ng t\u00ECm th\u1EA5y thi\u1EBFt b\u1ECB ho\u1EB7c thi\u1EBFt b\u1ECB kh\u00F4ng tr\u1EF1c tuy\u1EBFn +10195=S\u1ED1 l\u1EA7n t\u1EA3i l\u00EAn OTA v\u01B0\u1EE3t qu\u00E1 gi\u1EDBi h\u1EA1n \ No newline at end of file diff --git a/main/manager-api/src/main/resources/i18n/messages_zh_CN.properties b/main/manager-api/src/main/resources/i18n/messages_zh_CN.properties index 324fc4fd..25cd7021 100644 --- a/main/manager-api/src/main/resources/i18n/messages_zh_CN.properties +++ b/main/manager-api/src/main/resources/i18n/messages_zh_CN.properties @@ -200,4 +200,5 @@ 10191=\u9002\u914D\u5668\u7F13\u5B58\u9519\u8BEF 10192=\u9002\u914D\u5668\u7C7B\u578B\u672A\u627E\u5230 10193=\u8BBE\u5907ID\u4E0D\u80FD\u4E3A\u7A7A -10194=\u8BBE\u5907\u4E0D\u5B58\u5728 \ No newline at end of file +10194=\u8BBE\u5907\u4E0D\u5B58\u5728\u6216\u4E0D\u5728\u7EBF +10195=OTA\u4E0A\u4F20\u6B21\u6570\u8D85\u8FC7\u9650\u5236 \ No newline at end of file diff --git a/main/manager-api/src/main/resources/i18n/messages_zh_TW.properties b/main/manager-api/src/main/resources/i18n/messages_zh_TW.properties index 4c4f9b48..f6913eea 100644 --- a/main/manager-api/src/main/resources/i18n/messages_zh_TW.properties +++ b/main/manager-api/src/main/resources/i18n/messages_zh_TW.properties @@ -200,4 +200,5 @@ 10191=\u9002\u914D\u5668\u7F13\u5B58\u932F\u8AA4 10192=\u9002\u914D\u5668\u985E\u578B\u672A\u627E\u5230 10193=\u8A2D\u5099ID\u4E0D\u80FD\u4E3A\u7A7A -10194=\u8A2D\u5099\u4E0D\u5B58\u5728 +10194=\u8A2D\u5099\u4E0D\u5B58\u5728\u6216\u672A\u5728\u7DDA +10195=OTA\u4E0A\u4F20\u6B21\u6578\u8D85\u904E\u9650\u5236 \ No newline at end of file