- imagegen.Segmenter/SegmentationProvider: prompted mask via POST /upstream/<id>/v1/segment (file, prompt[, threshold], output=mask); white = prompted region, EditRequest.Mask polarity. - imagegen.Colorizer/ColorizeProvider: POST /upstream/<id>/v1/colorize. - imagegen.FaceRestorer/FaceRestoreProvider: POST /upstream/<id>/v1/restore_faces (upscale 1|2). - New ocr leaf package (Request/Page/Result, Recognize) + llamaswap OCRModel: POST /upstream/<id>/v1/ocr (file[, langs, max_pages]), tolerant per-page decode (join lines when page text absent), Raw escape hatch. - httptest contract tests per surface; ADR-0023; ADR index backfilled (0020-0022 rows were missing). Co-Authored-By: Claude Fable 5 <[email protected]>
115 lines
3.7 KiB
Go
115 lines
3.7 KiB
Go
// Package ocr is majordomo's canonical document text-recognition surface.
|
|
// Like imagegen/audio/videogen/musicgen, it is a deliberately separate leaf
|
|
// contract from the llm package (ADR-0023, following the ADR-0016→0022
|
|
// lineage: functional options, zero values = backend default, bytes-only
|
|
// I/O, Raw escape hatch). OCR is not chat-vision: it targets dedicated
|
|
// detection+recognition models (Surya style) that return exact per-page,
|
|
// per-line text rather than a model's paraphrase.
|
|
//
|
|
// The first implementation is provider/llamaswap, which posts the document
|
|
// to a Surya shim through the /upstream passthrough; the shim rasterizes
|
|
// PDFs itself, so Document may be an image (png/jpg/webp) or a PDF.
|
|
package ocr
|
|
|
|
import "context"
|
|
|
|
// Request is a text-recognition request. Zero values mean "backend default".
|
|
type Request struct {
|
|
// Document is the encoded document to recognize: an image (png/jpg/webp)
|
|
// or a PDF. Required. Carried as bytes, never a URL.
|
|
Document []byte
|
|
|
|
// MIME is the document MIME type (e.g. "image/png", "application/pdf");
|
|
// "" = let the backend sniff it.
|
|
MIME string
|
|
|
|
// Filename is the multipart filename hint some backends key their format
|
|
// detection on; "" derives one from MIME ("document.pdf") or falls back
|
|
// to "document".
|
|
Filename string
|
|
|
|
// Languages are ISO-639 hints for the recognizer (e.g. "en", "de");
|
|
// nil = backend default (auto/multilingual).
|
|
Languages []string
|
|
|
|
// MaxPages caps how many pages of a multi-page document are recognized;
|
|
// 0 = backend default (all pages, up to the backend's own ceiling).
|
|
MaxPages int
|
|
}
|
|
|
|
// Page is the recognized text of one page.
|
|
type Page struct {
|
|
// Number is the 1-based page number.
|
|
Number int
|
|
|
|
// Text is the page's recognized text.
|
|
Text string
|
|
}
|
|
|
|
// Result is the canonical text-recognition result.
|
|
type Result struct {
|
|
// Text is the full recognized text, pages joined in order.
|
|
Text string
|
|
|
|
// Pages are the per-page results in page order.
|
|
Pages []Page
|
|
|
|
// Raw is the provider-native response object (e.g. the per-line
|
|
// bbox/confidence/layout detail), an escape hatch for provider-specific
|
|
// fields. May be nil; never required for normal use.
|
|
Raw any
|
|
}
|
|
|
|
// Option mutates a Request before it is sent. Options passed to Recognize are
|
|
// applied to a copy of the request, so a Request value can be reused.
|
|
type Option func(*Request)
|
|
|
|
// WithLanguages sets the recognizer language hints.
|
|
func WithLanguages(langs ...string) Option {
|
|
return func(r *Request) { r.Languages = langs }
|
|
}
|
|
|
|
// WithMaxPages caps how many pages are recognized.
|
|
func WithMaxPages(n int) Option { return func(r *Request) { r.MaxPages = n } }
|
|
|
|
// Apply returns a copy of the request with all options applied. Providers
|
|
// call this once at the top of Recognize.
|
|
func (r Request) Apply(opts ...Option) Request {
|
|
for _, opt := range opts {
|
|
opt(&r)
|
|
}
|
|
return r
|
|
}
|
|
|
|
// Model recognizes text in documents.
|
|
type Model interface {
|
|
// Recognize extracts the document's text, page by page.
|
|
Recognize(ctx context.Context, req Request, opts ...Option) (*Result, error)
|
|
}
|
|
|
|
// ModelOption configures a Model at construction time. Reserved for future
|
|
// per-model settings.
|
|
type ModelOption func(*ModelConfig)
|
|
|
|
// ModelConfig carries per-model construction settings.
|
|
type ModelConfig struct{}
|
|
|
|
// ApplyModelOptions folds options into a config.
|
|
func ApplyModelOptions(opts []ModelOption) ModelConfig {
|
|
var cfg ModelConfig
|
|
for _, opt := range opts {
|
|
opt(&cfg)
|
|
}
|
|
return cfg
|
|
}
|
|
|
|
// Provider mints OCR models bound to one backend.
|
|
type Provider interface {
|
|
// Name is the registry identifier for the provider.
|
|
Name() string
|
|
|
|
// OCRModel returns a Model bound to the given id (passed through to the
|
|
// backend verbatim; no catalog validation).
|
|
OCRModel(id string, opts ...ModelOption) (Model, error)
|
|
}
|