WeKnora deployment source with the reviewed wiki identity, summary and recovery fixes
Anydoc / anydoc parser engine (push) Canceled after 0s
App / Format, vet, test, and build (push) Canceled after 0s
CLI / test (macos-latest / go 1.26) (push) Canceled after 0s
CLI / test (ubuntu-latest / go 1.26) (push) Canceled after 0s
CLI / test (windows-latest / go 1.26) (push) Canceled after 0s
Build and Push Docker Image / build-ui (push) Canceled after 0s
Build and Push Docker Image / build-docreader (push) Canceled after 0s
Build and Push Docker Image / build-sandbox (push) Canceled after 0s
Build and Push Docker Image / build-app (amd64, linux/amd64, ubuntu-latest) (push) Canceled after 0s
Build and Push Docker Image / build-app (arm64, linux/arm64, ubuntu-24.04-arm) (push) Canceled after 0s
DocReader / Python tests and Go client tests (push) Canceled after 0s
Build & Publish (dsh-weknora) / Typecheck, test, pack (push) Canceled after 0s
Build & Publish (dsh-weknora) / End-to-end inside dsh (pinned) (push) Canceled after 0s
Build & Publish (dsh-weknora) / End-to-end inside dsh (latest, advisory) (push) Canceled after 0s
Frontend / Test, type-check, and build (push) Canceled after 0s
Go Lint Cache / warm lint cache (.) (push) Canceled after 0s
Go Lint Cache / warm lint cache (cli) (push) Canceled after 0s
Go Lint Cache / warm lint cache (client) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.10) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.11) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.12) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.13) (push) Canceled after 0s
Build and Push Docker Image / merge (push) Canceled after 0s
Build & Publish (dsh-weknora) / Publish to npm (push) Canceled after 0s
Build & Publish (mcp-server) / Build sdist + wheel (push) Canceled after 0s
Build & Publish (mcp-server) / Publish to PyPI (push) Canceled after 0s
Anydoc / anydoc parser engine (push) Canceled after 0s
App / Format, vet, test, and build (push) Canceled after 0s
CLI / test (macos-latest / go 1.26) (push) Canceled after 0s
CLI / test (ubuntu-latest / go 1.26) (push) Canceled after 0s
CLI / test (windows-latest / go 1.26) (push) Canceled after 0s
Build and Push Docker Image / build-ui (push) Canceled after 0s
Build and Push Docker Image / build-docreader (push) Canceled after 0s
Build and Push Docker Image / build-sandbox (push) Canceled after 0s
Build and Push Docker Image / build-app (amd64, linux/amd64, ubuntu-latest) (push) Canceled after 0s
Build and Push Docker Image / build-app (arm64, linux/arm64, ubuntu-24.04-arm) (push) Canceled after 0s
DocReader / Python tests and Go client tests (push) Canceled after 0s
Build & Publish (dsh-weknora) / Typecheck, test, pack (push) Canceled after 0s
Build & Publish (dsh-weknora) / End-to-end inside dsh (pinned) (push) Canceled after 0s
Build & Publish (dsh-weknora) / End-to-end inside dsh (latest, advisory) (push) Canceled after 0s
Frontend / Test, type-check, and build (push) Canceled after 0s
Go Lint Cache / warm lint cache (.) (push) Canceled after 0s
Go Lint Cache / warm lint cache (cli) (push) Canceled after 0s
Go Lint Cache / warm lint cache (client) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.10) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.11) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.12) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.13) (push) Canceled after 0s
Build and Push Docker Image / merge (push) Canceled after 0s
Build & Publish (dsh-weknora) / Publish to npm (push) Canceled after 0s
Build & Publish (mcp-server) / Build sdist + wheel (push) Canceled after 0s
Build & Publish (mcp-server) / Publish to PyPI (push) Canceled after 0s
This commit is contained in:
@@ -0,0 +1,77 @@
|
||||
package docparser
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/JohannesKaufmann/html-to-markdown/v2/converter"
|
||||
"github.com/JohannesKaufmann/html-to-markdown/v2/plugin/base"
|
||||
"github.com/JohannesKaufmann/html-to-markdown/v2/plugin/commonmark"
|
||||
"github.com/JohannesKaufmann/html-to-markdown/v2/plugin/table"
|
||||
)
|
||||
|
||||
var (
|
||||
// htmlTableBlockPattern matches a single (non-nested) <table>...</table>
|
||||
// block, the form OCR/layout engines such as PaddleOCR-VL emit tables in.
|
||||
htmlTableBlockPattern = regexp.MustCompile(`(?is)<table\b[^>]*>.*?</table>`)
|
||||
|
||||
// htmlLayoutAttrPattern matches presentational HTML attributes that carry
|
||||
// no semantic value (text-align styles, CSS classes, sizing). Structural
|
||||
// attributes like rowspan/colspan are intentionally excluded.
|
||||
htmlLayoutAttrPattern = regexp.MustCompile(
|
||||
`(?is)\s+(?:style|class|align|valign|width|height|bgcolor)\s*=\s*(?:"[^"]*"|'[^']*'|[^\s>]+)`,
|
||||
)
|
||||
|
||||
// htmlSpanAttrPattern detects rowspan/colspan, which Markdown tables cannot
|
||||
// represent; such tables keep their HTML form (attributes stripped) instead.
|
||||
htmlSpanAttrPattern = regexp.MustCompile(`(?i)\b(?:row|col)span\b`)
|
||||
|
||||
// markdownTableSeparatorPattern matches the |---|---| delimiter row that a
|
||||
// valid GFM table must contain.
|
||||
markdownTableSeparatorPattern = regexp.MustCompile(`(?m)^\s*\|?\s*:?-+:?\s*(?:\|\s*:?-+:?\s*)+\|?\s*$`)
|
||||
)
|
||||
|
||||
// normalizeHTMLTables rewrites inline HTML <table> blocks embedded in OCR
|
||||
// markdown output. PaddleOCR-VL emits tables as HTML with per-cell text-align
|
||||
// styles, which (1) waste tokens on layout markup and (2) are not recognized
|
||||
// by the chunker's table-protection logic, so large tables get split mid-row.
|
||||
//
|
||||
// Each table block is converted to a GFM Markdown table when possible. Tables
|
||||
// that use rowspan/colspan (which Markdown cannot express) fall back to having
|
||||
// their presentational attributes stripped so they stay intact as HTML.
|
||||
func normalizeHTMLTables(md string) string {
|
||||
if !strings.Contains(strings.ToLower(md), "<table") {
|
||||
return md
|
||||
}
|
||||
|
||||
conv := converter.NewConverter(
|
||||
converter.WithPlugins(
|
||||
base.NewBasePlugin(),
|
||||
commonmark.NewCommonmarkPlugin(),
|
||||
table.NewTablePlugin(),
|
||||
),
|
||||
)
|
||||
|
||||
return htmlTableBlockPattern.ReplaceAllStringFunc(md, func(block string) string {
|
||||
if htmlSpanAttrPattern.MatchString(block) {
|
||||
return stripHTMLLayoutAttrs(block)
|
||||
}
|
||||
converted, err := conv.ConvertString(block)
|
||||
if err != nil {
|
||||
return stripHTMLLayoutAttrs(block)
|
||||
}
|
||||
converted = strings.TrimSpace(converted)
|
||||
if converted == "" || !markdownTableSeparatorPattern.MatchString(converted) {
|
||||
return stripHTMLLayoutAttrs(block)
|
||||
}
|
||||
// Pad with blank lines so the Markdown table is a standalone block that
|
||||
// the chunker recognizes (and protects) as a table.
|
||||
return "\n\n" + converted + "\n\n"
|
||||
})
|
||||
}
|
||||
|
||||
// stripHTMLLayoutAttrs removes presentational attributes from an HTML fragment
|
||||
// while preserving structural attributes (rowspan/colspan) and text content.
|
||||
func stripHTMLLayoutAttrs(html string) string {
|
||||
return htmlLayoutAttrPattern.ReplaceAllString(html, "")
|
||||
}
|
||||
Reference in New Issue
Block a user