auto md and excel module¶
General auto-generation module for converting markdown and Excel to Word documents.
AutoReportGenerator
¶
Convert markdown files and Excel tables to Word document sections with proper formatting.
Source code in autorpt/gen_auto.py
class AutoReportGenerator:
"""Convert markdown files and Excel tables to Word document sections with proper formatting."""
def __init__(self, document=None, content_folder="reports"):
"""Initialize the generator with an optional Word document.
Args:
document: Existing Word document object, or None to create new one
content_folder (str): Folder to scan for additional content files
"""
self.document = document if document else Document()
self.content_folder = Path(content_folder)
def discover_content_files(self, include_patterns=None, exclude_patterns=None):
"""Automatically discover markdown and Excel files in the content folder.
Args:
include_patterns (list): List of glob patterns to include (default: ['*.md', '*.xlsx', '*.xls'])
exclude_patterns (list): List of patterns to exclude (default: ['*report*.docx'])
Returns:
dict: Dictionary with 'markdown' and 'excel' file lists
"""
if include_patterns is None:
include_patterns = ['*.md', '*.markdown', '*.xlsx', '*.xls']
if exclude_patterns is None:
exclude_patterns = ['*report*.docx', '*report*.pdf']
discovered = {'markdown': [], 'excel': [], 'all': []}
if not self.content_folder.exists():
print(f"📁 Content folder '{self.content_folder}' not found")
return discovered
try:
# Find all matching files
all_files = []
for pattern in include_patterns:
all_files.extend(self.content_folder.glob(pattern))
# Filter out excluded patterns
filtered_files = []
for file_path in all_files:
exclude_file = False
for exclude_pattern in exclude_patterns:
if file_path.match(exclude_pattern):
exclude_file = True
break
if not exclude_file:
filtered_files.append(file_path)
# Categorize files
for file_path in filtered_files:
if file_path.suffix.lower() in ['.md', '.markdown']:
discovered['markdown'].append(file_path)
elif file_path.suffix.lower() in ['.xlsx', '.xls']:
discovered['excel'].append(file_path)
discovered['all'].append(file_path)
# Sort files by name for consistent ordering
discovered['markdown'].sort(key=lambda x: x.name)
discovered['excel'].sort(key=lambda x: x.name)
discovered['all'].sort(key=lambda x: x.name)
if discovered['all']:
print(
f"📂 Discovered {len(discovered['all'])} content files in '{self.content_folder}':")
for file_path in discovered['all']:
print(f" 📄 {file_path.name}")
else:
print(
f"📂 No additional content files found in '{self.content_folder}'")
except (OSError, PermissionError) as e:
print(f"❌ Error discovering content files: {e}")
return discovered
def parse_markdown_file(self, markdown_file_path):
"""Parse a markdown file and extract structured content.
Args:
markdown_file_path (str or Path): Path to the markdown file
Returns:
list: List of content blocks with headers and content
"""
markdown_path = Path(markdown_file_path)
if not markdown_path.exists():
print(f"Warning: Markdown file {markdown_path} not found")
return []
try:
with open(markdown_path, 'r', encoding='utf-8') as f:
content = f.read()
except (FileNotFoundError, PermissionError, UnicodeDecodeError) as e:
print(f"Error reading {markdown_path}: {e}")
return []
return self._parse_markdown_content(content)
def parse_excel_file(self, excel_file_path, sheet_name=None, table_title=None):
"""Parse an Excel file and extract table data.
Args:
excel_file_path (str or Path): Path to the Excel file
sheet_name (str): Optional sheet name to read (default: first sheet)
table_title (str): Optional title for the table
Returns:
dict: Dictionary with table data and metadata
"""
excel_path = Path(excel_file_path)
if not excel_path.exists():
print(f"Warning: Excel file {excel_path} not found")
return None
try:
# Read Excel file
if sheet_name:
data = pd.read_excel(excel_path, sheet_name=sheet_name)
else:
data = pd.read_excel(excel_path)
# Get sheet info for title if not provided
if not table_title:
if sheet_name:
table_title = f"Table: {sheet_name}"
else:
table_title = f"Table: {excel_path.stem}"
return {
'data': data,
'title': table_title,
'file_path': excel_path,
'sheet_name': sheet_name,
'columns': list(data.columns),
'rows': len(data)
}
except (FileNotFoundError, PermissionError, ValueError, ImportError) as e:
print(f"Error reading Excel file {excel_path}: {e}")
return None
def _parse_markdown_content(self, content):
"""Parse markdown content into structured blocks.
Args:
content (str): Raw markdown content
Returns:
list: List of dictionaries with 'type', 'level', 'text', and 'content'
"""
blocks = []
lines = content.split('\n')
current_section = None
current_content = []
for line in lines:
# Check for headers (# ## ### etc.)
header_match = re.match(r'^(#{1,6})\s+(.+)', line.strip())
if header_match:
# Save previous section if exists
if current_section is not None:
current_section['content'] = '\n'.join(
current_content).strip()
blocks.append(current_section)
# Start new section
level = len(header_match.group(1)) # Number of # characters
title = header_match.group(2).strip()
current_section = {
'type': 'header',
'level': level,
'text': title,
'content': ''
}
current_content = []
else:
# Add line to current content
current_content.append(line)
# Save last section
if current_section:
current_section['content'] = '\n'.join(current_content).strip()
blocks.append(current_section)
# If no headers found, treat entire content as one block
if not blocks and content.strip():
blocks.append({
'type': 'content',
'level': 0,
'text': '',
'content': content.strip()
})
return blocks
def add_markdown_to_document(self, markdown_file_path, start_header_level=1):
"""Add markdown content to the Word document with proper formatting.
Args:
markdown_file_path (str or Path): Path to the markdown file
start_header_level (int): Starting header level for Word document (1-9)
Returns:
bool: True if successful, False otherwise
"""
blocks = self.parse_markdown_file(markdown_file_path)
if not blocks:
return False
for block in blocks:
if block['type'] == 'header':
# Add header to document
word_level = min(start_header_level + block['level'] - 1, 9)
self.document.add_heading(block['text'], level=word_level)
# Add content if any
if block['content'].strip():
self._add_formatted_content(block['content'])
else:
# Add content without header
if block['content'].strip():
self._add_formatted_content(block['content'])
return True
def add_excel_table_to_document(self, excel_file_path, sheet_name=None, table_title=None,
include_header=True, start_header_level=1):
"""Add Excel table to the Word document with proper formatting.
Args:
excel_file_path (str or Path): Path to the Excel file
sheet_name (str): Optional sheet name to read
table_title (str): Optional title for the table
include_header (bool): Whether to add a header before the table
start_header_level (int): Header level for the table title
Returns:
bool: True if successful, False otherwise
"""
excel_data = self.parse_excel_file(
excel_file_path, sheet_name, table_title)
if not excel_data:
return False
data = excel_data['data']
title = excel_data['title']
# Add header if requested
if include_header:
self.document.add_heading(title, level=start_header_level)
# Add summary paragraph
summary_text = f"Data summary: {excel_data['rows']} rows, {len(excel_data['columns'])} columns"
self.document.add_paragraph(summary_text)
# Create table
table = self.document.add_table(rows=1, cols=len(data.columns))
table.style = 'Table Grid' # Use a clean table style
# Add header row
hdr_cells = table.rows[0].cells
for i, column_name in enumerate(data.columns):
hdr_cells[i].text = str(column_name)
# Make header bold
for paragraph in hdr_cells[i].paragraphs:
for run in paragraph.runs:
run.bold = True
# Add data rows
for _, row_data in data.iterrows():
row_cells = table.add_row().cells
for j, cell_value in enumerate(row_data):
# Format cell value
if pd.api.types.is_numeric_dtype(type(cell_value)) and pd.notna(cell_value):
# Format numbers with appropriate precision
if isinstance(cell_value, float):
if cell_value == int(cell_value):
row_cells[j].text = f"{int(cell_value):,}"
else:
row_cells[j].text = f"{cell_value:,.2f}"
else:
row_cells[j].text = f"{cell_value:,}"
else:
row_cells[j].text = str(
cell_value) if pd.notna(cell_value) else ""
# Right-align numeric columns
if pd.api.types.is_numeric_dtype(type(cell_value)):
for paragraph in row_cells[j].paragraphs:
paragraph.alignment = WD_ALIGN_PARAGRAPH.RIGHT
print(f"✅ Added Excel table: {title}")
return True
def add_mixed_content_to_document(self, content_files, start_header_level=1):
"""Add multiple markdown and Excel files to the document.
Args:
content_files (list): List of file paths or dictionaries with file info
start_header_level (int): Starting header level
Returns:
dict: Results summary with success/failure counts
"""
results = {'success': 0, 'failed': 0, 'files': []}
for item in content_files:
if isinstance(item, str):
file_path = Path(item)
options = {}
else:
file_path = Path(item['file'])
options = item.get('options', {})
try:
if file_path.suffix.lower() in ['.md', '.markdown']:
# Handle markdown file
success = self.add_markdown_to_document(
file_path,
options.get('start_header_level', start_header_level)
)
elif file_path.suffix.lower() in ['.xlsx', '.xls']:
# Handle Excel file
success = self.add_excel_table_to_document(
file_path,
sheet_name=options.get('sheet_name'),
table_title=options.get('table_title'),
include_header=options.get('include_header', True),
start_header_level=options.get(
'start_header_level', start_header_level)
)
else:
print(f"⚠️ Unsupported file type: {file_path.suffix}")
success = False
if success:
results['success'] += 1
results['files'].append(
{'file': str(file_path), 'status': 'success'})
else:
results['failed'] += 1
results['files'].append(
{'file': str(file_path), 'status': 'failed'})
except (FileNotFoundError, PermissionError, ValueError) as e:
print(f"❌ Error processing {file_path}: {e}")
results['failed'] += 1
results['files'].append(
{'file': str(file_path), 'status': 'error', 'error': str(e)})
return results
def add_all_content_from_folder(self, start_header_level=1, include_patterns=None, exclude_patterns=None):
"""Automatically discover and add all content files from the content folder.
Args:
start_header_level (int): Starting header level
include_patterns (list): List of glob patterns to include
exclude_patterns (list): List of patterns to exclude
Returns:
dict: Results summary with success/failure counts
"""
discovered = self.discover_content_files(
include_patterns, exclude_patterns)
if not discovered['all']:
return {'success': 0, 'failed': 0, 'files': [], 'discovered': 0}
# Convert Path objects to strings for add_mixed_content_to_document
file_paths = [str(file_path) for file_path in discovered['all']]
results = self.add_mixed_content_to_document(
file_paths, start_header_level)
results['discovered'] = len(discovered['all'])
return results
def _add_formatted_content(self, content):
"""Add formatted content to the document with markdown-style formatting.
Args:
content (str): Content to add with markdown formatting
"""
# Split content into paragraphs
paragraphs = content.split('\n\n')
for para in paragraphs:
para = para.strip()
if not para:
continue
# Handle different types of content
if para.startswith('- ') or para.startswith('* '):
self._add_bullet_list(para)
elif para.startswith('1. ') or re.match(r'^\d+\.\s', para):
self._add_numbered_list(para)
elif para.startswith('> '):
self._add_blockquote(para)
else:
self._add_regular_paragraph(para)
def _add_bullet_list(self, content):
"""Add bullet list items to the document."""
lines = content.split('\n')
for line in lines:
line = line.strip()
if line.startswith('- ') or line.startswith('* '):
bullet_text = line[2:].strip()
if bullet_text:
self.document.add_paragraph(
bullet_text, style='List Bullet')
def _add_numbered_list(self, content):
"""Add numbered list items to the document."""
lines = content.split('\n')
for line in lines:
line = line.strip()
if re.match(r'^\d+\.\s', line):
# Remove the number and period
numbered_text = re.sub(r'^\d+\.\s', '', line)
if numbered_text:
self.document.add_paragraph(
numbered_text, style='List Number')
def _add_blockquote(self, content):
"""Add blockquote content to the document."""
lines = content.split('\n')
for line in lines:
line = line.strip()
if line.startswith('> '):
quote_text = line[2:].strip()
if quote_text:
para = self.document.add_paragraph(quote_text)
# Style as italic for blockquotes
for run in para.runs:
run.italic = True
def _add_regular_paragraph(self, content):
"""Add regular paragraph with basic markdown formatting."""
# Handle basic markdown formatting
content = self._apply_basic_formatting(content)
# Split by lines for multi-line paragraphs
lines = content.split('\n')
for line in lines:
line = line.strip()
if line:
self.document.add_paragraph(line)
def _apply_basic_formatting(self, text):
"""Apply basic markdown formatting (bold, italic) to text.
Note: This is a simplified implementation. Word formatting
would require more complex handling of runs.
Args:
text (str): Text with markdown formatting
Returns:
str: Text with formatting markers removed (for now)
"""
# For now, just remove markdown formatting markers
# In a more advanced implementation, we'd convert these to Word formatting
text = re.sub(r'\*\*(.*?)\*\*', r'\1', text) # Bold
text = re.sub(r'\*(.*?)\*', r'\1', text) # Italic
text = re.sub(r'`(.*?)`', r'\1', text) # Code
return text
def generate_auto_report(self, content_files, output_path, document_title=None):
"""Generate a complete Word document from multiple content files.
Args:
content_files (list): List of markdown and Excel files to include
output_path (str or Path): Output path for the Word document
document_title (str): Optional title for the document
Returns:
bool: True if successful, False otherwise
"""
# Create new document
self.document = Document()
# Add document title if provided
if document_title:
self.document.add_heading(document_title, level=0)
# Process all content files
results = self.add_mixed_content_to_document(content_files)
# Save document
try:
self.document.save(output_path)
print(f"✅ Auto-generated report saved: {output_path}")
print(
f"📊 Processed {results['success']} files successfully, {results['failed']} failed")
return True
except (OSError, PermissionError) as e:
print(f"❌ Error saving document: {e}")
return False
__init__(self, document=None, content_folder='reports')
special
¶
Initialize the generator with an optional Word document.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
document |
Existing Word document object, or None to create new one |
None |
|
content_folder |
str |
Folder to scan for additional content files |
'reports' |
Source code in autorpt/gen_auto.py
def __init__(self, document=None, content_folder="reports"):
"""Initialize the generator with an optional Word document.
Args:
document: Existing Word document object, or None to create new one
content_folder (str): Folder to scan for additional content files
"""
self.document = document if document else Document()
self.content_folder = Path(content_folder)
add_all_content_from_folder(self, start_header_level=1, include_patterns=None, exclude_patterns=None)
¶
Automatically discover and add all content files from the content folder.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
start_header_level |
int |
Starting header level |
1 |
include_patterns |
list |
List of glob patterns to include |
None |
exclude_patterns |
list |
List of patterns to exclude |
None |
Returns:
| Type | Description |
|---|---|
dict |
Results summary with success/failure counts |
Source code in autorpt/gen_auto.py
def add_all_content_from_folder(self, start_header_level=1, include_patterns=None, exclude_patterns=None):
"""Automatically discover and add all content files from the content folder.
Args:
start_header_level (int): Starting header level
include_patterns (list): List of glob patterns to include
exclude_patterns (list): List of patterns to exclude
Returns:
dict: Results summary with success/failure counts
"""
discovered = self.discover_content_files(
include_patterns, exclude_patterns)
if not discovered['all']:
return {'success': 0, 'failed': 0, 'files': [], 'discovered': 0}
# Convert Path objects to strings for add_mixed_content_to_document
file_paths = [str(file_path) for file_path in discovered['all']]
results = self.add_mixed_content_to_document(
file_paths, start_header_level)
results['discovered'] = len(discovered['all'])
return results
add_excel_table_to_document(self, excel_file_path, sheet_name=None, table_title=None, include_header=True, start_header_level=1)
¶
Add Excel table to the Word document with proper formatting.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
excel_file_path |
str or Path |
Path to the Excel file |
required |
sheet_name |
str |
Optional sheet name to read |
None |
table_title |
str |
Optional title for the table |
None |
include_header |
bool |
Whether to add a header before the table |
True |
start_header_level |
int |
Header level for the table title |
1 |
Returns:
| Type | Description |
|---|---|
bool |
True if successful, False otherwise |
Source code in autorpt/gen_auto.py
def add_excel_table_to_document(self, excel_file_path, sheet_name=None, table_title=None,
include_header=True, start_header_level=1):
"""Add Excel table to the Word document with proper formatting.
Args:
excel_file_path (str or Path): Path to the Excel file
sheet_name (str): Optional sheet name to read
table_title (str): Optional title for the table
include_header (bool): Whether to add a header before the table
start_header_level (int): Header level for the table title
Returns:
bool: True if successful, False otherwise
"""
excel_data = self.parse_excel_file(
excel_file_path, sheet_name, table_title)
if not excel_data:
return False
data = excel_data['data']
title = excel_data['title']
# Add header if requested
if include_header:
self.document.add_heading(title, level=start_header_level)
# Add summary paragraph
summary_text = f"Data summary: {excel_data['rows']} rows, {len(excel_data['columns'])} columns"
self.document.add_paragraph(summary_text)
# Create table
table = self.document.add_table(rows=1, cols=len(data.columns))
table.style = 'Table Grid' # Use a clean table style
# Add header row
hdr_cells = table.rows[0].cells
for i, column_name in enumerate(data.columns):
hdr_cells[i].text = str(column_name)
# Make header bold
for paragraph in hdr_cells[i].paragraphs:
for run in paragraph.runs:
run.bold = True
# Add data rows
for _, row_data in data.iterrows():
row_cells = table.add_row().cells
for j, cell_value in enumerate(row_data):
# Format cell value
if pd.api.types.is_numeric_dtype(type(cell_value)) and pd.notna(cell_value):
# Format numbers with appropriate precision
if isinstance(cell_value, float):
if cell_value == int(cell_value):
row_cells[j].text = f"{int(cell_value):,}"
else:
row_cells[j].text = f"{cell_value:,.2f}"
else:
row_cells[j].text = f"{cell_value:,}"
else:
row_cells[j].text = str(
cell_value) if pd.notna(cell_value) else ""
# Right-align numeric columns
if pd.api.types.is_numeric_dtype(type(cell_value)):
for paragraph in row_cells[j].paragraphs:
paragraph.alignment = WD_ALIGN_PARAGRAPH.RIGHT
print(f"✅ Added Excel table: {title}")
return True
add_markdown_to_document(self, markdown_file_path, start_header_level=1)
¶
Add markdown content to the Word document with proper formatting.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
markdown_file_path |
str or Path |
Path to the markdown file |
required |
start_header_level |
int |
Starting header level for Word document (1-9) |
1 |
Returns:
| Type | Description |
|---|---|
bool |
True if successful, False otherwise |
Source code in autorpt/gen_auto.py
def add_markdown_to_document(self, markdown_file_path, start_header_level=1):
"""Add markdown content to the Word document with proper formatting.
Args:
markdown_file_path (str or Path): Path to the markdown file
start_header_level (int): Starting header level for Word document (1-9)
Returns:
bool: True if successful, False otherwise
"""
blocks = self.parse_markdown_file(markdown_file_path)
if not blocks:
return False
for block in blocks:
if block['type'] == 'header':
# Add header to document
word_level = min(start_header_level + block['level'] - 1, 9)
self.document.add_heading(block['text'], level=word_level)
# Add content if any
if block['content'].strip():
self._add_formatted_content(block['content'])
else:
# Add content without header
if block['content'].strip():
self._add_formatted_content(block['content'])
return True
add_mixed_content_to_document(self, content_files, start_header_level=1)
¶
Add multiple markdown and Excel files to the document.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
content_files |
list |
List of file paths or dictionaries with file info |
required |
start_header_level |
int |
Starting header level |
1 |
Returns:
| Type | Description |
|---|---|
dict |
Results summary with success/failure counts |
Source code in autorpt/gen_auto.py
def add_mixed_content_to_document(self, content_files, start_header_level=1):
"""Add multiple markdown and Excel files to the document.
Args:
content_files (list): List of file paths or dictionaries with file info
start_header_level (int): Starting header level
Returns:
dict: Results summary with success/failure counts
"""
results = {'success': 0, 'failed': 0, 'files': []}
for item in content_files:
if isinstance(item, str):
file_path = Path(item)
options = {}
else:
file_path = Path(item['file'])
options = item.get('options', {})
try:
if file_path.suffix.lower() in ['.md', '.markdown']:
# Handle markdown file
success = self.add_markdown_to_document(
file_path,
options.get('start_header_level', start_header_level)
)
elif file_path.suffix.lower() in ['.xlsx', '.xls']:
# Handle Excel file
success = self.add_excel_table_to_document(
file_path,
sheet_name=options.get('sheet_name'),
table_title=options.get('table_title'),
include_header=options.get('include_header', True),
start_header_level=options.get(
'start_header_level', start_header_level)
)
else:
print(f"⚠️ Unsupported file type: {file_path.suffix}")
success = False
if success:
results['success'] += 1
results['files'].append(
{'file': str(file_path), 'status': 'success'})
else:
results['failed'] += 1
results['files'].append(
{'file': str(file_path), 'status': 'failed'})
except (FileNotFoundError, PermissionError, ValueError) as e:
print(f"❌ Error processing {file_path}: {e}")
results['failed'] += 1
results['files'].append(
{'file': str(file_path), 'status': 'error', 'error': str(e)})
return results
discover_content_files(self, include_patterns=None, exclude_patterns=None)
¶
Automatically discover markdown and Excel files in the content folder.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
include_patterns |
list |
List of glob patterns to include (default: ['.md', '.xlsx', '*.xls']) |
None |
exclude_patterns |
list |
List of patterns to exclude (default: ['report.docx']) |
None |
Returns:
| Type | Description |
|---|---|
dict |
Dictionary with 'markdown' and 'excel' file lists |
Source code in autorpt/gen_auto.py
def discover_content_files(self, include_patterns=None, exclude_patterns=None):
"""Automatically discover markdown and Excel files in the content folder.
Args:
include_patterns (list): List of glob patterns to include (default: ['*.md', '*.xlsx', '*.xls'])
exclude_patterns (list): List of patterns to exclude (default: ['*report*.docx'])
Returns:
dict: Dictionary with 'markdown' and 'excel' file lists
"""
if include_patterns is None:
include_patterns = ['*.md', '*.markdown', '*.xlsx', '*.xls']
if exclude_patterns is None:
exclude_patterns = ['*report*.docx', '*report*.pdf']
discovered = {'markdown': [], 'excel': [], 'all': []}
if not self.content_folder.exists():
print(f"📁 Content folder '{self.content_folder}' not found")
return discovered
try:
# Find all matching files
all_files = []
for pattern in include_patterns:
all_files.extend(self.content_folder.glob(pattern))
# Filter out excluded patterns
filtered_files = []
for file_path in all_files:
exclude_file = False
for exclude_pattern in exclude_patterns:
if file_path.match(exclude_pattern):
exclude_file = True
break
if not exclude_file:
filtered_files.append(file_path)
# Categorize files
for file_path in filtered_files:
if file_path.suffix.lower() in ['.md', '.markdown']:
discovered['markdown'].append(file_path)
elif file_path.suffix.lower() in ['.xlsx', '.xls']:
discovered['excel'].append(file_path)
discovered['all'].append(file_path)
# Sort files by name for consistent ordering
discovered['markdown'].sort(key=lambda x: x.name)
discovered['excel'].sort(key=lambda x: x.name)
discovered['all'].sort(key=lambda x: x.name)
if discovered['all']:
print(
f"📂 Discovered {len(discovered['all'])} content files in '{self.content_folder}':")
for file_path in discovered['all']:
print(f" 📄 {file_path.name}")
else:
print(
f"📂 No additional content files found in '{self.content_folder}'")
except (OSError, PermissionError) as e:
print(f"❌ Error discovering content files: {e}")
return discovered
generate_auto_report(self, content_files, output_path, document_title=None)
¶
Generate a complete Word document from multiple content files.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
content_files |
list |
List of markdown and Excel files to include |
required |
output_path |
str or Path |
Output path for the Word document |
required |
document_title |
str |
Optional title for the document |
None |
Returns:
| Type | Description |
|---|---|
bool |
True if successful, False otherwise |
Source code in autorpt/gen_auto.py
def generate_auto_report(self, content_files, output_path, document_title=None):
"""Generate a complete Word document from multiple content files.
Args:
content_files (list): List of markdown and Excel files to include
output_path (str or Path): Output path for the Word document
document_title (str): Optional title for the document
Returns:
bool: True if successful, False otherwise
"""
# Create new document
self.document = Document()
# Add document title if provided
if document_title:
self.document.add_heading(document_title, level=0)
# Process all content files
results = self.add_mixed_content_to_document(content_files)
# Save document
try:
self.document.save(output_path)
print(f"✅ Auto-generated report saved: {output_path}")
print(
f"📊 Processed {results['success']} files successfully, {results['failed']} failed")
return True
except (OSError, PermissionError) as e:
print(f"❌ Error saving document: {e}")
return False
parse_excel_file(self, excel_file_path, sheet_name=None, table_title=None)
¶
Parse an Excel file and extract table data.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
excel_file_path |
str or Path |
Path to the Excel file |
required |
sheet_name |
str |
Optional sheet name to read (default: first sheet) |
None |
table_title |
str |
Optional title for the table |
None |
Returns:
| Type | Description |
|---|---|
dict |
Dictionary with table data and metadata |
Source code in autorpt/gen_auto.py
def parse_excel_file(self, excel_file_path, sheet_name=None, table_title=None):
"""Parse an Excel file and extract table data.
Args:
excel_file_path (str or Path): Path to the Excel file
sheet_name (str): Optional sheet name to read (default: first sheet)
table_title (str): Optional title for the table
Returns:
dict: Dictionary with table data and metadata
"""
excel_path = Path(excel_file_path)
if not excel_path.exists():
print(f"Warning: Excel file {excel_path} not found")
return None
try:
# Read Excel file
if sheet_name:
data = pd.read_excel(excel_path, sheet_name=sheet_name)
else:
data = pd.read_excel(excel_path)
# Get sheet info for title if not provided
if not table_title:
if sheet_name:
table_title = f"Table: {sheet_name}"
else:
table_title = f"Table: {excel_path.stem}"
return {
'data': data,
'title': table_title,
'file_path': excel_path,
'sheet_name': sheet_name,
'columns': list(data.columns),
'rows': len(data)
}
except (FileNotFoundError, PermissionError, ValueError, ImportError) as e:
print(f"Error reading Excel file {excel_path}: {e}")
return None
parse_markdown_file(self, markdown_file_path)
¶
Parse a markdown file and extract structured content.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
markdown_file_path |
str or Path |
Path to the markdown file |
required |
Returns:
| Type | Description |
|---|---|
list |
List of content blocks with headers and content |
Source code in autorpt/gen_auto.py
def parse_markdown_file(self, markdown_file_path):
"""Parse a markdown file and extract structured content.
Args:
markdown_file_path (str or Path): Path to the markdown file
Returns:
list: List of content blocks with headers and content
"""
markdown_path = Path(markdown_file_path)
if not markdown_path.exists():
print(f"Warning: Markdown file {markdown_path} not found")
return []
try:
with open(markdown_path, 'r', encoding='utf-8') as f:
content = f.read()
except (FileNotFoundError, PermissionError, UnicodeDecodeError) as e:
print(f"Error reading {markdown_path}: {e}")
return []
return self._parse_markdown_content(content)
add_excel_table_to_existing_document(document, excel_file, sheet_name=None, table_title=None, start_level=1)
¶
Add Excel table to an existing Word document.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
document |
Word document object |
required | |
excel_file |
str |
Path to Excel file |
required |
sheet_name |
str |
Optional sheet name |
None |
table_title |
str |
Optional table title |
None |
start_level |
int |
Starting header level (1-9) |
1 |
Returns:
| Type | Description |
|---|---|
bool |
True if successful, False otherwise |
Source code in autorpt/gen_auto.py
def add_excel_table_to_existing_document(document, excel_file, sheet_name=None,
table_title=None, start_level=1):
"""Add Excel table to an existing Word document.
Args:
document: Word document object
excel_file (str): Path to Excel file
sheet_name (str): Optional sheet name
table_title (str): Optional table title
start_level (int): Starting header level (1-9)
Returns:
bool: True if successful, False otherwise
"""
generator = AutoReportGenerator(document)
return generator.add_excel_table_to_document(
excel_file, sheet_name, table_title, True, start_level
)
add_markdown_to_existing_document(document, markdown_file, start_level=1)
¶
Add markdown content to an existing Word document.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
document |
Word document object |
required | |
markdown_file |
str |
Path to markdown file |
required |
start_level |
int |
Starting header level (1-9) |
1 |
Returns:
| Type | Description |
|---|---|
bool |
True if successful, False otherwise |
Source code in autorpt/gen_auto.py
def add_markdown_to_existing_document(document, markdown_file, start_level=1):
"""Add markdown content to an existing Word document.
Args:
document: Word document object
markdown_file (str): Path to markdown file
start_level (int): Starting header level (1-9)
Returns:
bool: True if successful, False otherwise
"""
generator = AutoReportGenerator(document)
return generator.add_markdown_to_document(markdown_file, start_level)
add_mixed_content_to_existing_document(document, content_files, start_level=1)
¶
Add markdown and Excel content to an existing Word document.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
document |
Word document object |
required | |
content_files |
list |
List of content files to add |
required |
start_level |
int |
Starting header level (1-9) |
1 |
Returns:
| Type | Description |
|---|---|
dict |
Results summary |
Source code in autorpt/gen_auto.py
def add_mixed_content_to_existing_document(document, content_files, start_level=1):
"""Add markdown and Excel content to an existing Word document.
Args:
document: Word document object
content_files (list): List of content files to add
start_level (int): Starting header level (1-9)
Returns:
dict: Results summary
"""
generator = AutoReportGenerator(document)
return generator.add_mixed_content_to_document(content_files, start_level)
auto_generate_from_folder(content_folder='reports', output_file=None, document_title=None, include_patterns=None, exclude_patterns=None)
¶
Automatically discover and convert all content files in a folder to a Word document.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
content_folder |
str |
Folder to scan for content files (default: "reports") |
'reports' |
output_file |
str |
Output path for Word document (auto-generated if None) |
None |
document_title |
str |
Optional document title |
None |
include_patterns |
list |
File patterns to include |
None |
exclude_patterns |
list |
File patterns to exclude |
None |
Returns:
| Type | Description |
|---|---|
dict |
Results with success/failure counts and output file path |
Source code in autorpt/gen_auto.py
def auto_generate_from_folder(content_folder="reports", output_file=None, document_title=None,
include_patterns=None, exclude_patterns=None):
"""Automatically discover and convert all content files in a folder to a Word document.
Args:
content_folder (str): Folder to scan for content files (default: "reports")
output_file (str): Output path for Word document (auto-generated if None)
document_title (str): Optional document title
include_patterns (list): File patterns to include
exclude_patterns (list): File patterns to exclude
Returns:
dict: Results with success/failure counts and output file path
"""
generator = AutoReportGenerator(content_folder=content_folder)
# Generate output filename if not provided
if not output_file:
from datetime import datetime
content_path = Path(content_folder)
timestamp = datetime.now().strftime("%Y-%m-%d_%H%M")
output_file = content_path / f"auto_report_{timestamp}.docx"
# Create new document with title
generator.document = Document()
if document_title:
generator.document.add_heading(document_title, level=0)
elif not document_title:
generator.document.add_heading("Auto-Generated Report", level=0)
# Add generation info
from datetime import datetime
date_para = generator.document.add_paragraph(
f"Generated on: {datetime.now().strftime('%B %d, %Y at %I:%M %p')}"
)
date_para.alignment = WD_ALIGN_PARAGRAPH.CENTER
# Process all discovered files
results = generator.add_all_content_from_folder(
start_header_level=1,
include_patterns=include_patterns,
exclude_patterns=exclude_patterns
)
# Save document
try:
generator.document.save(output_file)
results['output_file'] = str(output_file)
results['saved'] = True
print(f"✅ Auto-generated report saved: {output_file}")
print(
f"📊 Processed {results['success']}/{results['discovered']} files successfully")
if results['failed'] > 0:
print(f"⚠️ {results['failed']} files failed to process")
except (OSError, PermissionError) as e:
results['saved'] = False
results['error'] = str(e)
print(f"❌ Error saving document: {e}")
return results
convert_mixed_content_to_word(content_files, output_file, document_title=None)
¶
Convert multiple markdown and Excel files to a Word document.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
content_files |
list |
List of file paths or file dictionaries |
required |
output_file |
str |
Output path for Word document |
required |
document_title |
str |
Optional document title |
None |
Returns:
| Type | Description |
|---|---|
bool |
True if successful, False otherwise |
Source code in autorpt/gen_auto.py
def convert_mixed_content_to_word(content_files, output_file, document_title=None):
"""Convert multiple markdown and Excel files to a Word document.
Args:
content_files (list): List of file paths or file dictionaries
output_file (str): Output path for Word document
document_title (str): Optional document title
Returns:
bool: True if successful, False otherwise
"""
generator = AutoReportGenerator()
return generator.generate_auto_report(content_files, output_file, document_title)