|
|
|
|
| import os
|
| import json
|
| import re
|
| import pandas as pd
|
| import openpyxl
|
| from io import BytesIO
|
| from docx import Document
|
| from docx.shared import Inches, Pt, RGBColor
|
| from pptx import Presentation
|
| from pptx.util import Inches as PptxInches
|
| from pptx.enum.text import PP_ALIGN
|
| from PIL import Image, ImageDraw, ImageFont
|
| from reportlab.lib.pagesizes import letter
|
| from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle
|
| from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
|
| from reportlab.lib import colors
|
| from reportlab.lib.units import inch
|
| import textwrap
|
| from pathlib import Path
|
|
|
|
|
| class DocumentCreator:
|
| """Utility class for creating various types of documents"""
|
|
|
| def __init__(self, output_dir="generated_docs"):
|
| """Initialize with output directory"""
|
| self.output_dir = Path(output_dir)
|
| self.output_dir.mkdir(exist_ok=True)
|
| self.temp_dir = Path("temp_docs")
|
| self.temp_dir.mkdir(exist_ok=True)
|
|
|
| def create_word_document(self, content, filename):
|
| """Create a Word document from markdown-style content with proper formatting"""
|
| doc = Document()
|
|
|
|
|
| lines = content.split('\n')
|
| in_table = False
|
| table_rows = []
|
| current_heading_level = 0
|
|
|
| for line in lines:
|
| line = line.rstrip()
|
| if not line.strip():
|
| if not in_table:
|
| doc.add_paragraph()
|
| continue
|
|
|
|
|
| if '|' in line and line.count('|') >= 2:
|
|
|
| cells = [cell.strip() for cell in line.split('|')]
|
| cells = [c for c in cells if c or (cells.index(c) > 0 and cells.index(c) < len(cells)-1)]
|
|
|
| if not in_table:
|
|
|
| in_table = True
|
| table_rows = [cells]
|
| else:
|
|
|
| if all('-' in cell for cell in cells if cell):
|
| continue
|
| table_rows.append(cells)
|
| continue
|
| elif in_table:
|
|
|
| if table_rows:
|
| num_cols = max(len(row) for row in table_rows)
|
| table = doc.add_table(rows=len(table_rows), cols=num_cols)
|
| table.style = 'Table Grid'
|
| for i, row in enumerate(table_rows):
|
| for j, cell_text in enumerate(row):
|
| if j < num_cols:
|
| table.cell(i, j).text = cell_text
|
| doc.add_paragraph()
|
| in_table = False
|
| table_rows = []
|
|
|
| if line.strip():
|
| doc.add_paragraph(line)
|
| continue
|
|
|
|
|
| if line.startswith('# '):
|
| doc.add_heading(line[2:].strip(), level=1)
|
| current_heading_level = 1
|
| elif line.startswith('## '):
|
| doc.add_heading(line[3:].strip(), level=2)
|
| current_heading_level = 2
|
| elif line.startswith('### '):
|
| doc.add_heading(line[4:].strip(), level=3)
|
| current_heading_level = 3
|
| elif line.startswith('#### '):
|
| doc.add_heading(line[5:].strip(), level=4)
|
| current_heading_level = 4
|
|
|
| elif line.startswith('- ') or line.startswith('* '):
|
| p = doc.add_paragraph(line[2:].strip(), style='List Bullet')
|
|
|
| elif re.match(r'^\d+\.\s', line):
|
| p = doc.add_paragraph(line, style='List Number')
|
|
|
| elif line.strip() == '---' or line.strip() == '***':
|
| doc.add_paragraph('_' * 50)
|
|
|
| else:
|
|
|
| p = doc.add_paragraph()
|
| self._add_formatted_text(p, line)
|
|
|
|
|
| if in_table and table_rows:
|
| num_cols = max(len(row) for row in table_rows)
|
| table = doc.add_table(rows=len(table_rows), cols=num_cols)
|
| table.style = 'Table Grid'
|
| for i, row in enumerate(table_rows):
|
| for j, cell_text in enumerate(row):
|
| if j < num_cols:
|
| table.cell(i, j).text = cell_text
|
|
|
| output_path = self.output_dir / filename
|
| doc.save(str(output_path))
|
| return output_path
|
|
|
| def _add_formatted_text(self, paragraph, text):
|
| """Add text with markdown formatting to a paragraph"""
|
| from docx.shared import RGBColor
|
|
|
|
|
| parts = []
|
| current_pos = 0
|
| bold_pattern = r'\*\*([^*]+)\*\*'
|
| italic_pattern = r'\*([^*]+)\*'
|
|
|
|
|
| all_matches = []
|
| for match in re.finditer(bold_pattern, text):
|
| all_matches.append((match.start(), match.end(), 'bold', match.group(1)))
|
| for match in re.finditer(italic_pattern, text):
|
| all_matches.append((match.start(), match.end(), 'italic', match.group(1)))
|
|
|
| all_matches.sort(key=lambda x: x[0])
|
|
|
| if not all_matches:
|
| paragraph.add_run(text)
|
| return
|
|
|
| last_end = 0
|
| for start, end, style, content in all_matches:
|
| if start > last_end:
|
| paragraph.add_run(text[last_end:start])
|
| run = paragraph.add_run(content)
|
| if style == 'bold':
|
| run.bold = True
|
| elif style == 'italic':
|
| run.italic = True
|
| last_end = end
|
|
|
| if last_end < len(text):
|
| paragraph.add_run(text[last_end:])
|
|
|
| def create_text_file(self, content, filename):
|
| """Create a plain text file with proper formatting"""
|
| output_path = self.output_dir / filename
|
| with open(output_path, 'w', encoding='utf-8') as f:
|
| f.write(content)
|
| return output_path
|
|
|
| def create_excel_file(self, content, filename):
|
| """Create an Excel file from markdown table or CSV content"""
|
| import openpyxl
|
| from openpyxl.styles import Font, PatternFill, Alignment, Border, Side
|
|
|
| wb = openpyxl.Workbook()
|
| ws = wb.active
|
| ws.title = "Sheet1"
|
|
|
|
|
| lines = content.strip().split('\n')
|
| table_data = []
|
| in_table = False
|
|
|
| for line in lines:
|
| if '|' in line and line.count('|') >= 2:
|
| cells = [cell.strip() for cell in line.split('|')]
|
| cells = [c for c in cells if c or (cells.index(c) > 0 and cells.index(c) < len(cells)-1)]
|
| if cells:
|
| if not in_table:
|
| in_table = True
|
|
|
| if not all('-' in cell for cell in cells if cell):
|
| table_data.append(cells)
|
| elif in_table and not line.strip():
|
| in_table = False
|
|
|
| if not table_data:
|
|
|
| for line in lines:
|
| if ',' in line:
|
| table_data.append([cell.strip() for cell in line.split(',')])
|
| elif line.strip():
|
| table_data.append([line.strip()])
|
|
|
|
|
| if table_data:
|
| thin_border = Border(
|
| left=Side(style='thin'), right=Side(style='thin'),
|
| top=Side(style='thin'), bottom=Side(style='thin')
|
| )
|
| header_fill = PatternFill(start_color='366092', end_color='366092', fill_type='solid')
|
| header_font = Font(color='FFFFFF', bold=True)
|
|
|
| for i, row in enumerate(table_data):
|
| for j, cell_value in enumerate(row):
|
| cell = ws.cell(row=i+1, column=j+1, value=cell_value)
|
| cell.border = thin_border
|
| cell.alignment = Alignment(horizontal='left', vertical='center')
|
| if i == 0:
|
| cell.fill = header_fill
|
| cell.font = header_font
|
|
|
|
|
| for column in ws.columns:
|
| max_length = 0
|
| column_letter = column[0].column_letter
|
| for cell in column:
|
| try:
|
| if len(str(cell.value)) > max_length:
|
| max_length = len(str(cell.value))
|
| except:
|
| pass
|
| adjusted_width = min(max_length + 2, 50)
|
| ws.column_dimensions[column_letter].width = adjusted_width
|
|
|
| output_path = self.output_dir / filename
|
| wb.save(str(output_path))
|
| return output_path
|
|
|
| def create_csv_file(self, content, filename):
|
| """Create a CSV file from markdown table or text content"""
|
| import csv
|
|
|
|
|
| lines = content.strip().split('\n')
|
| table_data = []
|
| in_table = False
|
|
|
| for line in lines:
|
| if '|' in line and line.count('|') >= 2:
|
| cells = [cell.strip() for cell in line.split('|')]
|
| cells = [c for c in cells if c or (cells.index(c) > 0 and cells.index(c) < len(cells)-1)]
|
| if cells:
|
| if not in_table:
|
| in_table = True
|
| if not all('-' in cell for cell in cells if cell):
|
| table_data.append(cells)
|
| elif in_table and not line.strip():
|
| in_table = False
|
|
|
| if not table_data:
|
|
|
| for line in lines:
|
| if ',' in line:
|
| table_data.append([cell.strip() for cell in line.split(',')])
|
| elif line.strip():
|
| table_data.append([line.strip()])
|
|
|
| output_path = self.output_dir / filename
|
| with open(output_path, 'w', newline='', encoding='utf-8') as f:
|
| writer = csv.writer(f)
|
| writer.writerows(table_data)
|
|
|
| return output_path
|
|
|
| def create_powerpoint(self, content, filename):
|
| """Create a PowerPoint presentation with proper slide separation and formatting"""
|
| from pptx.util import Inches as PptxInches
|
| from pptx.enum.text import PP_ALIGN, MSO_ANCHOR
|
| from pptx.dml.color import RGBColor as PptxRGBColor
|
|
|
| prs = Presentation()
|
|
|
|
|
| prs.slide_width = PptxInches(13.333)
|
| prs.slide_height = PptxInches(7.5)
|
|
|
|
|
| slides_content = []
|
|
|
|
|
| if '---' in content:
|
| raw_slides = content.split('---')
|
| for slide in raw_slides:
|
| if slide.strip():
|
| slides_content.append(slide.strip())
|
| else:
|
|
|
| import re
|
| slide_pattern = r'(?:##\s*Slide\s*\d+)\s*\n(.*?)(?=(?:##\s*Slide|$))'
|
| matches = re.findall(slide_pattern, content, re.DOTALL)
|
| if matches:
|
| slides_content = matches
|
| else:
|
|
|
| numbered_slides = re.split(r'\n(?=\d+\.\s+[A-Z])', content)
|
| if len(numbered_slides) > 1:
|
| slides_content = numbered_slides
|
| else:
|
|
|
| slides_content = [content]
|
|
|
|
|
| if not slides_content:
|
| slides_content = [content]
|
|
|
| for slide_idx, slide_content in enumerate(slides_content):
|
| if not slide_content.strip():
|
| continue
|
|
|
| lines = slide_content.split('\n')
|
|
|
|
|
| while lines and not lines[0].strip():
|
| lines.pop(0)
|
| while lines and not lines[-1].strip():
|
| lines.pop()
|
|
|
| if not lines:
|
| continue
|
|
|
|
|
| slide_title = ""
|
| body_lines = []
|
|
|
|
|
| first_line = lines[0].strip()
|
|
|
|
|
| if first_line.startswith('#'):
|
| slide_title = first_line.lstrip('#').strip()
|
| body_lines = lines[1:]
|
| elif first_line.startswith('Slide') or first_line.startswith('**'):
|
| slide_title = first_line.replace('**', '').replace('Slide', '').strip()
|
| if slide_title and slide_title[0].isdigit():
|
|
|
| parts = slide_title.split(' ', 1)
|
| if len(parts) > 1:
|
| slide_title = parts[1]
|
| else:
|
| slide_title = f"Slide {slide_idx + 1}"
|
| body_lines = lines[1:] if len(lines) > 1 else []
|
| else:
|
|
|
| slide_title = f"Slide {slide_idx + 1}"
|
| body_lines = lines
|
|
|
|
|
| if slide_idx == 0 and (len(body_lines) == 0 or len(slide_title) < 30):
|
|
|
| slide_layout = prs.slide_layouts[0]
|
| slide = prs.slides.add_slide(slide_layout)
|
|
|
|
|
| if slide.shapes.title:
|
| title_shape = slide.shapes.title
|
| title_shape.text = slide_title if slide_title else "Presentation Title"
|
|
|
|
|
| for paragraph in title_shape.text_frame.paragraphs:
|
| paragraph.font.size = PptxInches(0.44)
|
| paragraph.font.bold = True
|
| paragraph.alignment = PP_ALIGN.CENTER
|
|
|
|
|
| if len(slide.placeholders) > 1 and body_lines:
|
| subtitle_placeholder = slide.placeholders[1]
|
| subtitle_text = '\n'.join(body_lines[:3])
|
| subtitle_placeholder.text = subtitle_text
|
|
|
|
|
| for paragraph in subtitle_placeholder.text_frame.paragraphs:
|
| paragraph.font.size = PptxInches(0.28)
|
| paragraph.alignment = PP_ALIGN.CENTER
|
| else:
|
|
|
| slide_layout = prs.slide_layouts[1]
|
| slide = prs.slides.add_slide(slide_layout)
|
|
|
|
|
| if slide.shapes.title:
|
| title_shape = slide.shapes.title
|
| title_shape.text = slide_title if slide_title else f"Slide {slide_idx + 1}"
|
|
|
|
|
| for paragraph in title_shape.text_frame.paragraphs:
|
| paragraph.font.size = PptxInches(0.36)
|
| paragraph.font.bold = True
|
|
|
|
|
| if len(slide.placeholders) > 1:
|
| content_placeholder = slide.placeholders[1]
|
|
|
|
|
| content_placeholder.text = ""
|
| text_frame = content_placeholder.text_frame
|
| text_frame.clear()
|
|
|
|
|
| for line in body_lines:
|
| line = line.strip()
|
| if not line:
|
| continue
|
|
|
|
|
| p = text_frame.add_paragraph()
|
|
|
|
|
| if line.startswith('- ') or line.startswith('* '):
|
| p.text = line[2:]
|
| p.level = 0
|
| p.bullet = True
|
| elif line.startswith(' - ') or line.startswith(' * '):
|
| p.text = line[4:]
|
| p.level = 1
|
| p.bullet = True
|
| elif line.startswith(' - ') or line.startswith(' * '):
|
| p.text = line[6:]
|
| p.level = 2
|
| p.bullet = True
|
| elif re.match(r'^\d+\.\s', line):
|
|
|
| p.text = line
|
| p.bullet = False
|
| elif line.startswith('**') and line.endswith('**'):
|
|
|
| p.text = line.strip('*')
|
| p.font.bold = True
|
| else:
|
|
|
| p.text = line
|
| p.bullet = False
|
|
|
|
|
| p.font.size = PptxInches(0.24)
|
|
|
|
|
| p.space_after = PptxInches(0.06)
|
|
|
|
|
| slides_to_remove = []
|
| for i, slide in enumerate(prs.slides):
|
| has_content = False
|
| for shape in slide.shapes:
|
| if hasattr(shape, "text") and shape.text and shape.text.strip():
|
| has_content = True
|
| break
|
| if not has_content and i > 0:
|
| slides_to_remove.append(i)
|
|
|
|
|
|
|
|
|
| output_path = self.output_dir / filename
|
| prs.save(str(output_path))
|
| return output_path
|
|
|
| def create_image_from_text(self, content, filename):
|
| """Create an image from text content with proper formatting"""
|
| from PIL import Image, ImageDraw, ImageFont
|
|
|
|
|
| lines = []
|
| for line in content.split('\n'):
|
| if line.strip():
|
|
|
| clean_line = re.sub(r'\*\*([^*]+)\*\*', r'\1', line)
|
| clean_line = re.sub(r'\*([^*]+)\*', r'\1', clean_line)
|
| clean_line = re.sub(r'#+\s*', '', clean_line)
|
| lines.append(clean_line)
|
|
|
| if not lines:
|
| lines = [content[:100]]
|
|
|
|
|
| max_line_length = max(len(line) for line in lines) if lines else 40
|
| img_width = min(1200, max(400, max_line_length * 12))
|
| line_height = 30
|
| img_height = max(400, len(lines) * line_height + 100)
|
|
|
| img = Image.new('RGB', (img_width, img_height), color='white')
|
| draw = ImageDraw.Draw(img)
|
|
|
|
|
| try:
|
| font = ImageFont.truetype("/usr/share/fonts/truetype/liberation/LiberationSans-Regular.ttf", 16)
|
| except:
|
| try:
|
| font = ImageFont.truetype("arial.ttf", 16)
|
| except:
|
| font = ImageFont.load_default()
|
|
|
| y = 40
|
| for line in lines:
|
|
|
| wrapped_lines = textwrap.wrap(line, width=img_width // 10)
|
| for wrapped in wrapped_lines:
|
| draw.text((20, y), wrapped, fill='black', font=font)
|
| y += line_height
|
|
|
| output_path = self.output_dir / filename
|
| img.save(str(output_path))
|
| return output_path
|
|
|
| def create_pdf_from_content(self, content, filename):
|
| """Create a PDF from markdown content with proper formatting"""
|
| from reportlab.lib.pagesizes import letter
|
| from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
|
| from reportlab.lib.units import inch
|
| from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle
|
| from reportlab.lib import colors
|
|
|
| output_path = self.output_dir / filename
|
| doc = SimpleDocTemplate(str(output_path), pagesize=letter,
|
| rightMargin=72, leftMargin=72,
|
| topMargin=72, bottomMargin=72)
|
|
|
| styles = getSampleStyleSheet()
|
| story = []
|
|
|
|
|
| heading1_style = ParagraphStyle('Heading1Custom', parent=styles['Heading1'], fontSize=16, spaceAfter=12, spaceBefore=12)
|
| heading2_style = ParagraphStyle('Heading2Custom', parent=styles['Heading2'], fontSize=14, spaceAfter=10, spaceBefore=10)
|
| normal_style = ParagraphStyle('NormalCustom', parent=styles['Normal'], fontSize=10, spaceAfter=6)
|
|
|
| lines = content.split('\n')
|
| in_table = False
|
| table_data = []
|
|
|
| for line in lines:
|
| line = line.strip()
|
| if not line:
|
| if not in_table:
|
| story.append(Spacer(1, 6))
|
| continue
|
|
|
|
|
| if '|' in line and line.count('|') >= 2:
|
| cells = [cell.strip() for cell in line.split('|')]
|
| cells = [c for c in cells if c or (cells.index(c) > 0 and cells.index(c) < len(cells)-1)]
|
| if cells:
|
| if not in_table:
|
| in_table = True
|
| table_data = [cells]
|
| elif not all('-' in cell for cell in cells if cell):
|
| table_data.append(cells)
|
| continue
|
| elif in_table:
|
|
|
| if table_data:
|
|
|
| rt_table = Table(table_data)
|
| rt_table.setStyle(TableStyle([
|
| ('BACKGROUND', (0, 0), (-1, 0), colors.grey),
|
| ('TEXTCOLOR', (0, 0), (-1, 0), colors.whitesmoke),
|
| ('ALIGN', (0, 0), (-1, -1), 'CENTER'),
|
| ('FONTNAME', (0, 0), (-1, 0), 'Helvetica-Bold'),
|
| ('FONTSIZE', (0, 0), (-1, 0), 10),
|
| ('BOTTOMPADDING', (0, 0), (-1, 0), 12),
|
| ('BACKGROUND', (0, 1), (-1, -1), colors.beige),
|
| ('GRID', (0, 0), (-1, -1), 1, colors.black)
|
| ]))
|
| story.append(rt_table)
|
| story.append(Spacer(1, 12))
|
| in_table = False
|
| table_data = []
|
| continue
|
|
|
|
|
| if line.startswith('# '):
|
| story.append(Paragraph(line[2:], heading1_style))
|
| elif line.startswith('## '):
|
| story.append(Paragraph(line[3:], heading2_style))
|
| elif line.startswith('### '):
|
| story.append(Paragraph(line[4:], normal_style))
|
| elif line.startswith('- ') or line.startswith('* '):
|
| story.append(Paragraph('• ' + line[2:], normal_style))
|
| elif re.match(r'^\d+\.\s', line):
|
| story.append(Paragraph(line, normal_style))
|
| else:
|
| story.append(Paragraph(line, normal_style))
|
|
|
| doc.build(story)
|
| return output_path
|
|
|
| def create_document(self, content, doc_type, filename, template_id=None):
|
| """
|
| Main method to create a document based on type
|
|
|
| Args:
|
| content: The content to put in the document
|
| doc_type: Type of document ('word', 'txt', 'excel', 'csv', 'ppt', 'image', 'pdf')
|
| filename: Desired filename (without extension)
|
| template_id: Optional template ID for formatting
|
|
|
| Returns:
|
| Path to created document
|
| """
|
|
|
| ext_map = {
|
| 'word': '.docx',
|
| 'txt': '.txt',
|
| 'pdf': '.pdf',
|
| 'excel': '.xlsx',
|
| 'csv': '.csv',
|
| 'ppt': '.pptx',
|
| 'image': '.png'
|
| }
|
|
|
| ext = ext_map.get(doc_type, '.txt')
|
| full_filename = f"{filename}{ext}"
|
|
|
|
|
| if template_id:
|
| content = self._apply_template_formatting(content, doc_type, template_id)
|
|
|
|
|
| if doc_type == 'word':
|
| return self.create_word_document(content, full_filename)
|
| elif doc_type == 'txt':
|
| return self.create_text_file(content, full_filename)
|
| elif doc_type == 'excel':
|
| return self.create_excel_file(content, full_filename)
|
| elif doc_type == 'csv':
|
| return self.create_csv_file(content, full_filename)
|
| elif doc_type == 'ppt':
|
| return self.create_powerpoint(content, full_filename)
|
| elif doc_type == 'image':
|
| return self.create_image_from_text(content, full_filename)
|
| elif doc_type == 'pdf':
|
| return self.create_pdf_from_content(content, full_filename)
|
| else:
|
| raise ValueError(f"Unsupported document type: {doc_type}")
|
|
|
| def _apply_template_formatting(self, content, doc_type, template_id):
|
| """Apply template-specific formatting instructions to content"""
|
| if template_id == 'professional':
|
| if doc_type == 'word':
|
| content += """
|
|
|
| Format this as a professional document with:
|
| - Clear headings (use ### for main sections)
|
| - Bullet points where appropriate
|
| - Professional tone
|
| - Proper spacing between sections"""
|
| elif doc_type == 'ppt':
|
| content += """
|
|
|
| Format this as a presentation with:
|
| - Title slide (presentation title)
|
| - 3-5 content slides with headings and bullet points
|
| - Closing slide with summary or call to action
|
| Separate slides with ---"""
|
| elif doc_type == 'excel':
|
| content += """
|
|
|
| Format this as structured data with:
|
| - Column headers as first row
|
| - Each row as a data entry
|
| - Use consistent formatting"""
|
|
|
| return content
|
|
|
| def get_download_url(self, filename, base_url="/api/docs/download/"):
|
| """Get download URL for a file"""
|
| return f"{base_url}{filename}"
|
|
|
|
|
|
|
|
|
| def create_word_document(content, filename, output_dir="generated_docs"):
|
| """Quickly create a Word document"""
|
| creator = DocumentCreator(output_dir)
|
| return creator.create_word_document(content, filename)
|
|
|
|
|
| def create_text_file(content, filename, output_dir="generated_docs"):
|
| """Quickly create a text file"""
|
| creator = DocumentCreator(output_dir)
|
| return creator.create_text_file(content, filename)
|
|
|
|
|
| def create_excel_file(content, filename, output_dir="generated_docs"):
|
| """Quickly create an Excel file"""
|
| creator = DocumentCreator(output_dir)
|
| return creator.create_excel_file(content, filename)
|
|
|
|
|
| def create_powerpoint(content, filename, output_dir="generated_docs"):
|
| """Quickly create a PowerPoint presentation"""
|
| creator = DocumentCreator(output_dir)
|
| return creator.create_powerpoint(content, filename)
|
|
|
|
|
| def create_image_from_text(content, filename, output_dir="generated_docs"):
|
| """Quickly create an image from text"""
|
| creator = DocumentCreator(output_dir)
|
| return creator.create_image_from_text(content, filename)
|
|
|
|
|
| def create_pdf_from_content(content, filename, output_dir="generated_docs"):
|
| """Quickly create a PDF from text"""
|
| creator = DocumentCreator(output_dir)
|
| return creator.create_pdf_from_content(content, filename)
|
|
|
|
|
|
|
| if __name__ == "__main__":
|
|
|
| creator = DocumentCreator()
|
|
|
|
|
| sample_content = """# Welcome to My Document
|
| ## Introduction
|
| This is a sample document created with the DocumentCreator class.
|
|
|
| ## Features
|
| - Easy document creation
|
| - Multiple format support
|
| - Professional formatting
|
|
|
| ### Conclusion
|
| Thank you for using this utility!"""
|
|
|
| doc_path = creator.create_document(sample_content, 'word', 'sample_document')
|
| print(f"Created Word document: {doc_path}")
|
|
|
|
|
| text_path = creator.create_document("Hello, World!", 'txt', 'hello_world')
|
| print(f"Created text file: {text_path}") |