wangzhibo
2026-08-31 17ac2ce0ed52874616c79c910667e41e34604826
xiaozhi-esp32-server/main/xiaozhi-server/core/handle/receiveAudioHandle.py
@@ -46,22 +46,24 @@
    actual_text = text
    try:
        # 尝试解析JSON格式的输入
        # FunASR 等会把结果包成 {"content","language","emotion"};声纹场景还有 speaker
        if text.strip().startswith("{") and text.strip().endswith("}"):
            data = json.loads(text)
            if "speaker" in data and "content" in data:
                speaker_name = data["speaker"]
                actual_content = data["content"]
                conn.logger.bind(tag=TAG).info(f"解析到说话人信息: {speaker_name}")
                # 仅在该说话人首次出现时保留 {"speaker":...} JSON,让模型自然称呼一次;
                # 后续轮降为纯文本,避免每轮重复出现名字诱导模型反复称呼
                if speaker_name not in conn.introduced_speakers:
                    conn.introduced_speakers.add(speaker_name)
                    actual_text = text
                else:
            if isinstance(data, dict) and "content" in data:
                speaker_name = data.get("speaker")
                actual_content = data.get("content") or ""
                if speaker_name:
                    conn.logger.bind(tag=TAG).info(f"解析到说话人信息: {speaker_name}")
                    # 仅在该说话人首次出现时保留 {"speaker":...} JSON,让模型自然称呼一次;
                    # 后续轮降为纯文本,避免每轮重复出现名字诱导模型反复称呼
                    if speaker_name not in conn.introduced_speakers:
                        conn.introduced_speakers.add(speaker_name)
                        actual_text = text
                    else:
                        actual_text = actual_content
                elif actual_content:
                    actual_text = actual_content
    except (json.JSONDecodeError, KeyError):
    except (json.JSONDecodeError, KeyError, TypeError):
        # 如果解析失败,继续使用原始文本
        pass
@@ -83,6 +85,70 @@
            await max_out_size(conn)
            return
    from core.app_runtime.runtime import (
        is_exit_translation,
        match_voice_switch,
        run_translation,
        start_app_task,
        VOICE_MENU,
    )
    from core.handle.intentHandler import speak_txt
    mode = getattr(conn, "interaction_mode", "CHAT")
    if getattr(conn, "awaiting_voice_app_choice", False):
        mapped = match_voice_switch(actual_text)
        conn.awaiting_voice_app_choice = False
        if mapped and mapped[0] == "__reserved__":
            speak_txt(conn, "这个游戏还没开放,我们先聊天吧。")
            await start_app_task(conn, "chat", "conversation", {}, source="voice")
            return
        if mapped and mapped[0] == "__menu__":
            conn.awaiting_voice_app_choice = True
            speak_txt(conn, VOICE_MENU)
            return
        if mapped and mapped[0] != "__menu__":
            params = {}
            await start_app_task(conn, mapped[0], mapped[1], params, source="voice")
            return
        speak_txt(conn, VOICE_MENU)
        conn.awaiting_voice_app_choice = True
        return
    mapped = match_voice_switch(actual_text)
    if mapped and mapped[0] == "__menu__":
        conn.awaiting_voice_app_choice = True
        speak_txt(conn, VOICE_MENU)
        return
    if mapped and mapped[0] == "__reserved__":
        speak_txt(conn, "这个还没开放,先继续当前内容吧。")
        return
    if mapped and mapped[0] in ("english_translation", "english_learning", "chat"):
        if mapped[0] == "english_learning" and mapped[1] == "repeater":
            speak_txt(conn, "复读需要指定 SD 卡上的文件名,或用小程序开始。")
            return
        await start_app_task(conn, mapped[0], mapped[1], {}, source="voice")
        return
    if mode == "PLAY_AUDIO":
        conn.logger.bind(tag=TAG).info("PLAY_AUDIO 模式忽略上行对话")
        return
    if mode == "TRANSLATION":
        if is_exit_translation(actual_text):
            await start_app_task(conn, "chat", "conversation", {}, source="voice")
            return
        await send_stt_message(conn, actual_text)
        conn.client_abort = False
        translated = await run_translation(conn, actual_text)
        if not translated:
            translated = "没有听清要翻译的内容,请再说一次。"
        if not conn.sentence_id:
            import uuid as _uuid
            conn.sentence_id = _uuid.uuid4().hex
        speak_txt(conn, translated)
        return
    # manual 模式下不打断正在播放的内容
    if conn.client_is_speaking and conn.client_listen_mode != "manual":
        await handleAbortMessage(conn)