mathpix 0.1.0

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.
Files changed (51) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +52 -0
  3. data/LICENSE +21 -0
  4. data/README.md +171 -0
  5. data/SECURITY.md +137 -0
  6. data/lib/mathpix/balanced_ternary.rb +86 -0
  7. data/lib/mathpix/batch.rb +155 -0
  8. data/lib/mathpix/capture_builder.rb +142 -0
  9. data/lib/mathpix/chemistry.rb +69 -0
  10. data/lib/mathpix/client.rb +439 -0
  11. data/lib/mathpix/configuration.rb +187 -0
  12. data/lib/mathpix/configuration.rb.backup +125 -0
  13. data/lib/mathpix/conversion.rb +257 -0
  14. data/lib/mathpix/document.rb +320 -0
  15. data/lib/mathpix/errors.rb +78 -0
  16. data/lib/mathpix/mcp/auth/oauth_provider.rb +346 -0
  17. data/lib/mathpix/mcp/auth/token_manager.rb +31 -0
  18. data/lib/mathpix/mcp/auth.rb +18 -0
  19. data/lib/mathpix/mcp/base_tool.rb +117 -0
  20. data/lib/mathpix/mcp/elicitations/ambiguity_elicitation.rb +162 -0
  21. data/lib/mathpix/mcp/elicitations/base_elicitation.rb +141 -0
  22. data/lib/mathpix/mcp/elicitations/confidence_elicitation.rb +162 -0
  23. data/lib/mathpix/mcp/elicitations.rb +78 -0
  24. data/lib/mathpix/mcp/middleware/cors_middleware.rb +94 -0
  25. data/lib/mathpix/mcp/middleware/oauth_middleware.rb +72 -0
  26. data/lib/mathpix/mcp/middleware/rate_limiting_middleware.rb +140 -0
  27. data/lib/mathpix/mcp/middleware.rb +13 -0
  28. data/lib/mathpix/mcp/resources/formats_list_resource.rb +113 -0
  29. data/lib/mathpix/mcp/resources/hierarchical_router.rb +237 -0
  30. data/lib/mathpix/mcp/resources/latest_snip_resource.rb +60 -0
  31. data/lib/mathpix/mcp/resources/recent_snips_resource.rb +75 -0
  32. data/lib/mathpix/mcp/resources/snip_stats_resource.rb +78 -0
  33. data/lib/mathpix/mcp/resources.rb +15 -0
  34. data/lib/mathpix/mcp/server.rb +174 -0
  35. data/lib/mathpix/mcp/tools/batch_convert_tool.rb +106 -0
  36. data/lib/mathpix/mcp/tools/check_document_status_tool.rb +66 -0
  37. data/lib/mathpix/mcp/tools/convert_document_tool.rb +90 -0
  38. data/lib/mathpix/mcp/tools/convert_image_tool.rb +91 -0
  39. data/lib/mathpix/mcp/tools/convert_strokes_tool.rb +82 -0
  40. data/lib/mathpix/mcp/tools/get_account_info_tool.rb +57 -0
  41. data/lib/mathpix/mcp/tools/get_usage_tool.rb +62 -0
  42. data/lib/mathpix/mcp/tools/list_formats_tool.rb +81 -0
  43. data/lib/mathpix/mcp/tools/search_results_tool.rb +111 -0
  44. data/lib/mathpix/mcp/transports/http_streaming_transport.rb +622 -0
  45. data/lib/mathpix/mcp/transports/sse_stream_handler.rb +236 -0
  46. data/lib/mathpix/mcp/transports.rb +12 -0
  47. data/lib/mathpix/mcp.rb +52 -0
  48. data/lib/mathpix/result.rb +364 -0
  49. data/lib/mathpix/version.rb +22 -0
  50. data/lib/mathpix.rb +229 -0
  51. metadata +283 -0
data/lib/mathpix.rb ADDED
@@ -0,0 +1,229 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'net/http'
4
+ require 'json'
5
+ require 'base64'
6
+
7
+ require_relative 'mathpix/version'
8
+ require_relative 'mathpix/configuration'
9
+ require_relative 'mathpix/client'
10
+ require_relative 'mathpix/capture_builder'
11
+ require_relative 'mathpix/result'
12
+ require_relative 'mathpix/conversion'
13
+ require_relative 'mathpix/chemistry'
14
+ require_relative 'mathpix/document'
15
+ require_relative 'mathpix/batch'
16
+ require_relative 'mathpix/errors'
17
+ require_relative 'mathpix/balanced_ternary'
18
+
19
+ # Mathpix OCR Ruby Client
20
+ # The geodesic path to mathematical OCR
21
+ module Mathpix
22
+ class << self
23
+ # Configure Mathpix client
24
+ #
25
+ # @yield [Configuration] config object
26
+ # @example
27
+ # Mathpix.configure do |config|
28
+ # config.app_id = ENV['MATHPIX_APP_ID']
29
+ # config.app_key = ENV['MATHPIX_APP_KEY']
30
+ # config.seed = 1069
31
+ # end
32
+ def configure
33
+ yield configuration
34
+ end
35
+
36
+ # Load configuration from file (feature parity with mpxpy)
37
+ #
38
+ # @param path [String] config file path (default: ~/.mathpix/config)
39
+ # @return [Configuration]
40
+ # @example
41
+ # Mathpix.load_config('~/.mathpix/config')
42
+ # Mathpix.load_config # Uses default path
43
+ def load_config(path = nil)
44
+ configuration.load_from_file(path || Configuration::DEFAULT_CONFIG_PATH)
45
+ configuration
46
+ end
47
+
48
+ # Get current configuration
49
+ # @return [Configuration]
50
+ def configuration
51
+ @configuration ||= Configuration.new
52
+ end
53
+
54
+ # Reset configuration to defaults
55
+ def reset!
56
+ @configuration = Configuration.new
57
+ @client = nil
58
+ end
59
+
60
+ # Get or create client instance
61
+ # @return [Client]
62
+ def client
63
+ @client ||= Client.new(configuration)
64
+ end
65
+
66
+ # Snap an image to equation (the poet's way)
67
+ #
68
+ # Supports both local file paths and remote URLs (feature parity with Python mpxpy)
69
+ # HTTP URLs are automatically upgraded to HTTPS for security
70
+ #
71
+ # @param image_path_or_url [String, Hash] path to image file, URL, or {url: '...'} / {path: '...'}
72
+ # @param options [Hash] capture options
73
+ # @return [Result]
74
+ # @example Local file
75
+ # equation = Mathpix.snap('equation.png')
76
+ # puts equation.latex
77
+ # @example Remote URL (HTTPS)
78
+ # result = Mathpix.snap('https://example.com/equation.png')
79
+ # puts result.source_url # => 'https://example.com/equation.png'
80
+ # @example Remote URL (HTTP - auto-upgraded)
81
+ # result = Mathpix.snap('http://example.com/equation.png')
82
+ # puts result.source_url # => 'https://example.com/equation.png' (auto-upgraded)
83
+ # @example Hash with URL
84
+ # result = Mathpix.snap(url: 'https://example.com/equation.png')
85
+ def snap(image_path_or_url, **options)
86
+ client.snap(image_path_or_url, **options)
87
+ end
88
+
89
+ # Start fluent capture builder (the artisan's way)
90
+ #
91
+ # @param image_path [String] path to image file
92
+ # @return [CaptureBuilder]
93
+ # @example
94
+ # result = Mathpix
95
+ # .from('integral.png')
96
+ # .with_formats(:latex, :mathml)
97
+ # .with_confidence(0.90)
98
+ # .capture
99
+ def from(image_path)
100
+ CaptureBuilder.new(client, image_path)
101
+ end
102
+
103
+ # Process image with block (the _why way)
104
+ #
105
+ # @param image_path [String] path to image file
106
+ # @yield [Result] result object
107
+ # @example
108
+ # Mathpix.process('page.png') do |result|
109
+ # puts result.latex
110
+ # puts result.confidence
111
+ # end
112
+ def process(image_path, **options)
113
+ result = snap(image_path, **options)
114
+ yield result if block_given?
115
+ result
116
+ end
117
+
118
+ # Chemistry capture builder (the chemist's way)
119
+ #
120
+ # @param image_path [String] path to structure diagram
121
+ # @return [Chemistry]
122
+ # @example
123
+ # molecule = Mathpix
124
+ # .chemistry('benzene.png')
125
+ # .with_smiles
126
+ # .capture
127
+ def chemistry(image_path)
128
+ Chemistry.new(client, image_path)
129
+ end
130
+
131
+ # Document processing builder (PDF, DOCX, PPTX)
132
+ #
133
+ # Feature parity with Python mpxpy: supports PDF + Office documents
134
+ #
135
+ # @param document_path [String] path to document file
136
+ # @return [Document]
137
+ # @example PDF
138
+ # doc = Mathpix
139
+ # .document('paper.pdf')
140
+ # .with_formats(:markdown, :latex)
141
+ # .convert
142
+ # @example DOCX
143
+ # doc = Mathpix
144
+ # .document('thesis.docx')
145
+ # .with_formats(:markdown)
146
+ # .convert
147
+ # @example PPTX
148
+ # doc = Mathpix
149
+ # .document('slides.pptx')
150
+ # .with_formats(:markdown)
151
+ # .convert
152
+ def document(document_path)
153
+ Document.new(client, document_path)
154
+ end
155
+
156
+ # PDF processing builder (backward compatibility alias)
157
+ #
158
+ # @param pdf_path [String] path to PDF file
159
+ # @return [Document]
160
+ # @example
161
+ # pdf = Mathpix
162
+ # .pdf('paper.pdf')
163
+ # .with_formats(:markdown, :latex)
164
+ # .convert
165
+ def pdf(pdf_path)
166
+ document(pdf_path)
167
+ end
168
+
169
+ # Batch processing (the efficient way)
170
+ #
171
+ # @param image_paths [Array<String>] paths to images
172
+ # @yield [Batch] batch configuration
173
+ # @return [Array<Result>]
174
+ # @example
175
+ # results = Mathpix.batch(images) do |batch|
176
+ # batch.formats :latex, :text
177
+ # batch.confidence_threshold 0.85
178
+ # end
179
+ def batch(image_paths, &block)
180
+ Batch.new(client, image_paths).tap do |batch|
181
+ block.call(batch) if block
182
+ end.process
183
+ end
184
+
185
+ # Search recent captures (the detective's way)
186
+ #
187
+ # @param options [Hash] search options
188
+ # @return [Array<Result>]
189
+ # @example
190
+ # recent = Mathpix.recent(limit: 10)
191
+ def recent(limit: 10)
192
+ client.recent(limit: limit)
193
+ end
194
+
195
+ # Search with query builder
196
+ #
197
+ # @yield [SearchQuery] query builder
198
+ # @return [Array<Result>]
199
+ # @example
200
+ # results = Mathpix.search do |q|
201
+ # q.text_contains("Pythagorean")
202
+ # q.confidence_above(0.90)
203
+ # end
204
+ def search(&block)
205
+ # TODO: Implement search query builder
206
+ client.search(&block)
207
+ end
208
+
209
+ # Convert Mathpix Markdown to multiple formats (feature parity with mpxpy)
210
+ #
211
+ # Async operation - returns Conversion object to poll for completion
212
+ #
213
+ # @param mmd [String] Mathpix Markdown content
214
+ # @param formats [Array<Symbol, String>] output formats (pdf, docx, html, etc.)
215
+ # @param options [Hash] conversion options
216
+ # @return [Conversion] conversion object (async)
217
+ # @example
218
+ # conversion = Mathpix.convert_mmd(
219
+ # mmd: "E = mc^2",
220
+ # formats: [:pdf, :docx, :html]
221
+ # )
222
+ # conversion.wait_until_complete
223
+ # conversion.to_pdf_file('output.pdf')
224
+ # conversion.to_docx_file('output.docx')
225
+ def convert_mmd(mmd:, formats:, **options)
226
+ client.convert_mmd(mmd: mmd, formats: formats, **options)
227
+ end
228
+ end
229
+ end
metadata ADDED
@@ -0,0 +1,283 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mathpix
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Barton Rhodes
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: mcp
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - "~>"
17
+ - !ruby/object:Gem::Version
18
+ version: 0.1.0
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - "~>"
24
+ - !ruby/object:Gem::Version
25
+ version: 0.1.0
26
+ - !ruby/object:Gem::Dependency
27
+ name: rack
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - "~>"
31
+ - !ruby/object:Gem::Version
32
+ version: '3.0'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '3.0'
40
+ - !ruby/object:Gem::Dependency
41
+ name: puma
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '6.0'
47
+ type: :runtime
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '6.0'
54
+ - !ruby/object:Gem::Dependency
55
+ name: concurrent-ruby
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: '1.2'
61
+ type: :runtime
62
+ prerelease: false
63
+ version_requirements: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: '1.2'
68
+ - !ruby/object:Gem::Dependency
69
+ name: cucumber
70
+ requirement: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - "~>"
73
+ - !ruby/object:Gem::Version
74
+ version: '9.0'
75
+ type: :development
76
+ prerelease: false
77
+ version_requirements: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - "~>"
80
+ - !ruby/object:Gem::Version
81
+ version: '9.0'
82
+ - !ruby/object:Gem::Dependency
83
+ name: rspec
84
+ requirement: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - "~>"
87
+ - !ruby/object:Gem::Version
88
+ version: '3.12'
89
+ type: :development
90
+ prerelease: false
91
+ version_requirements: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - "~>"
94
+ - !ruby/object:Gem::Version
95
+ version: '3.12'
96
+ - !ruby/object:Gem::Dependency
97
+ name: webmock
98
+ requirement: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - "~>"
101
+ - !ruby/object:Gem::Version
102
+ version: '3.18'
103
+ type: :development
104
+ prerelease: false
105
+ version_requirements: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - "~>"
108
+ - !ruby/object:Gem::Version
109
+ version: '3.18'
110
+ - !ruby/object:Gem::Dependency
111
+ name: vcr
112
+ requirement: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - "~>"
115
+ - !ruby/object:Gem::Version
116
+ version: '6.1'
117
+ type: :development
118
+ prerelease: false
119
+ version_requirements: !ruby/object:Gem::Requirement
120
+ requirements:
121
+ - - "~>"
122
+ - !ruby/object:Gem::Version
123
+ version: '6.1'
124
+ - !ruby/object:Gem::Dependency
125
+ name: dotenv
126
+ requirement: !ruby/object:Gem::Requirement
127
+ requirements:
128
+ - - "~>"
129
+ - !ruby/object:Gem::Version
130
+ version: '2.8'
131
+ type: :development
132
+ prerelease: false
133
+ version_requirements: !ruby/object:Gem::Requirement
134
+ requirements:
135
+ - - "~>"
136
+ - !ruby/object:Gem::Version
137
+ version: '2.8'
138
+ - !ruby/object:Gem::Dependency
139
+ name: rubocop
140
+ requirement: !ruby/object:Gem::Requirement
141
+ requirements:
142
+ - - "~>"
143
+ - !ruby/object:Gem::Version
144
+ version: '1.50'
145
+ type: :development
146
+ prerelease: false
147
+ version_requirements: !ruby/object:Gem::Requirement
148
+ requirements:
149
+ - - "~>"
150
+ - !ruby/object:Gem::Version
151
+ version: '1.50'
152
+ - !ruby/object:Gem::Dependency
153
+ name: yard
154
+ requirement: !ruby/object:Gem::Requirement
155
+ requirements:
156
+ - - "~>"
157
+ - !ruby/object:Gem::Version
158
+ version: '0.9'
159
+ type: :development
160
+ prerelease: false
161
+ version_requirements: !ruby/object:Gem::Requirement
162
+ requirements:
163
+ - - "~>"
164
+ - !ruby/object:Gem::Version
165
+ version: '0.9'
166
+ - !ruby/object:Gem::Dependency
167
+ name: bundler-audit
168
+ requirement: !ruby/object:Gem::Requirement
169
+ requirements:
170
+ - - "~>"
171
+ - !ruby/object:Gem::Version
172
+ version: '0.9'
173
+ type: :development
174
+ prerelease: false
175
+ version_requirements: !ruby/object:Gem::Requirement
176
+ requirements:
177
+ - - "~>"
178
+ - !ruby/object:Gem::Version
179
+ version: '0.9'
180
+ - !ruby/object:Gem::Dependency
181
+ name: brakeman
182
+ requirement: !ruby/object:Gem::Requirement
183
+ requirements:
184
+ - - "~>"
185
+ - !ruby/object:Gem::Version
186
+ version: '6.0'
187
+ type: :development
188
+ prerelease: false
189
+ version_requirements: !ruby/object:Gem::Requirement
190
+ requirements:
191
+ - - "~>"
192
+ - !ruby/object:Gem::Version
193
+ version: '6.0'
194
+ description: |
195
+ Transform mathematical images to LaTeX, chemistry structures to SMILES, and documents to
196
+ markdown with security-first design. Features HTTPS enforcement, path traversal protection,
197
+ structured logging, and complete MCP (Model Context Protocol) server integration.
198
+ The geodesic path to mathematical OCR in Ruby.
199
+ email:
200
+ - ies@prototypesf.org
201
+ executables: []
202
+ extensions: []
203
+ extra_rdoc_files: []
204
+ files:
205
+ - CHANGELOG.md
206
+ - LICENSE
207
+ - README.md
208
+ - SECURITY.md
209
+ - lib/mathpix.rb
210
+ - lib/mathpix/balanced_ternary.rb
211
+ - lib/mathpix/batch.rb
212
+ - lib/mathpix/capture_builder.rb
213
+ - lib/mathpix/chemistry.rb
214
+ - lib/mathpix/client.rb
215
+ - lib/mathpix/configuration.rb
216
+ - lib/mathpix/configuration.rb.backup
217
+ - lib/mathpix/conversion.rb
218
+ - lib/mathpix/document.rb
219
+ - lib/mathpix/errors.rb
220
+ - lib/mathpix/mcp.rb
221
+ - lib/mathpix/mcp/auth.rb
222
+ - lib/mathpix/mcp/auth/oauth_provider.rb
223
+ - lib/mathpix/mcp/auth/token_manager.rb
224
+ - lib/mathpix/mcp/base_tool.rb
225
+ - lib/mathpix/mcp/elicitations.rb
226
+ - lib/mathpix/mcp/elicitations/ambiguity_elicitation.rb
227
+ - lib/mathpix/mcp/elicitations/base_elicitation.rb
228
+ - lib/mathpix/mcp/elicitations/confidence_elicitation.rb
229
+ - lib/mathpix/mcp/middleware.rb
230
+ - lib/mathpix/mcp/middleware/cors_middleware.rb
231
+ - lib/mathpix/mcp/middleware/oauth_middleware.rb
232
+ - lib/mathpix/mcp/middleware/rate_limiting_middleware.rb
233
+ - lib/mathpix/mcp/resources.rb
234
+ - lib/mathpix/mcp/resources/formats_list_resource.rb
235
+ - lib/mathpix/mcp/resources/hierarchical_router.rb
236
+ - lib/mathpix/mcp/resources/latest_snip_resource.rb
237
+ - lib/mathpix/mcp/resources/recent_snips_resource.rb
238
+ - lib/mathpix/mcp/resources/snip_stats_resource.rb
239
+ - lib/mathpix/mcp/server.rb
240
+ - lib/mathpix/mcp/tools/batch_convert_tool.rb
241
+ - lib/mathpix/mcp/tools/check_document_status_tool.rb
242
+ - lib/mathpix/mcp/tools/convert_document_tool.rb
243
+ - lib/mathpix/mcp/tools/convert_image_tool.rb
244
+ - lib/mathpix/mcp/tools/convert_strokes_tool.rb
245
+ - lib/mathpix/mcp/tools/get_account_info_tool.rb
246
+ - lib/mathpix/mcp/tools/get_usage_tool.rb
247
+ - lib/mathpix/mcp/tools/list_formats_tool.rb
248
+ - lib/mathpix/mcp/tools/search_results_tool.rb
249
+ - lib/mathpix/mcp/transports.rb
250
+ - lib/mathpix/mcp/transports/http_streaming_transport.rb
251
+ - lib/mathpix/mcp/transports/sse_stream_handler.rb
252
+ - lib/mathpix/result.rb
253
+ - lib/mathpix/version.rb
254
+ homepage: https://github.com/teglonlabs/mathpix-mcp-server
255
+ licenses:
256
+ - MIT
257
+ metadata:
258
+ homepage_uri: https://github.com/teglonlabs/mathpix-mcp-server
259
+ source_code_uri: https://github.com/teglonlabs/mathpix-mcp-server
260
+ changelog_uri: https://github.com/teglonlabs/mathpix-mcp-server/blob/main/CHANGELOG.md
261
+ documentation_uri: https://docs.mathpix.com
262
+ bug_tracker_uri: https://github.com/teglonlabs/mathpix-mcp-server/issues
263
+ wiki_uri: https://github.com/teglonlabs/mathpix-mcp-server/wiki
264
+ rubygems_mfa_required: 'true'
265
+ security_policy_uri: https://github.com/teglonlabs/mathpix-mcp-server/blob/main/SECURITY.md
266
+ rdoc_options: []
267
+ require_paths:
268
+ - lib
269
+ required_ruby_version: !ruby/object:Gem::Requirement
270
+ requirements:
271
+ - - ">="
272
+ - !ruby/object:Gem::Version
273
+ version: 2.7.0
274
+ required_rubygems_version: !ruby/object:Gem::Requirement
275
+ requirements:
276
+ - - ">="
277
+ - !ruby/object:Gem::Version
278
+ version: '0'
279
+ requirements: []
280
+ rubygems_version: 3.7.1
281
+ specification_version: 4
282
+ summary: Secure Ruby client for Mathpix OCR API with MCP integration
283
+ test_files: []