fix(rag): HTML charset detection + opening block tag newlines

Two bugs fixed:
1. Opening block tags (<h3>, <div>) now also create newlines, not just
   closing tags. Fixes: gesetze-im-internet.de puts § inside <h3> which
   followed inline <a> text — § ended up mid-line, not at line start.

2. HTML charset detection from meta tag (charset=iso-8859-1). Files from
   gesetze-im-internet.de use ISO-8859-1, not UTF-8. The § byte (0xA7)
   was destroyed by UTF-8 decode. Now: try UTF-8 → check meta charset →
   fallback ISO-8859-1.

32 rag-service tests passing.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Benjamin Admin
2026-05-02 08:35:47 +02:00
parent ddad58f607
commit a459636bc4
3 changed files with 85 additions and 9 deletions
+9 -7
View File
@@ -7,7 +7,7 @@ from pydantic import BaseModel
from api.auth import optional_jwt_auth
from embedding_client import embedding_client
from html_utils import looks_like_html, strip_html
from html_utils import decode_html_bytes, looks_like_html, strip_html
from minio_client_wrapper import minio_wrapper
from qdrant_client_wrapper import qdrant_wrapper
@@ -102,9 +102,16 @@ async def upload_document(
try:
if content_type == "application/pdf" or filename.lower().endswith(".pdf"):
text = await embedding_client.extract_pdf(file_bytes)
elif filename.lower().endswith((".html", ".htm")):
text = decode_html_bytes(file_bytes)
text = strip_html(text)
logger.info("Decoded + stripped HTML from %s", filename)
else:
# Try to decode as text
text = file_bytes.decode("utf-8", errors="replace")
# Strip HTML if content looks like HTML despite extension
if looks_like_html(text):
text = strip_html(text)
logger.info("Stripped HTML tags from %s", filename)
except Exception as exc:
logger.error("Text extraction failed: %s", exc)
raise HTTPException(status_code=500, detail=f"Text extraction failed: {exc}")
@@ -112,11 +119,6 @@ async def upload_document(
if not text or not text.strip():
raise HTTPException(status_code=400, detail="Could not extract any text from the document")
# --- Strip HTML if detected ---
if looks_like_html(text):
text = strip_html(text)
logger.info("Stripped HTML tags from %s", filename)
# --- Chunk ---
try:
chunk_result = await embedding_client.chunk_text(