From 1fe9220ec95e0e99e73846444435e1421cfde15b Mon Sep 17 00:00:00 2001 From: xiaoyuyu6420 <93528429+xiaoyuyu6420@users.noreply.github.com> Date: Tue, 1 Sep 2026 01:56:17 +0800 Subject: [PATCH 1/3] fix(kb): route plain text uploads to TextParser without markitdown MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit select_parser sent .txt/.md/.markdown to MarkitdownParser, which imports the optional markitdown-no-magika dependency. When that dependency is not installed, uploading a plain text file raised ModuleNotFoundError that was swallowed into a generic "文档解析失败" message, with no hint about the missing dependency (issue #9598). Plain text formats are decoded directly by the existing TextParser, which needs no extra dependency and supports multiple encodings (utf-8/gbk/...). Route .txt/.md/.markdown to TextParser; keep .rst/.adoc/.xlsx/.docx/.xls on MarkitdownParser since those rely on conversion. Chunking in kb_helper still selects MarkdownChunker by file extension, so markdown heading hierarchy is unchanged. Fixes #9598 --- astrbot/core/knowledge_base/parsers/util.py | 10 ++++++++- tests/unit/test_parser_selection.py | 25 +++++++++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 tests/unit/test_parser_selection.py diff --git a/astrbot/core/knowledge_base/parsers/util.py b/astrbot/core/knowledge_base/parsers/util.py index a98ed60ed2..0659fa8aa4 100644 --- a/astrbot/core/knowledge_base/parsers/util.py +++ b/astrbot/core/knowledge_base/parsers/util.py @@ -2,7 +2,15 @@ async def select_parser(ext: str) -> BaseParser: - if ext in {".md", ".txt", ".markdown", ".rst", ".adoc", ".xlsx", ".docx", ".xls"}: + if ext in {".md", ".txt", ".markdown"}: + # Plain text formats are decoded directly by TextParser and do not + # require the optional markitdown dependency. Routing them here keeps + # txt/md uploads working even when markitdown-no-magika is missing + # (see https://github.com/AstrBotDevs/AstrBot/issues/9598). + from .text_parser import TextParser + + return TextParser() + if ext in {".rst", ".adoc", ".xlsx", ".docx", ".xls"}: from .markitdown_parser import MarkitdownParser return MarkitdownParser() diff --git a/tests/unit/test_parser_selection.py b/tests/unit/test_parser_selection.py new file mode 100644 index 0000000000..12de9c12e1 --- /dev/null +++ b/tests/unit/test_parser_selection.py @@ -0,0 +1,25 @@ +import pytest + +from astrbot.core.knowledge_base.parsers.markitdown_parser import MarkitdownParser +from astrbot.core.knowledge_base.parsers.text_parser import TextParser +from astrbot.core.knowledge_base.parsers.util import select_parser + + +@pytest.mark.asyncio +async def test_plain_text_formats_use_text_parser(): + for ext in (".txt", ".md", ".markdown"): + parser = await select_parser(ext) + assert isinstance(parser, TextParser) + + +@pytest.mark.asyncio +async def test_rich_text_formats_use_markitdown_parser(): + for ext in (".rst", ".adoc", ".xlsx", ".docx", ".xls"): + parser = await select_parser(ext) + assert isinstance(parser, MarkitdownParser) + + +@pytest.mark.asyncio +async def test_unsupported_format_raises(): + with pytest.raises(ValueError, match="不支持"): + await select_parser(".exe") From 0725a4124d46e6d693e84122e719af0649b45eaf Mon Sep 17 00:00:00 2001 From: xiaoyuyu6420 <93528429+xiaoyuyu6420@users.noreply.github.com> Date: Tue, 1 Sep 2026 08:49:56 +0800 Subject: [PATCH 2/3] test(kb): lazily import MarkitdownParser so tests collect without the optional dep Sourcery flagged that importing MarkitdownParser at module scope raises ModuleNotFoundError during test collection when markitdown-no-magika is absent - exactly the deployment scenario this change supports. Import it inside the rich-format test and skip that test when the optional dependency is unavailable, so the plain-text selection tests still run. --- tests/unit/test_parser_selection.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tests/unit/test_parser_selection.py b/tests/unit/test_parser_selection.py index 12de9c12e1..47e92c4dcf 100644 --- a/tests/unit/test_parser_selection.py +++ b/tests/unit/test_parser_selection.py @@ -1,6 +1,5 @@ import pytest -from astrbot.core.knowledge_base.parsers.markitdown_parser import MarkitdownParser from astrbot.core.knowledge_base.parsers.text_parser import TextParser from astrbot.core.knowledge_base.parsers.util import select_parser @@ -14,6 +13,14 @@ async def test_plain_text_formats_use_text_parser(): @pytest.mark.asyncio async def test_rich_text_formats_use_markitdown_parser(): + # Import lazily so the whole test module still collects when the optional + # markitdown-no-magika dependency is missing (issue #9598). + try: + from astrbot.core.knowledge_base.parsers.markitdown_parser import ( + MarkitdownParser, + ) + except ModuleNotFoundError: + pytest.skip("markitdown-no-magika is not installed") for ext in (".rst", ".adoc", ".xlsx", ".docx", ".xls"): parser = await select_parser(ext) assert isinstance(parser, MarkitdownParser) From 2afcb4336d60e433ab0b8a5ff9c9a0f18f584216 Mon Sep 17 00:00:00 2001 From: Soulter <37870767+Soulter@users.noreply.github.com> Date: Tue, 1 Sep 2026 09:22:57 +0800 Subject: [PATCH 3/3] Delete tests/unit/test_parser_selection.py --- tests/unit/test_parser_selection.py | 32 ----------------------------- 1 file changed, 32 deletions(-) delete mode 100644 tests/unit/test_parser_selection.py diff --git a/tests/unit/test_parser_selection.py b/tests/unit/test_parser_selection.py deleted file mode 100644 index 47e92c4dcf..0000000000 --- a/tests/unit/test_parser_selection.py +++ /dev/null @@ -1,32 +0,0 @@ -import pytest - -from astrbot.core.knowledge_base.parsers.text_parser import TextParser -from astrbot.core.knowledge_base.parsers.util import select_parser - - -@pytest.mark.asyncio -async def test_plain_text_formats_use_text_parser(): - for ext in (".txt", ".md", ".markdown"): - parser = await select_parser(ext) - assert isinstance(parser, TextParser) - - -@pytest.mark.asyncio -async def test_rich_text_formats_use_markitdown_parser(): - # Import lazily so the whole test module still collects when the optional - # markitdown-no-magika dependency is missing (issue #9598). - try: - from astrbot.core.knowledge_base.parsers.markitdown_parser import ( - MarkitdownParser, - ) - except ModuleNotFoundError: - pytest.skip("markitdown-no-magika is not installed") - for ext in (".rst", ".adoc", ".xlsx", ".docx", ".xls"): - parser = await select_parser(ext) - assert isinstance(parser, MarkitdownParser) - - -@pytest.mark.asyncio -async def test_unsupported_format_raises(): - with pytest.raises(ValueError, match="不支持"): - await select_parser(".exe")