Spaces:
				
			
			
	
			
			
		Sleeping
		
	
	
	
			
			
	
	
	
	
		
		
		Sleeping
		
	Update app.py
Browse files
    	
        app.py
    CHANGED
    
    | @@ -1,13 +1,10 @@ | |
| 1 | 
            -
             | 
|  | |
| 2 | 
             
            import io
         | 
| 3 | 
             
            import re
         | 
| 4 | 
             
            import streamlit as st
         | 
| 5 | 
            -
             | 
| 6 | 
            -
            st.set_page_config(layout="wide", initial_sidebar_state="collapsed")
         | 
| 7 | 
            -
             | 
| 8 | 
             
            from PIL import Image
         | 
| 9 | 
             
            import fitz
         | 
| 10 | 
            -
             | 
| 11 | 
             
            from reportlab.lib.pagesizes import A4
         | 
| 12 | 
             
            from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle
         | 
| 13 | 
             
            from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
         | 
| @@ -15,58 +12,190 @@ from reportlab.lib import colors | |
| 15 | 
             
            from reportlab.pdfbase import pdfmetrics
         | 
| 16 | 
             
            from reportlab.pdfbase.ttfonts import TTFont
         | 
| 17 |  | 
| 18 | 
            -
             | 
| 19 | 
            -
             | 
| 20 | 
            -
             | 
| 21 | 
            -
                 | 
| 22 | 
            -
                 | 
| 23 | 
            -
             | 
| 24 | 
            -
             | 
| 25 | 
            -
             | 
| 26 | 
            -
             | 
| 27 | 
            -
             | 
| 28 | 
            -
             | 
| 29 | 
            -
             | 
| 30 | 
            -
             | 
| 31 | 
            -
                 | 
| 32 | 
            -
                 | 
| 33 | 
            -
             | 
| 34 | 
            -
             | 
| 35 | 
            -
             | 
| 36 | 
            -
             | 
| 37 | 
            -
                     | 
| 38 | 
            -
             | 
| 39 | 
            -
             | 
| 40 | 
            -
             | 
| 41 | 
            -
             | 
| 42 | 
            -
                 | 
| 43 | 
            -
             | 
| 44 | 
            -
             | 
| 45 | 
            -
             | 
| 46 | 
            -
                )
         | 
| 47 | 
            -
             | 
| 48 | 
            -
             | 
| 49 | 
            -
             | 
| 50 | 
            -
             | 
| 51 | 
            -
             | 
| 52 | 
            -
             | 
| 53 | 
            -
             | 
| 54 | 
            -
             | 
| 55 | 
            -
             | 
| 56 | 
            -
             | 
| 57 | 
            -
             | 
| 58 | 
            -
             | 
| 59 | 
            -
                     | 
| 60 | 
            -
                     | 
| 61 | 
            -
             | 
| 62 | 
            -
             | 
| 63 | 
            -
             | 
| 64 | 
            -
             | 
| 65 | 
            -
                     | 
| 66 | 
            -
             | 
| 67 | 
            -
             | 
| 68 | 
            -
             | 
| 69 | 
            -
             | 
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
| 70 |  | 
| 71 | 
             
            default_markdown = """# 🌟 Deities Guide: Mythology and Moral Lessons 🌟
         | 
| 72 |  | 
| @@ -226,243 +355,5 @@ default_markdown = """# 🌟 Deities Guide: Mythology and Moral Lessons 🌟 | |
| 226 | 
             
            3. Saints/Prophets: Virtues (e.g., justice, prophecy).
         | 
| 227 | 
             
            """
         | 
| 228 |  | 
| 229 | 
            -
             | 
| 230 | 
            -
             | 
| 231 | 
            -
                pdf_content = []
         | 
| 232 | 
            -
                
         | 
| 233 | 
            -
                if plain_text_mode:
         | 
| 234 | 
            -
                    for line in lines:
         | 
| 235 | 
            -
                        line = line.strip()
         | 
| 236 | 
            -
                        if not line:
         | 
| 237 | 
            -
                            continue
         | 
| 238 | 
            -
                        if line.startswith('# '):
         | 
| 239 | 
            -
                            continue
         | 
| 240 | 
            -
                        bold_pattern = re.compile(r'\*\*(.*?)\*\*')
         | 
| 241 | 
            -
                        line = bold_pattern.sub(r'<b>\1</b>', line)
         | 
| 242 | 
            -
                        pdf_content.append(line)
         | 
| 243 | 
            -
                else:
         | 
| 244 | 
            -
                    in_list = False
         | 
| 245 | 
            -
                    current_item = None
         | 
| 246 | 
            -
                    sub_items = []
         | 
| 247 | 
            -
                    
         | 
| 248 | 
            -
                    for line in lines:
         | 
| 249 | 
            -
                        line = line.strip()
         | 
| 250 | 
            -
                        if not line:
         | 
| 251 | 
            -
                            continue
         | 
| 252 | 
            -
                            
         | 
| 253 | 
            -
                        if line.startswith('# '):
         | 
| 254 | 
            -
                            continue
         | 
| 255 | 
            -
                        elif line.startswith('## '):
         | 
| 256 | 
            -
                            if current_item and sub_items:
         | 
| 257 | 
            -
                                pdf_content.append([current_item, sub_items])
         | 
| 258 | 
            -
                                sub_items = []
         | 
| 259 | 
            -
                                current_item = None
         | 
| 260 | 
            -
                            section = line.replace('## ', '').strip()
         | 
| 261 | 
            -
                            pdf_content.append(f"<b>{section}</b>")
         | 
| 262 | 
            -
                            in_list = False
         | 
| 263 | 
            -
                        elif line.startswith('### '):
         | 
| 264 | 
            -
                            if current_item and sub_items:
         | 
| 265 | 
            -
                                pdf_content.append([current_item, sub_items])
         | 
| 266 | 
            -
                                sub_items = []
         | 
| 267 | 
            -
                                current_item = None
         | 
| 268 | 
            -
                            if show_subitems:
         | 
| 269 | 
            -
                                subsection = line.replace('### ', '').strip()
         | 
| 270 | 
            -
                                pdf_content.append(f"<b>{subsection}</b>")
         | 
| 271 | 
            -
                            in_list = False
         | 
| 272 | 
            -
                        elif re.match(r'^\d+\.', line):
         | 
| 273 | 
            -
                            if current_item and sub_items:
         | 
| 274 | 
            -
                                pdf_content.append([current_item, sub_items])
         | 
| 275 | 
            -
                                sub_items = []
         | 
| 276 | 
            -
                            current_item = line.strip()
         | 
| 277 | 
            -
                            in_list = True
         | 
| 278 | 
            -
                        elif re.match(r'^\d+\.\d+\.', line):
         | 
| 279 | 
            -
                            if show_subitems:
         | 
| 280 | 
            -
                                sub_items.append(line.strip())
         | 
| 281 | 
            -
                        elif line.startswith('*') and not in_list:
         | 
| 282 | 
            -
                            pdf_content.append(line.strip())
         | 
| 283 | 
            -
                        else:
         | 
| 284 | 
            -
                            if in_list:
         | 
| 285 | 
            -
                                sub_items.append(line.strip())
         | 
| 286 | 
            -
                            else:
         | 
| 287 | 
            -
                                pdf_content.append(line.strip())
         | 
| 288 | 
            -
                    
         | 
| 289 | 
            -
                    if current_item and sub_items:
         | 
| 290 | 
            -
                        pdf_content.append([current_item, sub_items])
         | 
| 291 | 
            -
                
         | 
| 292 | 
            -
                total_lines = sum(1 + len(subs) if isinstance(item, list) else 1 for item in pdf_content)
         | 
| 293 | 
            -
                total_chars = sum(len(item) if isinstance(item, str) else len(item[0]) + sum(len(sub) for sub in item[1]) for item in pdf_content)
         | 
| 294 | 
            -
                avg_line_length = total_chars / total_lines if total_lines > 0 else 1
         | 
| 295 | 
            -
                
         | 
| 296 | 
            -
                columns = [[] for _ in range(num_columns)]
         | 
| 297 | 
            -
                lines_per_column = total_lines / num_columns
         | 
| 298 | 
            -
                current_line_count = 0
         | 
| 299 | 
            -
                current_column = 0
         | 
| 300 | 
            -
                
         | 
| 301 | 
            -
                for item in pdf_content:
         | 
| 302 | 
            -
                    item_lines = 1 + (len(item[1]) if isinstance(item, list) else 0)
         | 
| 303 | 
            -
                    if current_line_count >= lines_per_column and current_column < num_columns - 1:
         | 
| 304 | 
            -
                        current_column += 1
         | 
| 305 | 
            -
                        current_line_count = 0
         | 
| 306 | 
            -
                    columns[current_column].append(item)
         | 
| 307 | 
            -
                    current_line_count += item_lines
         | 
| 308 | 
            -
                
         | 
| 309 | 
            -
                return columns, total_lines, num_columns
         | 
| 310 | 
            -
             | 
| 311 | 
            -
            def create_main_pdf(markdown_text, base_font_size=10, auto_size=False, show_subitems=True, plain_text_mode=False, num_columns=4):
         | 
| 312 | 
            -
                buffer = io.BytesIO()
         | 
| 313 | 
            -
                doc = SimpleDocTemplate(
         | 
| 314 | 
            -
                    buffer, 
         | 
| 315 | 
            -
                    pagesize=(A4[1] * 2, A4[0]),
         | 
| 316 | 
            -
                    leftMargin=36,
         | 
| 317 | 
            -
                    rightMargin=36,
         | 
| 318 | 
            -
                    topMargin=36,
         | 
| 319 | 
            -
                    bottomMargin=36
         | 
| 320 | 
            -
                )
         | 
| 321 | 
            -
                
         | 
| 322 | 
            -
                styles = getSampleStyleSheet()
         | 
| 323 | 
            -
                story = []
         | 
| 324 | 
            -
                spacer_height = 10
         | 
| 325 | 
            -
                columns, total_lines, num_columns = markdown_to_pdf_content(markdown_text, show_subitems, plain_text_mode, base_font_size, num_columns)
         | 
| 326 | 
            -
                
         | 
| 327 | 
            -
                if auto_size:
         | 
| 328 | 
            -
                    base_font_size = max(6, min(16, base_font_size * 300 / total_lines))
         | 
| 329 | 
            -
                
         | 
| 330 | 
            -
                item_font_size = base_font_size
         | 
| 331 | 
            -
                subitem_font_size = base_font_size * 0.85
         | 
| 332 | 
            -
                section_font_size = base_font_size * 1.1
         | 
| 333 | 
            -
                title_font_size = min(20, base_font_size * 1.4)
         | 
| 334 | 
            -
                
         | 
| 335 | 
            -
                title_style = ParagraphStyle(
         | 
| 336 | 
            -
                    'Heading1',
         | 
| 337 | 
            -
                    parent=styles['Heading1'],
         | 
| 338 | 
            -
                    fontName="Helvetica-Bold",
         | 
| 339 | 
            -
                    textColor=colors.darkblue,
         | 
| 340 | 
            -
                    alignment=1,
         | 
| 341 | 
            -
                    fontSize=title_font_size,
         | 
| 342 | 
            -
                    leading=title_font_size * 1.2
         | 
| 343 | 
            -
                )
         | 
| 344 | 
            -
                
         | 
| 345 | 
            -
                section_style = ParagraphStyle(
         | 
| 346 | 
            -
                    'SectionStyle',
         | 
| 347 | 
            -
                    parent=styles['Heading2'],
         | 
| 348 | 
            -
                    fontName="Helvetica-Bold",
         | 
| 349 | 
            -
                    textColor=colors.darkblue,
         | 
| 350 | 
            -
                    fontSize=section_font_size,
         | 
| 351 | 
            -
                    leading=section_font_size * 1.2,
         | 
| 352 | 
            -
                    spaceAfter=2
         | 
| 353 | 
            -
                )
         | 
| 354 | 
            -
                
         | 
| 355 | 
            -
                item_style = ParagraphStyle(
         | 
| 356 | 
            -
                    'ItemStyle',
         | 
| 357 | 
            -
                    parent=styles['Normal'],
         | 
| 358 | 
            -
                    fontName="Helvetica",
         | 
| 359 | 
            -
                    fontSize=item_font_size,
         | 
| 360 | 
            -
                    leading=item_font_size * 1.15,
         | 
| 361 | 
            -
                    spaceAfter=1
         | 
| 362 | 
            -
                )
         | 
| 363 | 
            -
                
         | 
| 364 | 
            -
                subitem_style = ParagraphStyle(
         | 
| 365 | 
            -
                    'SubItemStyle',
         | 
| 366 | 
            -
                    parent=styles['Normal'],
         | 
| 367 | 
            -
                    fontName="Helvetica",
         | 
| 368 | 
            -
                    fontSize=subitem_font_size,
         | 
| 369 | 
            -
                    leading=subitem_font_size * 1.15,
         | 
| 370 | 
            -
                    leftIndent=8,
         | 
| 371 | 
            -
                    spaceAfter=1
         | 
| 372 | 
            -
                )
         | 
| 373 | 
            -
                
         | 
| 374 | 
            -
                story.append(Paragraph(apply_emoji_font("Deities Guide: Mythology and Moral Lessons", selected_font_name), title_style))
         | 
| 375 | 
            -
                story.append(Spacer(1, spacer_height))
         | 
| 376 | 
            -
                
         | 
| 377 | 
            -
                column_cells = [[] for _ in range(num_columns)]
         | 
| 378 | 
            -
                for col_idx, column in enumerate(columns):
         | 
| 379 | 
            -
                    for item in column:
         | 
| 380 | 
            -
                        if plain_text_mode:
         | 
| 381 | 
            -
                            column_cells[col_idx].append(Paragraph(apply_emoji_font(item, selected_font_name), item_style))
         | 
| 382 | 
            -
                        else:
         | 
| 383 | 
            -
                            if isinstance(item, str) and item.startswith('<b>'):
         | 
| 384 | 
            -
                                text = item.replace('<b>', '').replace('</b>', '')
         | 
| 385 | 
            -
                                column_cells[col_idx].append(Paragraph(apply_emoji_font(text, selected_font_name), section_style))
         | 
| 386 | 
            -
                            elif isinstance(item, list):
         | 
| 387 | 
            -
                                main_item, sub_items = item
         | 
| 388 | 
            -
                                column_cells[col_idx].append(Paragraph(apply_emoji_font(main_item, selected_font_name), item_style))
         | 
| 389 | 
            -
                                for sub_item in sub_items:
         | 
| 390 | 
            -
                                    column_cells[col_idx].append(Paragraph(apply_emoji_font(sub_item, selected_font_name), subitem_style))
         | 
| 391 | 
            -
                            else:
         | 
| 392 | 
            -
                                column_cells[col_idx].append(Paragraph(apply_emoji_font(item, selected_font_name), item_style))
         | 
| 393 | 
            -
                
         | 
| 394 | 
            -
                max_cells = max(len(cells) for cells in column_cells)
         | 
| 395 | 
            -
                for cells in column_cells:
         | 
| 396 | 
            -
                    cells.extend([Paragraph("", item_style)] * (max_cells - len(cells)))
         | 
| 397 | 
            -
                
         | 
| 398 | 
            -
                col_width = (A4[1] * 2 - 72) / num_columns
         | 
| 399 | 
            -
                table_data = list(zip(*column_cells))
         | 
| 400 | 
            -
                table = Table(table_data, colWidths=[col_width] * num_columns, hAlign='CENTER')
         | 
| 401 | 
            -
                table.setStyle(TableStyle([
         | 
| 402 | 
            -
                    ('VALIGN', (0, 0), (-1, -1), 'TOP'),
         | 
| 403 | 
            -
                    ('ALIGN', (0, 0), (-1, -1), 'LEFT'),
         | 
| 404 | 
            -
                    ('BACKGROUND', (0, 0), (-1, -1), colors.white),
         | 
| 405 | 
            -
                    ('GRID', (0, 0), (-1, -1), 0, colors.white),
         | 
| 406 | 
            -
                    ('LINEAFTER', (0, 0), (num_columns-1, -1), 0.5, colors.grey),
         | 
| 407 | 
            -
                    ('LEFTPADDING', (0, 0), (-1, -1), 2),
         | 
| 408 | 
            -
                    ('RIGHTPADDING', (0, 0), (-1, -1), 2),
         | 
| 409 | 
            -
                    ('TOPPADDING', (0, 0), (-1, -1), 1),
         | 
| 410 | 
            -
                    ('BOTTOMPADDING', (0, 0), (-1, -1), 1),
         | 
| 411 | 
            -
                ]))
         | 
| 412 | 
            -
                
         | 
| 413 | 
            -
                story.append(table)
         | 
| 414 | 
            -
                doc.build(story)
         | 
| 415 | 
            -
                buffer.seek(0)
         | 
| 416 | 
            -
                return buffer.getvalue()
         | 
| 417 | 
            -
             | 
| 418 | 
            -
            def pdf_to_image(pdf_bytes):
         | 
| 419 | 
            -
                try:
         | 
| 420 | 
            -
                    doc = fitz.open(stream=pdf_bytes, filetype="pdf")
         | 
| 421 | 
            -
                    images = []
         | 
| 422 | 
            -
                    for page in doc:
         | 
| 423 | 
            -
                        pix = page.get_pixmap(matrix=fitz.Matrix(2.0, 2.0))
         | 
| 424 | 
            -
                        img = Image.frombytes("RGB", [pix.width, pix.height], pix.samples)
         | 
| 425 | 
            -
                        images.append(img)
         | 
| 426 | 
            -
                    doc.close()
         | 
| 427 | 
            -
                    return images
         | 
| 428 | 
            -
                except Exception as e:
         | 
| 429 | 
            -
                    st.error(f"Failed to render PDF preview: {e}")
         | 
| 430 | 
            -
                    return None
         | 
| 431 | 
            -
             | 
| 432 | 
            -
            if 'markdown_content' not in st.session_state:
         | 
| 433 | 
            -
                st.session_state.markdown_content = default_markdown
         | 
| 434 | 
            -
             | 
| 435 | 
            -
            with st.spinner("Generating PDF..."):
         | 
| 436 | 
            -
                pdf_bytes = create_main_pdf(st.session_state.markdown_content, base_font_size, auto_size, show_subitems, plain_text_mode, num_columns)
         | 
| 437 | 
            -
             | 
| 438 | 
            -
            with st.container():
         | 
| 439 | 
            -
                pdf_images = pdf_to_image(pdf_bytes)
         | 
| 440 | 
            -
                if pdf_images:
         | 
| 441 | 
            -
                    for i, img in enumerate(pdf_images):
         | 
| 442 | 
            -
                        st.image(img, caption=f"Multi-Column Spread", use_container_width=True)
         | 
| 443 | 
            -
                else:
         | 
| 444 | 
            -
                    st.info("Download the PDF to view it locally.")
         | 
| 445 | 
            -
             | 
| 446 | 
            -
            st.download_button(
         | 
| 447 | 
            -
                label="Download PDF",
         | 
| 448 | 
            -
                data=pdf_bytes,
         | 
| 449 | 
            -
                file_name="deities_guide_multi_column.pdf",
         | 
| 450 | 
            -
                mime="application/pdf"
         | 
| 451 | 
            -
            )
         | 
| 452 | 
            -
             | 
| 453 | 
            -
            edited_markdown = st.text_area(
         | 
| 454 | 
            -
                "Modify the markdown content below:",
         | 
| 455 | 
            -
                value=st.session_state.markdown_content,
         | 
| 456 | 
            -
                height=300
         | 
| 457 | 
            -
            )
         | 
| 458 | 
            -
             | 
| 459 | 
            -
            if st.button("Update PDF"):
         | 
| 460 | 
            -
                st.session_state.markdown_content = edited_markdown
         | 
| 461 | 
            -
                st.rerun()
         | 
| 462 | 
            -
             | 
| 463 | 
            -
            st.download_button(
         | 
| 464 | 
            -
                label="Save Markdown",
         | 
| 465 | 
            -
                data=st.session_state.markdown_content,
         | 
| 466 | 
            -
                file_name="deities_guide.md",
         | 
| 467 | 
            -
                mime="text/markdown"
         | 
| 468 | 
            -
            )
         | 
|  | |
| 1 | 
            +
             | 
| 2 | 
            +
             | 
| 3 | 
             
            import io
         | 
| 4 | 
             
            import re
         | 
| 5 | 
             
            import streamlit as st
         | 
|  | |
|  | |
|  | |
| 6 | 
             
            from PIL import Image
         | 
| 7 | 
             
            import fitz
         | 
|  | |
| 8 | 
             
            from reportlab.lib.pagesizes import A4
         | 
| 9 | 
             
            from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle
         | 
| 10 | 
             
            from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
         | 
|  | |
| 12 | 
             
            from reportlab.pdfbase import pdfmetrics
         | 
| 13 | 
             
            from reportlab.pdfbase.ttfonts import TTFont
         | 
| 14 |  | 
| 15 | 
            +
            st.set_page_config(layout="wide", initial_sidebar_state="collapsed")
         | 
| 16 | 
            +
             | 
| 17 | 
            +
            def create_pdf_tab(default_markdown):
         | 
| 18 | 
            +
                # Font setup
         | 
| 19 | 
            +
                available_fonts = {
         | 
| 20 | 
            +
                    "NotoEmoji Variable": "NotoEmoji-VariableFont_wght.ttf",
         | 
| 21 | 
            +
                    "NotoEmoji Bold": "NotoEmoji-Bold.ttf",
         | 
| 22 | 
            +
                    "NotoEmoji Light": "NotoEmoji-Light.ttf",
         | 
| 23 | 
            +
                    "NotoEmoji Medium": "NotoEmoji-Medium.ttf",
         | 
| 24 | 
            +
                    "NotoEmoji Regular": "NotoEmoji-Regular.ttf",
         | 
| 25 | 
            +
                    "NotoEmoji SemiBold": "NotoEmoji-SemiBold.ttf"
         | 
| 26 | 
            +
                }
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                # Sidebar configuration
         | 
| 29 | 
            +
                with st.sidebar:
         | 
| 30 | 
            +
                    selected_font_name = st.selectbox("Select NotoEmoji Font", options=list(available_fonts.keys()))
         | 
| 31 | 
            +
                    selected_font_path = available_fonts[selected_font_name]
         | 
| 32 | 
            +
                    auto_size = st.checkbox("Auto-size text", value=True)
         | 
| 33 | 
            +
                    base_font_size = st.slider("Base Font Size (points)", min_value=6, max_value=16, value=10, step=1)
         | 
| 34 | 
            +
                    if auto_size:
         | 
| 35 | 
            +
                        st.info("Font size will adjust between 6-16 points based on content length, starting from your base size.")
         | 
| 36 | 
            +
                    plain_text_mode = st.checkbox("Render as Plain Text (Preserve Bold Only)", value=False)
         | 
| 37 | 
            +
                    num_columns = st.selectbox("Number of Columns", options=[1, 2, 3, 4, 5, 6], index=0)  # Default to 1 column
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                # Register font
         | 
| 40 | 
            +
                pdfmetrics.registerFont(TTFont(selected_font_name, selected_font_path))
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                # Emoji font application
         | 
| 43 | 
            +
                def apply_emoji_font(text, emoji_font):
         | 
| 44 | 
            +
                    emoji_pattern = re.compile(
         | 
| 45 | 
            +
                        r"([\U0001F300-\U0001F5FF"
         | 
| 46 | 
            +
                        r"\U0001F600-\U0001F64F"
         | 
| 47 | 
            +
                        r"\U0001F680-\U0001F6FF"
         | 
| 48 | 
            +
                        r"\U0001F700-\U0001F77F"
         | 
| 49 | 
            +
                        r"\U0001F780-\U0001F7FF"
         | 
| 50 | 
            +
                        r"\U0001F800-\U0001F8FF"
         | 
| 51 | 
            +
                        r"\U0001F900-\U0001F9FF"
         | 
| 52 | 
            +
                        r"\U0001FA00-\U0001FA6F"
         | 
| 53 | 
            +
                        r"\U0001FA70-\U0001FAFF"
         | 
| 54 | 
            +
                        r"\u2600-\u26FF"
         | 
| 55 | 
            +
                        r"\u2700-\u27BF]+)"
         | 
| 56 | 
            +
                    )
         | 
| 57 | 
            +
                    def replace_emoji(match):
         | 
| 58 | 
            +
                        emoji = match.group(1)
         | 
| 59 | 
            +
                        if len(emoji) > 1:
         | 
| 60 | 
            +
                            emoji = emoji[0]
         | 
| 61 | 
            +
                        return f'<font face="{emoji_font}">{emoji}</font>'
         | 
| 62 | 
            +
                    return emoji_pattern.sub(replace_emoji, text)
         | 
| 63 | 
            +
             | 
| 64 | 
            +
                # Markdown to PDF content
         | 
| 65 | 
            +
                def markdown_to_pdf_content(markdown_text, plain_text_mode, font_size, num_columns):
         | 
| 66 | 
            +
                    lines = markdown_text.strip().split('\n')
         | 
| 67 | 
            +
                    pdf_content = []
         | 
| 68 | 
            +
             | 
| 69 | 
            +
                    if plain_text_mode:
         | 
| 70 | 
            +
                        for line in lines:
         | 
| 71 | 
            +
                            line = line.strip()
         | 
| 72 | 
            +
                            if not line or line.startswith('# '):
         | 
| 73 | 
            +
                                continue
         | 
| 74 | 
            +
                            bold_pattern = re.compile(r'\*\*(.*?)\*\*')
         | 
| 75 | 
            +
                            line = bold_pattern.sub(r'<b>\1</b>', line)
         | 
| 76 | 
            +
                            pdf_content.append(line)
         | 
| 77 | 
            +
                    else:
         | 
| 78 | 
            +
                        for line in lines:
         | 
| 79 | 
            +
                            line = line.strip()
         | 
| 80 | 
            +
                            if not line or line.startswith('# '):
         | 
| 81 | 
            +
                                continue
         | 
| 82 | 
            +
                            if line.startswith('## ') or line.startswith('### '):
         | 
| 83 | 
            +
                                text = line.replace('## ', '').replace('### ', '').strip()
         | 
| 84 | 
            +
                                pdf_content.append(f"<b>{text}</b>")
         | 
| 85 | 
            +
                            else:
         | 
| 86 | 
            +
                                pdf_content.append(line.strip())
         | 
| 87 | 
            +
             | 
| 88 | 
            +
                    total_lines = len(pdf_content)
         | 
| 89 | 
            +
                    columns = [[] for _ in range(num_columns)]
         | 
| 90 | 
            +
                    lines_per_column = total_lines / num_columns if num_columns > 0 else total_lines
         | 
| 91 | 
            +
                    current_line_count = 0
         | 
| 92 | 
            +
                    current_column = 0
         | 
| 93 | 
            +
             | 
| 94 | 
            +
                    for item in pdf_content:
         | 
| 95 | 
            +
                        if current_line_count >= lines_per_column and current_column < num_columns - 1:
         | 
| 96 | 
            +
                            current_column += 1
         | 
| 97 | 
            +
                            current_line_count = 0
         | 
| 98 | 
            +
                        columns[current_column].append(item)
         | 
| 99 | 
            +
                        current_line_count += 1
         | 
| 100 | 
            +
             | 
| 101 | 
            +
                    return columns, total_lines
         | 
| 102 | 
            +
             | 
| 103 | 
            +
                # Create PDF
         | 
| 104 | 
            +
                def create_pdf(markdown_text, base_font_size, auto_size, plain_text_mode, num_columns):
         | 
| 105 | 
            +
                    buffer = io.BytesIO()
         | 
| 106 | 
            +
                    doc = SimpleDocTemplate(buffer, pagesize=A4, leftMargin=36, rightMargin=36, topMargin=36, bottomMargin=36)
         | 
| 107 | 
            +
                    styles = getSampleStyleSheet()
         | 
| 108 | 
            +
                    story = []
         | 
| 109 | 
            +
                    spacer_height = 10
         | 
| 110 | 
            +
                    columns, total_lines = markdown_to_pdf_content(markdown_text, plain_text_mode, base_font_size, num_columns)
         | 
| 111 | 
            +
             | 
| 112 | 
            +
                    if auto_size and total_lines > 0:
         | 
| 113 | 
            +
                        base_font_size = max(6, min(16, base_font_size * 300 / total_lines))
         | 
| 114 | 
            +
             | 
| 115 | 
            +
                    item_font_size = base_font_size
         | 
| 116 | 
            +
                    section_font_size = base_font_size * 1.1
         | 
| 117 | 
            +
             | 
| 118 | 
            +
                    section_style = ParagraphStyle(
         | 
| 119 | 
            +
                        'SectionStyle', parent=styles['Heading2'], fontName="Helvetica-Bold",
         | 
| 120 | 
            +
                        textColor=colors.darkblue, fontSize=section_font_size, leading=section_font_size * 1.2, spaceAfter=2
         | 
| 121 | 
            +
                    )
         | 
| 122 | 
            +
                    item_style = ParagraphStyle(
         | 
| 123 | 
            +
                        'ItemStyle', parent=styles['Normal'], fontName="Helvetica",
         | 
| 124 | 
            +
                        fontSize=item_font_size, leading=item_font_size * 1.15, spaceAfter=1
         | 
| 125 | 
            +
                    )
         | 
| 126 | 
            +
             | 
| 127 | 
            +
                    story.append(Spacer(1, spacer_height))
         | 
| 128 | 
            +
                    column_cells = [[] for _ in range(num_columns)]
         | 
| 129 | 
            +
                    for col_idx, column in enumerate(columns):
         | 
| 130 | 
            +
                        for item in column:
         | 
| 131 | 
            +
                            if isinstance(item, str) and item.startswith('<b>'):
         | 
| 132 | 
            +
                                text = item.replace('<b>', '').replace('</b>', '')
         | 
| 133 | 
            +
                                column_cells[col_idx].append(Paragraph(apply_emoji_font(text, selected_font_name), section_style))
         | 
| 134 | 
            +
                            else:
         | 
| 135 | 
            +
                                column_cells[col_idx].append(Paragraph(apply_emoji_font(item, selected_font_name), item_style))
         | 
| 136 | 
            +
             | 
| 137 | 
            +
                    max_cells = max(len(cells) for cells in column_cells) if column_cells else 0
         | 
| 138 | 
            +
                    for cells in column_cells:
         | 
| 139 | 
            +
                        cells.extend([Paragraph("", item_style)] * (max_cells - len(cells)))
         | 
| 140 | 
            +
             | 
| 141 | 
            +
                    col_width = (A4[0] - 72) / num_columns if num_columns > 0 else A4[0] - 72
         | 
| 142 | 
            +
                    table_data = list(zip(*column_cells)) if column_cells else [[]]
         | 
| 143 | 
            +
                    table = Table(table_data, colWidths=[col_width] * num_columns, hAlign='CENTER')
         | 
| 144 | 
            +
                    table.setStyle(TableStyle([
         | 
| 145 | 
            +
                        ('VALIGN', (0, 0), (-1, -1), 'TOP'), ('ALIGN', (0, 0), (-1, -1), 'LEFT'),
         | 
| 146 | 
            +
                        ('BACKGROUND', (0, 0), (-1, -1), colors.white), ('GRID', (0, 0), (-1, -1), 0, colors.white),
         | 
| 147 | 
            +
                        ('LINEAFTER', (0, 0), (num_columns-1, -1), 0.5, colors.grey),
         | 
| 148 | 
            +
                        ('LEFTPADDING', (0, 0), (-1, -1), 2), ('RIGHTPADDING', (0, 0), (-1, -1), 2),
         | 
| 149 | 
            +
                        ('TOPPADDING', (0, 0), (-1, -1), 1), ('BOTTOMPADDING', (0, 0), (-1, -1), 1),
         | 
| 150 | 
            +
                    ]))
         | 
| 151 | 
            +
             | 
| 152 | 
            +
                    story.append(table)
         | 
| 153 | 
            +
                    doc.build(story)
         | 
| 154 | 
            +
                    buffer.seek(0)
         | 
| 155 | 
            +
                    return buffer.getvalue()
         | 
| 156 | 
            +
             | 
| 157 | 
            +
                # PDF to image
         | 
| 158 | 
            +
                def pdf_to_image(pdf_bytes):
         | 
| 159 | 
            +
                    try:
         | 
| 160 | 
            +
                        doc = fitz.open(stream=pdf_bytes, filetype="pdf")
         | 
| 161 | 
            +
                        images = []
         | 
| 162 | 
            +
                        for page in doc:
         | 
| 163 | 
            +
                            pix = page.get_pixmap(matrix=fitz.Matrix(2.0, 2.0))
         | 
| 164 | 
            +
                            img = Image.frombytes("RGB", [pix.width, pix.height], pix.samples)
         | 
| 165 | 
            +
                            images.append(img)
         | 
| 166 | 
            +
                        doc.close()
         | 
| 167 | 
            +
                        return images
         | 
| 168 | 
            +
                    except Exception as e:
         | 
| 169 | 
            +
                        st.error(f"Failed to render PDF preview: {e}")
         | 
| 170 | 
            +
                        return None
         | 
| 171 | 
            +
             | 
| 172 | 
            +
                # Main logic
         | 
| 173 | 
            +
                if 'markdown_content' not in st.session_state:
         | 
| 174 | 
            +
                    st.session_state.markdown_content = default_markdown
         | 
| 175 | 
            +
             | 
| 176 | 
            +
                with st.spinner("Generating PDF..."):
         | 
| 177 | 
            +
                    pdf_bytes = create_pdf(st.session_state.markdown_content, base_font_size, auto_size, plain_text_mode, num_columns)
         | 
| 178 | 
            +
             | 
| 179 | 
            +
                with st.container():
         | 
| 180 | 
            +
                    pdf_images = pdf_to_image(pdf_bytes)
         | 
| 181 | 
            +
                    if pdf_images:
         | 
| 182 | 
            +
                        for img in pdf_images:
         | 
| 183 | 
            +
                            st.image(img, use_container_width=True)
         | 
| 184 | 
            +
                    else:
         | 
| 185 | 
            +
                        st.info("Download the PDF to view it locally.")
         | 
| 186 | 
            +
             | 
| 187 | 
            +
                st.download_button(label="Download PDF", data=pdf_bytes, file_name="deities_guide.pdf", mime="application/pdf")
         | 
| 188 | 
            +
             | 
| 189 | 
            +
                edited_markdown = st.text_area("Modify the markdown content below:", value=st.session_state.markdown_content, height=300)
         | 
| 190 | 
            +
                if st.button("Update PDF"):
         | 
| 191 | 
            +
                    st.session_state.markdown_content = edited_markdown
         | 
| 192 | 
            +
                    st.rerun()
         | 
| 193 | 
            +
             | 
| 194 | 
            +
                st.download_button(label="Save Markdown", data=st.session_state.markdown_content, file_name="deities_guide.md", mime="text/markdown")
         | 
| 195 | 
            +
             | 
| 196 | 
            +
             | 
| 197 | 
            +
             | 
| 198 | 
            +
             | 
| 199 |  | 
| 200 | 
             
            default_markdown = """# 🌟 Deities Guide: Mythology and Moral Lessons 🌟
         | 
| 201 |  | 
|  | |
| 355 | 
             
            3. Saints/Prophets: Virtues (e.g., justice, prophecy).
         | 
| 356 | 
             
            """
         | 
| 357 |  | 
| 358 | 
            +
             | 
| 359 | 
            +
            create_pdf_tab(default_markdown)
         | 
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | 
