hako/internal/extractors/pdf.go
2026-01-12 19:35:18 +01:00

106 lines
2.5 KiB
Go

package extractors
import (
"context"
"fmt"
"io"
"os"
"os/exec"
)
// PDFExtractor extracts text content from PDF files using pdftotext
type PDFExtractor struct {
pdftotextPath string
available bool
initError error
}
// NewPDFExtractor creates a new PDF extractor
func NewPDFExtractor() *PDFExtractor {
return &PDFExtractor{}
}
// Key returns the unique identifier for this extractor
func (e *PDFExtractor) Key() string {
return "pdf"
}
// Name returns the human-readable name for this extractor
func (e *PDFExtractor) Name() string {
return "PDF Text Extractor"
}
// SupportedMimeTypes returns the MIME types this extractor supports
func (e *PDFExtractor) SupportedMimeTypes() []string {
return []string{"application/pdf"}
}
// Init initializes the extractor by checking if pdftotext is available
func (e *PDFExtractor) Init() error {
// Check if pdftotext is available in PATH
path, err := exec.LookPath("pdftotext")
if err != nil {
e.available = false
e.initError = fmt.Errorf("pdftotext binary not found in PATH: %w", err)
return e.initError
}
e.pdftotextPath = path
e.available = true
e.initError = nil
return nil
}
// Extract extracts text content from a PDF file
func (e *PDFExtractor) Extract(ctx context.Context, filePath string) (string, error) {
if !e.available {
return "", fmt.Errorf("PDF extractor is not available: %w", e.initError)
}
// Open the PDF file
file, err := os.Open(filePath)
if err != nil {
return "", fmt.Errorf("failed to open file: %w", err)
}
defer func() { _ = file.Close() }()
// Create command to run pdftotext
// Use "-" to read from stdin and output to stdout
cmd := exec.CommandContext(ctx, e.pdftotextPath, "-", "-")
cmd.Stdin = file
// Capture stdout
stdout, err := cmd.StdoutPipe()
if err != nil {
return "", fmt.Errorf("failed to create stdout pipe: %w", err)
}
// Start the command
if err := cmd.Start(); err != nil {
return "", fmt.Errorf("failed to start pdftotext: %w", err)
}
// Read all output
output, err := io.ReadAll(stdout)
if err != nil {
_ = cmd.Wait()
return "", fmt.Errorf("failed to read output: %w", err)
}
// Wait for command to complete
if err := cmd.Wait(); err != nil {
return "", fmt.Errorf("pdftotext failed: %w", err)
}
return string(output), nil
}
// GetInitError returns the initialization error if any
func (e *PDFExtractor) GetInitError() error {
return e.initError
}
// IsAvailable returns whether the extractor is available
func (e *PDFExtractor) IsAvailable() bool {
return e.available
}