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 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.
@@ -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)