Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,10 @@
from astrbot.api.platform import AstrBotMessage, PlatformMetadata
from astrbot.core.utils.astrbot_path import get_astrbot_temp_path
from astrbot.core.utils.io import download_image_by_url, file_to_base64
from astrbot.core.utils.tencent_record_helper import wav_to_tencent_silk
from astrbot.core.utils.tencent_record_helper import (
convert_to_pcm_wav,
wav_to_tencent_silk,
)


def _patch_qq_botpy_formdata() -> None:
Expand Down Expand Up @@ -602,22 +605,41 @@ async def _parse_to_qqofficial(message: MessageChain):
image_base64 = image_base64.removeprefix("base64://")
elif isinstance(i, Record):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (complexity): Consider extracting the audio conversion and WAV-normalization logic into focused helper functions so this block becomes a simple, linear call that just assigns the final record_file_path.

You can reduce the branching and state juggling here by pushing the conversion logic into a small helper and using linear flow instead of mutating record_wav_path / record_file_path in multiple branches.

For example, extract the audio handling into a dedicated helper:

async def _record_to_tencent_silk(record: Record) -> str | None:
    src_path = await record.convert_to_file_path()  # may not be wav
    temp_dir = get_astrbot_temp_path()
    silk_path = os.path.join(temp_dir, f"qqofficial_{uuid.uuid4()}.silk")

    try:
        wav_path = await _ensure_wav(src_path, temp_dir)
        if wav_path is None:
            return None

        duration = await wav_to_tencent_silk(wav_path, silk_path)
        if duration <= 0:
            logger.error("转换音频格式时出错:音频时长不大于0")
            return None

        return silk_path
    except Exception as e:
        logger.error(f"处理语音时出错: {e}")
        return None

with a focused WAV normalizer:

async def _ensure_wav(src_path: str, temp_dir: str) -> str | None:
    ext = os.path.splitext(src_path)[1].lower()
    if ext == ".wav":
        return src_path

    temp_wav_path = os.path.join(temp_dir, f"qqofficial_{uuid.uuid4()}.wav")
    try:
        return await convert_to_pcm_wav(src_path, temp_wav_path)
    except Exception as e:
        logger.error(f"转换音频为WAV格式时出错: {e}")
        return None

Then the calling site becomes much simpler and only handles the final state:

elif isinstance(i, Record):
    if i.file:
        record_file_path = await _record_to_tencent_silk(i)
    else:
        record_file_path = None

This keeps all existing behavior (non-WAV support, duration check, logging) but:

  • Eliminates using record_wav_path / record_file_path as control-flow flags.
  • Flattens nested if / try blocks into a linear flow.
  • Centralizes error handling so the event handler only needs one assignment and no duplicated record_file_path = None.

if i.file:
record_wav_path = await i.convert_to_file_path() # wav 路径
record_wav_path = await i.convert_to_file_path() # 可能不是wav
temp_dir = get_astrbot_temp_path()
record_tecent_silk_path = os.path.join(
temp_dir,
f"qqofficial_{uuid.uuid4()}.silk",
)
try:
duration = await wav_to_tencent_silk(
record_wav_path,
record_tecent_silk_path,
# 检查是否为 WAV 文件,非 WAV 需要先转换
ext = os.path.splitext(record_wav_path)[1].lower()
if ext != ".wav":
temp_wav_path = os.path.join(
temp_dir,
f"qqofficial_{uuid.uuid4()}.wav",
Comment on lines +617 to +619
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (performance): Consider cleaning up the intermediate WAV file after conversion to avoid temp-file buildup.

Since temp_wav_path is only used for the conversion, it should be removed once wav_to_tencent_silk finishes (whether it succeeds or fails). Otherwise, under sustained usage these temp files can accumulate and consume unnecessary disk space. Consider adding cleanup logic for this path.

Suggested implementation:

                        temp_dir,
                        f"qqofficial_{uuid.uuid4()}.silk",
                    )
                    # 检查是否为 WAV 文件,非 WAV 需要先转换
                    temp_wav_path: str | None = None
                    ext = os.path.splitext(record_wav_path)[1].lower()
                    if ext != ".wav":
                        temp_wav_path = os.path.join(
                            temp_dir,
                            f"qqofficial_{uuid.uuid4()}.wav",
                        )
                        try:
                            record_wav_path = await convert_to_pcm_wav(
                                record_wav_path,
                                temp_wav_path,
                            )
                        except Exception as e:
                            logger.error(f"转换音频为WAV格式时出错: {e}")
                            # 转换失败时清理中间 WAV 文件,避免临时文件堆积
                            if temp_wav_path and os.path.exists(temp_wav_path):
                                try:
                                    os.remove(temp_wav_path)
                                except Exception as cleanup_err:
                                    logger.warning(
                                        f"清理临时 WAV 文件失败 {temp_wav_path}: {cleanup_err}"
                                    )
                            record_file_path = None
                            record_wav_path = None

To fully implement your suggestion ("once wav_to_tencent_silk finishes"), you should also:

  1. Locate the code that calls wav_to_tencent_silk(record_wav_path, temp_silk_path, ...) (or similar).

  2. After that call completes (in a finally block or after error-handling), add cleanup logic:

    if temp_wav_path and os.path.exists(temp_wav_path):
        try:
            os.remove(temp_wav_path)
        except Exception as cleanup_err:
            logger.warning(f"清理临时 WAV 文件失败 {temp_wav_path}: {cleanup_err}")
  3. Ensure temp_wav_path remains in scope where wav_to_tencent_silk is called (e.g., by not shadowing/redefining it and keeping all related logic in the same function or closure).

This will guarantee the temporary WAV file is removed both on success and failure of the Silk conversion step.

)
Comment on lines 611 to 620
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (performance): Silk temp file might remain on disk when conversion fails, which could accumulate over time.

If wav_to_tencent_silk fails after partially writing record_tecent_silk_path, the unused temp file is left on disk. Please add a cleanup path (e.g., delete record_tecent_silk_path in the except block) to prevent temp file buildup in long-running processes.

Suggested implementation:

                    try:
                        await wav_to_tencent_silk(record_wav_path, record_tecent_silk_path)
                    except Exception as e:
                        # Cleanup partially written silk file to avoid temp file buildup
                        if os.path.exists(record_tecent_silk_path):
                            try:
                                os.remove(record_tecent_silk_path)
                            except OSError:
                                # Best-effort cleanup; log and continue raising original error
                                logger.warning(
                                    "Failed to remove temporary silk file %s after conversion error",
                                    record_tecent_silk_path,
                                )
                        logger.exception("Failed to convert wav to tencent silk: %s", e)
                        raise
  1. This change assumes os and logger are already imported and used in this module (they appear to be, given the existing snippet). If not, add import os and a module-level logger consistent with the rest of the codebase.
  2. If the exact logging message in the original except block differs, adjust the SEARCH and REPLACE strings accordingly while preserving the added cleanup logic around os.path.exists / os.remove.

if duration > 0:
record_file_path = record_tecent_silk_path
try:
record_wav_path = await convert_to_pcm_wav(
record_wav_path,
temp_wav_path,
)
except Exception as e:
logger.error(f"转换音频为WAV格式时出错: {e}")
record_file_path = None
record_wav_path = None
try:
if record_wav_path:
duration = await wav_to_tencent_silk(
record_wav_path,
record_tecent_silk_path,
)
if duration > 0:
record_file_path = record_tecent_silk_path
else:
record_file_path = None
logger.error("转换音频格式时出错:音频时长不大于0")
else:
record_file_path = None
logger.error("转换音频格式时出错:音频时长不大于0")
except Exception as e:
logger.error(f"处理语音时出错: {e}")
record_file_path = None
Comment on lines +614 to 645
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The temporary WAV file created during audio conversion is not being cleaned up, which can lead to an accumulation of files in the temporary directory. This is a resource leak.

I suggest refactoring this block to use a try...finally structure. This ensures that the temporary WAV file is always deleted after the Silk conversion is complete, even if errors occur. The proposed change also consolidates the logic and improves readability.

                    converted_wav_path = None
                    try:
                        # 检查是否为 WAV 文件,非 WAV 需要先转换
                        ext = os.path.splitext(record_wav_path)[1].lower()
                        if ext != ".wav":
                            temp_wav_path = os.path.join(
                                temp_dir,
                                f"qqofficial_{uuid.uuid4()}.wav",
                            )
                            converted_wav_path = temp_wav_path
                            try:
                                record_wav_path = await convert_to_pcm_wav(
                                    record_wav_path,
                                    temp_wav_path,
                                )
                            except Exception as e:
                                logger.error(f"转换音频为WAV格式时出错: {e}")
                                record_wav_path = None

                        if record_wav_path:
                            duration = await wav_to_tencent_silk(
                                record_wav_path,
                                record_tecent_silk_path,
                            )
                            if duration > 0:
                                record_file_path = record_tecent_silk_path
                            else:
                                record_file_path = None
                                logger.error("转换音频格式时出错:音频时长不大于0")
                        else:
                            record_file_path = None
                    except Exception as e:
                        logger.error(f"处理语音时出错: {e}")
                        record_file_path = None
                    finally:
                        if converted_wav_path and os.path.exists(converted_wav_path):
                            os.remove(converted_wav_path)

Expand Down
Loading