Configure cloud OCR providers for on-premise Reducto installations
Was this page helpful?
{"docsConfig":{"theme":"mint","$schema":"https://mintlify.com/docs.json","name":"Reducto","colors":{"primary":"#5c0c5c","light":"#c77dba","dark":"#5c0c5c"},"logo":{"light":"https://cdn.reducto.ai/logo.svg","dark":"https://cdn.reducto.ai/logo-dark.svg"},"favicon":"https://mintcdn.com/reducto/7owl8-bq0hdh9XB8/favicon.ico?fit=max\u0026auto=format\u0026n=7owl8-bq0hdh9XB8\u0026q=85\u0026s=90372b27ca6d42c4f6192cbba673afb5","api":{"examples":{"languages":["python","javascript","go"]}},"appearance":{"default":"light"},"navbar":{"links":[{"href":"https://reducto.ai/?utm_source=docs\u0026utm_medium=referral\u0026utm_campaign=docs_product_bridge\u0026utm_content=navbar_product","label":"Product"},{"href":"https://reducto.ai/blog","label":"Blog"}],"primary":{"type":"button","label":"Log In","href":"https://studio.reducto.ai/"}},"footer":{"socials":{"x":"https://x.com/reductoai","linkedin":"https://www.linkedin.com/company/reducto-ai"},"links":[{"header":"Product","items":[{"label":"Homepage","href":"https://reducto.ai/"},{"label":"Pricing","href":"https://reducto.ai/pricing"},{"label":"Playground","href":"https://studio.reducto.ai/"}]},{"header":"Company","items":[{"label":"Careers","href":"https://reducto.ai/careers"},{"label":"Blog","href":"https://reducto.ai/blog"},{"label":"Support","href":"mailto:support@Reducto.ai"}]},{"header":"Legal","items":[{"label":"Privacy Policy","href":"https://reducto.ai/privacy"},{"label":"Terms of Service","href":"https://reducto.ai/terms"}]}]},"fonts":{"heading":{"family":"Reducto Sans Bold","source":"https://cdn.reducto.ai/fonts/ReductoSansBold.woff2","format":"woff2"},"body":{"family":"Reducto Sans","source":"https://cdn.reducto.ai/fonts/ReductoSans.woff2","format":"woff2"}},"contextual":{"options":["copy","view","chatgpt","claude"],"display":"header"},"styling":{"latex":true},"navigation":{"global":{"anchors":[{"anchor":"Status","icon":"signal","href":"https://status.reducto.ai"},{"anchor":"Studio","icon":"browser","href":"https://studio.reducto.ai"},{"anchor":"Support","icon":"envelope","href":"mailto:support@reducto.ai"},{"anchor":"Model Versions","icon":"bell","href":"/reference/model-versions"},{"anchor":"Changelog","icon":"clock-rotate-left","href":"/reference/changelog"}]},"pages":[]}},"deployment":{"deploymentMetadataValue":{"subdomain":"reducto","hasAudioNarration":false,"actualSubdomain":"reducto","customDomains":["docs.reducto.ai"],"gitSource":{"type":"github","owner":"reductoai","repo":"api","deployBranch":"main","contentDirectory":"docs","isPrivate":true,"mountPath":"","label":""},"feedback":{"issues":false,"edits":false,"thumbs":true},"entitlements":{"AI_CHAT":{"status":"ENABLED"},"REMOVE_BRANDING":{"status":"ENABLED"},"CONTEXTUAL_FEEDBACK":{"status":"ENABLED"},"CODE_SNIPPET_FEEDBACK":{"status":"ENABLED"},"WEB_MCP":{"status":"ENABLED"},"NARRATION":{"status":"ENABLED"}},"buildId":"6af53fc828a841e71cb83542","clientVersion":"0.0.4117","searchFilterCounts":[{"language":"default","tag":"Documentation","count":82},{"language":"default","tag":"API Reference","count":36},{"language":"default","tag":"SDKs","count":30},{"language":"default","tag":"Document Processing","count":24},{"language":"default","tag":"Configurations","count":18},{"language":"default","tag":"On-premise Resources","count":18},{"language":"default","tag":"Core Methods","count":18},{"language":"default","tag":"Core Functions","count":15},{"language":"default","tag":"Utilities","count":10},{"language":"default","tag":"Parse Configurations","count":10}]},"assistantConfig":{"deflection":{"enabled":true,"email":"support@reducto.ai","showHelpButton":true}},"basePath":"","hasChatPermissions":true,"hasWebMcpPermissions":true,"toggles":[{"name":"kill-isr","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"custom-rbac-roles","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"agent-mintlify-slack","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"agent-integrations-settings","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"rbac-expansion","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automations-pr-grouping","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"custom-prefix","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"analytics-v7","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"user-flows-analytics","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"no-publish-flow","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-onboarding","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"llms-txt-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"snapshot-serving-live","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"stripTemperatureMiddleware","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"support-platform-pylon-zendesk","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"snapshot-serving","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"instant-rollback","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"granular-notifications-server","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"granular-notifications","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automations-fable","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"fixed-ai-action-pricing","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automation-resolve-merge-conflict","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"scoped-publishing","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"mintql","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"page-level-analytics","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"editor-version-history-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"billing-page-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"full-page-search","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workspace-projects","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"assistant-v5","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"fork-pr-previews","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"revalidation-jwt","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-sso-scim","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"hobby-abuse-scan","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"dashboard-inbox","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-signup","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"turbopuffer-dual-write","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-enabled","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"approve-review-flow","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"editor-metadata","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"sso-setup-deadline-banner","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"turbopuffer-serve","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"live-agents","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false}],"googleFontsInlined":false},"customCss":[],"page":{"pagePath":"onprem/ocr_options","slug":"/onprem/ocr_options","pageMetadata":{"title":"OCR provider configuration","description":"Configure cloud OCR providers for on-premise Reducto installations","href":"/onprem/ocr_options"},"description":{"compiledSource":"\"use strict\";\nconst {jsx: _jsx} = arguments[0];\nconst {useMDXComponents: _provideComponents} = arguments[0];\nfunction _createMdxContent(props) {\n const _components = {\n p: \"p\",\n ..._provideComponents(),\n ...props.components\n };\n return _jsx(_components.p, {\n children: \"Configure cloud OCR providers for on-premise Reducto installations\"\n });\n}\nfunction MDXContent(props = {}) {\n const {wrapper: MDXLayout} = {\n ..._provideComponents(),\n ...props.components\n };\n return MDXLayout ? _jsx(MDXLayout, {\n ...props,\n children: _jsx(_createMdxContent, {\n ...props\n })\n }) : _createMdxContent(props);\n}\nreturn {\n default: MDXContent\n};\n","frontmatter":{},"scope":{}},"pageType":"default","mdx":{"mdxSource":{"compiledSource":"\"use strict\";const{Fragment:_Fragment,jsx:_jsx,jsxs:_jsxs}=arguments[0];const{useMDXComponents:_provideComponents}=arguments[0];const PasswordProtect=({children})=>{const[password,setPassword]=useState(``);const[isAuthenticated,setIsAuthenticated]=useState(false);const[error,setError]=useState(``);const correctPasswordHash=`9daff39ca2584edc54444193f62e5e54dce0bcd5e5d604b1748c79bfb3d7d1fd`;const hashPassword=async inputPassword=>{const encoder=new TextEncoder;const data=encoder.encode(inputPassword);const hashBuffer=await crypto.subtle.digest(`SHA-256`,data);const hashArray=Array.from(new Uint8Array(hashBuffer));return hashArray.map(b=>b.toString(16).padStart(2,`0`)).join(``)};useEffect(()=>{const storedPassword=localStorage.getItem(`reducto-onprem-password`);if(storedPassword){checkStoredPassword(storedPassword)}},[]);const checkStoredPassword=async storedPassword=>{const hashedStored=await hashPassword(storedPassword);if(hashedStored===correctPasswordHash){setIsAuthenticated(true);setError(``)}};const handleSubmit=async e=>{e.preventDefault();const hashedInput=await hashPassword(password);if(hashedInput===correctPasswordHash){setIsAuthenticated(true);setError(``);localStorage.setItem(`reducto-onprem-password`,password)}else{setError(`Incorrect password. Please try again.`);setPassword(``)}};if(isAuthenticated){return _jsx(_Fragment,{children})}return _jsxs(`div`,{style:{padding:`2rem`,border:`2px solid #e2e8f0`,borderRadius:`8px`,textAlign:`center`,margin:`2rem 0`},children:[_jsx(`div`,{style:{fontSize:`2rem`,marginBottom:`1rem`},children:`🔒`}),_jsx(`h2`,{children:`Protected Content`}),_jsx(`p`,{children:`This content requires a password to access.`}),_jsxs(`form`,{onSubmit:handleSubmit,style:{marginTop:`1rem`},children:[_jsx(`input`,{type:`password`,value:password,onChange:e=>setPassword(e.target.value),placeholder:`Enter password`,style:{padding:`0.5rem`,border:`1px solid #cbd5e0`,borderRadius:`4px`,marginRight:`0.5rem`,fontSize:`1rem`}}),_jsx(`button`,{type:`submit`,style:{padding:`0.5rem 1rem`,backgroundColor:`#5c0c5c`,color:`white`,border:`none`,borderRadius:`4px`,cursor:`pointer`,fontSize:`1rem`},children:`Unlock`})]}),error\u0026\u0026_jsx(`p`,{style:{color:`red`,marginTop:`1rem`},children:error})]})};function _createMdxContent(props){const _components={a:`a`,code:`code`,hr:`hr`,li:`li`,ol:`ol`,p:`p`,pre:`pre`,span:`span`,strong:`strong`,tbody:`tbody`,td:`td`,th:`th`,thead:`thead`,tr:`tr`,ul:`ul`,..._provideComponents(),...props.components},{CodeBlock,Heading,Note,Table,Warning,_MdxComponentBoundary}=_components;if(!CodeBlock)_missingMdxReference(`CodeBlock`,true);if(!Heading)_missingMdxReference(`Heading`,true);if(!Note)_missingMdxReference(`Note`,true);if(!Table)_missingMdxReference(`Table`,true);if(!Warning)_missingMdxReference(`Warning`,true);if(!_MdxComponentBoundary)_missingMdxReference(`_MdxComponentBoundary`,true);return _jsx(_MdxComponentBoundary,{name:`PasswordProtect`,children:_jsxs(PasswordProtect,{children:[_jsx(_components.p,{children:`Reducto supports local OCR on CPU or GPU, as well as cloud OCR providers. By default, Reducto uses its own local OCR models, but you can configure cloud OCR providers for broader language support.`}),_jsx(Heading,{level:`2`,id:`provider-overview`,children:`Provider overview`}),_jsxs(Table,{children:[_jsx(_components.thead,{children:_jsxs(_components.tr,{children:[_jsx(_components.th,{children:`Provider`}),_jsx(_components.th,{children:`Credentials needed`}),_jsx(_components.th,{children:`Best for`})]})}),_jsxs(_components.tbody,{children:[_jsxs(_components.tr,{children:[_jsx(_components.td,{children:_jsx(_components.strong,{children:`Reducto local OCR`})}),_jsx(_components.td,{children:`None (default)`}),_jsx(_components.td,{children:`General-purpose, privacy-sensitive, GPU-equipped deployments`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:_jsx(_components.strong,{children:`AWS Textract`})}),_jsxs(_components.td,{children:[_jsx(_components.code,{children:`AWS_ACCESS_KEY_ID`}),`, `,_jsx(_components.code,{children:`AWS_SECRET_ACCESS_KEY`})]}),_jsx(_components.td,{children:`AWS-native deployments`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:_jsx(_components.strong,{children:`Azure Vision Read`})}),_jsxs(_components.td,{children:[_jsx(_components.code,{children:`AZURE_VISION_ENDPOINT`}),` + `,_jsx(_components.code,{children:`AZURE_VISION_KEY`}),` (or `,_jsx(_components.code,{children:`AZURE_VISION_ARRAY`}),`), or workload identity`]}),_jsx(_components.td,{children:`Azure-native deployments`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:_jsx(_components.strong,{children:`GCP Vision API`})}),_jsxs(_components.td,{children:[_jsx(_components.code,{children:`GOOGLE_APPLICATION_CREDENTIALS`}),` + `,_jsx(_components.code,{children:`GCP_PROJECT_ID`}),` (or `,_jsx(_components.code,{children:`GCP_SERVICE_ACCOUNT_EMAIL`}),` for workload identity)`]}),_jsx(_components.td,{children:`GCP-native deployments, cross-cloud deployments wanting GCP OCR, 60+ language support`})]})]})]}),_jsx(Heading,{level:`2`,id:`how-ocr-provider-is-selected`,children:`How OCR provider is selected`}),_jsxs(_components.p,{children:[`The `,_jsx(_components.code,{children:`ocr_system`}),` parameter in API requests controls provider routing. Only two values are available to API callers: `,_jsx(_components.code,{children:`standard`}),` (default) and `,_jsx(_components.code,{children:`legacy`}),`.`]}),_jsx(_components.p,{children:_jsxs(_components.strong,{children:[_jsx(_components.code,{children:`standard`}),` (default) routing priority:`]})}),_jsxs(_components.ol,{children:[`\n`,_jsx(_components.li,{children:`GCP Vision API, if GCP credentials are configured`}),`\n`,_jsx(_components.li,{children:`Azure Vision or AWS Textract, if configured (Azure is preferred over Textract)`}),`\n`]}),_jsx(_components.p,{children:_jsxs(_components.strong,{children:[_jsx(_components.code,{children:`legacy`}),` routing priority:`]})}),_jsxs(_components.ol,{children:[`\n`,_jsx(_components.li,{children:`Azure Vision or AWS Textract, if configured (Azure is preferred over Textract)`}),`\n`,_jsx(_components.li,{children:`GCP Vision API, as fallback if only GCP credentials are available`}),`\n`]}),_jsxs(_components.p,{children:[`In practice: if you configure GCP credentials, `,_jsx(_components.code,{children:`standard`}),` requests use GCP Vision. If you only have Azure/AWS credentials, both `,_jsx(_components.code,{children:`standard`}),` and `,_jsx(_components.code,{children:`legacy`}),` use those.`]}),_jsx(Heading,{level:`3`,id:`auto-detection-gcp-only-environments`,children:`Auto-detection: GCP-only environments`}),_jsxs(_components.p,{children:[`When `,_jsx(_components.strong,{children:`only`}),` GCP credentials are configured (no AWS or Azure), Reducto auto-detects this and routes all OCR through GCP Vision regardless of the `,_jsx(_components.code,{children:`ocr_system`}),` value. This requires:`]}),_jsxs(_components.ul,{children:[`\n`,_jsxs(_components.li,{children:[`No Azure credentials (`,_jsx(_components.code,{children:`AZURE_VISION_ENDPOINT`}),` and `,_jsx(_components.code,{children:`AZURE_VISION_ARRAY`}),` both unset)`]}),`\n`,_jsxs(_components.li,{children:[`No AWS credentials (`,_jsx(_components.code,{children:`AWS_ACCESS_KEY_ID`}),` unset)`]}),`\n`,_jsxs(_components.li,{children:[`GCP credentials available (`,_jsx(_components.code,{children:`GOOGLE_APPLICATION_CREDENTIALS`}),` or `,_jsx(_components.code,{children:`GCP_SERVICE_ACCOUNT_EMAIL`}),`)`]}),`\n`,_jsxs(_components.li,{children:[_jsx(_components.code,{children:`GCP_PROJECT_ID`}),` is set`]}),`\n`]}),_jsx(_components.hr,{}),_jsx(Heading,{level:`2`,id:`aws-textract`,children:`AWS Textract`}),_jsx(Heading,{level:`3`,id:`environment-variables`,children:`Environment variables`}),_jsxs(Table,{children:[_jsx(_components.thead,{children:_jsxs(_components.tr,{children:[_jsx(_components.th,{children:`Variable`}),_jsx(_components.th,{children:`Description`}),_jsx(_components.th,{children:`Required`})]})}),_jsxs(_components.tbody,{children:[_jsxs(_components.tr,{children:[_jsx(_components.td,{children:_jsx(_components.code,{children:`AWS_ACCESS_KEY_ID`})}),_jsx(_components.td,{children:`AWS access key ID`}),_jsx(_components.td,{children:`Yes`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:_jsx(_components.code,{children:`AWS_SECRET_ACCESS_KEY`})}),_jsx(_components.td,{children:`AWS secret access key`}),_jsx(_components.td,{children:`Yes`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:_jsx(_components.code,{children:`TEXTRACT_REGIONS`})}),_jsxs(_components.td,{children:[`Comma-separated `,_jsx(_components.code,{children:`region:quota`}),` pairs for load balancing`]}),_jsx(_components.td,{children:`No`})]})]})]}),_jsxs(_components.p,{children:[`Default regions: `,_jsx(_components.code,{children:`us-east-2:100,us-east-1:100,us-west-2:100,ap-south-1:5,eu-west-1:5`})]}),_jsx(CodeBlock,{filename:``,numberOfLines:`5`,language:`shellscript`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`shellscript`,children:_jsxs(_components.code,{language:`shellscript`,numberOfLines:`5`,children:[_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#6E7781`,\"--shiki-dark\":`#6A9955`},children:`# Format: region:quota pairs (quota defaults to 1 if omitted)`})}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`TEXTRACT_REGIONS`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`=`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`us-east-1:50,us-west-2:25,eu-west-1:10`})]}),`\n`,_jsx(_components.span,{className:`line`}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#6E7781`,\"--shiki-dark\":`#6A9955`},children:`# Government Cloud`})}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`TEXTRACT_REGIONS`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`=`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`us-gov-west-1:10,us-gov-east-1:10`})]}),`\n`]})})}),_jsx(Heading,{level:`3`,id:`required-iam-permissions`,children:`Required IAM permissions`}),_jsx(CodeBlock,{filename:``,numberOfLines:`10`,language:`json`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`json`,children:_jsxs(_components.code,{language:`json`,numberOfLines:`10`,children:[_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`{`})}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:` \"Version\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`\"2012-10-17\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`,`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:` \"Statement\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: [`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` {`})}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:` \"Effect\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`\"Allow\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`,`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:` \"Action\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`\"textract:DetectDocumentText\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`,`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:` \"Resource\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`\"*\"`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` }`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` ]`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`}`})}),`\n`]})})}),_jsx(_components.hr,{}),_jsx(Heading,{level:`2`,id:`azure-vision-read`,children:`Azure Vision Read`}),_jsx(Heading,{level:`3`,id:`environment-variables-2`,children:`Environment variables`}),_jsx(_components.p,{children:_jsx(_components.strong,{children:`Single endpoint:`})}),_jsxs(Table,{children:[_jsx(_components.thead,{children:_jsxs(_components.tr,{children:[_jsx(_components.th,{children:`Variable`}),_jsx(_components.th,{children:`Description`}),_jsx(_components.th,{children:`Required`})]})}),_jsxs(_components.tbody,{children:[_jsxs(_components.tr,{children:[_jsx(_components.td,{children:_jsx(_components.code,{children:`AZURE_VISION_ENDPOINT`})}),_jsx(_components.td,{children:`Azure Computer Vision endpoint URL`}),_jsxs(_components.td,{children:[`Yes (unless using `,_jsx(_components.code,{children:`AZURE_VISION_ARRAY`}),`)`]})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:_jsx(_components.code,{children:`AZURE_VISION_KEY`})}),_jsx(_components.td,{children:`Azure Computer Vision API key`}),_jsxs(_components.td,{children:[`Yes (unless using `,_jsx(_components.code,{children:`AZURE_VISION_ARRAY`}),` or workload identity)`]})]})]})]}),_jsx(_components.p,{children:_jsx(_components.strong,{children:`Multiple endpoints (load balancing and failover):`})}),_jsxs(Table,{children:[_jsx(_components.thead,{children:_jsxs(_components.tr,{children:[_jsx(_components.th,{children:`Variable`}),_jsx(_components.th,{children:`Description`}),_jsx(_components.th,{children:`Required`})]})}),_jsxs(_components.tbody,{children:[_jsxs(_components.tr,{children:[_jsx(_components.td,{children:_jsx(_components.code,{children:`AZURE_VISION_ARRAY`})}),_jsxs(_components.td,{children:[`JSON array of `,_jsx(_components.code,{children:`{\"endpoint\": \"...\", \"key\": \"...\"}`}),` objects`]}),_jsx(_components.td,{children:`No`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:_jsx(_components.code,{children:`AZURE_VISION_ARRAY_STRATEGY`})}),_jsxs(_components.td,{children:[_jsx(_components.code,{children:`load_balance`}),` (default) or `,_jsx(_components.code,{children:`priority`})]}),_jsx(_components.td,{children:`No`})]})]})]}),_jsx(CodeBlock,{filename:``,numberOfLines:`4`,language:`shellscript`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`shellscript`,children:_jsxs(_components.code,{language:`shellscript`,numberOfLines:`4`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`AZURE_VISION_ARRAY`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`=`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`'[`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` {\"endpoint\": \"https://vision-east.cognitiveservices.azure.com/\", \"key\": \"\u003ckey-1>\"},`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` {\"endpoint\": \"https://vision-west.cognitiveservices.azure.com/\", \"key\": \"\u003ckey-2>\"}`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`]'`})}),`\n`]})})}),_jsxs(Table,{children:[_jsx(_components.thead,{children:_jsxs(_components.tr,{children:[_jsx(_components.th,{children:`Strategy`}),_jsx(_components.th,{children:`Behavior`})]})}),_jsxs(_components.tbody,{children:[_jsxs(_components.tr,{children:[_jsxs(_components.td,{children:[_jsx(_components.code,{children:`load_balance`}),` (default)`]}),_jsx(_components.td,{children:`Randomly selects an endpoint per request. On transient error, retries then fails over to next.`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:_jsx(_components.code,{children:`priority`})}),_jsx(_components.td,{children:`Tries endpoints in order. On transient error, retries then fails over to next.`})]})]})]}),_jsx(_components.p,{children:_jsx(_components.strong,{children:`Timeout and retry tuning:`})}),_jsxs(Table,{children:[_jsx(_components.thead,{children:_jsxs(_components.tr,{children:[_jsx(_components.th,{children:`Variable`}),_jsx(_components.th,{children:`Default`}),_jsx(_components.th,{children:`Description`})]})}),_jsxs(_components.tbody,{children:[_jsxs(_components.tr,{children:[_jsx(_components.td,{children:_jsx(_components.code,{children:`AZURE_VISION_TOTAL_CALL_TIMEOUT`})}),_jsxs(_components.td,{children:[_jsx(_components.code,{children:`45`}),` (seconds)`]}),_jsxs(_components.td,{children:[`Hard cancellation cap per `,_jsx(_components.code,{children:`analyze`}),` call, including all retries.`]})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:_jsx(_components.code,{children:`AZURE_VISION_WALL_TIMEOUT`})}),_jsxs(_components.td,{children:[_jsx(_components.code,{children:`120`}),` (seconds)`]}),_jsx(_components.td,{children:`SDK-level wall-clock timeout (checked between retries).`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:_jsx(_components.code,{children:`AZURE_VISION_CONNECTION_TIMEOUT`})}),_jsxs(_components.td,{children:[_jsx(_components.code,{children:`10`}),` (seconds)`]}),_jsx(_components.td,{children:`Per-attempt TCP connect timeout.`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:_jsx(_components.code,{children:`AZURE_VISION_READ_TIMEOUT`})}),_jsxs(_components.td,{children:[_jsx(_components.code,{children:`30`}),` (seconds)`]}),_jsx(_components.td,{children:`Per-attempt socket read timeout.`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:_jsx(_components.code,{children:`AZURE_VISION_MAX_RETRIES`})}),_jsx(_components.td,{\"data-numeric\":`true`,children:_jsx(_components.code,{children:`2`})}),_jsxs(_components.td,{children:[`Retries per endpoint. Total attempts = `,_jsx(_components.code,{children:`1 + MAX_RETRIES`}),`.`]})]})]})]}),_jsx(_components.p,{children:`Transient errors (408, 429, 5xx, network errors) trigger retries and failover. Non-retryable 4xx errors surface immediately.`}),_jsxs(_components.p,{children:[_jsx(_components.strong,{children:`API version:`}),` `,_jsx(_components.code,{children:`AZURE_VISION_API`}),` defaults to `,_jsx(_components.code,{children:`image_analysis_4.0`}),`, which calls Image Analysis 4.0. Some regions, such as US Gov Arizona, do not offer Image Analysis 4.0, so every OCR call there returns 404. Set `,_jsx(_components.code,{children:`AZURE_VISION_API=read_3.2`}),` in those regions to call the v3.2 Read API. It uses the same endpoints, keys or workload identity, retries, and timeouts.`]}),_jsx(Note,{children:_jsxs(_components.p,{children:[`When `,_jsx(_components.code,{children:`AZURE_VISION_ARRAY`}),` is set, `,_jsx(_components.code,{children:`AZURE_VISION_ENDPOINT`}),` and `,_jsx(_components.code,{children:`AZURE_VISION_KEY`}),` are ignored.`]})}),_jsx(Heading,{level:`3`,id:`workload-identity-no-api-key`,children:`Workload identity (no API key)`}),_jsxs(_components.p,{children:[`When your Azure AI services resource disables key authentication, set `,_jsx(_components.code,{children:`AZURE_AI_SERVICES_AUTH=workload_identity`}),` and leave out every key. Reducto then signs each Azure Vision call with an Entra ID token of the pod’s workload identity, the same identity that signs Blob Storage result links and calls Azure OpenAI. See `,_jsx(_components.a,{href:`/onprem/azure_workload_identity`,children:`Azure workload identity`}),` for the setup, the roles, and Azure Government.`]}),_jsx(CodeBlock,{filename:``,numberOfLines:`8`,language:`shellscript`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`shellscript`,children:_jsxs(_components.code,{language:`shellscript`,numberOfLines:`8`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`AZURE_AI_SERVICES_AUTH`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`=`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`workload_identity`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`AZURE_VISION_ENDPOINT`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`=`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`https://`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`\u003c`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`resource-name`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`>`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`.cognitiveservices.azure.us/`})]}),`\n`,_jsx(_components.span,{className:`line`}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#6E7781`,\"--shiki-dark\":`#6A9955`},children:`# Or several endpoints, with no keys`})}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`AZURE_VISION_ARRAY`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`=`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`'[`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` {\"endpoint\": \"https://vision-east.cognitiveservices.azure.us/\"},`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` {\"endpoint\": \"https://vision-west.cognitiveservices.azure.us/\"}`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`]'`})}),`\n`]})})}),_jsx(_components.hr,{}),_jsx(Heading,{level:`2`,id:`gcp-vision-api`,children:`GCP Vision API`}),_jsx(Heading,{level:`3`,id:`environment-variables-3`,children:`Environment variables`}),_jsxs(Table,{children:[_jsx(_components.thead,{children:_jsxs(_components.tr,{children:[_jsx(_components.th,{children:`Variable`}),_jsx(_components.th,{children:`Description`}),_jsx(_components.th,{children:`Required`})]})}),_jsxs(_components.tbody,{children:[_jsxs(_components.tr,{children:[_jsx(_components.td,{children:_jsx(_components.code,{children:`GOOGLE_APPLICATION_CREDENTIALS`})}),_jsx(_components.td,{children:`Path to service account key JSON file, or the raw JSON content. Handles both OCR routing detection and Vision API authentication via Application Default Credentials.`}),_jsxs(_components.td,{children:[`Yes (unless using `,_jsx(_components.code,{children:`GCP_SERVICE_ACCOUNT_EMAIL`}),`)`]})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:_jsx(_components.code,{children:`GCP_PROJECT_ID`})}),_jsx(_components.td,{children:`GCP project ID for quota attribution`}),_jsx(_components.td,{children:`Yes`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:_jsx(_components.code,{children:`GCP_SERVICE_ACCOUNT_EMAIL`})}),_jsxs(_components.td,{children:[`Service account email for workload identity auth (alternative to `,_jsx(_components.code,{children:`GOOGLE_APPLICATION_CREDENTIALS`}),`).`]}),_jsx(_components.td,{children:`No`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:_jsx(_components.code,{children:`GCP_API_KEY`})}),_jsxs(_components.td,{children:[_jsx(_components.a,{href:`https://console.cloud.google.com/apis/credentials`,children:`API key`}),` with Cloud Vision API enabled. Optional; if set, the Vision API client uses this instead of ADC.`]}),_jsx(_components.td,{children:`No`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:_jsx(_components.code,{children:`GCP_REGION`})}),_jsx(_components.td,{children:`Region for Vertex AI`}),_jsxs(_components.td,{children:[`No (default: `,_jsx(_components.code,{children:`us-central1`}),`)`]})]})]})]}),_jsx(Heading,{level:`3`,id:`authentication-methods`,children:`Authentication methods`}),_jsx(_components.p,{children:_jsx(_components.strong,{children:`Option 1: Service account key (recommended)`})}),_jsxs(_components.p,{children:[_jsx(_components.code,{children:`GOOGLE_APPLICATION_CREDENTIALS`}),` handles everything: Reducto uses it to detect GCP availability for routing, and the Vision API client picks it up via Application Default Credentials (ADC).`]}),_jsx(CodeBlock,{filename:``,numberOfLines:`2`,language:`shellscript`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`shellscript`,children:_jsxs(_components.code,{language:`shellscript`,numberOfLines:`2`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`GOOGLE_APPLICATION_CREDENTIALS`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`=`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`/path/to/service-account-key.json`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`GCP_PROJECT_ID`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`=`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`your-project-id`})]}),`\n`]})})}),_jsxs(_components.p,{children:[_jsx(_components.code,{children:`GOOGLE_APPLICATION_CREDENTIALS`}),` can be a file path or the raw JSON content of the service account key.`]}),_jsx(_components.p,{children:_jsx(_components.strong,{children:`Option 2: Workload identity (GKE)`})}),_jsxs(_components.p,{children:[`Set `,_jsx(_components.code,{children:`GCP_SERVICE_ACCOUNT_EMAIL`}),` to use GKE workload identity. No key file needed.`]}),_jsx(CodeBlock,{filename:``,numberOfLines:`2`,language:`shellscript`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`shellscript`,children:_jsxs(_components.code,{language:`shellscript`,numberOfLines:`2`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`GCP_SERVICE_ACCOUNT_EMAIL`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`=`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`ocr-sa@your-project.iam.gserviceaccount.com`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`GCP_PROJECT_ID`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`=`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`your-project-id`})]}),`\n`]})})}),_jsx(Heading,{level:`3`,id:`required-gcp-api-and-roles`,children:`Required GCP API and roles`}),_jsxs(_components.ul,{children:[`\n`,_jsxs(_components.li,{children:[_jsx(_components.strong,{children:`Cloud Vision API`}),` must be enabled on the project (`,_jsx(_components.code,{children:`GCP_PROJECT_ID`}),`).`]}),`\n`,_jsxs(_components.li,{children:[`If using a service account, it needs at minimum the `,_jsx(_components.code,{children:`roles/cloudvision.user`}),` role.`]}),`\n`,_jsxs(_components.li,{children:[`If using `,_jsx(_components.code,{children:`GOOGLE_APPLICATION_CREDENTIALS`}),` for broader GCP features (storage, Vertex AI), the service account also needs:`,`\n`,_jsxs(_components.ul,{children:[`\n`,_jsxs(_components.li,{children:[_jsx(_components.code,{children:`roles/aiplatform.user`}),` (for Vertex AI / Gemini LLM calls)`]}),`\n`,_jsxs(_components.li,{children:[_jsx(_components.code,{children:`roles/storage.objectAdmin`}),` (if using GCS for file storage)`]}),`\n`]}),`\n`]}),`\n`]}),_jsx(_components.hr,{}),_jsx(Heading,{level:`2`,id:`cross-cloud-ocr-using-gcp-vision-on-non-gcp-infrastructure`,children:`Cross-cloud OCR: using GCP Vision on non-GCP infrastructure`}),_jsxs(_components.p,{children:[`If you run on Azure or AWS but want GCP Vision for OCR, set `,_jsx(_components.code,{children:`GCP_OCR_ONLY=true`}),` so Reducto uses GCP only for Vision API calls and does not initialize GCS storage.`]}),_jsxs(Table,{children:[_jsx(_components.thead,{children:_jsxs(_components.tr,{children:[_jsx(_components.th,{children:`Variable`}),_jsx(_components.th,{children:`Description`}),_jsx(_components.th,{children:`Default`})]})}),_jsx(_components.tbody,{children:_jsxs(_components.tr,{children:[_jsx(_components.td,{children:_jsx(_components.code,{children:`GCP_OCR_ONLY`})}),_jsx(_components.td,{children:`Use GCP for Vision API OCR only, not for storage.`}),_jsx(_components.td,{children:_jsx(_components.code,{children:`false`})})]})})]}),_jsx(Heading,{level:`3`,id:`example-azure-infrastructure-with-gcp-vision-ocr`,children:`Example: Azure infrastructure with GCP Vision OCR`}),_jsx(CodeBlock,{filename:``,numberOfLines:`14`,language:`shellscript`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`shellscript`,children:_jsxs(_components.code,{language:`shellscript`,numberOfLines:`14`,children:[_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#6E7781`,\"--shiki-dark\":`#6A9955`},children:`# --- Azure storage (unchanged) ---`})}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`AZURE_STORAGE_CONNECTION_STRING`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`=`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`DefaultEndpointsProtocol`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`=`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`https`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`;`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`AccountName`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`=`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`...`})]}),`\n`,_jsx(_components.span,{className:`line`}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#6E7781`,\"--shiki-dark\":`#6A9955`},children:`# --- Azure Vision (optional, keep as fallback or remove) ---`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#6E7781`,\"--shiki-dark\":`#6A9955`},children:`# If you want to remove Azure Vision entirely, delete these.`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#6E7781`,\"--shiki-dark\":`#6A9955`},children:`# If you keep them, 'legacy' OCR requests will still use Azure Vision,`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#6E7781`,\"--shiki-dark\":`#6A9955`},children:`# while 'standard' (default) requests will use GCP Vision.`})}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`AZURE_VISION_ENDPOINT`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`=`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`https://your-vision.cognitiveservices.azure.com/`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`AZURE_VISION_KEY`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`=`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`your-azure-vision-key`})]}),`\n`,_jsx(_components.span,{className:`line`}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#6E7781`,\"--shiki-dark\":`#6A9955`},children:`# --- GCP Vision OCR ---`})}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`GOOGLE_APPLICATION_CREDENTIALS`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`=`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`/path/to/service-account-key.json`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`GCP_PROJECT_ID`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`=`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`your-gcp-project-id`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`GCP_OCR_ONLY`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`=`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`true`})]}),`\n`]})})}),_jsx(_components.p,{children:`With this configuration:`}),_jsxs(_components.ul,{children:[`\n`,_jsxs(_components.li,{children:[_jsx(_components.strong,{children:`Default API requests`}),` (`,_jsx(_components.code,{children:`ocr_system=standard`}),` or unset) route to `,_jsx(_components.strong,{children:`GCP Vision API`})]}),`\n`,_jsxs(_components.li,{children:[_jsxs(_components.strong,{children:[_jsx(_components.code,{children:`ocr_system=legacy`}),` requests`]}),` route to `,_jsx(_components.strong,{children:`Azure Vision`}),` (if Azure Vision credentials are still set) or `,_jsx(_components.strong,{children:`GCP Vision`}),` (if Azure Vision credentials are removed)`]}),`\n`,_jsxs(_components.li,{children:[_jsx(_components.strong,{children:`File storage`}),` remains on `,_jsx(_components.strong,{children:`Azure Blob Storage`})]}),`\n`]}),_jsx(Heading,{level:`3`,id:`example-aws-infrastructure-with-gcp-vision-ocr`,children:`Example: AWS infrastructure with GCP Vision OCR`}),_jsx(CodeBlock,{filename:``,numberOfLines:`9`,language:`shellscript`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`shellscript`,children:_jsxs(_components.code,{language:`shellscript`,numberOfLines:`9`,children:[_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#6E7781`,\"--shiki-dark\":`#6A9955`},children:`# --- AWS storage ---`})}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`AWS_ACCESS_KEY_ID`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`=`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`your-aws-key`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`AWS_SECRET_ACCESS_KEY`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`=`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`your-aws-secret`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`BUCKET`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`=`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`your-s3-bucket`})]}),`\n`,_jsx(_components.span,{className:`line`}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#6E7781`,\"--shiki-dark\":`#6A9955`},children:`# --- GCP Vision OCR ---`})}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`GOOGLE_APPLICATION_CREDENTIALS`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`=`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`/path/to/service-account-key.json`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`GCP_PROJECT_ID`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`=`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`your-gcp-project-id`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`GCP_OCR_ONLY`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`=`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`true`})]}),`\n`]})})}),_jsx(Heading,{level:`3`,id:`migration-path-switching-from-azure-vision-to-gcp-vision`,children:`Migration path: switching from Azure Vision to GCP Vision`}),_jsx(_components.p,{children:`If you are currently using Azure Vision and want to switch to GCP Vision as your primary OCR:`}),_jsxs(_components.ol,{children:[`\n`,_jsxs(_components.li,{children:[`\n`,_jsxs(_components.p,{children:[_jsx(_components.strong,{children:`Add GCP credentials`}),` to your deployment:`]}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`3`,language:`shellscript`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`shellscript`,children:_jsxs(_components.code,{language:`shellscript`,numberOfLines:`3`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`GOOGLE_APPLICATION_CREDENTIALS`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`=`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`/path/to/service-account-key.json`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`GCP_PROJECT_ID`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`=`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`your-gcp-project-id`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`GCP_OCR_ONLY`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`=`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`true`})]}),`\n`]})})}),`\n`]}),`\n`,_jsxs(_components.li,{children:[`\n`,_jsxs(_components.p,{children:[_jsx(_components.strong,{children:`Test with a few requests.`}),` The default `,_jsx(_components.code,{children:`ocr_system=standard`}),` will now route to GCP Vision. Verify OCR quality meets your expectations.`]}),`\n`]}),`\n`,_jsxs(_components.li,{children:[`\n`,_jsxs(_components.p,{children:[_jsx(_components.strong,{children:`Optionally remove Azure Vision credentials.`}),` If you no longer need Azure Vision as a fallback for `,_jsx(_components.code,{children:`legacy`}),` requests, remove `,_jsx(_components.code,{children:`AZURE_VISION_ENDPOINT`}),` and `,_jsx(_components.code,{children:`AZURE_VISION_KEY`}),` (or `,_jsx(_components.code,{children:`AZURE_VISION_ARRAY`}),`). This simplifies the configuration.`]}),`\n`]}),`\n`,_jsxs(_components.li,{children:[`\n`,_jsxs(_components.p,{children:[_jsxs(_components.strong,{children:[_jsx(_components.code,{children:`GCP_OCR_ONLY`}),` should remain set`]}),` as long as you are using non-GCP file storage.`]}),`\n`]}),`\n`]}),_jsx(_components.hr,{}),_jsx(Heading,{level:`2`,id:`local-cpu-ocr-tuning`,children:`Local CPU OCR tuning`}),_jsxs(_components.p,{children:[`The legacy worker can tune its in-process ONNX OCR detector and CRNN recognizer\nwithout a separate inference service. Enable the settings below explicitly;\nthey apply only when those models use `,_jsx(_components.code,{children:`CPUExecutionProvider`}),` exclusively.`]}),_jsxs(_components.ul,{children:[`\n`,_jsxs(_components.li,{children:[_jsx(_components.code,{children:`OCR_CPU_MEM_ARENA`}),` defaults to `,_jsx(_components.code,{children:`false`}),`. Set it to `,_jsx(_components.code,{children:`true`}),` to reuse CPU allocations\nbetween inference calls. This can retain more memory.`]}),`\n`,_jsxs(_components.li,{children:[_jsx(_components.code,{children:`OCR_CPU_INTRA_OP_THREADS`}),` defaults to unset. Set a positive per-model thread\ncount to also use one inter-op thread and disable idle spinning in both pools.`]}),`\n`]}),_jsxs(_components.p,{children:[`For a CPU worker with an eight-vCPU limit, a candidate to validate is\n`,_jsx(_components.code,{children:`OCR_CPU_MEM_ARENA=true`}),` with `,_jsx(_components.code,{children:`OCR_CPU_INTRA_OP_THREADS=8`}),`. Choose the thread count\nagainst available CPU per pod and the number of pods sharing each node. Set these\nenvironment variables on the worker deployment and restart workers to recreate\nthe model sessions.`]}),_jsxs(_components.p,{children:[`These controls leave memory patterns disabled and do not change CUDA sessions,\nPaddle recognition, or layout/table model settings. `,_jsx(_components.code,{children:`OCR_THREADS`}),` controls the\nOCR service request executor separately; it does not limit ONNX model threads.\nRuntime session overrides, such as benchmark `,_jsx(_components.code,{children:`sitecustomize.py`}),` hooks, must not\noverwrite these settings. Preserve any separate tuning needed by non-OCR models.`]}),_jsxs(_components.p,{children:[`Before enabling arena reuse across a fleet, validate completed jobs and peak\nmemory with all worker models loaded at the intended pod density. Roll back by\nsetting `,_jsx(_components.code,{children:`OCR_CPU_MEM_ARENA=false`}),`, removing `,_jsx(_components.code,{children:`OCR_CPU_INTRA_OP_THREADS`}),`, and\nrestarting workers. This restores the previous OCR session options.`]}),_jsxs(Heading,{level:`2`,id:`gpu-ocr-deployment-ocr_only-mode`,children:[`GPU OCR deployment (`,_jsx(_components.code,{children:`OCR_ONLY`}),` mode)`]}),_jsxs(_components.p,{children:[`For deployments that want to use Reducto’s own OCR models (which run on GPU) as a dedicated service, set `,_jsx(_components.code,{children:`OCR_ONLY=true`}),`. This starts a lightweight service exposing only the `,_jsx(_components.code,{children:`/ocr`}),` endpoint.`]}),_jsxs(Table,{children:[_jsx(_components.thead,{children:_jsxs(_components.tr,{children:[_jsx(_components.th,{children:`Variable`}),_jsx(_components.th,{children:`Description`}),_jsx(_components.th,{children:`Default`})]})}),_jsxs(_components.tbody,{children:[_jsxs(_components.tr,{children:[_jsx(_components.td,{children:_jsx(_components.code,{children:`OCR_ONLY`})}),_jsx(_components.td,{children:`Enable OCR-only mode`}),_jsx(_components.td,{children:_jsx(_components.code,{children:`false`})})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:_jsx(_components.code,{children:`OFFLINE`})}),_jsxs(_components.td,{children:[`Must be `,_jsx(_components.code,{children:`1`}),` for on-prem deployments`]}),_jsx(_components.td,{\"data-numeric\":`true`,children:`-`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:_jsx(_components.code,{children:`HTTP_WORKERS`})}),_jsx(_components.td,{children:`HTTP worker processes`}),_jsx(_components.td,{\"data-numeric\":`true`,children:_jsx(_components.code,{children:`8`})})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:_jsx(_components.code,{children:`MAX_PROCESSING_REQUESTS`})}),_jsx(_components.td,{children:`Max concurrent OCR requests per worker`}),_jsx(_components.td,{\"data-numeric\":`true`,children:_jsx(_components.code,{children:`1`})})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:_jsx(_components.code,{children:`MAX_QUEUED_REQUESTS`})}),_jsx(_components.td,{children:`Max queued requests per worker`}),_jsx(_components.td,{\"data-numeric\":`true`,children:_jsx(_components.code,{children:`0`})})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:_jsx(_components.code,{children:`OCR_THREADS`})}),_jsx(_components.td,{children:`Thread pool size for OCR`}),_jsx(_components.td,{\"data-numeric\":`true`,children:_jsx(_components.code,{children:`5`})})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:_jsx(_components.code,{children:`NUM_GPUS`})}),_jsx(_components.td,{children:`GPUs available (for CUDA device assignment)`}),_jsx(_components.td,{\"data-numeric\":`true`,children:_jsx(_components.code,{children:`0`})})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:_jsx(_components.code,{children:`REQUIRE_GPU`})}),_jsxs(_components.td,{children:[`Fail startup if ONNX Runtime cannot reach the GPU. Defaults to on for GPU images. Set `,_jsx(_components.code,{children:`false`}),` to intentionally run a GPU image on CPU nodes.`]}),_jsxs(_components.td,{children:[`(GPU images: `,_jsx(_components.code,{children:`true`}),`)`]})]})]})]}),_jsxs(Warning,{children:[_jsx(_components.p,{children:`GPU images refuse to start when ONNX Runtime cannot actually reach the GPU, rather\nthan silently falling back to CPU at a fraction of the throughput. The startup log\nnames the cause and the commands to confirm it.`}),_jsxs(_components.p,{children:[`The most common cause on NVSwitch hardware (HGX/SXM H100, H200, A100) is\n`,_jsx(_components.code,{children:`nvidia-fabricmanager`}),` not running, or running at a version that does not exactly\nmatch the installed driver. Note that `,_jsx(_components.code,{children:`nvidia-smi`}),` still reports a perfectly healthy\nGPU in this state, because NVML does not touch fabric state. To confirm on the node:`]}),_jsx(CodeBlock,{filename:``,numberOfLines:`3`,language:`shellscript`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`shellscript`,children:_jsxs(_components.code,{language:`shellscript`,numberOfLines:`3`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:`nvidia-smi`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:` -q`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:` |`}),_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:` grep`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:` -i`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:` -A3`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` fabric`}),_jsx(_components.span,{style:{color:`#6E7781`,\"--shiki-dark\":`#6A9955`},children:` # expect \"State: Completed\"`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:`systemctl`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` status`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` nvidia-fabricmanager`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:`cat`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` /proc/driver/nvidia/version`}),_jsx(_components.span,{style:{color:`#6E7781`,\"--shiki-dark\":`#6A9955`},children:` # must match the fabricmanager package version`})]}),`\n`]})})}),_jsxs(_components.p,{children:[`Repair the node before upgrading the image: a deployment that was previously serving\ndegraded CPU-only OCR will now fail its readiness check instead. If you need to run a\nGPU image on CPU nodes deliberately, set `,_jsx(_components.code,{children:`REQUIRE_GPU=false`}),`.`]})]}),_jsx(CodeBlock,{filename:``,numberOfLines:`9`,language:`yaml`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`yaml`,children:_jsxs(_components.code,{language:`yaml`,numberOfLines:`9`,children:[_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#6E7781`,\"--shiki-dark\":`#6A9955`},children:`# Helm values`})}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:`gpuOcr`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`:`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` enabled`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:`true`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` replicaCount`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#B5CEA8`},children:`1`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` resources`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`:`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` requests`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`:`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` nvidia.com/gpu`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#B5CEA8`},children:`1`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` limits`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`:`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` nvidia.com/gpu`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#B5CEA8`},children:`1`})]}),`\n`]})})}),_jsxs(_components.p,{children:[`The Helm chart sets `,_jsx(_components.code,{children:`OCR_ONLY=true`}),` and `,_jsx(_components.code,{children:`OFFLINE=1`}),` automatically.`]}),_jsxs(_components.p,{children:[`The readiness probes require a GPU OCR image that includes the `,_jsx(_components.code,{children:`/ready`}),` endpoint;\nuse the image built from this change or a later release. Because the chart and\nimage are independently upgradeable, both probes are disabled by default for\ncompatibility with existing pinned images. Enable both together after upgrading\nthe image. If `,_jsx(_components.code,{children:`gpuOcrImage.tag`}),` is pinned to an older image, upgrade that image\nfirst; an older image with the probes enabled returns `,_jsx(_components.code,{children:`404`}),` and never becomes\nReady.`]}),_jsx(Heading,{level:`3`,id:`startup-behavior-and-readiness`,children:`Startup behavior and readiness`}),_jsxs(_components.p,{children:[`The pod loads its OCR models `,_jsx(_components.strong,{children:`before`}),` accepting traffic, rather than on the first\nrequest. When the probes are enabled, a pod on a node whose GPU is unusable never\nbecomes Ready, so Kubernetes routes no traffic to it and the problem is visible\nfrom `,_jsx(_components.code,{children:`kubectl get pods`}),` at deploy time instead of surfacing later as failed jobs.`]}),_jsxs(_components.p,{children:[`Every worker process loads its own copy, one at a time. With the probes enabled,\nthe pod reports Ready only after all `,_jsx(_components.code,{children:`HTTP_WORKERS`}),` finish. Reporting Ready earlier\nwould advertise full capacity while most workers were still loading, and\n`,_jsx(_components.code,{children:`MAX_QUEUED_REQUESTS`}),` defaults to `,_jsx(_components.code,{children:`0`}),`, so the surplus comes back as `,_jsx(_components.code,{children:`429`}),`. After the pod has been fully warm once\nit stays in service while any worker can serve, so losing one worker later reduces\ncapacity instead of removing the pod.`]}),_jsxs(_components.p,{children:[`Size `,_jsx(_components.code,{children:`HTTP_WORKERS`}),` against GPU and host memory, not just latency: every worker\nholds its own copy of the models, and the pod now needs all of them resident before\nit serves. Set it under `,_jsx(_components.code,{children:`gpuOcr.extraEnv`}),`, so changing the OCR worker count does\nnot also resize the main HTTP tier:`]}),_jsx(CodeBlock,{filename:``,numberOfLines:`4`,language:`yaml`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`yaml`,children:_jsxs(_components.code,{language:`yaml`,numberOfLines:`4`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:`gpuOcr`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`:`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` extraEnv`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`:`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` - `}),_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:`name`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`HTTP_WORKERS`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` value`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`\"4\"`})]}),`\n`]})})}),_jsxs(_components.p,{children:[`The shared environment remains the fallback for existing installations; when a\nname appears in both places, `,_jsx(_components.code,{children:`gpuOcr.extraEnv`}),` wins for the GPU OCR pod only.`]}),_jsx(_components.p,{children:`Read the real per-worker load time off the startup logs to check it against the\nreadiness budget:`}),_jsx(CodeBlock,{filename:``,numberOfLines:`1`,language:`shellscript`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`shellscript`,children:_jsxs(_components.code,{language:`shellscript`,numberOfLines:`1`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:`kubectl`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` logs`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` deploy/`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`\u003c`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`releas`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`e`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`>`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`-reducto-gpu-ocr`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:` |`}),_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:` grep`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` \"OCR model load complete\"`})]}),`\n`]})})}),_jsxs(_components.p,{children:[`Warm-up is roughly that duration times `,_jsx(_components.code,{children:`HTTP_WORKERS`}),`, because the loads are\nserialized. If that exceeds the probe budget below, lower `,_jsx(_components.code,{children:`HTTP_WORKERS`}),` or raise\n`,_jsx(_components.code,{children:`failureThreshold`}),`. The rollout deadline also includes image pull and GPU-node\nscheduling time.`]}),_jsxs(_components.p,{children:[`When the cause is the GPU check, the pod stays running (not `,_jsx(_components.code,{children:`CrashLoopBackOff`}),`) so\nyou can inspect it for as long as the `,_jsx(_components.code,{children:`startupProbe`}),` budget lasts, about 500s with\nthe shipped values. After that the kubelet kills the container and Kubernetes\nrestarts it, so a persistently unusable GPU does end in a restart loop; use\n`,_jsx(_components.code,{children:`kubectl logs --previous`}),` once that starts. Any other model-load failure, such as\nmissing weights or an out-of-memory kill, ends the container immediately.`]}),_jsxs(_components.p,{children:[_jsx(_components.code,{children:`/ready`}),` returns `,_jsx(_components.code,{children:`503`}),` until every worker is warm and reports how many are;\n`,_jsx(_components.code,{children:`/health`}),` remains a plain liveness signal. Once the pod has been fully warm it\nstays in service while any worker can serve, so losing a worker later reduces\ncapacity instead of removing the pod.`]}),_jsx(CodeBlock,{filename:``,numberOfLines:`3`,language:`shellscript`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`shellscript`,children:_jsxs(_components.code,{language:`shellscript`,numberOfLines:`3`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:`kubectl`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` get`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` pods`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:` -l`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` app=reducto-gpu-ocr`}),_jsx(_components.span,{style:{color:`#6E7781`,\"--shiki-dark\":`#6A9955`},children:` # 0/1 means the models did not load`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:`kubectl`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` exec`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` deploy/`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`\u003c`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`releas`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`e`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`>`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`-reducto-gpu-ocr`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:` --`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` curl`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:` -s`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` localhost:80/ready`}),_jsx(_components.span,{style:{color:`#6E7781`,\"--shiki-dark\":`#6A9955`},children:` # replace 80 if gpuOcr.port is overridden`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:`kubectl`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` logs`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` deploy/`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`\u003c`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`releas`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`e`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`>`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`-reducto-gpu-ocr`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:` |`}),_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:` grep`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:` -i`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` \"OCR model init failed\"`})]}),`\n`]})})}),_jsx(_components.p,{children:`Three consequences worth planning for:`}),_jsxs(_components.ul,{children:[`\n`,_jsxs(_components.li,{children:[_jsx(_components.strong,{children:`Startup is slower`}),`, by roughly `,_jsx(_components.code,{children:`HTTP_WORKERS`}),` model loads. Lower `,_jsx(_components.code,{children:`HTTP_WORKERS`}),`\nto shorten it. There is no `,_jsx(_components.code,{children:`livenessProbe`}),`, so a slow load never restarts a pod\nthat is making progress; the `,_jsx(_components.code,{children:`startupProbe`}),` does restart one that never warms up.`]}),`\n`,_jsxs(_components.li,{children:[_jsx(_components.strong,{children:`A deployment previously serving degraded CPU-only OCR will stop serving.`}),` Repair\nthe node first, or set `,_jsx(_components.code,{children:`REQUIRE_GPU=false`}),` to deliberately run on CPU.`]}),`\n`,_jsxs(_components.li,{children:[_jsx(_components.strong,{children:`Running degraded rejects the surplus.`}),` Once the pod has been fully warm it\nstays in service while any worker can serve, but the OCR client does not retry,\nso requests beyond the remaining capacity fail rather than queue. Prefer more\nreplicas over a high `,_jsx(_components.code,{children:`HTTP_WORKERS`}),` if losing a worker must not fail jobs.`]}),`\n`,_jsxs(_components.li,{children:[_jsx(_components.strong,{children:`A worker that cannot reach the GPU exits and is respawned.`}),` It never serves,\nso requests are not routed to a handler that would fail them. A transient cause,\nsuch as a pod scheduled while `,_jsx(_components.code,{children:`nvidia-fabricmanager`}),` is still starting on a fresh\nnode, therefore recovers without operator action. A persistent one logs the reason\non every attempt and eventually restarts the container.`]}),`\n`,_jsxs(_components.li,{children:[_jsx(_components.strong,{children:`One bad GPU on a multi-GPU node stops the whole pod.`}),` Workers are pinned per\ndevice (`,_jsx(_components.code,{children:`CUDA_VISIBLE_DEVICES = pid % NUM_GPUS`}),`), so only the workers landing on\nthe bad device fail, but the initial gate needs every worker warm, so the pod\nnever becomes Ready and is restarted rather than serving at reduced capacity. The\nsymptom is a never-Ready pod, not an obvious GPU error, so grep the logs for\n`,_jsx(_components.code,{children:`OCR model init failed`}),` to identify it.`]}),`\n`]}),_jsxs(_components.p,{children:[`Two probes, because the two windows differ. `,_jsx(_components.code,{children:`startupProbe`}),` absorbs the warm-up;\nKubernetes suppresses readiness until it passes, which lets `,_jsx(_components.code,{children:`readinessProbe`}),` stay\ntight and pull a pod that stops serving in about 30s instead of waiting out the\nwhole warm-up budget.`]}),_jsx(CodeBlock,{filename:``,numberOfLines:`12`,language:`yaml`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`yaml`,children:_jsxs(_components.code,{language:`yaml`,numberOfLines:`12`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:`gpuOcr`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`:`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` progressDeadlineSeconds`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#B5CEA8`},children:`1800`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` startupProbe`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`:`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` enabled`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:`true`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` periodSeconds`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#B5CEA8`},children:`10`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` timeoutSeconds`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#B5CEA8`},children:`5`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` failureThreshold`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#B5CEA8`},children:`50`}),_jsx(_components.span,{style:{color:`#6E7781`,\"--shiki-dark\":`#6A9955`},children:` # 500s of warm-up, with rollout margin`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` readinessProbe`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`:`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` enabled`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:`true`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` periodSeconds`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#B5CEA8`},children:`10`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` timeoutSeconds`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#B5CEA8`},children:`5`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` failureThreshold`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#B5CEA8`},children:`3`}),_jsx(_components.span,{style:{color:`#6E7781`,\"--shiki-dark\":`#6A9955`},children:` # ~30s to stop routing to a pod that goes bad`})]}),`\n`]})})}),_jsx(Note,{children:_jsxs(_components.p,{children:[_jsx(_components.code,{children:`gpuOcr.port`}),` sets the container port, the Service target, the readiness probe and\n`,_jsx(_components.code,{children:`HTTP_PORT`}),` together, so the port the app binds always matches the one Kubernetes\nprobes. It defaults to `,_jsx(_components.code,{children:`80`}),` to preserve rolling upgrades of existing standard GPU\nimages. Chainguard images run as a non-root user and require `,_jsx(_components.code,{children:`gpuOcr.port: 8888`}),`.\nThe Service still publishes `,_jsx(_components.code,{children:`80`}),`, so callers are unaffected. Set the port before\nswitching image families; changing it and the image in one upgrade is a port\nmigration, not a transparent rolling update.`]})})]})})}function MDXContent(props={}){const{wrapper:MDXLayout}={..._provideComponents(),...props.components};return MDXLayout?_jsx(MDXLayout,{...props,children:_jsx(_createMdxContent,{...props})}):_createMdxContent(props)}return{PasswordProtect,default:MDXContent};function _missingMdxReference(id,component){throw new Error(`Expected `+(component?`component`:`object`)+\" `\"+id+\"` to be defined: you likely forgot to import, pass, or provide it.\")}","frontmatter":{},"scope":{"config":{},"pageMetadata":{"title":"OCR provider configuration","description":"Configure cloud OCR providers for on-premise Reducto installations","href":"/onprem/ocr_options"}}},"mdxSourceWithNoJs":null,"noJsSplices":[[19,38,""],[151,2252,")=>null;function _cr"]]},"mdxExtracts":{"tableOfContents":[{"title":"Provider overview","slug":"provider-overview","depth":2,"children":[]},{"title":"How OCR provider is selected","slug":"how-ocr-provider-is-selected","depth":2,"children":[{"title":"Auto-detection: GCP-only environments","slug":"auto-detection-gcp-only-environments","depth":3,"children":[]}]},{"title":"AWS Textract","slug":"aws-textract","depth":2,"children":[{"title":"Environment variables","slug":"environment-variables","depth":3,"children":[]},{"title":"Required IAM permissions","slug":"required-iam-permissions","depth":3,"children":[]}]},{"title":"Azure Vision Read","slug":"azure-vision-read","depth":2,"children":[{"title":"Environment variables","slug":"environment-variables-2","depth":3,"children":[]},{"title":"Workload identity (no API key)","slug":"workload-identity-no-api-key","depth":3,"children":[]}]},{"title":"GCP Vision API","slug":"gcp-vision-api","depth":2,"children":[{"title":"Environment variables","slug":"environment-variables-3","depth":3,"children":[]},{"title":"Authentication methods","slug":"authentication-methods","depth":3,"children":[]},{"title":"Required GCP API and roles","slug":"required-gcp-api-and-roles","depth":3,"children":[]}]},{"title":"Cross-cloud OCR: using GCP Vision on non-GCP infrastructure","slug":"cross-cloud-ocr-using-gcp-vision-on-non-gcp-infrastructure","depth":2,"children":[{"title":"Example: Azure infrastructure with GCP Vision OCR","slug":"example-azure-infrastructure-with-gcp-vision-ocr","depth":3,"children":[]},{"title":"Example: AWS infrastructure with GCP Vision OCR","slug":"example-aws-infrastructure-with-gcp-vision-ocr","depth":3,"children":[]},{"title":"Migration path: switching from Azure Vision to GCP Vision","slug":"migration-path-switching-from-azure-vision-to-gcp-vision","depth":3,"children":[]}]},{"title":"Local CPU OCR tuning","slug":"local-cpu-ocr-tuning","depth":2,"children":[]},{"title":"GPU OCR deployment (OCR_ONLY mode)","slug":"gpu-ocr-deployment-ocr_only-mode","depth":2,"children":[{"title":"Startup behavior and readiness","slug":"startup-behavior-and-readiness","depth":3,"children":[]}]}],"codeExamples":{}},"jsLinks":[],"subdomain":"reducto","siteName":"Reducto","title":"OCR provider configuration - Reducto","navMaps":{"firstHrefInVersion":{},"firstHrefInLanguage":{}},"lastModified":"2026-11-06T00:20:08.060Z","originalFileLocation":"onprem/ocr_options.mdx"},"headHtml":"\u003cscript data-mint-head>(function(){var d=document.documentElement,p=null;if(!p){try{p=localStorage.getItem(\"isDarkMode\")}catch(e){}if(p==='true')p='dark';else if(p==='false')p='light';if(p!=='light'\u0026\u0026p!=='dark'\u0026\u0026p!=='system')p=\"light\"}var r=p==='system'?(matchMedia(\"(prefers-color-scheme: dark)\").matches?'dark':'light'):p;d.classList.remove(r==='dark'?'light':'dark');d.classList.add(r);d.setAttribute(\"data-theme-preference\",p)})();\u003c/script>\u003cmeta data-mint-head name=\"description\" content=\"Configure cloud OCR providers for on-premise Reducto installations\">\u003cmeta data-mint-head name=\"application-name\" content=\"Reducto\">\u003cmeta data-mint-head name=\"generator\" content=\"Mintlify\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"192x192\" href=\"/mintlify-assets/_mintlify/favicons/reducto/riSUMTseceMg4CLB/_generated/favicon/android-chrome-192x192.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"apple-touch-icon\" type=\"image/png\" sizes=\"180x180\" href=\"/mintlify-assets/_mintlify/favicons/reducto/riSUMTseceMg4CLB/_generated/favicon/apple-touch-icon.png\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"/mintlify-assets/_mintlify/favicons/reducto/riSUMTseceMg4CLB/_generated/favicon/favicon-16x16.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"/mintlify-assets/_mintlify/favicons/reducto/riSUMTseceMg4CLB/_generated/favicon/favicon-32x32.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"shortcut icon\" type=\"image/x-icon\" href=\"/mintlify-assets/_mintlify/favicons/reducto/riSUMTseceMg4CLB/_generated/favicon/favicon.ico\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"192x192\" href=\"/mintlify-assets/_mintlify/favicons/reducto/riSUMTseceMg4CLB/_generated/favicon-dark/android-chrome-192x192.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"/mintlify-assets/_mintlify/favicons/reducto/riSUMTseceMg4CLB/_generated/favicon-dark/favicon-16x16.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"/mintlify-assets/_mintlify/favicons/reducto/riSUMTseceMg4CLB/_generated/favicon-dark/favicon-32x32.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"shortcut icon\" type=\"image/x-icon\" href=\"/mintlify-assets/_mintlify/favicons/reducto/riSUMTseceMg4CLB/_generated/favicon-dark/favicon.ico\" media=\"(prefers-color-scheme: dark)\">\u003cmeta data-mint-head property=\"og:title\" content=\"OCR provider configuration - Reducto\">\u003cmeta data-mint-head property=\"og:description\" content=\"Configure cloud OCR providers for on-premise Reducto installations\">\u003cmeta data-mint-head property=\"og:site_name\" content=\"Reducto\">\u003cmeta data-mint-head property=\"og:url\" content=\"https://docs.reducto.ai/onprem/ocr_options\">\u003cmeta data-mint-head property=\"og:type\" content=\"website\">\u003cmeta data-mint-head property=\"og:image\" content=\"https://reducto.mintlify.site/_mintlify/api/og/v2?division=On-premise+Resources\u0026amp;title=OCR+provider+configuration\u0026amp;description=Configure+cloud+OCR+providers+for+on-premise+Reducto+installations\u0026amp;theme=8265b8622ae183e65f8e9b16\u0026amp;signature=ed217d880aaac9a9f7ce59145adf79b876c39a51feaf1648a69b746f54f77b7f\">\u003cmeta data-mint-head property=\"og:image:width\" content=\"1200\">\u003cmeta data-mint-head property=\"og:image:height\" content=\"630\">\u003cmeta data-mint-head name=\"twitter:card\" content=\"summary_large_image\">\u003cmeta data-mint-head name=\"twitter:title\" content=\"OCR provider configuration - Reducto\">\u003cmeta data-mint-head name=\"twitter:description\" content=\"Configure cloud OCR providers for on-premise Reducto installations\">\u003cmeta data-mint-head name=\"twitter:image\" content=\"https://reducto.mintlify.site/_mintlify/api/og/v2?division=On-premise+Resources\u0026amp;title=OCR+provider+configuration\u0026amp;description=Configure+cloud+OCR+providers+for+on-premise+Reducto+installations\u0026amp;theme=8265b8622ae183e65f8e9b16\u0026amp;signature=ed217d880aaac9a9f7ce59145adf79b876c39a51feaf1648a69b746f54f77b7f\">\u003cmeta data-mint-head name=\"twitter:image:width\" content=\"1200\">\u003cmeta data-mint-head name=\"twitter:image:height\" content=\"630\">\u003cmeta data-mint-head name=\"msapplication-config\" content=\"/mintlify-assets/_mintlify/favicons/reducto/riSUMTseceMg4CLB/_generated/favicon/browserconfig.xml\">\u003cmeta data-mint-head name=\"apple-mobile-web-app-title\" content=\"Reducto\">\u003cmeta data-mint-head name=\"msapplication-TileColor\" content=\"#5c0c5c\">\u003clink data-mint-head rel=\"canonical\" href=\"https://docs.reducto.ai/onprem/ocr_options\">\u003clink data-mint-head rel=\"alternate\" type=\"application/xml\" href=\"/sitemap.xml\">\u003clink data-mint-head rel=\"alternate\" type=\"text/markdown\" href=\"/onprem/ocr_options.md\">\u003cscript data-mint-head type=\"application/ld+json\">{\"@context\":\"https://schema.org\",\"@graph\":[{\"@type\":\"Organization\",\"@id\":\"https://docs.reducto.ai/#organization\",\"name\":\"Reducto\",\"url\":\"https://docs.reducto.ai\",\"logo\":{\"@type\":\"ImageObject\",\"url\":\"https://cdn.reducto.ai/logo.svg\"}},{\"@type\":\"WebSite\",\"@id\":\"https://docs.reducto.ai#website\",\"name\":\"Reducto\",\"url\":\"https://docs.reducto.ai\",\"publisher\":{\"@id\":\"https://docs.reducto.ai/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https://docs.reducto.ai/onprem/ocr_options#webpage\",\"url\":\"https://docs.reducto.ai/onprem/ocr_options\",\"name\":\"OCR provider configuration\",\"description\":\"Configure cloud OCR providers for on-premise Reducto installations\",\"dateModified\":\"2026-11-06T00:20:08.060Z\",\"isPartOf\":{\"@id\":\"https://docs.reducto.ai#website\"},\"breadcrumb\":{\"@id\":\"https://docs.reducto.ai/onprem/ocr_options#breadcrumb\"}},{\"@type\":\"BreadcrumbList\",\"@id\":\"https://docs.reducto.ai/onprem/ocr_options#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"On-premise Resources\",\"item\":\"https://docs.reducto.ai/onprem/hybrid-vpc-deployment\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"OCR provider configuration\",\"item\":\"https://docs.reducto.ai/onprem/ocr_options\"}]},{\"@type\":[\"Article\",\"TechArticle\"],\"@id\":\"https://docs.reducto.ai/onprem/ocr_options#article\",\"headline\":\"OCR provider configuration\",\"name\":\"OCR provider configuration\",\"description\":\"Configure cloud OCR providers for on-premise Reducto installations\",\"url\":\"https://docs.reducto.ai/onprem/ocr_options\",\"mainEntityOfPage\":{\"@id\":\"https://docs.reducto.ai/onprem/ocr_options#webpage\"},\"dateModified\":\"2026-11-06T00:20:08.060Z\",\"publisher\":{\"@id\":\"https://docs.reducto.ai/#organization\"},\"isPartOf\":{\"@id\":\"https://docs.reducto.ai#website\"}}]}\u003c/script>","agentPointerHref":"/onprem/ocr_options.md","siteName":"Reducto","nav":{"global":{"anchors":[{"anchor":"Status","icon":"signal","href":"https://status.reducto.ai"},{"anchor":"Studio","icon":"browser","href":"https://studio.reducto.ai"},{"anchor":"Support","icon":"envelope","href":"mailto:support@reducto.ai"},{"anchor":"Model Versions","icon":"bell","href":"/reference/model-versions"},{"anchor":"Changelog","icon":"clock-rotate-left","href":"/reference/changelog"}]},"tabs":[{"tab":"Documentation","groups":[{"group":"Get Started","public":true,"pages":[{"title":"Overview","icon":"house","sidebarTitle":"Overview","href":"/overview"},{"title":"API Quickstart","icon":"rocket","href":"/quickstart"},{"title":"Studio Quickstart","icon":"crystal-ball","href":"/studio-quickstart"},{"title":"Reducto API Reference for Coding Agents","sidebarTitle":"Agent Guide","icon":"robot","href":"/agent-guide"}]},{"group":"Developer Tools","pages":[{"title":"Reducto CLI","icon":"code","iconType":"solid","href":"/cli"},{"title":"Reducto MCP Server","icon":"plug","iconType":"solid","href":"/mcp-server"}]},{"group":"Core Functions","public":true,"pages":[{"group":"Upload","pages":[{"title":"Upload","href":"/upload/overview"},{"title":"Uploading Large Files","href":"/upload/large-files"}]},{"group":"Parse","pages":[{"title":"Parse overview","sidebarTitle":"Overview","href":"/parse/overview"},{"title":"Parse r-1, r-1 mini","sidebarTitle":"Parse r-1, r-1 mini","href":"/parse/r-1"},{"title":"Parse Response Format","sidebarTitle":"Response Format","href":"/parse/response-format"},{"title":"Parse Best Practices","sidebarTitle":"Best Practices","href":"/parse/best-practices"}]},{"group":"Extract","pages":[{"title":"Extract","sidebarTitle":"Overview","href":"/extract/overview"},{"title":"Extract Response Format","sidebarTitle":"Response Format","href":"/extract/response-format"},{"title":"Schema Keyword Support","sidebarTitle":"Schema Keywords","href":"/extract/schema-keywords"},{"title":"Extract Best Practices","sidebarTitle":"Best Practices","href":"/extraction/best-practices-extract"}]},{"title":"Split","href":"/split"},{"group":"Classify","pages":[{"title":"Classify","sidebarTitle":"Overview","href":"/classify/overview"},{"title":"Classify Response Format","sidebarTitle":"Response Format","href":"/classify/response-format"},{"title":"Classify Best Practices","sidebarTitle":"Best Practices","href":"/classify/best-practices"}]},{"title":"Edit","href":"/editing/edit-overview"}]},{"group":"Workflows and Pipelines","public":true,"pages":[{"group":"Pipelines","pages":[{"title":"Pipeline Basics","href":"/workflows/pipeline-basics"},{"title":"Multi-document Pipelines","href":"/workflows/multi-document-pipelines"}]},{"title":"Chaining API Calls","href":"/workflows/chaining-endpoints"},{"group":"Async Processing \u0026 Webhooks","pages":[{"title":"Async Processing","href":"/workflows/async-overview"},{"title":"Svix Webhooks","href":"/workflows/svix-webhooks"},{"title":"Direct Webhooks","href":"/workflows/direct-webhooks"},{"title":"Batch Processing","href":"/workflows/batch-processing"},{"title":"Batch Queue","href":"/workflows/batch-queue"},{"title":"Deleting Jobs \u0026 Uploads","href":"/workflows/deletion"}]}]},{"group":"Configurations","public":true,"pages":[{"title":"Configuration Overview","href":"/configs/overview"},{"group":"Parse Configurations","pages":[{"title":"r-1 configuration compatibility","sidebarTitle":"r-1 compatibility","href":"/configs/parse/r-1-configuration-compatibility"},{"group":"Enhance","pages":[{"title":"Agentic Modes","href":"/configs/parse/agentic-modes"},{"title":"Chart Extraction","href":"/configs/parse/chart-extraction"}]},{"group":"Retrieval","pages":[{"title":"Chunking Methods","href":"/configs/parse/chunking-methods"}]},{"group":"Formatting","pages":[{"title":"Table Output Formats","href":"/configs/parse/table-output-formats"},{"title":"Additional Document Data","href":"/configs/parse/additional-document-data"}]},{"group":"Spreadsheet","pages":[{"title":"Spreadsheet Processing","href":"/configs/parse/spreadsheet"}]},{"group":"Settings","pages":[{"title":"Processing Settings","href":"/configs/parse/ocr-settings"},{"title":"Page Ranges","href":"/configs/parse/page-ranges"},{"title":"Word and Cell Citations","href":"/configs/parse/citations"}]}]},{"group":"Extract Configurations","pages":[{"title":"Deep Extract","href":"/configs/extract/deep-extract"},{"title":"Array Extraction","href":"/configs/extract/array-extraction"},{"title":"Citations","href":"/configs/extract/citations"}]},{"group":"Split Configurations","pages":[{"title":"Split Configuration","href":"/configs/split/configuration"},{"title":"Deep Split","href":"/configs/split/deep-split"}]},{"group":"Classify Configurations","pages":[{"title":"Classify Configuration","href":"/configs/classify/configuration"}]},{"group":"Edit Configurations","pages":[{"title":"Form Schema","href":"/configs/edit/form-schema"}]}]},{"group":"Reference","public":true,"pages":[{"title":"Version Pinning","href":"/reference/version-pinning"},{"title":"Error Codes","href":"/reference/error-codes"},{"title":"Rate Limits","href":"/reference/rate-limits"},{"title":"Checking API Health \u0026 Usage","href":"/reference/checking-api-health"},{"title":"Usage and Pricing","href":"/reference/credit-usage"},{"title":"Pricing Migration Guide","href":"/reference/pricing-migration"},{"title":"Usage Export API","href":"/reference/usage-export-api"},{"title":"Per-Page Billing Breakdown","href":"/reference/page-billing-breakdown"},{"title":"Glossary","href":"/reference/glossary"},{"title":"Frequently Asked Questions","href":"/reference/faq"}]},{"group":"Hidden pages","public":true,"hidden":true,"pages":[{"title":"Legacy Credit Usage and Rates","href":"/faq/legacy-credit-usage-overview"},{"title":"Legacy Credit Usage","href":"/reference/legacy-credit-usage"},{"title":"Concurrency Throttle (Legacy)","href":"/reference/throttling"},{"title":"OpenAPI Schema","href":"/api-reference/openapi.json"}]},{"group":"Components","public":true,"pages":[{"title":"SpreadsheetViewer","href":"/components/spreadsheet-viewer"}]},{"group":"Enterprise Resources","public":true,"pages":[{"title":"Enterprise Readiness","href":"/enterprise/enterprise-readiness"},{"title":"Deployment options (Cloud, On-prem, Hybrid)","href":"/onprem/enterprise_deployment_options"}]},{"group":"Security and privacy","public":true,"pages":[{"title":"Data policies \u0026 compliance","href":"/security/policies"},{"title":"Filing Complaints","href":"/security/filing-complaints"},{"title":"EU data residency \u0026 processing","href":"/security/eu-data-residency"},{"title":"Single sign-on (SSO) FAQ","href":"/security/sso-saml-faq"}]},{"group":"On-premise Resources","icon":"archway","pages":[{"group":"Hybrid VPC","pages":[{"title":"Hybrid VPC Deployment","href":"/onprem/hybrid-vpc-deployment"},{"title":"Hybrid VPC — AWS S3","href":"/onprem/hybrid-vpc-aws"},{"title":"Hybrid VPC — Azure Blob Storage","href":"/onprem/hybrid-vpc-azure"},{"title":"Hybrid VPC — Box","href":"/onprem/hybrid-vpc-box"},{"title":"Hybrid VPC — Google Cloud Storage","href":"/onprem/hybrid-vpc-gcs"}]},{"title":"On-prem security model","href":"/onprem/security_model"},{"title":"Securing Reducto","description":"Learn how to secure on-premise Reducto deployments","href":"/onprem/securing_reducto"},{"title":"OCR provider configuration","href":"/onprem/ocr_options"},{"title":"LLM \u0026 service configuration options","description":"Complete guide to LLM configuration and environment variables for Reducto","href":"/onprem/llm_options"},{"title":"Database configuration","href":"/onprem/database_configuration"},{"title":"Azure Blob Storage authentication","href":"/onprem/azure_blob_storage"},{"title":"Azure workload identity","href":"/onprem/azure_workload_identity"},{"title":"On-premise changelog","href":"/onprem/changelog"},{"title":"Observability \u0026 Monitoring","href":"/onprem/observability"},{"title":"Operations","href":"/onprem/operations"},{"title":"Self-hosted fair queueing with Reducto","href":"/onprem/fair_queueing"},{"title":"Automatic file cleanup","href":"/onprem/file_cleanup"},{"title":"Air-gapped usage for billing","href":"/onprem/usage_for_billing"}]}]},{"tab":"API Reference","versions":[{"version":"Current","groups":[{"group":"Document Processing","pages":[{"openapi":"openapi.json post /parse","title":"Parse","href":"/api-reference/parse"},{"title":"Parse Async","openapi":"openapi.json post /parse_async","href":"/api-reference/async-parse"},{"openapi":"openapi.json post /upload","title":"Upload","href":"/api-reference/upload"},{"openapi":"openapi.json post /extract","title":"Extract","href":"/api-reference/extract"},{"openapi":"openapi.json post /extract_async","title":"Extract Async","href":"/api-reference/extract-async"},{"openapi":"openapi.json post /split","title":"Split","href":"/api-reference/split"},{"openapi":"openapi.json post /split_async","title":"Split Async","href":"/api-reference/split-async"},{"openapi":"openapi.json post /classify","title":"Classify","href":"/api-reference/classify"},{"openapi":"openapi.json post /classify_async","title":"Classify Async","href":"/api-reference/classify-async"},{"openapi":"openapi.json post /edit","title":"Edit","href":"/api-reference/edit"},{"openapi":"openapi.json post /edit_async","title":"Edit Async","href":"/api-reference/edit-async"},{"openapi":"openapi.json post /pipeline","title":"Pipeline","href":"/api-reference/pipeline"},{"openapi":"openapi.json post /pipeline_async","title":"Pipeline Async","href":"/api-reference/pipeline-async"}]},{"group":"Job Management","pages":[{"title":"Retrieve Job","openapi":"openapi.json get /job/{job_id}","href":"/api-reference/retrieve-parse"},{"openapi":"openapi.json post /cancel/{job_id}","title":"Cancel Job","href":"/api-reference/cancel-job"},{"title":"Delete Job","openapi":"openapi.json delete /job/{job_id}","href":"/api-reference/delete-job"},{"openapi":"openapi.json get /jobs","title":"Get Jobs","href":"/api-reference/get-jobs"}]},{"group":"File Management","pages":[{"title":"Delete Upload","openapi":"openapi.json delete /upload/{file_id}","href":"/api-reference/delete-upload"}]},{"group":"Utilities","pages":[{"openapi":"openapi.json post /configure_webhook","title":"Webhook Portal","href":"/api-reference/webhook-portal"},{"openapi":"openapi.json get /version","title":"Get Version","href":"/api-reference/get-version"}]}]},{"version":"Legacy API","pages":[{"title":"Legacy API","href":"/api-reference/legacy/parse"}]}]},{"tab":"Cookbooks","pages":[{"title":"Cookbooks","href":"/cookbooks/overview"}]},{"tab":"SDKs","versions":[{"version":"Python","groups":[{"group":"Get Started","pages":[{"title":"Python SDK Overview","sidebarTitle":"Overview","href":"/sdk/python/overview"}]},{"group":"Core Methods","pages":[{"title":"Upload","sidebarTitle":"Upload","href":"/sdk/python/upload"},{"title":"Parse","sidebarTitle":"Parse","href":"/sdk/python/parse"},{"title":"Extract","sidebarTitle":"Extract","href":"/sdk/python/extract"},{"title":"Split","sidebarTitle":"Split","href":"/sdk/python/split"},{"title":"Edit","sidebarTitle":"Edit","href":"/sdk/python/edit"},{"title":"Pipeline","sidebarTitle":"Pipeline","href":"/sdk/python/pipeline"}]},{"group":"Async \u0026 Utilities","pages":[{"title":"Async Client","sidebarTitle":"Async Client","href":"/sdk/python/async"},{"title":"Job Management","sidebarTitle":"Job Management","href":"/sdk/python/job-management"},{"title":"Error Handling","sidebarTitle":"Error Handling","href":"/sdk/python/error-handling"}]}]},{"version":"JavaScript","pages":[{"title":"JavaScript","href":"/sdk/javascript/overview"}]},{"version":"Go","pages":[{"title":"Go","href":"/sdk/go/overview"}]}]},{"tab":"Studio","pages":[{"title":"Studio","href":"/studio-parse"}]}]},"basePath":"","title":"OCR provider configuration - Reducto","buildId":"dpl_41S5Z2jG9QnfDRwN1KZrLdBwj7DM","deploymentId":"dpl_41S5Z2jG9QnfDRwN1KZrLdBwj7DM","dynamics":[],"chunks":[]}