universal_document_processor 1.0.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.
- checksums.yaml +7 -0
- data/AI_USAGE_GUIDE.md +404 -0
- data/CHANGELOG.md +67 -0
- data/GEM_RELEASE_GUIDE.md +288 -0
- data/Gemfile +27 -0
- data/LICENSE +21 -0
- data/README.md +726 -0
- data/Rakefile +36 -0
- data/lib/universal_document_processor/ai_agent.rb +491 -0
- data/lib/universal_document_processor/document.rb +225 -0
- data/lib/universal_document_processor/processors/archive_processor.rb +290 -0
- data/lib/universal_document_processor/processors/base_processor.rb +58 -0
- data/lib/universal_document_processor/processors/character_validator.rb +283 -0
- data/lib/universal_document_processor/processors/excel_processor.rb +219 -0
- data/lib/universal_document_processor/processors/image_processor.rb +172 -0
- data/lib/universal_document_processor/processors/pdf_processor.rb +105 -0
- data/lib/universal_document_processor/processors/powerpoint_processor.rb +214 -0
- data/lib/universal_document_processor/processors/text_processor.rb +360 -0
- data/lib/universal_document_processor/processors/word_processor.rb +137 -0
- data/lib/universal_document_processor/utils/file_detector.rb +83 -0
- data/lib/universal_document_processor/utils/japanese_filename_handler.rb +205 -0
- data/lib/universal_document_processor/version.rb +3 -0
- data/lib/universal_document_processor.rb +223 -0
- metadata +198 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 35c7ce3be00b697398ed7be3f364c2b9b29002cc763265c9a9b29519dceb2439
|
4
|
+
data.tar.gz: 0c9636fdf3323e5629da41e62747dbabdf0af369e359bf1096cceed5642ee248
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: a9f33acf6694f950ae5e4dff14a1adc2b40a51b8fe95311598c51fd5cdf2fa762700cbe078fa8589b39f170a1a98136a065b0f9fa94dd92e832a497d1c817249
|
7
|
+
data.tar.gz: facc2f1555429de4aa5076c570d8547022b791a34e55bd54350225dea73c17f968eae063bc83520f89702c97c8bfec150b1c4175f39322bad1071aa3ed09bfea
|
data/AI_USAGE_GUIDE.md
ADDED
@@ -0,0 +1,404 @@
|
|
1
|
+
# 🤖 Universal Document Processor - AI Agent Usage Guide
|
2
|
+
|
3
|
+
## Overview
|
4
|
+
|
5
|
+
The Universal Document Processor gem includes powerful AI-powered document analysis capabilities through its built-in **Agentic AI** features. Once you've installed the gem, you can leverage AI to analyze, summarize, extract information, and interact with your documents intelligently.
|
6
|
+
|
7
|
+
## 🚀 Quick Setup
|
8
|
+
|
9
|
+
### 1. Install the Gem
|
10
|
+
|
11
|
+
```bash
|
12
|
+
gem install universal_document_processor
|
13
|
+
```
|
14
|
+
|
15
|
+
### 2. Set Up Your OpenAI API Key
|
16
|
+
|
17
|
+
```bash
|
18
|
+
# Set environment variable
|
19
|
+
export OPENAI_API_KEY="your-openai-api-key-here"
|
20
|
+
```
|
21
|
+
|
22
|
+
Or pass it directly in your code:
|
23
|
+
|
24
|
+
```ruby
|
25
|
+
options = { api_key: 'your-openai-api-key-here' }
|
26
|
+
```
|
27
|
+
|
28
|
+
### 3. Basic AI Usage
|
29
|
+
|
30
|
+
```ruby
|
31
|
+
require 'universal_document_processor'
|
32
|
+
|
33
|
+
# Basic AI analysis
|
34
|
+
result = UniversalDocumentProcessor.ai_analyze('document.pdf')
|
35
|
+
puts result
|
36
|
+
```
|
37
|
+
|
38
|
+
## 🧠 AI Features Overview
|
39
|
+
|
40
|
+
### Available AI Methods
|
41
|
+
|
42
|
+
1. **`ai_analyze`** - Comprehensive document analysis
|
43
|
+
2. **`ai_summarize`** - Generate summaries of different lengths
|
44
|
+
3. **`ai_extract_info`** - Extract specific information categories
|
45
|
+
4. **`ai_translate`** - Translate document content
|
46
|
+
5. **`ai_classify`** - Classify document type and purpose
|
47
|
+
6. **`ai_insights`** - Generate insights and recommendations
|
48
|
+
7. **`ai_action_items`** - Extract actionable items
|
49
|
+
8. **`ai_compare`** - Compare multiple documents
|
50
|
+
9. **`ai_chat`** - Interactive chat about documents
|
51
|
+
|
52
|
+
## 📝 Detailed Usage Examples
|
53
|
+
|
54
|
+
### 1. Document Analysis
|
55
|
+
|
56
|
+
#### General Analysis
|
57
|
+
```ruby
|
58
|
+
# Analyze any document comprehensively
|
59
|
+
analysis = UniversalDocumentProcessor.ai_analyze('report.pdf')
|
60
|
+
puts analysis
|
61
|
+
```
|
62
|
+
|
63
|
+
#### Specific Query Analysis
|
64
|
+
```ruby
|
65
|
+
# Ask specific questions about the document
|
66
|
+
analysis = UniversalDocumentProcessor.ai_analyze('contract.pdf', {
|
67
|
+
query: "What are the key terms and conditions?"
|
68
|
+
})
|
69
|
+
puts analysis
|
70
|
+
```
|
71
|
+
|
72
|
+
### 2. Document Summarization
|
73
|
+
|
74
|
+
```ruby
|
75
|
+
# Short summary (2-3 sentences)
|
76
|
+
summary = UniversalDocumentProcessor.ai_summarize('document.pdf', length: :short)
|
77
|
+
|
78
|
+
# Medium summary (1-2 paragraphs) - default
|
79
|
+
summary = UniversalDocumentProcessor.ai_summarize('document.pdf', length: :medium)
|
80
|
+
|
81
|
+
# Detailed summary
|
82
|
+
summary = UniversalDocumentProcessor.ai_summarize('document.pdf', length: :long)
|
83
|
+
|
84
|
+
puts summary
|
85
|
+
```
|
86
|
+
|
87
|
+
### 3. Information Extraction
|
88
|
+
|
89
|
+
```ruby
|
90
|
+
# Extract default categories
|
91
|
+
info = UniversalDocumentProcessor.ai_extract_info('meeting_notes.pdf')
|
92
|
+
|
93
|
+
# Extract specific categories
|
94
|
+
info = UniversalDocumentProcessor.ai_extract_info('contract.pdf', [
|
95
|
+
'parties', 'dates', 'financial_terms', 'obligations', 'deadlines'
|
96
|
+
])
|
97
|
+
|
98
|
+
puts info
|
99
|
+
```
|
100
|
+
|
101
|
+
### 4. Document Translation
|
102
|
+
|
103
|
+
```ruby
|
104
|
+
# Translate to different languages
|
105
|
+
spanish_content = UniversalDocumentProcessor.ai_translate('document.pdf', 'Spanish')
|
106
|
+
japanese_content = UniversalDocumentProcessor.ai_translate('document.pdf', 'Japanese')
|
107
|
+
french_content = UniversalDocumentProcessor.ai_translate('document.pdf', 'French')
|
108
|
+
|
109
|
+
puts spanish_content
|
110
|
+
```
|
111
|
+
|
112
|
+
### 5. Document Classification
|
113
|
+
|
114
|
+
```ruby
|
115
|
+
# Classify document type and purpose
|
116
|
+
classification = UniversalDocumentProcessor.ai_classify('unknown_document.pdf')
|
117
|
+
|
118
|
+
# Returns structured information about document type
|
119
|
+
puts classification
|
120
|
+
```
|
121
|
+
|
122
|
+
### 6. Generate Insights
|
123
|
+
|
124
|
+
```ruby
|
125
|
+
# Get AI-powered insights and recommendations
|
126
|
+
insights = UniversalDocumentProcessor.ai_insights('business_plan.pdf')
|
127
|
+
|
128
|
+
# Returns analysis of key themes, recommendations, etc.
|
129
|
+
puts insights
|
130
|
+
```
|
131
|
+
|
132
|
+
### 7. Extract Action Items
|
133
|
+
|
134
|
+
```ruby
|
135
|
+
# Extract actionable items from documents
|
136
|
+
action_items = UniversalDocumentProcessor.ai_action_items('meeting_minutes.pdf')
|
137
|
+
|
138
|
+
# Returns structured list of tasks, deadlines, assignments
|
139
|
+
puts action_items
|
140
|
+
```
|
141
|
+
|
142
|
+
### 8. Compare Documents
|
143
|
+
|
144
|
+
```ruby
|
145
|
+
# Compare multiple documents
|
146
|
+
comparison = UniversalDocumentProcessor.ai_compare([
|
147
|
+
'version1.pdf',
|
148
|
+
'version2.pdf',
|
149
|
+
'version3.pdf'
|
150
|
+
], :content)
|
151
|
+
|
152
|
+
puts comparison
|
153
|
+
```
|
154
|
+
|
155
|
+
## 🎯 Advanced Usage with Document Objects
|
156
|
+
|
157
|
+
### Using Document Objects for More Control
|
158
|
+
|
159
|
+
```ruby
|
160
|
+
# Create document object for advanced operations
|
161
|
+
doc = UniversalDocumentProcessor::Document.new('complex_document.pdf')
|
162
|
+
|
163
|
+
# Use AI methods on the document object
|
164
|
+
summary = doc.ai_summarize(length: :medium)
|
165
|
+
insights = doc.ai_insights
|
166
|
+
action_items = doc.ai_action_items
|
167
|
+
|
168
|
+
# Interactive chat about the document
|
169
|
+
response = doc.ai_chat("What are the main risks mentioned in this document?")
|
170
|
+
puts response
|
171
|
+
```
|
172
|
+
|
173
|
+
### Creating and Reusing AI Agent
|
174
|
+
|
175
|
+
```ruby
|
176
|
+
# Create an AI agent with custom configuration
|
177
|
+
ai_agent = UniversalDocumentProcessor.create_ai_agent({
|
178
|
+
model: 'gpt-4',
|
179
|
+
temperature: 0.7,
|
180
|
+
api_key: 'your-api-key'
|
181
|
+
})
|
182
|
+
|
183
|
+
# Process document
|
184
|
+
doc_result = UniversalDocumentProcessor.process('document.pdf')
|
185
|
+
|
186
|
+
# Use AI agent for multiple operations
|
187
|
+
summary = ai_agent.summarize_document(doc_result, length: :short)
|
188
|
+
insights = ai_agent.generate_insights(doc_result)
|
189
|
+
classification = ai_agent.classify_document(doc_result)
|
190
|
+
|
191
|
+
# Interactive chat
|
192
|
+
response = ai_agent.chat("Tell me about the financial projections", doc_result)
|
193
|
+
```
|
194
|
+
|
195
|
+
## 🛠️ Configuration Options
|
196
|
+
|
197
|
+
### AI Agent Configuration
|
198
|
+
|
199
|
+
```ruby
|
200
|
+
options = {
|
201
|
+
api_key: 'your-openai-api-key', # OpenAI API key
|
202
|
+
model: 'gpt-4', # AI model to use
|
203
|
+
temperature: 0.7, # Response creativity (0.0-1.0)
|
204
|
+
max_history: 10, # Conversation history limit
|
205
|
+
base_url: 'https://api.openai.com/v1' # API endpoint
|
206
|
+
}
|
207
|
+
|
208
|
+
# Use with any AI method
|
209
|
+
result = UniversalDocumentProcessor.ai_analyze('document.pdf', options)
|
210
|
+
```
|
211
|
+
|
212
|
+
## 💡 Use Case Examples
|
213
|
+
|
214
|
+
### 1. Legal Document Analysis
|
215
|
+
|
216
|
+
```ruby
|
217
|
+
# Analyze legal contracts
|
218
|
+
contract_analysis = UniversalDocumentProcessor.ai_analyze('contract.pdf', {
|
219
|
+
query: "Extract all key terms, obligations, and potential risks"
|
220
|
+
})
|
221
|
+
|
222
|
+
# Extract specific legal information
|
223
|
+
legal_info = UniversalDocumentProcessor.ai_extract_info('contract.pdf', [
|
224
|
+
'parties', 'effective_date', 'termination_clauses', 'payment_terms', 'liabilities'
|
225
|
+
])
|
226
|
+
```
|
227
|
+
|
228
|
+
### 2. Business Report Processing
|
229
|
+
|
230
|
+
```ruby
|
231
|
+
# Summarize quarterly reports
|
232
|
+
summary = UniversalDocumentProcessor.ai_summarize('q4_report.pdf', length: :medium)
|
233
|
+
|
234
|
+
# Extract key business metrics
|
235
|
+
metrics = UniversalDocumentProcessor.ai_extract_info('q4_report.pdf', [
|
236
|
+
'revenue', 'expenses', 'profit_margins', 'growth_metrics', 'forecasts'
|
237
|
+
])
|
238
|
+
|
239
|
+
# Get strategic insights
|
240
|
+
insights = UniversalDocumentProcessor.ai_insights('q4_report.pdf')
|
241
|
+
```
|
242
|
+
|
243
|
+
### 3. Meeting Minutes Processing
|
244
|
+
|
245
|
+
```ruby
|
246
|
+
# Extract action items from meeting notes
|
247
|
+
action_items = UniversalDocumentProcessor.ai_action_items('meeting_notes.pdf')
|
248
|
+
|
249
|
+
# Summarize meeting outcomes
|
250
|
+
summary = UniversalDocumentProcessor.ai_summarize('meeting_notes.pdf', length: :short)
|
251
|
+
|
252
|
+
# Extract key decisions and follow-ups
|
253
|
+
decisions = UniversalDocumentProcessor.ai_extract_info('meeting_notes.pdf', [
|
254
|
+
'decisions_made', 'action_items', 'deadlines', 'assigned_people'
|
255
|
+
])
|
256
|
+
```
|
257
|
+
|
258
|
+
### 4. Research Paper Analysis
|
259
|
+
|
260
|
+
```ruby
|
261
|
+
# Analyze research papers
|
262
|
+
analysis = UniversalDocumentProcessor.ai_analyze('research_paper.pdf', {
|
263
|
+
query: "What are the main findings and methodology used?"
|
264
|
+
})
|
265
|
+
|
266
|
+
# Extract research data
|
267
|
+
research_info = UniversalDocumentProcessor.ai_extract_info('research_paper.pdf', [
|
268
|
+
'hypothesis', 'methodology', 'results', 'conclusions', 'future_work'
|
269
|
+
])
|
270
|
+
```
|
271
|
+
|
272
|
+
## 🔄 Interactive Document Chat
|
273
|
+
|
274
|
+
```ruby
|
275
|
+
# Create document object
|
276
|
+
doc = UniversalDocumentProcessor::Document.new('document.pdf')
|
277
|
+
|
278
|
+
# Start interactive chat session
|
279
|
+
puts "Chat with your document (type 'exit' to quit):"
|
280
|
+
|
281
|
+
loop do
|
282
|
+
print "> "
|
283
|
+
user_input = gets.chomp
|
284
|
+
break if user_input.downcase == 'exit'
|
285
|
+
|
286
|
+
response = doc.ai_chat(user_input)
|
287
|
+
puts "AI: #{response}\n\n"
|
288
|
+
end
|
289
|
+
```
|
290
|
+
|
291
|
+
## 📊 Batch AI Processing
|
292
|
+
|
293
|
+
```ruby
|
294
|
+
# Process multiple documents with AI
|
295
|
+
documents = ['doc1.pdf', 'doc2.docx', 'doc3.xlsx']
|
296
|
+
|
297
|
+
# Batch summarization
|
298
|
+
summaries = documents.map do |file|
|
299
|
+
{
|
300
|
+
file: file,
|
301
|
+
summary: UniversalDocumentProcessor.ai_summarize(file, length: :short)
|
302
|
+
}
|
303
|
+
end
|
304
|
+
|
305
|
+
# Batch classification
|
306
|
+
classifications = documents.map do |file|
|
307
|
+
{
|
308
|
+
file: file,
|
309
|
+
classification: UniversalDocumentProcessor.ai_classify(file)
|
310
|
+
}
|
311
|
+
end
|
312
|
+
```
|
313
|
+
|
314
|
+
## 🚨 Error Handling
|
315
|
+
|
316
|
+
```ruby
|
317
|
+
begin
|
318
|
+
result = UniversalDocumentProcessor.ai_analyze('document.pdf')
|
319
|
+
puts result
|
320
|
+
rescue ArgumentError => e
|
321
|
+
puts "Configuration error: #{e.message}"
|
322
|
+
puts "Please check your OpenAI API key"
|
323
|
+
rescue UniversalDocumentProcessor::ProcessingError => e
|
324
|
+
puts "Processing error: #{e.message}"
|
325
|
+
rescue StandardError => e
|
326
|
+
puts "Unexpected error: #{e.message}"
|
327
|
+
end
|
328
|
+
```
|
329
|
+
|
330
|
+
## 🎛️ Environment Variables
|
331
|
+
|
332
|
+
Set these environment variables for seamless operation:
|
333
|
+
|
334
|
+
```bash
|
335
|
+
# Required
|
336
|
+
export OPENAI_API_KEY="your-openai-api-key"
|
337
|
+
|
338
|
+
# Optional
|
339
|
+
export OPENAI_MODEL="gpt-4"
|
340
|
+
export OPENAI_TEMPERATURE="0.7"
|
341
|
+
export OPENAI_BASE_URL="https://api.openai.com/v1"
|
342
|
+
```
|
343
|
+
|
344
|
+
## 🔧 Troubleshooting
|
345
|
+
|
346
|
+
### Common Issues and Solutions
|
347
|
+
|
348
|
+
1. **Missing API Key**
|
349
|
+
```ruby
|
350
|
+
# Error: ArgumentError: OpenAI API key is required
|
351
|
+
# Solution: Set OPENAI_API_KEY environment variable or pass api_key in options
|
352
|
+
```
|
353
|
+
|
354
|
+
2. **API Rate Limits**
|
355
|
+
```ruby
|
356
|
+
# Add delays between requests for large batch operations
|
357
|
+
documents.each_with_index do |doc, index|
|
358
|
+
result = UniversalDocumentProcessor.ai_analyze(doc)
|
359
|
+
sleep(1) if index % 10 == 0 # Pause every 10 requests
|
360
|
+
end
|
361
|
+
```
|
362
|
+
|
363
|
+
3. **Large Documents**
|
364
|
+
```ruby
|
365
|
+
# For very large documents, consider processing in chunks
|
366
|
+
options = { max_content_length: 10000 }
|
367
|
+
result = UniversalDocumentProcessor.ai_analyze('large_doc.pdf', options)
|
368
|
+
```
|
369
|
+
|
370
|
+
## 📚 Best Practices
|
371
|
+
|
372
|
+
1. **Optimize API Usage**
|
373
|
+
- Cache results for repeated analysis
|
374
|
+
- Use appropriate summary lengths
|
375
|
+
- Batch similar operations
|
376
|
+
|
377
|
+
2. **Security**
|
378
|
+
- Store API keys securely
|
379
|
+
- Don't log sensitive document content
|
380
|
+
- Use environment variables for configuration
|
381
|
+
|
382
|
+
3. **Performance**
|
383
|
+
- Process documents in parallel when possible
|
384
|
+
- Use specific queries rather than general analysis
|
385
|
+
- Consider document size when choosing AI operations
|
386
|
+
|
387
|
+
## 🎯 Next Steps
|
388
|
+
|
389
|
+
1. **Explore Advanced Features**: Try different AI models and temperature settings
|
390
|
+
2. **Integrate with Your Application**: Build AI-powered document workflows
|
391
|
+
3. **Customize for Your Domain**: Create domain-specific extraction categories
|
392
|
+
4. **Scale Your Usage**: Implement batch processing for large document sets
|
393
|
+
|
394
|
+
## 📞 Support
|
395
|
+
|
396
|
+
For issues with AI functionality:
|
397
|
+
1. Check your OpenAI API key and credits
|
398
|
+
2. Verify document format compatibility
|
399
|
+
3. Review error messages for specific guidance
|
400
|
+
4. Consult the main gem documentation for additional features
|
401
|
+
|
402
|
+
---
|
403
|
+
|
404
|
+
*This guide covers the AI capabilities of the Universal Document Processor gem. The AI features require an OpenAI API key and internet connection to function.*
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
# Changelog
|
2
|
+
|
3
|
+
All notable changes to this project will be documented in this file.
|
4
|
+
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
7
|
+
|
8
|
+
## [Unreleased]
|
9
|
+
|
10
|
+
## [1.0.0] - 2025-06-23
|
11
|
+
|
12
|
+
### Added
|
13
|
+
- Initial release of Universal Document Processor
|
14
|
+
- Support for multiple document formats (PDF, DOC, DOCX, XLS, XLSX, PPT, PPTX, TXT, HTML, XML, CSV, Images, Archives)
|
15
|
+
- Unified API for document processing across all formats
|
16
|
+
- Text extraction from all supported formats
|
17
|
+
- Metadata extraction (author, creation date, file size, etc.)
|
18
|
+
- Image extraction from documents
|
19
|
+
- Table detection and extraction
|
20
|
+
- Character validation and encoding support
|
21
|
+
- Multi-language support including Japanese (日本語)
|
22
|
+
- Invalid character detection and cleaning
|
23
|
+
- Japanese filename handling with proper encoding
|
24
|
+
- Archive processing (ZIP, RAR, 7Z)
|
25
|
+
- Document conversion capabilities
|
26
|
+
- Batch processing support
|
27
|
+
- Production-ready error handling and fallbacks
|
28
|
+
|
29
|
+
### AI Features Added
|
30
|
+
- **AI-Powered Document Analysis**: Comprehensive document analysis using OpenAI GPT models
|
31
|
+
- **Document Summarization**: Generate summaries of different lengths (short, medium, long)
|
32
|
+
- **Information Extraction**: Extract specific categories of information from documents
|
33
|
+
- **Document Translation**: Translate document content to any language
|
34
|
+
- **Document Classification**: Classify document type and purpose automatically
|
35
|
+
- **Insights Generation**: Generate AI-powered insights and recommendations
|
36
|
+
- **Action Items Extraction**: Extract actionable items and tasks from documents
|
37
|
+
- **Document Comparison**: Compare multiple documents intelligently
|
38
|
+
- **Interactive Chat**: Chat with documents using natural language
|
39
|
+
- **Conversation Memory**: Maintain conversation history for context
|
40
|
+
- **Custom AI Configuration**: Configurable AI models, temperature, and settings
|
41
|
+
|
42
|
+
### Features
|
43
|
+
- **Processor Classes**: Specialized processors for each document type
|
44
|
+
- **Japanese Support**: Full support for Japanese text and filenames
|
45
|
+
- **Character Validation**: Detect and clean invalid characters
|
46
|
+
- **File Detection**: Intelligent MIME type detection
|
47
|
+
- **Extensible Architecture**: Easy to add new processors and formats
|
48
|
+
- **Comprehensive Error Handling**: Graceful fallbacks and error recovery
|
49
|
+
- **Memory Efficient**: Optimized for large document processing
|
50
|
+
- **Thread Safe**: Safe for concurrent processing
|
51
|
+
|
52
|
+
### Dependencies
|
53
|
+
- activesupport (~> 7.0)
|
54
|
+
- marcel (~> 1.0) - MIME type detection
|
55
|
+
- nokogiri (~> 1.13) - XML/HTML parsing
|
56
|
+
- rubyzip (~> 2.3) - Archive processing
|
57
|
+
|
58
|
+
### Optional Dependencies
|
59
|
+
- pdf-reader (~> 2.0) - Enhanced PDF processing
|
60
|
+
- prawn (~> 2.4) - PDF generation
|
61
|
+
- docx (~> 0.8) - Word document processing
|
62
|
+
- roo (~> 2.8) - Excel/Spreadsheet processing
|
63
|
+
- mini_magick (~> 4.11) - Image processing
|
64
|
+
- yomu (~> 0.2) - Universal text extraction fallback
|
65
|
+
|
66
|
+
[Unreleased]: https://github.com/vikas-vpatil/universal_document_processor/compare/v1.0.0...HEAD
|
67
|
+
[1.0.0]: https://github.com/vikas-vpatil/universal_document_processor/releases/tag/v1.0.0
|