Skip to content

feat: support loading models from memory#153

Merged
GreatV merged 1 commit into
mainfrom
model-from-memory-37
Jul 8, 2026
Merged

feat: support loading models from memory#153
GreatV merged 1 commit into
mainfrom
model-from-memory-37

Conversation

@GreatV

@GreatV GreatV commented Jul 8, 2026

Copy link
Copy Markdown
Owner

Summary

Implements #37: models can now be loaded from memory (e.g. include_bytes! for single-binary deployments, or buffers decrypted at runtime) instead of only from file paths.

  • Adds ModelSource (Path(PathBuf) | Memory(Arc<[u8]>)) in oar-ocr-core with From conversions for paths, strings, Vec<u8>, &'static [u8]/arrays, and Arc<[u8]>.
  • AdapterBuilder::build, every model builder (DBModelBuilder, CRNNModelBuilder, ...), every adapter builder, every task predictor build(), and the OAROCRBuilder/OARStructureBuilder model setters now take impl Into<ModelSource>existing path-based call sites compile unchanged.
  • Memory sources go through ort's commit_from_memory; Path sources keep the exact previous behavior, including auto-download resolution (in-memory sources skip it).
  • The character dictionary can be supplied in-memory via OAROCRBuilder::character_dict_content(...) (e.g. include_str!).
  • Model-family detection that relied on file names (table structure / table cell) falls back to defaults or the explicit model_name/model_variant setters for in-memory sources.

Usage:

static DET: &[u8] = include_bytes!("../models/pp-ocrv6_tiny_det.onnx");
static REC: &[u8] = include_bytes!("../models/pp-ocrv6_tiny_rec.onnx");
static DICT: &str = include_str!("../models/ppocrv6_tiny_dict.txt");

let ocr = OAROCRBuilder::new(DET, REC, "")
    .character_dict_content(DICT)
    .build()?;

Documented in docs/usage.md ("Loading Models from Memory"). Models with external-data sidecar files cannot be loaded from memory (ONNX Runtime limitation); PP-OCR models are single-file and unaffected.

Testing

  • cargo fmt --check, cargo clippy --workspace --all-targets (no warnings), cargo test --workspace — 594 tests + doctests pass.
  • Unit tests for ModelSource conversions.
  • Local E2E: built the OCR pipeline twice on PP-OCRv6 tiny — once from paths, once from Vec<u8> model bytes + in-memory dict — and verified byte-identical recognition output on a real image; also re-ran the path-based ocr example as a regression check.

Closes #37.

🤖 Generated with Claude Code

Add ModelSource (Path | Memory) and thread it through AdapterBuilder,
all model/adapter/predictor builders, and the OAROCR/OARStructure
builders. Every model-accepting build() now takes impl Into<ModelSource>,
so existing path-based call sites are unchanged while raw ONNX bytes
(include_bytes!, decrypted buffers) load via ort commit_from_memory.
The character dictionary can likewise be supplied as an in-memory
string via character_dict_content(). In-memory sources skip
auto-download resolution.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a ModelSource abstraction to support loading ONNX models either from a filesystem path or directly from in-memory bytes (e.g., via include_bytes!). Consequently, all model-accepting builders, adapters, predictors, and pipeline builders (such as OAROCRBuilder and OARStructureBuilder) have been updated to accept impl Into instead of rigid file paths. Additionally, support for in-memory character dictionaries has been added via the character_dict_content builder method, and the documentation has been updated to demonstrate these new in-memory loading capabilities. There are no review comments, so no further feedback is provided.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

@GreatV GreatV merged commit d881b2e into main Jul 8, 2026
7 checks passed
@GreatV GreatV deleted the model-from-memory-37 branch July 8, 2026 06:09

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c67a7c5d87

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

ModelSource::Path(path) => builder.commit_from_file(path).map_err(|e| {
OCRError::model_load_error(path, SESSION_CREATION_FAILURE, suggestion, Some(e))
})?,
ModelSource::Memory(bytes) => builder.commit_from_memory(bytes).map_err(|e| {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep memory buffers alive for zero-copy ORT configs

When a caller loads ModelSource::Memory together with ORT config entries such as session.use_ort_model_bytes_directly or session.use_ort_model_bytes_for_initializers, ONNX Runtime can keep pointers into the supplied buffer instead of copying it; the ort crate models that case with an InMemorySession lifetime. Here the Arc<[u8]> is local to load_session_with and OrtInfer stores only a display path, so the buffer can be dropped immediately after session creation, leaving ORT with dangling model data. Please either keep the memory source alive for the session lifetime or reject those zero-copy entries for in-memory sources.

Useful? React with 👍 / 👎.

Comment on lines +164 to 167
model_source
.as_path()
.and_then(TableStructureModelFamily::detect_from_path)
.unwrap_or(TableStructureModelFamily::Wired)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Require the table family for in-memory table models

For in-memory SLANet/SLANet_plus table-structure bytes where the caller does not set model_name, as_path() is always None, so this now silently falls through to the wired family. That selects the wired adapter/default shape instead of the wireless/SLANet pipeline, corrupting predictions rather than telling the caller the model family cannot be inferred from bytes. Please return a configuration error for memory sources without model_name or require an explicit family before building.

Useful? React with 👍 / 👎.

GreatV added a commit that referenced this pull request Jul 8, 2026
#154)

- Add docs/FAQ.md (Windows MSVC linker requirements from #105, GPU vs
  CPU expectations for PP-OCRv6 from #151) and link it from the README.
- Mention in-memory model loading in the README and crate docs, and note
  in docs/models.md that in-memory sources bypass auto-download path
  resolution.
- Bump workspace version to 0.8.0: #153 changed the AdapterBuilder::build
  signature, which is a breaking API change.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Load the models from memory?

1 participant