Spaces:
Running
Running
| """ | |
| DOCX Export Module for EasyRead | |
| Provides functionality to export Easy Read documents to Microsoft Word format. | |
| """ | |
| import os | |
| import tempfile | |
| from typing import Optional | |
| from docx import Document | |
| from docx.shared import Inches, Pt, RGBColor | |
| from docx.enum.text import WD_ALIGN_PARAGRAPH | |
| from docx.enum.table import WD_TABLE_ALIGNMENT | |
| def export_to_docx( | |
| title: str, | |
| sentences: list[dict], | |
| image_data: Optional[dict[str, bytes]] = None, | |
| output_path: Optional[str] = None, | |
| ) -> str: | |
| """ | |
| Export Easy Read content to a Word document. | |
| Args: | |
| title: Document title | |
| sentences: List of sentence dictionaries with keys: | |
| - sentence: The text content | |
| - image_prompt: Description of the image | |
| - highlighted: Whether this is a key sentence | |
| - image_path: Optional path to the icon image | |
| image_data: Optional dict mapping image paths to image bytes | |
| output_path: Optional output file path. If None, creates temp file. | |
| Returns: | |
| Path to the generated DOCX file | |
| """ | |
| doc = Document() | |
| # Set document title | |
| title_paragraph = doc.add_heading(title, level=0) | |
| title_paragraph.alignment = WD_ALIGN_PARAGRAPH.CENTER | |
| # Add spacing after title | |
| doc.add_paragraph() | |
| # Create a table for side-by-side layout (image | text) | |
| for item in sentences: | |
| sentence = item.get("sentence", "") | |
| highlighted = item.get("highlighted", False) | |
| image_path = item.get("image_path", "") | |
| # Create a 1-row, 2-column table for each sentence | |
| table = doc.add_table(rows=1, cols=2) | |
| table.alignment = WD_TABLE_ALIGNMENT.CENTER | |
| table.autofit = True | |
| # Set column widths | |
| for cell in table.columns[0].cells: | |
| cell.width = Inches(1.5) | |
| for cell in table.columns[1].cells: | |
| cell.width = Inches(5.0) | |
| row = table.rows[0] | |
| icon_cell = row.cells[0] | |
| text_cell = row.cells[1] | |
| # Add image to the icon cell if available | |
| image_key = image_path.split("/")[-1] if image_path else None | |
| if image_data and image_key and image_key in image_data: | |
| img_bytes = image_data[image_key] | |
| # Save image to temp file for docx insertion | |
| with tempfile.NamedTemporaryFile( | |
| suffix=".png", delete=False | |
| ) as tmp_img: | |
| tmp_img.write(img_bytes) | |
| tmp_img_path = tmp_img.name | |
| try: | |
| icon_paragraph = icon_cell.paragraphs[0] | |
| icon_paragraph.alignment = WD_ALIGN_PARAGRAPH.CENTER | |
| run = icon_paragraph.add_run() | |
| run.add_picture(tmp_img_path, width=Inches(1.2)) | |
| finally: | |
| # Clean up temp file | |
| if os.path.exists(tmp_img_path): | |
| os.remove(tmp_img_path) | |
| else: | |
| # Placeholder for missing image | |
| icon_paragraph = icon_cell.paragraphs[0] | |
| icon_paragraph.alignment = WD_ALIGN_PARAGRAPH.CENTER | |
| run = icon_paragraph.add_run("[Icon]") | |
| run.font.color.rgb = RGBColor(128, 128, 128) | |
| # Add text to the text cell | |
| text_paragraph = text_cell.paragraphs[0] | |
| text_paragraph.alignment = WD_ALIGN_PARAGRAPH.LEFT | |
| run = text_paragraph.add_run(sentence) | |
| run.font.size = Pt(14) | |
| # Highlight key sentences | |
| if highlighted: | |
| run.font.bold = True | |
| run.font.color.rgb = RGBColor(0, 102, 204) | |
| # Add some spacing between rows | |
| doc.add_paragraph() | |
| # Generate output path if not provided | |
| if not output_path: | |
| with tempfile.NamedTemporaryFile( | |
| suffix=".docx", prefix="easyread_", delete=False | |
| ) as tmp: | |
| output_path = tmp.name | |
| doc.save(output_path) | |
| return output_path | |
| def export_to_docx_bytes( | |
| title: str, | |
| sentences: list[dict], | |
| image_data: Optional[dict[str, bytes]] = None, | |
| ) -> bytes: | |
| """ | |
| Export Easy Read content to a Word document and return as bytes. | |
| Args: | |
| title: Document title | |
| sentences: List of sentence dictionaries | |
| image_data: Optional dict mapping image paths to image bytes | |
| Returns: | |
| DOCX file content as bytes | |
| """ | |
| # Create temp file, export, read, and clean up | |
| output_path = export_to_docx(title, sentences, image_data) | |
| try: | |
| with open(output_path, "rb") as f: | |
| return f.read() | |
| finally: | |
| if os.path.exists(output_path): | |
| os.remove(output_path) | |