Skip to content

fix: 修复 MiniMax TTS 空字符串配置解析报错#8126

Open
Blueteemo wants to merge 4 commits into
AstrBotDevs:masterfrom
Blueteemo:fix/issue-8100-minimax-tts-empty-json
Open

fix: 修复 MiniMax TTS 空字符串配置解析报错#8126
Blueteemo wants to merge 4 commits into
AstrBotDevs:masterfrom
Blueteemo:fix/issue-8100-minimax-tts-empty-json

Conversation

@Blueteemo
Copy link
Copy Markdown
Contributor

@Blueteemo Blueteemo commented May 9, 2026

问题描述

当用户保存 MiniMax TTS 配置时,minimax-timber-weight 字段可能为空字符串 "",此时 json.loads("") 会抛出 JSONDecodeError,导致 TTS 功能无法正常使用。

修复方案

  1. 在解析 JSON 前增加空字符串判断
  2. 增加 try-except 异常捕获,防止解析失败时程序崩溃
  3. 解析失败时使用默认值作为兜底

修改内容

  1. minimax_tts_api_source.py:提取 default_timber_weight 变量减少重复代码;添加 logger.warning() 记录 JSON 解析失败

Related Issue

Fixes #8100

Summary by Sourcery

Handle MiniMax TTS timber weight configuration more robustly to avoid crashes on invalid or empty values.

Bug Fixes:

  • Prevent JSON parsing errors when minimax-timber-weight is an empty or invalid string by falling back to a default configuration.

Enhancements:

  • Centralize the default timber weight configuration and log a warning when JSON parsing fails.

Tests:

  • Add unit tests covering empty, whitespace, invalid, custom, and missing minimax-timber-weight configurations for MiniMax TTS.

@dosubot dosubot Bot added size:S This PR changes 10-29 lines, ignoring generated files. area:provider The bug / feature is about AI Provider, Models, LLM Agent, LLM Agent Runner. labels May 9, 2026
Copy link
Copy Markdown
Contributor

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

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

Hey - I've found 2 issues, and left some high level feedback:

  • Consider extracting the default timber weight value into a named constant or variable to avoid repeating the same literal list in multiple places and make future changes easier.
  • The self.timber_weight attribute lost its type annotation in this refactor; reintroducing the explicit type hint on the attribute definition will help static analysis and readability.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- Consider extracting the default timber weight value into a named constant or variable to avoid repeating the same literal list in multiple places and make future changes easier.
- The `self.timber_weight` attribute lost its type annotation in this refactor; reintroducing the explicit type hint on the attribute definition will help static analysis and readability.

## Individual Comments

### Comment 1
<location path="astrbot/core/provider/sources/minimax_tts_api_source.py" line_range="45" />
<code_context>
+            '[{"voice_id": "Chinese (Mandarin)_Warm_Girl", "weight": 1}]',
         )
+        try:
+            self.timber_weight = (
+                json.loads(raw_timber_weight)
+                if raw_timber_weight
</code_context>
<issue_to_address>
**suggestion:** Reintroduce or add a type annotation for `self.timber_weight` to keep the type contract explicit.

Previously this attribute was annotated as `list[dict[str, str | int]]`, but after the refactor it’s only assigned inside the `try`/`except`. Adding back a class-level or instance-level annotation will restore static type checking and clarify the expected structure.
</issue_to_address>

### Comment 2
<location path="astrbot/core/provider/sources/minimax_tts_api_source.py" line_range="40-49" />
<code_context>
-                "minimax-timber-weight",
-                '[{"voice_id": "Chinese (Mandarin)_Warm_Girl", "weight": 1}]',
-            ),
+        raw_timber_weight = provider_config.get(
+            "minimax-timber-weight",
+            '[{"voice_id": "Chinese (Mandarin)_Warm_Girl", "weight": 1}]',
         )
+        try:
+            self.timber_weight = (
+                json.loads(raw_timber_weight)
+                if raw_timber_weight
+                else [{"voice_id": "Chinese (Mandarin)_Warm_Girl", "weight": 1}]
+            )
+        except json.JSONDecodeError:
+            self.timber_weight = [
+                {"voice_id": "Chinese (Mandarin)_Warm_Girl", "weight": 1}
+            ]
</code_context>
<issue_to_address>
**suggestion:** Avoid duplicating the default timber weight literal in multiple places.

This default `[{"voice_id": "Chinese (Mandarin)_Warm_Girl", "weight": 1}]` is repeated in the `get` default, the `if not raw_timber_weight` branch, and the `except` block. Please extract it to a shared constant (e.g., `DEFAULT_TIMBER_WEIGHT`) to avoid duplication and simplify future changes.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread astrbot/core/provider/sources/minimax_tts_api_source.py Outdated
Comment thread astrbot/core/provider/sources/minimax_tts_api_source.py Outdated
Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

The pull request introduces error handling for the MiniMax TTS configuration by wrapping the JSON parsing of timber weights in a try-except block. The reviewer suggested refactoring the repeated default configuration into a single variable to improve maintainability, adding a warning log for parsing failures as originally intended, and including unit tests for the new functionality.

Comment thread astrbot/core/provider/sources/minimax_tts_api_source.py Outdated
@Blueteemo
Copy link
Copy Markdown
Contributor Author

@sourcery-ai review

Copy link
Copy Markdown
Contributor

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

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

Hey - I've found 2 issues, and left some high level feedback:

  • Consider moving DEFAULT_TIMBER_WEIGHT to a module-level constant instead of redefining it inside __init__ so it is clearly shared and not reallocated on each instance creation.
  • For values like whitespace-only strings, you might want to strip() before checking truthiness (e.g., if raw_timber_weight and raw_timber_weight.strip(): ...) to avoid emitting a JSON decode warning for what is effectively an empty configuration.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- Consider moving `DEFAULT_TIMBER_WEIGHT` to a module-level constant instead of redefining it inside `__init__` so it is clearly shared and not reallocated on each instance creation.
- For values like whitespace-only strings, you might want to `strip()` before checking truthiness (e.g., `if raw_timber_weight and raw_timber_weight.strip(): ...`) to avoid emitting a JSON decode warning for what is effectively an empty configuration.

## Individual Comments

### Comment 1
<location path="astrbot/core/provider/sources/minimax_tts_api_source.py" line_range="47-57" />
<code_context>
+                if raw_timber_weight
+                else DEFAULT_TIMBER_WEIGHT
+            )
+        except json.JSONDecodeError:
+            logger.warning(
+                f"MiniMax TTS: 解析 timber_weight 配置失败,使用默认值。原始值: {raw_timber_weight!r}"
+            )
+            self.timber_weight: list[dict[str, str | int]] = DEFAULT_TIMBER_WEIGHT

         self.voice_setting: dict = {
</code_context>
<issue_to_address>
**suggestion:** Log the JSON error details or use logger formatting instead of f-string for efficiency.

Consider logging the exception as well as the raw value, e.g. `logger.warning("MiniMax TTS: timber_weight JSON decode failed: %r", raw_timber_weight, exc_info=True)`, so malformed configs are easier to debug and to avoid building the log message when the warning level is disabled.

```suggestion
        try:
            self.timber_weight: list[dict[str, str | int]] = (
                json.loads(raw_timber_weight)
                if raw_timber_weight
                else DEFAULT_TIMBER_WEIGHT
            )
        except json.JSONDecodeError:
            logger.warning(
                "MiniMax TTS: 解析 timber_weight 配置失败,使用默认值。原始值: %r",
                raw_timber_weight,
                exc_info=True,
            )
            self.timber_weight: list[dict[str, str | int]] = DEFAULT_TIMBER_WEIGHT
```
</issue_to_address>

### Comment 2
<location path="tests/test_minimax_tts_api_source.py" line_range="53-20" />
<code_context>
+    ]
+
+
+def test_minimax_tts_invalid_json_falls_back():
+    provider = ProviderMiniMaxTTSAPI(
+        _provider_config(**{"minimax-timber-weight": "not a json"}),
+        {},
+    )
+
+    assert provider.timber_weight == [
+        {"voice_id": "Chinese (Mandarin)_Warm_Girl", "weight": 1},
+    ]
</code_context>
<issue_to_address>
**suggestion (testing):** Add an assertion that a warning is logged when invalid JSON is provided for `minimax-timber-weight`.

The fix now logs a warning on JSON parse failure, but this test only verifies the fallback value. Please also assert that a warning is emitted (e.g., via `caplog` or the project’s logging helper), ideally checking for a distinctive substring like `解析 timber_weight 配置失败`, to prevent regressions in the logging behavior.

Suggested implementation:

```python
def test_minimax_tts_invalid_json_falls_back(caplog):
    with caplog.at_level(logging.WARNING):
        provider = ProviderMiniMaxTTSAPI(
            _provider_config(**{"minimax-timber-weight": "not a json"}),
            {},
        )

    assert provider.timber_weight == [
        {"voice_id": "Chinese (Mandarin)_Warm_Girl", "weight": 1},
    ]
    assert "解析 timber_weight 配置失败" in caplog.text

```

1. Ensure `import logging` is present near the top of `tests/test_minimax_tts_api_source.py` (or wherever test imports are defined), for example:
   `import logging`
2. If the project uses a custom logging helper instead of the standard library logger, wrap the provider construction with that helper’s context instead of `caplog.at_level(logging.WARNING)`, and adjust the assertion accordingly (e.g., checking the helper’s collected messages for the same substring).
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread astrbot/core/provider/sources/minimax_tts_api_source.py Outdated
Comment thread tests/test_minimax_tts_api_source.py Outdated
@Blueteemo Blueteemo force-pushed the fix/issue-8100-minimax-tts-empty-json branch from 237a217 to 9520167 Compare May 9, 2026 21:05
Comment thread astrbot/core/core_lifecycle.py Outdated
# The Launcher monitors stdout for this signal to determine when the instance is ready.
# This must use print (stdout) rather than logger (stderr) to be detectable by the Launcher.
await asyncio.sleep(0)
print("AstrBot 启动完成", flush=True)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

这是在干啥,和pr无关

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:provider The bug / feature is about AI Provider, Models, LLM Agent, LLM Agent Runner. size:S This PR changes 10-29 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]新增MiniMax TTS API报错

2 participants