Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package ocrs for openSUSE:Factory checked in 
at 2024-06-05 17:42:49
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/ocrs (Old)
 and      /work/SRC/openSUSE:Factory/.ocrs.new.24587 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "ocrs"

Wed Jun  5 17:42:49 2024 rev:3 rq:1178678 version:0.8.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/ocrs/ocrs.changes        2024-05-20 
18:14:24.640417779 +0200
+++ /work/SRC/openSUSE:Factory/.ocrs.new.24587/ocrs.changes     2024-06-05 
17:43:29.920505706 +0200
@@ -1,0 +2,11 @@
+Wed Jun  5 07:53:14 UTC 2024 - Muhammad Akbar Yanuar Mantari <[email protected]>
+
+- Update to version 0.8.0
+  * Updated rten to v0.10.0: This improves performance when
+    recognizing long lines of text and improves efficiency by
+    setting the number of threads to match the number of physical
+    cores.
+  * Errors that occur when running the text recognition model are
+    now propagated to the caller instead of causing a panic.
+
+-------------------------------------------------------------------

Old:
----
  ocrs-ocrs-v0.7.0.tar.gz

New:
----
  ocrs-ocrs-v0.8.0.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ ocrs.spec ++++++
--- /var/tmp/diff_new_pack.GJtFtM/_old  2024-06-05 17:43:30.872540377 +0200
+++ /var/tmp/diff_new_pack.GJtFtM/_new  2024-06-05 17:43:30.876540523 +0200
@@ -22,7 +22,7 @@
 %bcond_without test
 %endif
 Name:           ocrs
-Version:        0.7.0
+Version:        0.8.0
 Release:        0
 Summary:        A modern OCR engine written in Rust
 License:        Apache-2.0 AND MIT

++++++ ocrs-ocrs-v0.7.0.tar.gz -> ocrs-ocrs-v0.8.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ocrs-ocrs-v0.7.0/CHANGELOG.md 
new/ocrs-ocrs-v0.8.0/CHANGELOG.md
--- old/ocrs-ocrs-v0.7.0/CHANGELOG.md   2024-05-16 10:41:41.000000000 +0200
+++ new/ocrs-ocrs-v0.8.0/CHANGELOG.md   2024-05-25 10:41:11.000000000 +0200
@@ -5,6 +5,26 @@
 The format is based on [Keep a 
Changelog](https://keepachangelog.com/en/1.0.0/),
 and this project adheres to [Semantic 
Versioning](https://semver.org/spec/v2.0.0.html).
 
+## [0.8.0] - 2024-05-25
+
+### Breaking changes
+
+This release changes Ocrs's internal use of threads, which may affect consumers
+that are using their own parallelism. Specifically Ocrs no longer uses the
+global Rayon thread pool but instead a custom thread pool which is sized to
+match the number of physical rather than logical cores. See
+https://github.com/robertknight/ocrs/pull/79 for more details and information 
on
+adapting.
+
+### Changes
+
+- Updated rten to v0.10.0. This improves performance when recognizing long 
lines
+  of text (https://github.com/robertknight/ocrs/pull/79) and improves 
efficiency
+  by setting the number of threads to match the number of physical cores.
+
+- Errors that occur when running the text recognition model are now propagated
+  to the caller instead of causing a panic 
(https://github.com/robertknight/ocrs/pull/77)
+
 ## [0.7.0] - 2024-05-16
 
 ### Breaking changes
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ocrs-ocrs-v0.7.0/Cargo.lock 
new/ocrs-ocrs-v0.8.0/Cargo.lock
--- old/ocrs-ocrs-v0.7.0/Cargo.lock     2024-05-16 10:41:41.000000000 +0200
+++ new/ocrs-ocrs-v0.8.0/Cargo.lock     2024-05-25 10:41:11.000000000 +0200
@@ -173,6 +173,12 @@
 ]
 
 [[package]]
+name = "hermit-abi"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
+
+[[package]]
 name = "home"
 version = "0.5.9"
 source = "registry+https://github.com/rust-lang/crates.io-index";
@@ -266,8 +272,18 @@
 ]
 
 [[package]]
+name = "num_cpus"
+version = "1.16.0"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43"
+dependencies = [
+ "hermit-abi",
+ "libc",
+]
+
+[[package]]
 name = "ocrs"
-version = "0.7.0"
+version = "0.8.0"
 dependencies = [
  "anyhow",
  "fastrand",
@@ -283,7 +299,7 @@
 
 [[package]]
 name = "ocrs-cli"
-version = "0.7.0"
+version = "0.8.0"
 dependencies = [
  "anyhow",
  "home",
@@ -378,13 +394,15 @@
 
 [[package]]
 name = "rten"
-version = "0.9.0"
+version = "0.10.0"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "cb9d6d80601e57cab46f477955be6e3be1a4c92ed0aebb3376e1f19d24e83bb1"
+checksum = "09c030cdf90e64c5eeeba389ca59da14b0a106b1b8366c15591251bb6a2e777f"
 dependencies = [
  "flatbuffers",
  "libm",
+ "num_cpus",
  "rayon",
+ "rten-simd",
  "rten-tensor",
  "rten-vecmath",
  "rustc-hash",
@@ -394,27 +412,36 @@
 
 [[package]]
 name = "rten-imageproc"
-version = "0.9.0"
+version = "0.10.0"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "529fdef25f8232ebb08fb6cfc785ec97a7fb268bebc4895e36e8750e2bbeaa51"
+checksum = "5ba61077269b2b2c90445bfd55fb798dcd544b56e7fd78faaea51940b8e429ae"
 dependencies = [
  "rten-tensor",
 ]
 
 [[package]]
+name = "rten-simd"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "8eb16da64e0d08ce56dc17d8304ab2da541176ee30430c0b0e581a7841a660ae"
+
+[[package]]
 name = "rten-tensor"
-version = "0.9.0"
+version = "0.10.0"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "ffa78180a98337a43163e9da8f202120e9ae3b82366cccfb05a5a854e48cd581"
+checksum = "52f5e53d2e43bb736e89e4ea41b707e024190f8ba47c3eddf5a3c2d022089909"
 dependencies = [
  "smallvec",
 ]
 
 [[package]]
 name = "rten-vecmath"
-version = "0.9.0"
+version = "0.10.0"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "495f48d459768d61ca37b418f79ac7aac3a707024c79fa49a14dd2c1ad8a2c0e"
+checksum = "56eccc46a7e7a2df2cebb7ba95e613a01942a01e0f2f2f7d6122176ab7372e9f"
+dependencies = [
+ "rten-simd",
+]
 
 [[package]]
 name = "rustc-hash"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ocrs-ocrs-v0.7.0/Cargo.toml 
new/ocrs-ocrs-v0.8.0/Cargo.toml
--- old/ocrs-ocrs-v0.7.0/Cargo.toml     2024-05-16 10:41:41.000000000 +0200
+++ new/ocrs-ocrs-v0.8.0/Cargo.toml     2024-05-25 10:41:11.000000000 +0200
@@ -4,3 +4,8 @@
   "ocrs",
   "ocrs-cli",
 ]
+
+[workspace.dependencies]
+rten = { version = "0.10.0" }
+rten-imageproc = { version = "0.10.0" }
+rten-tensor = { version = "0.10.0" }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ocrs-ocrs-v0.7.0/Makefile 
new/ocrs-ocrs-v0.8.0/Makefile
--- old/ocrs-ocrs-v0.7.0/Makefile       2024-05-16 10:41:41.000000000 +0200
+++ new/ocrs-ocrs-v0.8.0/Makefile       2024-05-25 10:41:11.000000000 +0200
@@ -41,5 +41,12 @@
        wasm-bindgen target/wasm32-unknown-unknown/release/ocrs.wasm --out-dir 
js/dist/ --target web --reference-types --weak-refs
        tools/optimize-wasm.sh js/dist/ocrs_bg.wasm
 
+# Build Ocrs CLI for non-browser WebAssembly runtimes (eg. wasmtime). Run 
using:
+#
+#      wasmtime --dir . target/wasm32-wasi/release/ocrs.wasm --detect-model 
text-detection.rten --rec-model text-recognition.rten 
ocrs-cli/test-data/why-rust.png
+.PHONY: wasm-wasi
+wasm-wasi:
+       RUSTFLAGS="-C target-feature=+simd128" cargo build --release --target 
wasm32-wasi --package ocrs-cli
+
 .PHONY: wasm-all
 wasm-all: wasm wasm-nosimd
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ocrs-ocrs-v0.7.0/ocrs/Cargo.toml 
new/ocrs-ocrs-v0.8.0/ocrs/Cargo.toml
--- old/ocrs-ocrs-v0.7.0/ocrs/Cargo.toml        2024-05-16 10:41:41.000000000 
+0200
+++ new/ocrs-ocrs-v0.8.0/ocrs/Cargo.toml        2024-05-25 10:41:11.000000000 
+0200
@@ -1,6 +1,6 @@
 [package]
 name = "ocrs"
-version = "0.7.0"
+version = "0.8.0"
 edition = "2021"
 authors = ["Robert Knight"]
 description = "OCR engine"
@@ -11,9 +11,9 @@
 [dependencies]
 anyhow = "1.0.80"
 rayon = "1.10.0"
-rten = { version = "0.9.0" }
-rten-imageproc = { version = "0.9.0" }
-rten-tensor = { version = "0.9.0" }
+rten = { workspace = true }
+rten-imageproc = { workspace = true }
+rten-tensor = { workspace = true }
 thiserror = "1.0.59"
 
 [target.'cfg(target_arch = "wasm32")'.dependencies]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ocrs-ocrs-v0.7.0/ocrs/src/errors.rs 
new/ocrs-ocrs-v0.8.0/ocrs/src/errors.rs
--- old/ocrs-ocrs-v0.7.0/ocrs/src/errors.rs     1970-01-01 01:00:00.000000000 
+0100
+++ new/ocrs-ocrs-v0.8.0/ocrs/src/errors.rs     2024-05-25 10:41:11.000000000 
+0200
@@ -0,0 +1,25 @@
+use std::error::Error;
+use std::fmt;
+
+/// The error type returned when running a machine learning model fails.
+#[derive(Debug)]
+pub enum ModelRunError {
+    /// Model execution failed.
+    RunFailed(Box<dyn Error + Send + Sync>),
+
+    /// The model output had a different data type or shape than expected.
+    WrongOutput,
+}
+
+impl fmt::Display for ModelRunError {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
+        match self {
+            ModelRunError::RunFailed(err) => write!(f, "model run failed: {}", 
err),
+            ModelRunError::WrongOutput => {
+                write!(f, "model output had unexpected type or shape")
+            }
+        }
+    }
+}
+
+impl Error for ModelRunError {}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ocrs-ocrs-v0.7.0/ocrs/src/lib.rs 
new/ocrs-ocrs-v0.8.0/ocrs/src/lib.rs
--- old/ocrs-ocrs-v0.7.0/ocrs/src/lib.rs        2024-05-16 10:41:41.000000000 
+0200
+++ new/ocrs-ocrs-v0.8.0/ocrs/src/lib.rs        2024-05-25 10:41:11.000000000 
+0200
@@ -5,6 +5,7 @@
 use rten_tensor::NdTensor;
 
 mod detection;
+mod errors;
 mod geom_util;
 mod layout_analysis;
 mod log;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ocrs-ocrs-v0.7.0/ocrs/src/recognition.rs 
new/ocrs-ocrs-v0.8.0/ocrs/src/recognition.rs
--- old/ocrs-ocrs-v0.7.0/ocrs/src/recognition.rs        2024-05-16 
10:41:41.000000000 +0200
+++ new/ocrs-ocrs-v0.8.0/ocrs/src/recognition.rs        2024-05-25 
10:41:11.000000000 +0200
@@ -3,13 +3,14 @@
 use anyhow::anyhow;
 use rayon::prelude::*;
 use rten::ctc::{CtcDecoder, CtcHypothesis};
-use rten::{Dimension, FloatOperators, Model, NodeId};
+use rten::{thread_pool, Dimension, FloatOperators, Model, NodeId};
 use rten_imageproc::{
     bounding_rect, BoundingRect, Line, Point, PointF, Polygon, Rect, 
RotatedRect,
 };
 use rten_tensor::prelude::*;
 use rten_tensor::{NdTensor, NdTensorView, Tensor};
 
+use crate::errors::ModelRunError;
 use crate::geom_util::{downwards_line, leftmost_edge, rightmost_edge};
 use crate::preprocess::BLACK_VALUE;
 use crate::text_items::{TextChar, TextLine};
@@ -359,12 +360,14 @@
 
     /// Run text recognition on an NCHW batch of text line images, and return
     /// a `[batch, seq, label]` tensor of class probabilities.
-    fn run(&self, input: NdTensor<f32, 4>) -> anyhow::Result<NdTensor<f32, 3>> 
{
+    fn run(&self, input: NdTensor<f32, 4>) -> Result<NdTensor<f32, 3>, 
ModelRunError> {
         let input: Tensor<f32> = input.into();
-        let [output] =
-            self.model
-                .run_n(&[(self.input_id, (&input).into())], [self.output_id], 
None)?;
-        let mut rec_sequence: NdTensor<f32, 3> = output.try_into()?;
+        let [output] = self
+            .model
+            .run_n(&[(self.input_id, (&input).into())], [self.output_id], None)
+            .map_err(|err| ModelRunError::RunFailed(err.into()))?;
+        let mut rec_sequence: NdTensor<f32, 3> =
+            output.try_into().map_err(|_| ModelRunError::WrongOutput)?;
 
         // Transpose from [seq, batch, class] => [batch, seq, class]
         rec_sequence.permute([1, 0, 2]);
@@ -470,52 +473,59 @@
             .collect();
 
         // Run text recognition on batches of lines.
-        let mut line_rec_results: Vec<LineRecResult> = line_groups
-            .into_par_iter()
-            .flat_map(|(group_width, lines)| {
-                if debug {
-                    println!(
-                        "Processing group of {} lines of width {}",
-                        lines.len(),
-                        group_width,
-                    );
-                }
-
-                let rec_input = prepare_text_line_batch(
-                    &image,
-                    &lines,
-                    page_rect,
-                    rec_img_height as usize,
-                    group_width as usize,
-                );
-
-                // TODO - Propagate errors from recognition model to caller.
-                let rec_output = self.run(rec_input).expect("recognition 
failed");
-                let ctc_input_len = rec_output.shape()[1];
-
-                // Apply CTC decoding to get the label sequence for each line.
-                lines
-                    .into_iter()
-                    .enumerate()
-                    .map(|(group_line_index, line)| {
-                        let decoder = CtcDecoder::new();
-                        let input_seq = rec_output.slice([group_line_index]);
-                        let ctc_output = match decode_method {
-                            DecodeMethod::Greedy => 
decoder.decode_greedy(input_seq),
-                            DecodeMethod::BeamSearch { width } => {
-                                decoder.decode_beam(input_seq, width)
-                            }
-                        };
-                        LineRecResult {
-                            line,
-                            rec_input_len: group_width as usize,
-                            ctc_input_len,
-                            ctc_output,
+        let batch_rec_results: Result<Vec<Vec<LineRecResult>>, ModelRunError> =
+            thread_pool().run(|| {
+                line_groups
+                    .into_par_iter()
+                    .map(|(group_width, lines)| {
+                        if debug {
+                            println!(
+                                "Processing group of {} lines of width {}",
+                                lines.len(),
+                                group_width,
+                            );
                         }
+
+                        let rec_input = prepare_text_line_batch(
+                            &image,
+                            &lines,
+                            page_rect,
+                            rec_img_height as usize,
+                            group_width as usize,
+                        );
+
+                        let rec_output = self.run(rec_input)?;
+                        let ctc_input_len = rec_output.shape()[1];
+
+                        // Apply CTC decoding to get the label sequence for 
each line.
+                        let line_rec_results = lines
+                            .into_iter()
+                            .enumerate()
+                            .map(|(group_line_index, line)| {
+                                let decoder = CtcDecoder::new();
+                                let input_seq = 
rec_output.slice([group_line_index]);
+                                let ctc_output = match decode_method {
+                                    DecodeMethod::Greedy => 
decoder.decode_greedy(input_seq),
+                                    DecodeMethod::BeamSearch { width } => {
+                                        decoder.decode_beam(input_seq, width)
+                                    }
+                                };
+                                LineRecResult {
+                                    line,
+                                    rec_input_len: group_width as usize,
+                                    ctc_input_len,
+                                    ctc_output,
+                                }
+                            })
+                            .collect::<Vec<_>>();
+
+                        Ok(line_rec_results)
                     })
-                    .collect::<Vec<_>>()
-            })
-            .collect();
+                    .collect()
+            });
+
+        let mut line_rec_results: Vec<LineRecResult> =
+            batch_rec_results?.into_iter().flatten().collect();
 
         // The recognition outputs are in a different order than the inputs 
due to
         // batching and parallel processing. Re-sort them into input order.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ocrs-ocrs-v0.7.0/ocrs-cli/Cargo.toml 
new/ocrs-ocrs-v0.8.0/ocrs-cli/Cargo.toml
--- old/ocrs-ocrs-v0.7.0/ocrs-cli/Cargo.toml    2024-05-16 10:41:41.000000000 
+0200
+++ new/ocrs-ocrs-v0.8.0/ocrs-cli/Cargo.toml    2024-05-25 10:41:11.000000000 
+0200
@@ -1,6 +1,6 @@
 [package]
 name = "ocrs-cli"
-version = "0.7.0"
+version = "0.8.0"
 edition = "2021"
 authors = ["Robert Knight"]
 description = "OCR CLI tool for extracting text from images"
@@ -12,16 +12,18 @@
 image = { version = "0.25.1", default-features = false, features = ["png", 
"jpeg", "webp"] }
 png = "0.17.6"
 serde_json = "1.0.116"
-rten = { version = "0.9.0" }
-rten-imageproc = { version = "0.9.0" }
-rten-tensor = { version = "0.9.0" }
-ocrs = { path = "../ocrs", version = "0.7.0" }
+rten = { workspace = true }
+rten-imageproc = { workspace = true }
+rten-tensor = { workspace = true }
+ocrs = { path = "../ocrs", version = "0.8.0" }
 lexopt = "0.3.0"
-ureq = "2.9.7"
 url = "2.4.0"
-home = "0.5.9"
 anyhow = "1.0.79"
 
+[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
+ureq = "2.9.7"
+home = "0.5.9"
+
 [features]
 # Use AVX-512 instructions if available. Requires nightly Rust.
 avx512 = ["rten/avx512"]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ocrs-ocrs-v0.7.0/ocrs-cli/src/models.rs 
new/ocrs-ocrs-v0.8.0/ocrs-cli/src/models.rs
--- old/ocrs-ocrs-v0.7.0/ocrs-cli/src/models.rs 2024-05-16 10:41:41.000000000 
+0200
+++ new/ocrs-ocrs-v0.8.0/ocrs-cli/src/models.rs 2024-05-25 10:41:11.000000000 
+0200
@@ -1,13 +1,18 @@
 use std::fmt;
-use std::fs;
-use std::path::{Path, PathBuf};
+use std::path::PathBuf;
+
+#[cfg(not(target_arch = "wasm32"))]
+use std::{fs, path::Path};
 
 use anyhow::anyhow;
 use rten::Model;
+
+#[cfg(not(target_arch = "wasm32"))]
 use url::Url;
 
 /// Return the path to the directory in which cached models etc. should be
 /// saved.
+#[cfg(not(target_arch = "wasm32"))]
 fn cache_dir() -> Result<PathBuf, anyhow::Error> {
     let mut cache_dir: PathBuf =
         home::home_dir().ok_or(anyhow!("Failed to determine home directory"))?;
@@ -22,6 +27,7 @@
 /// Extract the last path segment from a URL.
 ///
 /// eg. "https://models.com/text-detection.rten"; => "text-detection.rten".
+#[cfg(not(target_arch = "wasm32"))]
 #[allow(rustdoc::bare_urls)]
 fn filename_from_url(url: &str) -> Option<String> {
     let parsed = Url::parse(url).ok()?;
@@ -33,6 +39,7 @@
 
 /// Download a file from `url` to a local cache, if not already fetched, and
 /// return the path to the local file.
+#[cfg(not(target_arch = "wasm32"))]
 fn download_file(url: &str, filename: Option<&str>) -> Result<PathBuf, 
anyhow::Error> {
     let cache_dir = cache_dir()?;
     let filename = match filename {
@@ -55,6 +62,13 @@
     Ok(file_path)
 }
 
+#[cfg(target_arch = "wasm32")]
+fn download_file(_url: &str, _filename: Option<&str>) -> Result<PathBuf, 
anyhow::Error> {
+    Err(anyhow!(
+        "Downloading models from a URL is not supported on the current 
platform"
+    ))
+}
+
 /// Location that a model can be loaded from.
 #[derive(Clone, Copy)]
 pub enum ModelSource<'a> {

++++++ vendor.tar.zst ++++++
/work/SRC/openSUSE:Factory/ocrs/vendor.tar.zst 
/work/SRC/openSUSE:Factory/.ocrs.new.24587/vendor.tar.zst differ: char 255581, 
line 1058

Reply via email to