Files
xk-ai-agent/internal/kb/parser_pdf.go
2026-08-14 21:50:48 +08:00

63 lines
2.0 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package kb
import (
"bytes"
"fmt"
"strings"
"github.com/ledongthuc/pdf"
)
// ========================================================================
// PDF 解析器:从 PDF 字节流抽取纯文本
// ========================================================================
// 选型说明:
// - 用 github.com/ledongthuc/pdfrsc.io/pdf 的维护分支,纯 Go 无 CGO
// 许可证 BSD可商用不引 unioffice/unipdfAGPL 商用有坑)
// - 只能抽「文字型 PDF」的文本扫描版/图片型 PDF 没有文字层,
// 需要 OCR超出本服务范围由上层给出友好报错
// ========================================================================
// extractPDFText 逐页抽取 PDF 文本,页与页之间用双换行分隔
//
// 为什么逐页而不是整本 GetPlainText
// 页边界是天然的段落边界,配合 ChunkPlainText 按双换行切段,
// 能避免跨页内容被硬拼成一大段
//
// 为什么要 recover
// ledongthuc/pdf 遇到畸形/加密 PDF 时内部会直接 panic继承自 rsc.io/pdf 的风格),
// 不兜底会把整个 HTTP 请求打崩
func extractPDFText(data []byte) (text string, err error) {
defer func() {
if r := recover(); r != nil {
err = fmt.Errorf("kb: PDF 解析异常(文件可能损坏或加密): %v", r)
}
}()
reader, err := pdf.NewReader(bytes.NewReader(data), int64(len(data)))
if err != nil {
return "", fmt.Errorf("kb: 打开 PDF 失败: %w", err)
}
var sb strings.Builder
totalPage := reader.NumPage()
for i := 1; i <= totalPage; i++ {
page := reader.Page(i)
if page.V.IsNull() {
continue
}
// 单页解析失败不中断整本导入(常见于个别页含特殊字体)
pageText, perr := page.GetPlainText(nil)
if perr != nil {
continue
}
pageText = strings.TrimSpace(pageText)
if pageText == "" {
continue
}
sb.WriteString(pageText)
sb.WriteString("\n\n")
}
return strings.TrimSpace(sb.String()), nil
}