activestorage-ocr 0.1.1 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c2944589a15452bdc9189df16529baf298e7db1d39898c6a127558dd8e55e58a
4
- data.tar.gz: bc222d478d3c122f1bdba2e0f7a8b58893a9c0581ec86d06c2c8025410d36a20
3
+ metadata.gz: 407f4e4098cfdf7804094b783efa4e9dd6a8ef18ede70a8bf571eae693a17fa7
4
+ data.tar.gz: 368ec4b42ffa94ca71e6b6df4677d0af87dadd9ab14bf95e57a44aa2904e6a2d
5
5
  SHA512:
6
- metadata.gz: b6569b0027e7976cb5afa6cf45294eb1680e7f6f769be27db98794f64cf5079f6254587f56b70adcb72a033b566bb6836879b7563fab18470b15ec7434b215b5
7
- data.tar.gz: 45839fed9f4f618c50246c89f7acc3345a3c57d52a07c348fed17420bbb465ecf883f6d1b711f1b33ea57a35975995cdbe8ab26c1486ade6267778a34db8cf59
6
+ metadata.gz: 8cf7e677131db26961ca31684f932f4aff67a85c3b16ba1bb460ec49b1e74f172e64bd1be777bd0a0620df8756c62bdc858d9409857e27da48eb166bc0735669
7
+ data.tar.gz: 25b5ae857880af8f0e3a11e4874f15896f4451685e8cae45a0dce2cf6e1c9a8b5ac15f89f1e80920fa9f2bd3ce8bfcfb9a62ef38d99e57b4c977de5b8d65b30c
data/README.md CHANGED
@@ -13,7 +13,7 @@ OCR for Rails Active Storage attachments, powered by Rust and [ocrs](https://git
13
13
  - **Pure Rust** - No Tesseract or system dependencies required
14
14
  - **Self-contained** - Models download automatically on first run (~50MB)
15
15
  - **Fast** - Processes images in ~150ms
16
- - **HTTP/JSON API** - Easy to debug and integrate
16
+ - **Automatic** - OCR runs automatically when files are uploaded via Active Storage
17
17
 
18
18
  **Supported Formats:**
19
19
  - Images: PNG, JPEG, TIFF, WebP, GIF, BMP
@@ -32,53 +32,95 @@ OCR for Rails Active Storage attachments, powered by Rust and [ocrs](https://git
32
32
 
33
33
  ## Installation
34
34
 
35
- Add to your Gemfile:
35
+ **1. Add to your Gemfile:**
36
36
 
37
37
  ```ruby
38
38
  gem "activestorage-ocr"
39
39
  ```
40
40
 
41
- Then install the OCR server binary:
41
+ **2. Install the gem and OCR server binary:**
42
42
 
43
43
  ```bash
44
44
  bundle install
45
45
  bin/rails activestorage_ocr:install
46
46
  ```
47
47
 
48
- ## Quick Start
48
+ **3. Add the OCR server to your `Procfile.dev`:**
49
49
 
50
- 1. **Start the OCR server:**
50
+ ```procfile
51
+ web: bin/rails server
52
+ ocr: activestorage-ocr-server --host 127.0.0.1 --port 9292
53
+ ```
54
+
55
+ Now when you run `bin/dev`, the OCR server starts automatically alongside Rails.
56
+
57
+ > **Note:** If you don't have a `Procfile.dev`, create one. Rails 7+ apps typically use `bin/dev` with [foreman](https://github.com/ddollar/foreman) or [overmind](https://github.com/DarthSim/overmind) to manage multiple processes.
58
+
59
+ ## Usage
60
+
61
+ Once installed, OCR happens **automatically** when you upload images or PDFs through Active Storage. The extracted text is stored in the blob's metadata.
62
+
63
+ ### Accessing OCR Results
64
+
65
+ ```ruby
66
+ # After uploading a file
67
+ document.file.analyze # Triggers OCR (usually happens automatically)
68
+
69
+ # Access the results from metadata
70
+ document.file.metadata["ocr_text"] # => "Extracted text..."
71
+ document.file.metadata["ocr_confidence"] # => 0.85
72
+ document.file.metadata["ocr_processed_at"] # => "2024-12-24T12:00:00Z"
73
+ ```
74
+
75
+ ### Helper Methods (Optional)
76
+
77
+ Add convenience methods to your model:
78
+
79
+ ```ruby
80
+ class Document < ApplicationRecord
81
+ has_one_attached :file
82
+
83
+ def ocr_text
84
+ file.metadata["ocr_text"]
85
+ end
86
+
87
+ def ocr_confidence
88
+ file.metadata["ocr_confidence"]
89
+ end
90
+
91
+ def ocr_processed?
92
+ file.metadata["ocr_processed_at"].present?
93
+ end
94
+ end
95
+ ```
51
96
 
52
- ```bash
53
- bin/rails activestorage_ocr:start
54
- ```
97
+ ### Using the Client Directly
55
98
 
56
- 2. **Use the client in your Rails app:**
99
+ You can also use the client directly for more control:
57
100
 
58
- ```ruby
59
- # In rails console or your code
60
- client = ActiveStorage::Ocr::Client.new
101
+ ```ruby
102
+ client = ActiveStorage::Ocr::Client.new
61
103
 
62
- # Check server health
63
- client.healthy? # => true
104
+ # Check server health
105
+ client.healthy? # => true
64
106
 
65
- # Extract text from a file
66
- result = client.extract_text_from_path("/path/to/image.png", content_type: "image/png")
67
- result.text # => "Extracted text..."
68
- result.confidence # => 0.95
107
+ # Extract text from a file path
108
+ result = client.extract_text_from_path("/path/to/image.png")
109
+ result.text # => "Extracted text..."
110
+ result.confidence # => 0.95
69
111
 
70
- # Extract text from an Active Storage attachment
71
- result = client.extract_text(document.file)
72
- ```
112
+ # Extract text from an Active Storage attachment
113
+ result = client.extract_text(document.file)
114
+ ```
73
115
 
74
116
  ## Configuration
75
117
 
76
118
  ```ruby
77
119
  # config/initializers/activestorage_ocr.rb
78
120
  ActiveStorage::Ocr.configure do |config|
79
- config.server_host = "127.0.0.1"
80
- config.server_port = 9292
81
- config.timeout = 60
121
+ config.server_url = ENV.fetch("ACTIVESTORAGE_OCR_SERVER_URL", "http://127.0.0.1:9292")
122
+ config.timeout = 60 # Request timeout in seconds
123
+ config.open_timeout = 10 # Connection timeout in seconds
82
124
  end
83
125
  ```
84
126
 
@@ -86,8 +128,132 @@ end
86
128
 
87
129
  | Variable | Default | Description |
88
130
  |----------|---------|-------------|
89
- | `ACTIVESTORAGE_OCR_HOST` | `127.0.0.1` | Server host |
90
- | `ACTIVESTORAGE_OCR_PORT` | `9292` | Server port |
131
+ | `ACTIVESTORAGE_OCR_SERVER_URL` | `http://127.0.0.1:9292` | Full URL to the OCR server |
132
+
133
+ ## Production Deployment
134
+
135
+ For production deployments, the OCR server binary needs to be installed in your app's `bin/` directory (not the gem directory) so it can be referenced from your Procfile.
136
+
137
+ ### Setup for Production
138
+
139
+ **1. Run the install generator:**
140
+
141
+ ```bash
142
+ rails generate activestorage_ocr:install
143
+ ```
144
+
145
+ This creates:
146
+ - `bin/activestorage-ocr-server` - A wrapper script that runs the OCR server
147
+ - `bin/dist/activestorage-ocr-server` - The actual binary (gitignored)
148
+
149
+ **2. Add to your Procfile:**
150
+
151
+ ```procfile
152
+ web: bundle exec puma -C config/puma.rb
153
+ ocr: bin/activestorage-ocr-server --host 127.0.0.1 --port 9292
154
+ ```
155
+
156
+ ### Docker Deployment
157
+
158
+ In your `Dockerfile`, run the generator during the build to install the binary:
159
+
160
+ ```dockerfile
161
+ # Install gems
162
+ RUN bundle install
163
+
164
+ # Install OCR server binary to bin/dist/
165
+ RUN bundle exec rails activestorage_ocr:install path=./bin/dist
166
+
167
+ # Alternatively, run the full generator:
168
+ # RUN bundle exec rails generate activestorage_ocr:install
169
+ ```
170
+
171
+ Use foreman to manage both processes:
172
+
173
+ ```dockerfile
174
+ # Procfile
175
+ CMD ["bundle", "exec", "foreman", "start"]
176
+ ```
177
+
178
+ ### Fly.io Deployment
179
+
180
+ **fly.toml configuration:**
181
+
182
+ ```toml
183
+ app = "your-app-name"
184
+ primary_region = "iad"
185
+
186
+ [deploy]
187
+ # Note: Don't use release_command for SQLite with volumes
188
+ # Migrations run in docker-entrypoint instead
189
+
190
+ [env]
191
+ RAILS_ENV = "production"
192
+ ACTIVESTORAGE_OCR_SERVER_URL = "http://127.0.0.1:9292"
193
+
194
+ [http_service]
195
+ internal_port = 8080
196
+ force_https = true
197
+
198
+ [[mounts]]
199
+ source = "data"
200
+ destination = "/rails/storage"
201
+
202
+ [[vm]]
203
+ memory = "1024mb"
204
+ cpu_kind = "shared"
205
+ cpus = 2
206
+ ```
207
+
208
+ **Procfile for Fly.io:**
209
+
210
+ ```procfile
211
+ web: bundle exec puma -C config/puma.rb
212
+ ocr: bin/activestorage-ocr-server --host 127.0.0.1 --port 9292
213
+ ```
214
+
215
+ **Important notes for Fly.io:**
216
+ - Use `foreman` as the entrypoint to run both processes
217
+ - The OCR server binds to `127.0.0.1` (internal only)
218
+ - Set `ACTIVESTORAGE_OCR_SERVER_URL` env var to `http://127.0.0.1:9292`
219
+ - For SQLite with volumes, run migrations in `docker-entrypoint` not `release_command`
220
+
221
+ ### Environment Variables
222
+
223
+ | Variable | Default | Description |
224
+ |----------|---------|-------------|
225
+ | `ACTIVESTORAGE_OCR_SERVER_URL` | `http://127.0.0.1:9292` | URL where the OCR server is running |
226
+ | `ACTIVESTORAGE_OCR_TIMEOUT` | `30` | Request timeout in seconds |
227
+ | `ACTIVESTORAGE_OCR_OPEN_TIMEOUT` | `5` | Connection timeout in seconds |
228
+
229
+ ### Troubleshooting
230
+
231
+ **Binary not found:**
232
+ ```
233
+ Error: bin/activestorage-ocr-server: No such file or directory
234
+ ```
235
+ Solution: Run `rails generate activestorage_ocr:install` or `rails activestorage_ocr:install path=./bin/dist`
236
+
237
+ **Connection refused:**
238
+ ```
239
+ Faraday::ConnectionFailed: Connection refused
240
+ ```
241
+ Solution: Ensure the OCR server is running and `ACTIVESTORAGE_OCR_SERVER_URL` is correctly configured.
242
+
243
+ **Timeout errors:**
244
+ ```
245
+ Faraday::TimeoutError
246
+ ```
247
+ Solution: Increase timeout values in the initializer or reduce image/PDF sizes.
248
+
249
+ **Health check:**
250
+ ```bash
251
+ # Verify the OCR server is responding
252
+ curl http://localhost:9292/health
253
+
254
+ # Or via rake task
255
+ bin/rails activestorage_ocr:health
256
+ ```
91
257
 
92
258
  ## Rake Tasks
93
259
 
@@ -95,7 +261,7 @@ end
95
261
  # Install the OCR server binary for your platform
96
262
  bin/rails activestorage_ocr:install
97
263
 
98
- # Start the OCR server
264
+ # Start the OCR server (for manual testing)
99
265
  bin/rails activestorage_ocr:start
100
266
 
101
267
  # Check server health
@@ -120,11 +120,12 @@ module ActiveStorage
120
120
 
121
121
  # Downloads and installs the binary.
122
122
  #
123
- # Downloads from GitHub releases and extracts to the gem's bin directory.
123
+ # Downloads from GitHub releases and extracts to the specified directory.
124
124
  #
125
125
  # ==== Parameters
126
126
  #
127
127
  # * +force+ - If true, reinstalls even if already installed
128
+ # * +path+ - Custom installation directory (defaults to gem's bin directory)
128
129
  #
129
130
  # ==== Returns
130
131
  #
@@ -133,8 +134,16 @@ module ActiveStorage
133
134
  # ==== Raises
134
135
  #
135
136
  # RuntimeError if the download fails.
136
- def install!(force: false)
137
- return binary_path if installed? && !force
137
+ def install!(force: false, path: nil)
138
+ target_dir = path || install_dir
139
+ target_path = File.join(target_dir, BINARY_NAME)
140
+
141
+ if !force && File.executable?(target_path)
142
+ puts "Binary already installed at #{target_path}"
143
+ return target_path
144
+ end
145
+
146
+ FileUtils.mkdir_p(target_dir)
138
147
 
139
148
  puts "Downloading activestorage-ocr-server for #{platform}..."
140
149
 
@@ -147,9 +156,9 @@ module ActiveStorage
147
156
  "You may need to build from source: cd rust && cargo build --release"
148
157
  end
149
158
 
150
- extract_binary(response.body)
151
- puts "Installed to #{binary_path}"
152
- binary_path
159
+ extract_binary(response.body, target_path)
160
+ puts "Installed to #{target_path}"
161
+ target_path
153
162
  end
154
163
 
155
164
  private
@@ -174,17 +183,17 @@ module ActiveStorage
174
183
  end
175
184
 
176
185
  # Extracts the binary from a gzipped tarball.
177
- def extract_binary(tarball_data)
186
+ def extract_binary(tarball_data, target_path)
178
187
  gz = Zlib::GzipReader.new(StringIO.new(tarball_data))
179
188
  tar = Gem::Package::TarReader.new(gz)
180
189
 
181
190
  tar.each do |entry|
182
191
  next unless entry.file? && entry.full_name == BINARY_NAME
183
192
 
184
- File.open(binary_path, "wb") do |f|
193
+ File.open(target_path, "wb") do |f|
185
194
  f.write(entry.read)
186
195
  end
187
- File.chmod(0o755, binary_path)
196
+ File.chmod(0o755, target_path)
188
197
  return
189
198
  end
190
199
 
@@ -29,9 +29,10 @@ module ActiveStorage
29
29
  # Defines rake tasks for server management.
30
30
  rake_tasks do
31
31
  namespace :activestorage_ocr do
32
- desc "Install the OCR server binary"
32
+ desc "Install the OCR server binary (optional: path=./bin/dist)"
33
33
  task :install do
34
- ActiveStorage::Ocr::Binary.install!
34
+ path = ENV["path"]
35
+ ActiveStorage::Ocr::Binary.install!(path: path)
35
36
  end
36
37
 
37
38
  desc "Check OCR server health"
@@ -2,6 +2,6 @@
2
2
 
3
3
  module ActiveStorage
4
4
  module Ocr
5
- VERSION = "0.1.1"
5
+ VERSION = "0.1.2"
6
6
  end
7
7
  end
@@ -0,0 +1,12 @@
1
+ Description:
2
+ Installs the OCR server binary and creates a wrapper script.
3
+
4
+ Example:
5
+ rails generate activestorage_ocr:install
6
+
7
+ This will create:
8
+ bin/activestorage-ocr-server - Wrapper script that runs the OCR server
9
+ bin/dist/activestorage-ocr-server - The actual binary (gitignored)
10
+
11
+ And update:
12
+ .gitignore - Adds /bin/dist/ to ignore the binary
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails/generators"
4
+
5
+ module ActivestorageOcr
6
+ module Generators
7
+ # Installs the OCR server binary and creates a binstub.
8
+ #
9
+ # This generator creates a bin/activestorage-ocr-server script that
10
+ # automatically downloads the binary if needed and runs it.
11
+ #
12
+ # == Usage
13
+ #
14
+ # rails generate activestorage_ocr:install
15
+ #
16
+ # == What it does
17
+ #
18
+ # 1. Creates bin/activestorage-ocr-server (wrapper script)
19
+ # 2. Downloads binary to bin/dist/activestorage-ocr-server
20
+ # 3. Adds bin/dist/ to .gitignore
21
+ #
22
+ class InstallGenerator < Rails::Generators::Base
23
+ source_root File.expand_path("templates", __dir__)
24
+
25
+ desc "Installs the OCR server binary and creates a binstub"
26
+
27
+ def create_binstub
28
+ template "bin/activestorage-ocr-server", "bin/activestorage-ocr-server"
29
+ chmod "bin/activestorage-ocr-server", 0o755
30
+ end
31
+
32
+ def update_gitignore
33
+ gitignore_path = Rails.root.join(".gitignore")
34
+ return unless File.exist?(gitignore_path)
35
+
36
+ gitignore_content = File.read(gitignore_path)
37
+ return if gitignore_content.include?("/bin/dist")
38
+
39
+ append_to_file ".gitignore", "\n# OCR server binary\n/bin/dist/\n"
40
+ end
41
+
42
+ def download_binary
43
+ say "Downloading OCR server binary...", :green
44
+ require "activestorage/ocr/binary"
45
+ dist_dir = Rails.root.join("bin", "dist")
46
+ ActiveStorage::Ocr::Binary.install!(path: dist_dir.to_s)
47
+ end
48
+
49
+ def show_instructions
50
+ say ""
51
+ say "OCR server installed successfully!", :green
52
+ say ""
53
+ say "Add to your Procfile:", :yellow
54
+ say " ocr: bin/activestorage-ocr-server --host 127.0.0.1 --port 9292"
55
+ say ""
56
+ say "Configure the server URL in config/initializers/activestorage_ocr.rb:", :yellow
57
+ say " ActiveStorage::Ocr.configure do |config|"
58
+ say " config.server_url = ENV.fetch('ACTIVESTORAGE_OCR_SERVER_URL', 'http://127.0.0.1:9292')"
59
+ say " end"
60
+ say ""
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env bash
2
+ set -e
3
+
4
+ # Navigate to app root
5
+ cd "$(dirname "$0")/.."
6
+
7
+ BINARY_PATH="./bin/dist/activestorage-ocr-server"
8
+
9
+ # Download binary if not present
10
+ if [ ! -f "$BINARY_PATH" ]; then
11
+ echo "OCR server binary not found. Downloading..."
12
+ ./bin/rails activestorage_ocr:install path=./bin/dist
13
+ fi
14
+
15
+ # Execute the binary with all passed arguments
16
+ exec "$BINARY_PATH" "$@"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activestorage-ocr
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michael Rispoli
@@ -112,6 +112,9 @@ files:
112
112
  - lib/activestorage/ocr/railtie.rb
113
113
  - lib/activestorage/ocr/result.rb
114
114
  - lib/activestorage/ocr/version.rb
115
+ - lib/generators/activestorage_ocr/install/USAGE
116
+ - lib/generators/activestorage_ocr/install/install_generator.rb
117
+ - lib/generators/activestorage_ocr/install/templates/bin/activestorage-ocr-server
115
118
  homepage: https://github.com/Cause-of-a-Kind/activestorage-ocr
116
119
  licenses:
117
120
  - MIT