diff --git a/README.md b/README.md index 989cc130..a783b3e9 100644 --- a/README.md +++ b/README.md @@ -163,6 +163,8 @@ server: ``` 智控台地址: https://2662r3426b.vicp.fun + +服务测试工具: https://2662r3426b.vicp.fun/test/ OTA接口地址: https://2662r3426b.vicp.fun/xiaozhi/ota/ Websocket接口地址: wss://2662r3426b.vicp.fun/xiaozhi/v1/ ``` diff --git a/docs/FAQ.md b/docs/FAQ.md index c859498a..cfcbe373 100644 --- a/docs/FAQ.md +++ b/docs/FAQ.md @@ -106,10 +106,6 @@ VAD: ### 8、更多问题,可联系我们反馈 💬 -我们的联系方式放在[百度网盘中,点击前往](https://pan.baidu.com/s/1x6USjvP1nTRsZ45XlJu65Q),提取码是`223y`。 +可以在[issues](https://github.com/xinnan-tech/xiaozhi-esp32-server/issues)提交您的问题。 -网盘里有"硬件烧录QQ群"、"开源服务端交流群"、"产品建议联系人" 三张图片,请根据需要选择加入。 - -- 硬件烧录QQ群:适用于硬件烧录问题 -- 开源服务端交流群:适用于服务端问题 -- 产品建议联系人:适用于产品功能、产品设计等建议 \ No newline at end of file +也可以发邮件我们取得联系:huangrongzhuang@xin-nan.com \ No newline at end of file diff --git a/docs/firmware-build.md b/docs/firmware-build.md index f9935951..fffac288 100644 --- a/docs/firmware-build.md +++ b/docs/firmware-build.md @@ -86,14 +86,9 @@ idf.py set-target esp32s3 idf.py menuconfig ``` -![图片](images/build_setting01.png) - -进入菜单配置后,再进入`Xiaozhi Assistant`,将`CONNECTION_TYPE`设置为`Websocket` -回退到主菜单,再进入`Xiaozhi Assistant`,将`BOARD_TYPE`设置你板子的具体型号 +进入菜单配置后,再进入`Xiaozhi Assistant`,将`BOARD_TYPE`设置你板子的具体型号 保存退出,回到终端命令行。 -![图片](images/build_setting02.png) - ## 第5步 编译固件 ``` diff --git a/docs/images/build_setting01.png b/docs/images/build_setting01.png deleted file mode 100644 index 24e2aeec..00000000 Binary files a/docs/images/build_setting01.png and /dev/null differ diff --git a/docs/images/build_setting02.png b/docs/images/build_setting02.png deleted file mode 100644 index 791a5b05..00000000 Binary files a/docs/images/build_setting02.png and /dev/null differ diff --git a/docs/images/vscode_idf.png b/docs/images/vscode_idf.png deleted file mode 100644 index f943b71e..00000000 Binary files a/docs/images/vscode_idf.png and /dev/null differ diff --git a/main/manager-api/src/main/java/xiaozhi/modules/device/controller/OTAController.java b/main/manager-api/src/main/java/xiaozhi/modules/device/controller/OTAController.java index 6333c627..05d36e9a 100644 --- a/main/manager-api/src/main/java/xiaozhi/modules/device/controller/OTAController.java +++ b/main/manager-api/src/main/java/xiaozhi/modules/device/controller/OTAController.java @@ -28,7 +28,6 @@ import xiaozhi.modules.device.dto.DeviceReportReqDTO; import xiaozhi.modules.device.dto.DeviceReportRespDTO; import xiaozhi.modules.device.entity.DeviceEntity; import xiaozhi.modules.device.service.DeviceService; -import xiaozhi.modules.device.utils.NetworkUtil; import xiaozhi.modules.sys.service.SysParamsService; @Tag(name = "设备管理", description = "OTA 相关接口") @@ -53,7 +52,7 @@ public class OTAController { clientId = deviceId; } String macAddress = deviceReportReqDTO.getMacAddress(); - boolean macAddressValid = NetworkUtil.isMacAddressValid(macAddress); + boolean macAddressValid = isMacAddressValid(macAddress); // 设备Id和Mac地址应是一致的, 并且必须需要application字段 if (!deviceId.equals(macAddress) || !macAddressValid || deviceReportReqDTO.getApplication() == null) { return createResponse(DeviceReportRespDTO.createError("Invalid OTA request")); @@ -102,4 +101,19 @@ public class OTAController { .contentLength(jsonBytes.length) .body(json); } + + /** + * 简单判断mac地址是否有效(非严格) + * + * @param macAddress + * @return + */ + private boolean isMacAddressValid(String macAddress) { + if (StringUtils.isBlank(macAddress)) { + return false; + } + // MAC地址通常为12位十六进制数字,可以包含冒号或连字符分隔符 + String macPattern = "^([0-9A-Za-z]{2}[:-]){5}([0-9A-Za-z]{2})$"; + return macAddress.matches(macPattern); + } } diff --git a/main/manager-api/src/main/java/xiaozhi/modules/device/utils/NetworkUtil.java b/main/manager-api/src/main/java/xiaozhi/modules/device/utils/NetworkUtil.java deleted file mode 100644 index ab269f7b..00000000 --- a/main/manager-api/src/main/java/xiaozhi/modules/device/utils/NetworkUtil.java +++ /dev/null @@ -1,34 +0,0 @@ -package xiaozhi.modules.device.utils; - -import java.util.regex.Pattern; - -import org.apache.commons.lang3.StringUtils; - -/** - * 网络工具类 - */ -public class NetworkUtil { - /** - * MAC地址正则表达式 - */ - private static final Pattern macPattern = Pattern.compile("^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$"); - - /** - * 判断MAC地址是否合法 - */ - public static boolean isMacAddressValid(String mac) { - if (StringUtils.isBlank(mac)) { - return false; - } - // 正则校验格式 - if (!macPattern.matcher(mac).matches()) { - return false; - } - // 校验MAC地址是否为单播地址 - String normalized = mac.toLowerCase(); - String[] parts = normalized.split("[:-]"); - int firstByte = Integer.parseInt(parts[0], 16); - return (firstByte & 1) == 0; // 最低位为0表示单播地址,合法 - } - -} diff --git a/main/xiaozhi-server/core/connection.py b/main/xiaozhi-server/core/connection.py index 3cf6b018..fe8d1ef3 100644 --- a/main/xiaozhi-server/core/connection.py +++ b/main/xiaozhi-server/core/connection.py @@ -241,7 +241,7 @@ class ConnectionHandler: ) private_config["delete_audio"] = bool(self.config.get("delete_audio", True)) self.logger.bind(tag=TAG).info( - f"{time.time() - begin_time} 秒,获取差异化配置成功: {private_config}" + f"{time.time() - begin_time} 秒,获取差异化配置成功: {json.dumps(filter_sensitive_info(private_config), ensure_ascii=False)}" ) except DeviceNotFoundException as e: self.need_bind = True @@ -448,7 +448,7 @@ class ConnectionHandler: pos = current_text.rfind(punct) prev_char = current_text[pos - 1] if pos - 1 >= 0 else "" # 如果.前面是数字统一判断为小数 - if prev_char.isdigit() and punct == '.': + if prev_char.isdigit() and punct == ".": number_flag = False if pos > last_punct_pos and number_flag: last_punct_pos = pos @@ -579,7 +579,7 @@ class ConnectionHandler: pos = current_text.rfind(punct) prev_char = current_text[pos - 1] if pos - 1 >= 0 else "" # 如果.前面是数字统一判断为小数 - if prev_char.isdigit() and punct == '.': + if prev_char.isdigit() and punct == ".": number_flag = False if pos > last_punct_pos and number_flag: last_punct_pos = pos @@ -945,3 +945,36 @@ class ConnectionHandler: break except Exception as e: self.logger.bind(tag=TAG).error(f"超时检查任务出错: {e}") + + +def filter_sensitive_info(config: dict) -> dict: + """ + 过滤配置中的敏感信息 + Args: + config: 原始配置字典 + Returns: + 过滤后的配置字典 + """ + sensitive_keys = [ + "api_key", + "personal_access_token", + "access_token", + "token", + "access_key_secret", + "secret_key", + ] + + def _filter_dict(d: dict) -> dict: + filtered = {} + for k, v in d.items(): + if any(sensitive in k.lower() for sensitive in sensitive_keys): + filtered[k] = "***" + elif isinstance(v, dict): + filtered[k] = _filter_dict(v) + elif isinstance(v, list): + filtered[k] = [_filter_dict(i) if isinstance(i, dict) else i for i in v] + else: + filtered[k] = v + return filtered + + return _filter_dict(copy.deepcopy(config)) diff --git a/main/xiaozhi-server/core/handle/sendAudioHandle.py b/main/xiaozhi-server/core/handle/sendAudioHandle.py index ec29a9fd..3387a133 100644 --- a/main/xiaozhi-server/core/handle/sendAudioHandle.py +++ b/main/xiaozhi-server/core/handle/sendAudioHandle.py @@ -2,51 +2,52 @@ from config.logger import setup_logging import json import asyncio import time -from core.utils.util import ( - get_string_no_punctuation_or_emoji, - analyze_emotion -) +from core.utils.util import get_string_no_punctuation_or_emoji, analyze_emotion TAG = __name__ logger = setup_logging() emoji_map = { - 'neutral': '😶', - 'happy': '🙂', - 'laughing': '😆', - 'funny': '😂', - 'sad': '😔', - 'angry': '😠', - 'crying': '😭', - 'loving': '😍', - 'embarrassed': '😳', - 'surprised': '😲', - 'shocked': '😱', - 'thinking': '🤔', - 'winking': '😉', - 'cool': '😎', - 'relaxed': '😌', - 'delicious': '🤤', - 'kissy': '😘', - 'confident': '😏', - 'sleepy': '😴', - 'silly': '😜', - 'confused': '🙄' + "neutral": "😶", + "happy": "🙂", + "laughing": "😆", + "funny": "😂", + "sad": "😔", + "angry": "😠", + "crying": "😭", + "loving": "😍", + "embarrassed": "😳", + "surprised": "😲", + "shocked": "😱", + "thinking": "🤔", + "winking": "😉", + "cool": "😎", + "relaxed": "😌", + "delicious": "🤤", + "kissy": "😘", + "confident": "😏", + "sleepy": "😴", + "silly": "😜", + "confused": "🙄", } + async def sendAudioMessage(conn, audios, text, text_index=0): # 发送句子开始消息 - emotion = analyze_emotion(text) - emoji = emoji_map.get(emotion, '🙂') # 默认使用笑脸 - await conn.websocket.send(json.dumps( - { - "type": "llm", - "text": emoji, - "emotion": emotion, - "session_id": conn.session_id, - } + if text is not None: + emotion = analyze_emotion(text) + emoji = emoji_map.get(emotion, "🙂") # 默认使用笑脸 + await conn.websocket.send( + json.dumps( + { + "type": "llm", + "text": emoji, + "emotion": emotion, + "session_id": conn.session_id, + } + ) ) - ) + if text_index == conn.tts_first_text_index: logger.bind(tag=TAG).info(f"发送第一段语音: {text}") await send_tts_message(conn, "sentence_start", text)