Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,16 @@

本文件记录 MindBase 各版本的显著变更。格式参照 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.1.0/)。

## [Unreleased] — 2026-11-04

### Added

- **云盘智能化 P0**:图片/截图/扫描 PDF 走 vision OCR 入库(pdfcpu 提取页图,`pipeline.ocr.*` 可配);文档 L1 摘要新增可执行待办并通过 `GET /cloud/video/{uuid}/summary` 暴露;新增文件夹范围的 `GET /cloud/search/semantic` 与 `GET /cloud/video/{uuid}/similar`;云盘详情页展示 AI 摘要/标签/关键点/待办/可回答问题与相似文件,支持「问这份文件」(`/chat?upload_uuid=`);聊天来源支持云盘文件深链;app-ts 新增 `cloud_doc_summary` 工具(经 `/internal/cloud/summary`,uid 由会话注入)。摘要模型默认 `z-ai/glm-5.3-flash`,OCR/摘要均复用 Higress embedding 网关连接。

### Changed

- 非音视频云盘文件初始 `asr_status` 改为 `not_supported`(不再永远显示转写中);OCR/摘要/语义检索失败按可重试与永久不支持分流。

## [Unreleased] — 2026-11-03

### Changed
Expand Down
8 changes: 5 additions & 3 deletions app-go/app-cloud/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,18 @@

> 云盘域唯一权威:分块上传(10MB 分片 presigned multipart + 心跳 + 断点续传)、文件夹树、
> 存储配额、百度式分享(提取码/有效期/下载上限)、回收站、搜索、RAG 工作区,
> 以及 Go 原生文档解析向量化管线(PDF/Office/md/html/text → 语义分块 → Higress embedding
> → Milvus cloud_drive + Mongo 全文)。**多实例就绪**(2026-10-15 完成 ①–⑤ 分布式强化)。
> Go 原生文档解析/OCR 向量化管线(PDF/Office/md/html/text + 图片/截图/扫描 PDF OCR → 语义分块
> → Higress embedding → Milvus cloud_drive + Mongo 全文),以及 AI 摘要、语义检索、相似文件。
> **多实例就绪**(2026-10-15 完成 ①–⑤ 分布式强化)。

## 端口与路由(:8007)

| 路由 | 说明 |
|------|------|
| `/cloud/*` | 用户面:上传 init/heartbeat/complete/resume、文件夹、文件详情/预览/处理、配额、搜索、回收站、分享 owner 面(nginx /cloud/ 直连,auth_request 注入 X-Uid) |
| `/cloud/*` | 用户面:上传 init/heartbeat/complete/resume、文件夹、文件详情/预览/处理、配额、文件名/语义搜索、AI 摘要、相似文件、回收站、分享 owner 面(nginx /cloud/ 直连,auth_request 注入 X-Uid) |
| `/cloud/s/{token}` | 公开分享页数据面(免登录;attest 设备证明 + access 提取码校验) |
| `/workspaces/*` | RAG 工作区 CRUD/绑定/文件展开(APISIX 兜底路由) |
| `/internal/cloud/{summary,similar}` | app-ts M2M(`internal.api_key` = APISIX_CONSUMER_KEY;uid 显式传入) |
| `/internal/cloud/reconcile?uid=` | 对账(loopback,仅运维) |
| `/metrics` | Prometheus 指标(HTTP 黄金信号 / 上传完成结果 / 配额预留结果 / 管线队列 / 租约竞争;集群内可达,nginx 不路由) |
| `/health` | 探活 |
Expand Down
33 changes: 28 additions & 5 deletions app-go/app-cloud/default.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,15 @@ admin_review:
# env: APPCLOUD__ADMIN_REVIEW__TOKEN
token: ""

internal:
# Shared secret for the machine-to-machine document endpoints
# (/internal/cloud/summary, /internal/cloud/similar) consumed by app-ts.
# Requests must carry it in the apikey header (Authorization: Bearer is also
# accepted). Empty = those endpoints answer 503 (fail closed); the legacy
# /internal/cloud/reconcile endpoint is unaffected.
# env: APPCLOUD__INTERNAL__API_KEY (compose passes APISIX_CONSUMER_KEY)
api_key: ""

quota:
# tier → storage quota (bytes). Lookup: app-pay /internal/pay/membership/{uid}
# via APISIX key-auth; fail-closed → free tier when unreachable.
Expand All @@ -112,8 +121,8 @@ pipeline:
max_workers: 16 # elastic ceiling: workers grow toward this when the queue backs up
autoscale: true # grow workers (never shrink) while pending depth is high
admission:
# Capacity layer (plan 1.0.15): protect the downstream LLM/embedding
# gateways from unbounded trigger bursts. 0 disables the check.
# Capacity layer: protect the downstream LLM/embedding gateways from
# unbounded trigger bursts. 0 disables the check.
max_per_uid: 3 # max in-flight vectorize tasks per user
max_queue_depth: 50000 # global pending+processing hard cap (429 beyond)
embedding:
Expand All @@ -129,15 +138,29 @@ pipeline:
collection: cloud_drive # existing collection (schema owned by the pipeline, guarded)
analyzer: chinese # BM25 analyzer; must match the existing collection
summary:
# L1 routing payload (plan 1.0.15): a small-model structured summary
# L1 routing payload: a small-model structured summary
# stored with the parsed document (Mongo) for doc-level retrieval.
# BEST-EFFORT: failures are logged and skipped — vectorization (L2) never
# blocks on it. Credentials/base URL are shared with embedding (same
# Higress gateway); the model MUST be routable there.
enabled: true
model: "" # empty => stage skipped; env APPCLOUD__PIPELINE__SUMMARY__MODEL
model: "z-ai/glm-5.3-flash" # empty => stage skipped; env APPCLOUD__PIPELINE__SUMMARY__MODEL
max_input_chars: 60000 # full text truncated before the summary call
max_output_tokens: 1500
max_output_tokens: 3000
ocr:
# Vision OCR for images / screenshots / image-only (scanned) PDFs. OCR MUST
# go through the same OpenAI-compatible Higress gateway as embedding/summary;
# there is deliberately no provider base_url/api_key here (one
# AI_GATEWAY__* pair wires every AI call). Empty model disables the stage
# (images then stay not_supported).
# env: APPCLOUD__PIPELINE__OCR__{ENABLED,MODEL,MAX_IMAGE_BYTES,
# MAX_PDF_PAGES,MAX_IMAGES,TIMEOUT_SECONDS}
enabled: true
model: "z-ai/glm-5.3-flash"
max_image_bytes: 10485760 # per image fed to the vision model (10 MiB)
max_pdf_pages: 20 # scanned-PDF pages inspected for embedded images
max_images: 40 # extracted images OCR'd per scanned PDF
timeout_seconds: 90 # per OCR call

kg:
# app-kg internal cloud-doc routing endpoints (health-mux JSON; L1 graph
Expand Down
7 changes: 7 additions & 0 deletions app-go/app-cloud/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ require (
github.com/ledongthuc/pdf v0.0.0-20260907135840-6c8c28e0e8a0
github.com/milvus-io/milvus/client/v2 v2.5.6
github.com/minio/minio-go/v7 v7.0.87
github.com/pdfcpu/pdfcpu v0.11.0
github.com/prometheus/client_golang v1.14.0
github.com/redis/go-redis/v9 v9.14.0
go.mongodb.org/mongo-driver/v2 v2.5.0
Expand Down Expand Up @@ -62,6 +63,9 @@ require (
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect
github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 // indirect
github.com/hhrutter/lzw v1.0.0 // indirect
github.com/hhrutter/pkcs7 v0.2.0 // indirect
github.com/hhrutter/tiff v1.0.2 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect
github.com/jonboulle/clockwork v0.2.2 // indirect
Expand All @@ -73,6 +77,7 @@ require (
github.com/leodido/go-urn v1.4.0 // indirect
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-runewidth v0.0.16 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
github.com/milvus-io/milvus-proto/go-api/v2 v2.5.16 // indirect
github.com/milvus-io/milvus/pkg/v2 v2.5.7 // indirect
Expand All @@ -91,6 +96,7 @@ require (
github.com/prometheus/procfs v0.9.0 // indirect
github.com/quic-go/qpack v0.6.0 // indirect
github.com/quic-go/quic-go v0.59.0 // indirect
github.com/rivo/uniseg v0.4.7 // indirect
github.com/rogpeppe/go-internal v1.12.0 // indirect
github.com/rs/xid v1.6.0 // indirect
github.com/samber/lo v1.27.0 // indirect
Expand Down Expand Up @@ -140,6 +146,7 @@ require (
golang.org/x/arch v0.22.0 // indirect
golang.org/x/crypto v0.48.0 // indirect
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 // indirect
golang.org/x/image v0.27.0 // indirect
golang.org/x/net v0.51.0 // indirect
golang.org/x/sync v0.19.0 // indirect
golang.org/x/sys v0.41.0 // indirect
Expand Down
15 changes: 15 additions & 0 deletions app-go/app-cloud/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,12 @@ github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO
github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
github.com/hhrutter/lzw v1.0.0 h1:laL89Llp86W3rRs83LvKbwYRx6INE8gDn0XNb1oXtm0=
github.com/hhrutter/lzw v1.0.0/go.mod h1:2HC6DJSn/n6iAZfgM3Pg+cP1KxeWc3ezG8bBqW5+WEo=
github.com/hhrutter/pkcs7 v0.2.0 h1:i4HN2XMbGQpZRnKBLsUwO3dSckzgX142TNqY/KfXg+I=
github.com/hhrutter/pkcs7 v0.2.0/go.mod h1:aEzKz0+ZAlz7YaEMY47jDHL14hVWD6iXt0AgqgAvWgE=
github.com/hhrutter/tiff v1.0.2 h1:7H3FQQpKu/i5WaSChoD1nnJbGx4MxU5TlNqqpxw55z8=
github.com/hhrutter/tiff v1.0.2/go.mod h1:pcOeuK5loFUE7Y/WnzGw20YxUdnqjY1P0Jlcieb/cCw=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/hydrogen18/memlistener v0.0.0-20200120041712-dcc25e7acd91/go.mod h1:qEIFzExnS6016fRpRfxrExeVn2gbClQA99gQhnIcdhE=
github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA=
Expand Down Expand Up @@ -364,6 +370,8 @@ github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Ky
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw=
Expand Down Expand Up @@ -417,6 +425,8 @@ github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFSt
github.com/panjf2000/ants/v2 v2.11.3 h1:AfI0ngBoXJmYOpDh9m516vjqoUu2sLrIVgppI9TZVpg=
github.com/panjf2000/ants/v2 v2.11.3/go.mod h1:8u92CYMUc6gyvTIw8Ru7Mt7+/ESnJahz5EVtqfrilek=
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pdfcpu/pdfcpu v0.11.0 h1:mL18Y3hSHzSezmnrzA21TqlayBOXuAx7BUzzZyroLGM=
github.com/pdfcpu/pdfcpu v0.11.0/go.mod h1:F1ca4GIVFdPtmgvIdvXAycAm88noyNxZwzr9CpTy+Mw=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=
github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
Expand Down Expand Up @@ -469,6 +479,9 @@ github.com/quic-go/quic-go v0.59.0 h1:OLJkp1Mlm/aS7dpKgTc6cnpynnD2Xg7C1pwL6vy/SA
github.com/quic-go/quic-go v0.59.0/go.mod h1:upnsH4Ju1YkqpLXC305eW3yDZ4NfnNbmQRCMWS58IKU=
github.com/redis/go-redis/v9 v9.14.0 h1:u4tNCjXOyzfgeLN+vAZaW1xUooqWDqVEsZN0U01jfAE=
github.com/redis/go-redis/v9 v9.14.0/go.mod h1:huWgSWd8mW6+m0VPhJjSSQ+d6Nh1VICQ6Q5lHuCH/Iw=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
Expand Down Expand Up @@ -681,6 +694,8 @@ golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 h1:vr/HnozRka3pE4EsMEg1lgkXJ
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.27.0 h1:C8gA4oWU/tKkdCfYT6T2u4faJu3MeNS5O8UPWlPF61w=
golang.org/x/image v0.27.0/go.mod h1:xbdrClrAUway1MUTEZDq9mz/UpRwYAkFFNUslZtcB+g=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
Expand Down
74 changes: 74 additions & 0 deletions app-go/app-cloud/internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ type Config struct {
Quota QuotaConfig `yaml:"quota"`
Trash TrashConfig `yaml:"trash"`
Pipeline PipelineConfig `yaml:"pipeline"`
Internal InternalConfig `yaml:"internal"`
Kg KgConfig `yaml:"kg"`
WSBridge WSBridgeConfig `yaml:"ws_bridge"`
CORS CORSConfig `yaml:"cors"`
Expand Down Expand Up @@ -180,6 +181,7 @@ type PipelineConfig struct {
Embedding EmbeddingConfig `yaml:"embedding"`
Milvus MilvusConfig `yaml:"milvus"`
Summary SummaryConfig `yaml:"summary"`
OCR OCRConfig `yaml:"ocr"`
}

// AdmissionConfig — queue admission control (capacity layer): without it a
Expand All @@ -203,6 +205,38 @@ type SummaryConfig struct {
MaxOutputTok int `yaml:"max_output_tokens"`
}

// OCRConfig — vision-model OCR for images and image-only PDFs. OCR MUST go
// through the same Higress gateway as embedding/summary: this struct deliberately
// has no provider base_url/api_key, so one AI_GATEWAY__* pair wires every AI call
// and there is no code path that could point OCR at a vendor API directly.
// Limits bound one file's OCR work (bytes fed to the model, pages inspected,
// images extracted) so a huge scan cannot monopolise a pipeline worker.
type OCRConfig struct {
Enabled bool `yaml:"enabled"`
Model string `yaml:"model"`
MaxImageBytes int64 `yaml:"max_image_bytes"`
MaxPDFPages int `yaml:"max_pdf_pages"`
MaxImages int `yaml:"max_images"`
TimeoutSecs int `yaml:"timeout_seconds"`
}

// Default OCR limits, applied when a value is unset or non-positive.
const (
DefaultOCRMaxImageBytes = int64(10 * 1024 * 1024)
DefaultOCRMaxPDFPages = 20
DefaultOCRMaxImages = 40
DefaultOCRTimeoutSecs = 90
)

// InternalConfig protects the newly added machine-to-machine endpoints only
// (/internal/cloud/summary and /internal/cloud/similar). The legacy
// /internal/cloud/reconcile endpoint keeps its loopback-only deployment
// posture and is deliberately unaffected. Empty key = new endpoints answer
// 503 (fail closed).
type InternalConfig struct {
APIKey string `yaml:"api_key"`
}

type WSBridgeConfig struct {
Enabled bool `yaml:"enabled"`
Channel string `yaml:"channel"`
Expand Down Expand Up @@ -242,9 +276,29 @@ func Load(yamlBytes []byte) (*Config, error) {
if cfg.Joblock.LeaseTTLSecs <= 0 {
cfg.Joblock.LeaseTTLSecs = DefaultJoblockLeaseTTLSecs
}
normalizeOCR(&cfg.Pipeline.OCR)
return &cfg, nil
}

// normalizeOCR fills the documented defaults for unset (zero/negative) OCR
// limits. Explicit env overrides of 0 are treated as "unset" — an OCR call
// with a zero byte cap or zero timeout could never succeed.
func normalizeOCR(cfg *OCRConfig) {
if cfg.MaxImageBytes <= 0 {
cfg.MaxImageBytes = DefaultOCRMaxImageBytes
}
if cfg.MaxPDFPages <= 0 {
cfg.MaxPDFPages = DefaultOCRMaxPDFPages
}
if cfg.MaxImages <= 0 {
cfg.MaxImages = DefaultOCRMaxImages
}
if cfg.TimeoutSecs <= 0 {
cfg.TimeoutSecs = DefaultOCRTimeoutSecs
}
cfg.Model = strings.TrimSpace(cfg.Model)
}

func applyEnvOverrides(cfg *Config) {
get := func(key string) string { return strings.TrimSpace(os.Getenv(key)) }
getBool := func(key string) (bool, bool) {
Expand Down Expand Up @@ -343,6 +397,19 @@ func applyEnvOverrides(cfg *Config) {
if v := get("APPCLOUD__PIPELINE__SUMMARY__MODEL"); v != "" {
cfg.Pipeline.Summary.Model = v
}
if b, ok := getBool("APPCLOUD__PIPELINE__OCR__ENABLED"); ok {
cfg.Pipeline.OCR.Enabled = b
}
if v := get("APPCLOUD__PIPELINE__OCR__MODEL"); v != "" {
cfg.Pipeline.OCR.Model = v
}
atol("APPCLOUD__PIPELINE__OCR__MAX_IMAGE_BYTES", &cfg.Pipeline.OCR.MaxImageBytes)
atoi("APPCLOUD__PIPELINE__OCR__MAX_PDF_PAGES", &cfg.Pipeline.OCR.MaxPDFPages)
atoi("APPCLOUD__PIPELINE__OCR__MAX_IMAGES", &cfg.Pipeline.OCR.MaxImages)
atoi("APPCLOUD__PIPELINE__OCR__TIMEOUT_SECONDS", &cfg.Pipeline.OCR.TimeoutSecs)
if v := get("APPCLOUD__INTERNAL__API_KEY"); v != "" {
cfg.Internal.APIKey = v
}
if v := get("APPCLOUD__KG__BASE_URL"); v != "" {
cfg.Kg.BaseURL = v
}
Expand Down Expand Up @@ -390,5 +457,12 @@ func Validate(cfg *Config) error {
if cfg.Pipeline.Enabled && cfg.Pipeline.Embedding.Dimension <= 0 {
return fmt.Errorf("pipeline.embedding.dimension must be positive when pipeline enabled")
}
if cfg.Pipeline.OCR.Enabled && cfg.Pipeline.OCR.Model != "" {
if cfg.Pipeline.OCR.MaxImageBytes <= 0 || cfg.Pipeline.OCR.MaxPDFPages <= 0 ||
cfg.Pipeline.OCR.MaxImages <= 0 || cfg.Pipeline.OCR.TimeoutSecs <= 0 {
return fmt.Errorf("pipeline.ocr limits must be positive when OCR is enabled " +
"(MAX_IMAGE_BYTES / MAX_PDF_PAGES / MAX_IMAGES / TIMEOUT_SECONDS)")
}
}
return nil
}
Loading
Loading