contaix 0.0.2__tar.gz
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.
- contaix-0.0.2/LICENSE +21 -0
- contaix-0.0.2/PKG-INFO +207 -0
- contaix-0.0.2/README.md +166 -0
- contaix-0.0.2/contaix/__init__.py +49 -0
- contaix-0.0.2/contaix/aggregation.py +86 -0
- contaix-0.0.2/contaix/code.py +252 -0
- contaix-0.0.2/contaix/markdown.py +890 -0
- contaix-0.0.2/contaix/urls.py +348 -0
- contaix-0.0.2/contaix/util.py +122 -0
- contaix-0.0.2/contaix.egg-info/PKG-INFO +207 -0
- contaix-0.0.2/contaix.egg-info/SOURCES.txt +16 -0
- contaix-0.0.2/contaix.egg-info/dependency_links.txt +1 -0
- contaix-0.0.2/contaix.egg-info/not-zip-safe +1 -0
- contaix-0.0.2/contaix.egg-info/requires.txt +34 -0
- contaix-0.0.2/contaix.egg-info/top_level.txt +1 -0
- contaix-0.0.2/setup.cfg +41 -0
- contaix-0.0.2/setup.py +3 -0
contaix-0.0.2/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) [year] [fullname]
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
contaix-0.0.2/PKG-INFO
ADDED
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: contaix
|
|
3
|
+
Version: 0.0.2
|
|
4
|
+
Summary: Tools to make contexts for AI
|
|
5
|
+
Home-page: https://github.com/thorwhalen/contaix
|
|
6
|
+
Author: Thor Whalen
|
|
7
|
+
License: mit
|
|
8
|
+
Platform: any
|
|
9
|
+
Description-Content-Type: text/markdown
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Requires-Dist: dol
|
|
12
|
+
Requires-Dist: lkj
|
|
13
|
+
Requires-Dist: pypdf
|
|
14
|
+
Requires-Dist: mammoth
|
|
15
|
+
Requires-Dist: pandas
|
|
16
|
+
Requires-Dist: pptx
|
|
17
|
+
Requires-Dist: html2text
|
|
18
|
+
Requires-Dist: nbconvert
|
|
19
|
+
Requires-Dist: nbformat
|
|
20
|
+
Provides-Extra: pdf
|
|
21
|
+
Requires-Dist: pypdf; extra == "pdf"
|
|
22
|
+
Provides-Extra: office
|
|
23
|
+
Requires-Dist: mammoth; extra == "office"
|
|
24
|
+
Requires-Dist: pandas; extra == "office"
|
|
25
|
+
Requires-Dist: pptx; extra == "office"
|
|
26
|
+
Provides-Extra: html
|
|
27
|
+
Requires-Dist: html2text; extra == "html"
|
|
28
|
+
Provides-Extra: jupyter
|
|
29
|
+
Requires-Dist: nbconvert; extra == "jupyter"
|
|
30
|
+
Requires-Dist: nbformat; extra == "jupyter"
|
|
31
|
+
Provides-Extra: all
|
|
32
|
+
Requires-Dist: pypdf; extra == "all"
|
|
33
|
+
Requires-Dist: mammoth; extra == "all"
|
|
34
|
+
Requires-Dist: pandas; extra == "all"
|
|
35
|
+
Requires-Dist: pptx; extra == "all"
|
|
36
|
+
Requires-Dist: html2text; extra == "all"
|
|
37
|
+
Requires-Dist: nbconvert; extra == "all"
|
|
38
|
+
Requires-Dist: nbformat; extra == "all"
|
|
39
|
+
Requires-Dist: python-magic; extra == "all"
|
|
40
|
+
Dynamic: license-file
|
|
41
|
+
|
|
42
|
+
# contaix
|
|
43
|
+
|
|
44
|
+
Tools to make contexts for AI
|
|
45
|
+
|
|
46
|
+
To install: ```pip install contaix```
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
# Markdown Conversion
|
|
50
|
+
|
|
51
|
+
This module provides tools for converting various file formats to Markdown. It supports common formats such as PDF, Word, Excel, PowerPoint, HTML, and Jupyter notebooks.
|
|
52
|
+
|
|
53
|
+
## Key Features
|
|
54
|
+
|
|
55
|
+
- Convert files to Markdown from bytes with format auto-detection
|
|
56
|
+
- Batch convert multiple files
|
|
57
|
+
- Customize output filenames and processing
|
|
58
|
+
- Extensible converter system
|
|
59
|
+
|
|
60
|
+
## Basic Usage
|
|
61
|
+
|
|
62
|
+
### Converting a Single File
|
|
63
|
+
|
|
64
|
+
The primary function `bytes_to_markdown` converts a file's bytes to Markdown text:
|
|
65
|
+
|
|
66
|
+
```python
|
|
67
|
+
from contaix import bytes_to_markdown
|
|
68
|
+
|
|
69
|
+
# Convert with explicit format
|
|
70
|
+
pdf_bytes = get_file_bytes('document.pdf')
|
|
71
|
+
markdown_text = bytes_to_markdown(pdf_bytes, "pdf")
|
|
72
|
+
|
|
73
|
+
# Or let the function detect the format from filename
|
|
74
|
+
markdown_text = bytes_to_markdown(file_bytes, input_format=None, key="document.docx")
|
|
75
|
+
|
|
76
|
+
# Or analyze the content to detect format (when no information is available)
|
|
77
|
+
markdown_text = bytes_to_markdown(
|
|
78
|
+
unknown_bytes,
|
|
79
|
+
input_format=None,
|
|
80
|
+
key=None,
|
|
81
|
+
try_bytes_detection=True
|
|
82
|
+
)
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### Converting Multiple Files
|
|
86
|
+
|
|
87
|
+
Use `bytes_store_to_markdown_store` to process multiple files at once:
|
|
88
|
+
|
|
89
|
+
```python
|
|
90
|
+
from contaix import bytes_store_to_markdown_store
|
|
91
|
+
from dol import Files
|
|
92
|
+
|
|
93
|
+
# Convert all files in a directory
|
|
94
|
+
src_files = Files('/path/to/documents')
|
|
95
|
+
target_store = {}
|
|
96
|
+
bytes_store_to_markdown_store(src_files, target_store)
|
|
97
|
+
|
|
98
|
+
# Now target_store contains {"file1.docx.md": "converted markdown...", ...}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## Advanced Usage
|
|
102
|
+
|
|
103
|
+
### Selective Conversion
|
|
104
|
+
|
|
105
|
+
If you only want to convert specific file types:
|
|
106
|
+
|
|
107
|
+
```python
|
|
108
|
+
# Filter to only include certain file types
|
|
109
|
+
filtered_files = {k: v for k, v in src_files.items()
|
|
110
|
+
if k.endswith('.docx') or k.endswith('.pdf')}
|
|
111
|
+
bytes_store_to_markdown_store(filtered_files, target_store)
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### Custom Output Naming
|
|
115
|
+
|
|
116
|
+
You can control how output filenames are generated:
|
|
117
|
+
|
|
118
|
+
```python
|
|
119
|
+
def custom_key_transform(key):
|
|
120
|
+
# Remove the extension and add "-markdown.md"
|
|
121
|
+
base_name = os.path.splitext(key)[0]
|
|
122
|
+
return f"{base_name}-markdown.md"
|
|
123
|
+
|
|
124
|
+
bytes_store_to_markdown_store(
|
|
125
|
+
src_files,
|
|
126
|
+
target_store,
|
|
127
|
+
old_to_new_key=custom_key_transform
|
|
128
|
+
)
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### Content Aggregation
|
|
132
|
+
|
|
133
|
+
After conversion, you might want to combine all the markdown into a single document:
|
|
134
|
+
|
|
135
|
+
```python
|
|
136
|
+
def aggregate_content(store):
|
|
137
|
+
"""Combine all markdown content into a single document with headers."""
|
|
138
|
+
result = "# Combined Markdown Document\n\n"
|
|
139
|
+
|
|
140
|
+
for filename, content in store.items():
|
|
141
|
+
result += f"## {filename}\n\n{content}\n\n---\n\n"
|
|
142
|
+
|
|
143
|
+
return result
|
|
144
|
+
|
|
145
|
+
combined_markdown = bytes_store_to_markdown_store(
|
|
146
|
+
src_files,
|
|
147
|
+
{},
|
|
148
|
+
target_store_egress=aggregate_content
|
|
149
|
+
)
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### Custom Converters
|
|
153
|
+
|
|
154
|
+
You can extend the system with your own converters:
|
|
155
|
+
|
|
156
|
+
```python
|
|
157
|
+
def custom_txt_converter(b):
|
|
158
|
+
"""A custom converter for text files."""
|
|
159
|
+
text = b.decode('utf-8', errors='ignore')
|
|
160
|
+
lines = text.split('\n')
|
|
161
|
+
result = f"# Custom Converted Text File\n\n"
|
|
162
|
+
|
|
163
|
+
for line in lines:
|
|
164
|
+
if line.strip():
|
|
165
|
+
result += f"> {line}\n"
|
|
166
|
+
|
|
167
|
+
return result
|
|
168
|
+
|
|
169
|
+
custom_converters = {"txt": custom_txt_converter}
|
|
170
|
+
|
|
171
|
+
bytes_store_to_markdown_store(
|
|
172
|
+
src_files,
|
|
173
|
+
target_store,
|
|
174
|
+
converters=custom_converters
|
|
175
|
+
)
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
## Format Detection Logic
|
|
179
|
+
|
|
180
|
+
The `bytes_to_markdown` function employs a prioritized strategy to find the right converter:
|
|
181
|
+
|
|
182
|
+
1. **Explicit Format**: If you provide `input_format`, it uses that directly
|
|
183
|
+
2. **Filename-Based**: If `input_format` is None but `key` (filename) is provided, it extracts the format from the extension
|
|
184
|
+
3. **Content-Based**: If `try_bytes_detection` is True, it analyzes the bytes to determine the format
|
|
185
|
+
4. **Fallback**: If no converter is found through the above methods, it uses the fallback converter
|
|
186
|
+
|
|
187
|
+
This flexible approach means you can control how formats are detected based on your specific needs.
|
|
188
|
+
|
|
189
|
+
## Performance Considerations
|
|
190
|
+
|
|
191
|
+
- If you know the file format in advance, specifying `input_format` will be faster
|
|
192
|
+
- To disable content-based detection (for better performance), set `try_bytes_detection=False`
|
|
193
|
+
- When processing large batches, filtering to only include supported formats can improve efficiency
|
|
194
|
+
|
|
195
|
+
## Supported Formats
|
|
196
|
+
|
|
197
|
+
The module currently supports the following formats:
|
|
198
|
+
|
|
199
|
+
- PDF (`.pdf`)
|
|
200
|
+
- Microsoft Word (`.docx`, `.doc`)
|
|
201
|
+
- Microsoft Excel (`.xlsx`, `.xls`)
|
|
202
|
+
- Microsoft PowerPoint (`.pptx`, `.ppt`)
|
|
203
|
+
- HTML (`.html`)
|
|
204
|
+
- Jupyter Notebooks (`.ipynb`)
|
|
205
|
+
- Plain text (`.txt`, `.md`)
|
|
206
|
+
|
|
207
|
+
Additional formats can be supported by adding custom converters.
|
contaix-0.0.2/README.md
ADDED
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
# contaix
|
|
2
|
+
|
|
3
|
+
Tools to make contexts for AI
|
|
4
|
+
|
|
5
|
+
To install: ```pip install contaix```
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
# Markdown Conversion
|
|
9
|
+
|
|
10
|
+
This module provides tools for converting various file formats to Markdown. It supports common formats such as PDF, Word, Excel, PowerPoint, HTML, and Jupyter notebooks.
|
|
11
|
+
|
|
12
|
+
## Key Features
|
|
13
|
+
|
|
14
|
+
- Convert files to Markdown from bytes with format auto-detection
|
|
15
|
+
- Batch convert multiple files
|
|
16
|
+
- Customize output filenames and processing
|
|
17
|
+
- Extensible converter system
|
|
18
|
+
|
|
19
|
+
## Basic Usage
|
|
20
|
+
|
|
21
|
+
### Converting a Single File
|
|
22
|
+
|
|
23
|
+
The primary function `bytes_to_markdown` converts a file's bytes to Markdown text:
|
|
24
|
+
|
|
25
|
+
```python
|
|
26
|
+
from contaix import bytes_to_markdown
|
|
27
|
+
|
|
28
|
+
# Convert with explicit format
|
|
29
|
+
pdf_bytes = get_file_bytes('document.pdf')
|
|
30
|
+
markdown_text = bytes_to_markdown(pdf_bytes, "pdf")
|
|
31
|
+
|
|
32
|
+
# Or let the function detect the format from filename
|
|
33
|
+
markdown_text = bytes_to_markdown(file_bytes, input_format=None, key="document.docx")
|
|
34
|
+
|
|
35
|
+
# Or analyze the content to detect format (when no information is available)
|
|
36
|
+
markdown_text = bytes_to_markdown(
|
|
37
|
+
unknown_bytes,
|
|
38
|
+
input_format=None,
|
|
39
|
+
key=None,
|
|
40
|
+
try_bytes_detection=True
|
|
41
|
+
)
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### Converting Multiple Files
|
|
45
|
+
|
|
46
|
+
Use `bytes_store_to_markdown_store` to process multiple files at once:
|
|
47
|
+
|
|
48
|
+
```python
|
|
49
|
+
from contaix import bytes_store_to_markdown_store
|
|
50
|
+
from dol import Files
|
|
51
|
+
|
|
52
|
+
# Convert all files in a directory
|
|
53
|
+
src_files = Files('/path/to/documents')
|
|
54
|
+
target_store = {}
|
|
55
|
+
bytes_store_to_markdown_store(src_files, target_store)
|
|
56
|
+
|
|
57
|
+
# Now target_store contains {"file1.docx.md": "converted markdown...", ...}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Advanced Usage
|
|
61
|
+
|
|
62
|
+
### Selective Conversion
|
|
63
|
+
|
|
64
|
+
If you only want to convert specific file types:
|
|
65
|
+
|
|
66
|
+
```python
|
|
67
|
+
# Filter to only include certain file types
|
|
68
|
+
filtered_files = {k: v for k, v in src_files.items()
|
|
69
|
+
if k.endswith('.docx') or k.endswith('.pdf')}
|
|
70
|
+
bytes_store_to_markdown_store(filtered_files, target_store)
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### Custom Output Naming
|
|
74
|
+
|
|
75
|
+
You can control how output filenames are generated:
|
|
76
|
+
|
|
77
|
+
```python
|
|
78
|
+
def custom_key_transform(key):
|
|
79
|
+
# Remove the extension and add "-markdown.md"
|
|
80
|
+
base_name = os.path.splitext(key)[0]
|
|
81
|
+
return f"{base_name}-markdown.md"
|
|
82
|
+
|
|
83
|
+
bytes_store_to_markdown_store(
|
|
84
|
+
src_files,
|
|
85
|
+
target_store,
|
|
86
|
+
old_to_new_key=custom_key_transform
|
|
87
|
+
)
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### Content Aggregation
|
|
91
|
+
|
|
92
|
+
After conversion, you might want to combine all the markdown into a single document:
|
|
93
|
+
|
|
94
|
+
```python
|
|
95
|
+
def aggregate_content(store):
|
|
96
|
+
"""Combine all markdown content into a single document with headers."""
|
|
97
|
+
result = "# Combined Markdown Document\n\n"
|
|
98
|
+
|
|
99
|
+
for filename, content in store.items():
|
|
100
|
+
result += f"## {filename}\n\n{content}\n\n---\n\n"
|
|
101
|
+
|
|
102
|
+
return result
|
|
103
|
+
|
|
104
|
+
combined_markdown = bytes_store_to_markdown_store(
|
|
105
|
+
src_files,
|
|
106
|
+
{},
|
|
107
|
+
target_store_egress=aggregate_content
|
|
108
|
+
)
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### Custom Converters
|
|
112
|
+
|
|
113
|
+
You can extend the system with your own converters:
|
|
114
|
+
|
|
115
|
+
```python
|
|
116
|
+
def custom_txt_converter(b):
|
|
117
|
+
"""A custom converter for text files."""
|
|
118
|
+
text = b.decode('utf-8', errors='ignore')
|
|
119
|
+
lines = text.split('\n')
|
|
120
|
+
result = f"# Custom Converted Text File\n\n"
|
|
121
|
+
|
|
122
|
+
for line in lines:
|
|
123
|
+
if line.strip():
|
|
124
|
+
result += f"> {line}\n"
|
|
125
|
+
|
|
126
|
+
return result
|
|
127
|
+
|
|
128
|
+
custom_converters = {"txt": custom_txt_converter}
|
|
129
|
+
|
|
130
|
+
bytes_store_to_markdown_store(
|
|
131
|
+
src_files,
|
|
132
|
+
target_store,
|
|
133
|
+
converters=custom_converters
|
|
134
|
+
)
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
## Format Detection Logic
|
|
138
|
+
|
|
139
|
+
The `bytes_to_markdown` function employs a prioritized strategy to find the right converter:
|
|
140
|
+
|
|
141
|
+
1. **Explicit Format**: If you provide `input_format`, it uses that directly
|
|
142
|
+
2. **Filename-Based**: If `input_format` is None but `key` (filename) is provided, it extracts the format from the extension
|
|
143
|
+
3. **Content-Based**: If `try_bytes_detection` is True, it analyzes the bytes to determine the format
|
|
144
|
+
4. **Fallback**: If no converter is found through the above methods, it uses the fallback converter
|
|
145
|
+
|
|
146
|
+
This flexible approach means you can control how formats are detected based on your specific needs.
|
|
147
|
+
|
|
148
|
+
## Performance Considerations
|
|
149
|
+
|
|
150
|
+
- If you know the file format in advance, specifying `input_format` will be faster
|
|
151
|
+
- To disable content-based detection (for better performance), set `try_bytes_detection=False`
|
|
152
|
+
- When processing large batches, filtering to only include supported formats can improve efficiency
|
|
153
|
+
|
|
154
|
+
## Supported Formats
|
|
155
|
+
|
|
156
|
+
The module currently supports the following formats:
|
|
157
|
+
|
|
158
|
+
- PDF (`.pdf`)
|
|
159
|
+
- Microsoft Word (`.docx`, `.doc`)
|
|
160
|
+
- Microsoft Excel (`.xlsx`, `.xls`)
|
|
161
|
+
- Microsoft PowerPoint (`.pptx`, `.ppt`)
|
|
162
|
+
- HTML (`.html`)
|
|
163
|
+
- Jupyter Notebooks (`.ipynb`)
|
|
164
|
+
- Plain text (`.txt`, `.md`)
|
|
165
|
+
|
|
166
|
+
Additional formats can be supported by adding custom converters.
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Tools for working with AI contexts
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
"""
|
|
6
|
+
Tools to make contexts (knowledge bases for AI agents)
|
|
7
|
+
|
|
8
|
+
Examples:
|
|
9
|
+
|
|
10
|
+
Download all articles from a markdown string and save them as PDF files:
|
|
11
|
+
|
|
12
|
+
>>> download_articles(md_string) # doctest: +SKIP
|
|
13
|
+
|
|
14
|
+
Verify URLs in a markdown string by checking their status codes
|
|
15
|
+
(useful when trying to verify if AI hallucinated the urls)
|
|
16
|
+
x`
|
|
17
|
+
>>> verify_urls(md_string) # doctest: +SKIP
|
|
18
|
+
|
|
19
|
+
Make an md file with all the code in a directory:
|
|
20
|
+
|
|
21
|
+
>>> md_string = code_aggregate(package_or_folder_or_github_url) # doctest: +SKIP
|
|
22
|
+
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
# --------------------------------------------------------------------------------------
|
|
26
|
+
# General utilities
|
|
27
|
+
|
|
28
|
+
from contaix.util import (
|
|
29
|
+
identity,
|
|
30
|
+
fullpath,
|
|
31
|
+
url_to_contents,
|
|
32
|
+
save_to_file_and_return_file,
|
|
33
|
+
)
|
|
34
|
+
from contaix.aggregation import aggregate_store
|
|
35
|
+
from contaix.code import code_aggregate, PackageCodeContexts
|
|
36
|
+
from contaix.urls import (
|
|
37
|
+
extract_urls,
|
|
38
|
+
verify_urls,
|
|
39
|
+
download_articles,
|
|
40
|
+
download_articles_by_section,
|
|
41
|
+
)
|
|
42
|
+
from contaix.markdown import (
|
|
43
|
+
bytes_to_markdown,
|
|
44
|
+
bytes_store_to_markdown_store,
|
|
45
|
+
dflt_converters,
|
|
46
|
+
add_dflt_converter,
|
|
47
|
+
truncate_text,
|
|
48
|
+
notebook_to_markdown,
|
|
49
|
+
)
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"""Tools for aggregating contexts"""
|
|
2
|
+
|
|
3
|
+
from typing import Optional, Mapping, Iterable, Union, Callable
|
|
4
|
+
from dol import TextFiles, filt_iter, wrap_kvs, Pipe, store_aggregate
|
|
5
|
+
from contaix.util import identity
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def aggregate_store(
|
|
9
|
+
store: Mapping,
|
|
10
|
+
*,
|
|
11
|
+
min_number_of_duplicated_lines: Optional[int] = None,
|
|
12
|
+
max_num_characters: Optional[int] = None,
|
|
13
|
+
exclude: Optional[Iterable] = None,
|
|
14
|
+
chk_size=None,
|
|
15
|
+
egress: Optional[Union[str, Callable]] = None,
|
|
16
|
+
**store_aggregate_kwargs,
|
|
17
|
+
):
|
|
18
|
+
"""
|
|
19
|
+
Aggregates and processes text files from a store.
|
|
20
|
+
|
|
21
|
+
Parameters:
|
|
22
|
+
store: The source store (e.g., TextFiles instance)
|
|
23
|
+
min_number_of_duplicated_lines (int): If not None, minimum block size for deduplication.
|
|
24
|
+
max_num_characters (int): Maximum number of characters per file.
|
|
25
|
+
exclude (set): Set of filenames to exclude.
|
|
26
|
+
chk_size (int): Chunk size for aggregation. If None, won't chunk
|
|
27
|
+
egress (str or callable): Template for output filenames or function to call on each chunk
|
|
28
|
+
**store_aggregate_kwargs: Additional keyword arguments to pass to store_aggregate.
|
|
29
|
+
"""
|
|
30
|
+
if exclude is None:
|
|
31
|
+
exclude = set()
|
|
32
|
+
|
|
33
|
+
wrappers = []
|
|
34
|
+
|
|
35
|
+
if exclude is not None:
|
|
36
|
+
wrappers.append(filt_iter(filt=lambda x: x not in exclude))
|
|
37
|
+
|
|
38
|
+
if min_number_of_duplicated_lines is not None:
|
|
39
|
+
from hg import deduplicate_string_lines
|
|
40
|
+
|
|
41
|
+
remove_duplicate_lines = wrap_kvs(
|
|
42
|
+
value_decoder=lambda v: deduplicate_string_lines(
|
|
43
|
+
v,
|
|
44
|
+
min_block_size=min_number_of_duplicated_lines,
|
|
45
|
+
return_removed_blocks=False,
|
|
46
|
+
)
|
|
47
|
+
)
|
|
48
|
+
else:
|
|
49
|
+
remove_duplicate_lines = identity
|
|
50
|
+
|
|
51
|
+
if max_num_characters is not None:
|
|
52
|
+
wrappers.append(wrap_kvs(value_decoder=lambda v: v[:max_num_characters]))
|
|
53
|
+
|
|
54
|
+
capped_num_characters = wrap_kvs(value_decoder=lambda v: v[:max_num_characters])
|
|
55
|
+
|
|
56
|
+
if len(wrappers) > 0:
|
|
57
|
+
store_wrap = Pipe(
|
|
58
|
+
filt_iter(filt=lambda x: x.endswith(".md") and x not in exclude),
|
|
59
|
+
remove_duplicate_lines,
|
|
60
|
+
capped_num_characters,
|
|
61
|
+
)
|
|
62
|
+
else:
|
|
63
|
+
store_wrap = identity
|
|
64
|
+
|
|
65
|
+
wrapped_store = store_wrap(store)
|
|
66
|
+
|
|
67
|
+
if isinstance(egress, str):
|
|
68
|
+
output_template = egress
|
|
69
|
+
egress = output_template.format
|
|
70
|
+
else:
|
|
71
|
+
assert egress is None or callable(
|
|
72
|
+
egress
|
|
73
|
+
), "egress must be None, str, or callable"
|
|
74
|
+
|
|
75
|
+
if isinstance(chk_size, int):
|
|
76
|
+
from lkj.chunking import chunk_iterable
|
|
77
|
+
|
|
78
|
+
chunks = chunk_iterable(wrapped_store, chk_size)
|
|
79
|
+
if egress is not None:
|
|
80
|
+
egress = "store_aggregate_{:02.0f}.md"
|
|
81
|
+
for i, sub_store in enumerate(chunks, 1):
|
|
82
|
+
store_aggregate(sub_store, egress=egress(i), **store_aggregate_kwargs)
|
|
83
|
+
else:
|
|
84
|
+
if egress is None:
|
|
85
|
+
egress = identity
|
|
86
|
+
return store_aggregate(wrapped_store, egress=egress, **store_aggregate_kwargs)
|