feat: add stdlib-only markdown and html text extraction for indexing
This commit is contained in:
parent
f9c612927a
commit
2a7a197b95
38
backend/app/text_extract.py
Normal file
38
backend/app/text_extract.py
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
import re
|
||||||
|
from html.parser import HTMLParser
|
||||||
|
|
||||||
|
|
||||||
|
class _HTMLTextExtractor(HTMLParser):
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
self._chunks = []
|
||||||
|
|
||||||
|
def handle_data(self, data):
|
||||||
|
self._chunks.append(data)
|
||||||
|
|
||||||
|
def get_text(self):
|
||||||
|
return "".join(self._chunks)
|
||||||
|
|
||||||
|
|
||||||
|
def html_to_text(text: str) -> str:
|
||||||
|
parser = _HTMLTextExtractor()
|
||||||
|
parser.feed(text)
|
||||||
|
parser.close()
|
||||||
|
raw = parser.get_text()
|
||||||
|
return re.sub(r"\s+", " ", raw).strip()
|
||||||
|
|
||||||
|
|
||||||
|
def markdown_to_text(text: str) -> str:
|
||||||
|
result = text
|
||||||
|
result = re.sub(r"```.*?```", " ", result, flags=re.DOTALL)
|
||||||
|
result = re.sub(r"`([^`]*)`", r"\1", result)
|
||||||
|
result = re.sub(r"!\[([^\]]*)\]\([^)]*\)", r"\1", result)
|
||||||
|
result = re.sub(r"\[([^\]]*)\]\([^)]*\)", r"\1", result)
|
||||||
|
result = re.sub(r"^\s{0,3}#{1,6}\s*", "", result, flags=re.MULTILINE)
|
||||||
|
result = re.sub(r"(\*\*\*|___)(.+?)\1", r"\2", result)
|
||||||
|
result = re.sub(r"(\*\*|__)(.+?)\1", r"\2", result)
|
||||||
|
result = re.sub(r"(\*|_)(.+?)\1", r"\2", result)
|
||||||
|
result = re.sub(r"^\s*([-*+]|\d+\.)\s+", "", result, flags=re.MULTILINE)
|
||||||
|
result = re.sub(r"^\s*>\s*", "", result, flags=re.MULTILINE)
|
||||||
|
result = re.sub(r"\s+", " ", result).strip()
|
||||||
|
return result
|
||||||
77
backend/tests/test_text_extract.py
Normal file
77
backend/tests/test_text_extract.py
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
from app.text_extract import html_to_text, markdown_to_text
|
||||||
|
|
||||||
|
|
||||||
|
def test_html_to_text_strips_tags():
|
||||||
|
html = """
|
||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
<h1>架构设计</h1>
|
||||||
|
<p>DocHub 是一个基于 <strong>MinIO</strong> 的文档管理系统。</p>
|
||||||
|
<ul>
|
||||||
|
<li>浏览文档</li>
|
||||||
|
<li>全文检索</li>
|
||||||
|
</ul>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
"""
|
||||||
|
result = html_to_text(html)
|
||||||
|
assert "架构设计" in result
|
||||||
|
assert "DocHub 是一个基于 MinIO 的文档管理系统。" in result
|
||||||
|
assert "浏览文档" in result
|
||||||
|
assert "<h1>" not in result
|
||||||
|
assert "<strong>" not in result
|
||||||
|
|
||||||
|
|
||||||
|
def test_html_to_text_collapses_whitespace():
|
||||||
|
html = "<p>第一段</p>\n\n\n<p>第二段</p>"
|
||||||
|
result = html_to_text(html)
|
||||||
|
assert result == "第一段 第二段"
|
||||||
|
|
||||||
|
|
||||||
|
def test_markdown_to_text_strips_headers_and_emphasis():
|
||||||
|
markdown = """# 架构设计
|
||||||
|
|
||||||
|
## 背景
|
||||||
|
|
||||||
|
DocHub 是一个 **基于 MinIO** 的 _文档管理系统_,支持全文检索。
|
||||||
|
"""
|
||||||
|
result = markdown_to_text(markdown)
|
||||||
|
assert "#" not in result
|
||||||
|
assert "**" not in result
|
||||||
|
assert "_" not in result
|
||||||
|
assert "架构设计" in result
|
||||||
|
assert "背景" in result
|
||||||
|
assert "基于 MinIO" in result
|
||||||
|
assert "文档管理系统" in result
|
||||||
|
|
||||||
|
|
||||||
|
def test_markdown_to_text_strips_links_and_list_markers():
|
||||||
|
markdown = """## 功能列表
|
||||||
|
|
||||||
|
- 浏览 [MinIO](https://min.io) 中存储的文档
|
||||||
|
- 支持 [Meilisearch](https://www.meilisearch.com) 全文检索
|
||||||
|
1. 在线编辑并保存
|
||||||
|
"""
|
||||||
|
result = markdown_to_text(markdown)
|
||||||
|
assert "[" not in result
|
||||||
|
assert "](" not in result
|
||||||
|
assert "浏览 MinIO 中存储的文档" in result
|
||||||
|
assert "支持 Meilisearch 全文检索" in result
|
||||||
|
assert "在线编辑并保存" in result
|
||||||
|
|
||||||
|
|
||||||
|
def test_markdown_to_text_strips_code_fences_and_inline_code():
|
||||||
|
markdown = """使用 `pip install -r requirements.txt` 安装依赖。
|
||||||
|
|
||||||
|
```python
|
||||||
|
def hello():
|
||||||
|
return "world"
|
||||||
|
```
|
||||||
|
|
||||||
|
安装完成后启动服务。
|
||||||
|
"""
|
||||||
|
result = markdown_to_text(markdown)
|
||||||
|
assert "```" not in result
|
||||||
|
assert "def hello" not in result
|
||||||
|
assert "使用 pip install -r requirements.txt 安装依赖。" in result
|
||||||
|
assert "安装完成后启动服务。" in result
|
||||||
Loading…
Reference in New Issue
Block a user