awacke1 commited on
Commit
cfcefd2
Β·
verified Β·
1 Parent(s): d5ec0f0

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +28 -53
app.py CHANGED
@@ -3,11 +3,10 @@ import io
3
  import re
4
  import streamlit as st
5
 
6
- # Must be the very first Streamlit command.
7
  st.set_page_config(layout="wide", initial_sidebar_state="collapsed")
8
 
9
  from PIL import Image
10
- import fitz # PyMuPDF
11
 
12
  from reportlab.lib.pagesizes import A4
13
  from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle
@@ -16,8 +15,6 @@ from reportlab.lib import colors
16
  from reportlab.pdfbase import pdfmetrics
17
  from reportlab.pdfbase.ttfonts import TTFont
18
 
19
- # ---------------------------------------------------------------
20
- # Define available NotoEmoji fonts (assumed in the base directory)
21
  available_fonts = {
22
  "NotoEmoji Variable": "NotoEmoji-VariableFont_wght.ttf",
23
  "NotoEmoji Bold": "NotoEmoji-Bold.ttf",
@@ -27,7 +24,6 @@ available_fonts = {
27
  "NotoEmoji SemiBold": "NotoEmoji-SemiBold.ttf"
28
  }
29
 
30
- # Sidebar: Font selection and size adjustment.
31
  with st.sidebar:
32
  selected_font_name = st.selectbox(
33
  "Select NotoEmoji Font",
@@ -40,11 +36,8 @@ with st.sidebar:
40
  if auto_size:
41
  st.info("Font size will adjust between 6-16 points based on content length, starting from your base size.")
42
 
43
- # Register the chosen emoji font with ReportLab.
44
  pdfmetrics.registerFont(TTFont(selected_font_name, selected_font_path))
45
 
46
- # ---------------------------------------------------------------
47
- # Helper function to wrap emoji characters with a font tag.
48
  def apply_emoji_font(text, emoji_font):
49
  emoji_pattern = re.compile(
50
  r"([\U0001F300-\U0001F5FF"
@@ -61,8 +54,6 @@ def apply_emoji_font(text, emoji_font):
61
  )
62
  return emoji_pattern.sub(r'<font face="{}">\1</font>'.format(emoji_font), text)
63
 
64
- # ---------------------------------------------------------------
65
- # Default markdown content with your Deities Guide.
66
  default_markdown = """# 🌟 Deities Guide: Mythology and Moral Lessons 🌟
67
 
68
  ## 1. πŸ“œ Introduction
@@ -221,8 +212,6 @@ default_markdown = """# 🌟 Deities Guide: Mythology and Moral Lessons 🌟
221
  3. Saints/Prophets: Virtues (e.g., justice, prophecy).
222
  """
223
 
224
- # ---------------------------------------------------------------
225
- # Process markdown into a two-column layout for a double-page spread.
226
  def markdown_to_pdf_content(markdown_text):
227
  lines = markdown_text.strip().split('\n')
228
  pdf_content = []
@@ -236,7 +225,6 @@ def markdown_to_pdf_content(markdown_text):
236
  continue
237
 
238
  if line.startswith('# '):
239
- # Skip the main title for now, added separately.
240
  pass
241
  elif line.startswith('## '):
242
  if current_item and sub_items:
@@ -267,31 +255,33 @@ def markdown_to_pdf_content(markdown_text):
267
  if current_item and sub_items:
268
  pdf_content.append([current_item, sub_items])
269
 
270
- # Split into two columns (left and right) based on line count.
271
- total_lines = sum(1 + len(subs) if isinstance(item, list) else 1 for item in pdf_content)
272
- target_lines = total_lines // 2
 
 
 
 
 
273
  left_column = []
274
  right_column = []
275
- current_lines = 0
276
 
277
  for item in pdf_content:
278
- line_count = 1 + (len(item[1]) if isinstance(item, list) else 0)
279
- if current_lines < target_lines or len(left_column) == 0:
280
  left_column.append(item)
281
- current_lines += line_count
282
  else:
283
  right_column.append(item)
284
 
285
  return left_column, right_column
286
 
287
- # ---------------------------------------------------------------
288
- # Create the PDF as a double-page spread.
289
  def create_main_pdf(markdown_text, base_font_size=10, auto_size=False):
290
  buffer = io.BytesIO()
291
- # Double-page spread: Two A4 pages side-by-side (landscape).
292
  doc = SimpleDocTemplate(
293
  buffer,
294
- pagesize=(A4[1] * 2, A4[0]), # Width = 2 * A4 width, Height = A4 height
295
  leftMargin=36,
296
  rightMargin=36,
297
  topMargin=36,
@@ -303,23 +293,23 @@ def create_main_pdf(markdown_text, base_font_size=10, auto_size=False):
303
  spacer_height = 10
304
  left_column, right_column = markdown_to_pdf_content(markdown_text)
305
 
306
- total_items = sum(1 + len(subs) if isinstance(item, list) else 1 for item in left_column + right_column)
307
  if auto_size:
308
- base_font_size = max(6, min(16, base_font_size * 200 / total_items)) # Scale based on user’s base size.
309
 
310
  item_font_size = base_font_size
311
- subitem_font_size = base_font_size * 0.9
312
- section_font_size = base_font_size * 1.2
313
- title_font_size = min(20, base_font_size * 1.5)
314
 
315
- # Define ParagraphStyles using Helvetica for normal text.
316
  title_style = ParagraphStyle(
317
  'Heading1',
318
  parent=styles['Heading1'],
319
  fontName="Helvetica-Bold",
320
  textColor=colors.darkblue,
321
  alignment=1,
322
- fontSize=title_font_size
 
323
  )
324
 
325
  section_style = ParagraphStyle(
@@ -337,7 +327,7 @@ def create_main_pdf(markdown_text, base_font_size=10, auto_size=False):
337
  parent=styles['Normal'],
338
  fontName="Helvetica",
339
  fontSize=item_font_size,
340
- leading=item_font_size * 1.2,
341
  spaceAfter=1
342
  )
343
 
@@ -346,16 +336,14 @@ def create_main_pdf(markdown_text, base_font_size=10, auto_size=False):
346
  parent=styles['Normal'],
347
  fontName="Helvetica",
348
  fontSize=subitem_font_size,
349
- leading=subitem_font_size * 1.2,
350
- leftIndent=10,
351
  spaceAfter=1
352
  )
353
 
354
- # Title spanning both columns.
355
  story.append(Paragraph(apply_emoji_font("Deities Guide: Mythology and Moral Lessons", selected_font_name), title_style))
356
  story.append(Spacer(1, spacer_height))
357
 
358
- # Prepare two-column layout.
359
  left_cells = []
360
  for item in left_column:
361
  if isinstance(item, str) and item.startswith('<b>'):
@@ -382,21 +370,19 @@ def create_main_pdf(markdown_text, base_font_size=10, auto_size=False):
382
  else:
383
  right_cells.append(Paragraph(apply_emoji_font(item, selected_font_name), item_style))
384
 
385
- # Balance the columns by padding with empty strings.
386
  max_cells = max(len(left_cells), len(right_cells))
387
- left_cells.extend([""] * (max_cells - len(left_cells)))
388
- right_cells.extend([""] * (max_cells - len(right_cells)))
389
 
390
- # Create a table for the double-page spread.
391
  table_data = list(zip(left_cells, right_cells))
392
- col_width = (A4[1] - 36) # Half the spread width minus margins.
393
  table = Table(table_data, colWidths=[col_width, col_width], hAlign='CENTER')
394
  table.setStyle(TableStyle([
395
  ('VALIGN', (0, 0), (-1, -1), 'TOP'),
396
  ('ALIGN', (0, 0), (-1, -1), 'LEFT'),
397
  ('BACKGROUND', (0, 0), (-1, -1), colors.white),
398
  ('GRID', (0, 0), (-1, -1), 0, colors.white),
399
- ('LINEAFTER', (0, 0), (0, -1), 0.5, colors.grey), # Divider between columns.
400
  ('LEFTPADDING', (0, 0), (-1, -1), 2),
401
  ('RIGHTPADDING', (0, 0), (-1, -1), 2),
402
  ('TOPPADDING', (0, 0), (-1, -1), 1),
@@ -408,8 +394,6 @@ def create_main_pdf(markdown_text, base_font_size=10, auto_size=False):
408
  buffer.seek(0)
409
  return buffer.getvalue()
410
 
411
- # ---------------------------------------------------------------
412
- # Convert PDF bytes to an image for preview using PyMuPDF.
413
  def pdf_to_image(pdf_bytes):
414
  try:
415
  doc = fitz.open(stream=pdf_bytes, filetype="pdf")
@@ -424,17 +408,12 @@ def pdf_to_image(pdf_bytes):
424
  st.error(f"Failed to render PDF preview: {e}")
425
  return None
426
 
427
- # ---------------------------------------------------------------
428
- # Persist markdown content in session state.
429
  if 'markdown_content' not in st.session_state:
430
  st.session_state.markdown_content = default_markdown
431
 
432
- # ---------------------------------------------------------------
433
- # Generate the PDF.
434
  with st.spinner("Generating PDF..."):
435
  pdf_bytes = create_main_pdf(st.session_state.markdown_content, base_font_size, auto_size)
436
 
437
- # Display PDF preview.
438
  with st.container():
439
  pdf_images = pdf_to_image(pdf_bytes)
440
  if pdf_images:
@@ -443,7 +422,6 @@ with st.container():
443
  else:
444
  st.info("Download the PDF to view it locally.")
445
 
446
- # PDF Download button.
447
  st.download_button(
448
  label="Download PDF",
449
  data=pdf_bytes,
@@ -451,19 +429,16 @@ st.download_button(
451
  mime="application/pdf"
452
  )
453
 
454
- # Markdown editor.
455
  edited_markdown = st.text_area(
456
  "Modify the markdown content below:",
457
  value=st.session_state.markdown_content,
458
  height=300
459
  )
460
 
461
- # Update PDF on button click.
462
  if st.button("Update PDF"):
463
  st.session_state.markdown_content = edited_markdown
464
  st.rerun()
465
 
466
- # Markdown Download button.
467
  st.download_button(
468
  label="Save Markdown",
469
  data=st.session_state.markdown_content,
 
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
 
15
  from reportlab.pdfbase import pdfmetrics
16
  from reportlab.pdfbase.ttfonts import TTFont
17
 
 
 
18
  available_fonts = {
19
  "NotoEmoji Variable": "NotoEmoji-VariableFont_wght.ttf",
20
  "NotoEmoji Bold": "NotoEmoji-Bold.ttf",
 
24
  "NotoEmoji SemiBold": "NotoEmoji-SemiBold.ttf"
25
  }
26
 
 
27
  with st.sidebar:
28
  selected_font_name = st.selectbox(
29
  "Select NotoEmoji Font",
 
36
  if auto_size:
37
  st.info("Font size will adjust between 6-16 points based on content length, starting from your base size.")
38
 
 
39
  pdfmetrics.registerFont(TTFont(selected_font_name, selected_font_path))
40
 
 
 
41
  def apply_emoji_font(text, emoji_font):
42
  emoji_pattern = re.compile(
43
  r"([\U0001F300-\U0001F5FF"
 
54
  )
55
  return emoji_pattern.sub(r'<font face="{}">\1</font>'.format(emoji_font), text)
56
 
 
 
57
  default_markdown = """# 🌟 Deities Guide: Mythology and Moral Lessons 🌟
58
 
59
  ## 1. πŸ“œ Introduction
 
212
  3. Saints/Prophets: Virtues (e.g., justice, prophecy).
213
  """
214
 
 
 
215
  def markdown_to_pdf_content(markdown_text):
216
  lines = markdown_text.strip().split('\n')
217
  pdf_content = []
 
225
  continue
226
 
227
  if line.startswith('# '):
 
228
  pass
229
  elif line.startswith('## '):
230
  if current_item and sub_items:
 
255
  if current_item and sub_items:
256
  pdf_content.append([current_item, sub_items])
257
 
258
+ total_weight = 0
259
+ for item in pdf_content:
260
+ if isinstance(item, list):
261
+ total_weight += 1 + len(item[1])
262
+ else:
263
+ total_weight += 1
264
+
265
+ target_weight = total_weight / 2
266
  left_column = []
267
  right_column = []
268
+ current_weight = 0
269
 
270
  for item in pdf_content:
271
+ item_weight = 1 + (len(item[1]) if isinstance(item, list) else 0)
272
+ if current_weight < target_weight or not left_column:
273
  left_column.append(item)
274
+ current_weight += item_weight
275
  else:
276
  right_column.append(item)
277
 
278
  return left_column, right_column
279
 
 
 
280
  def create_main_pdf(markdown_text, base_font_size=10, auto_size=False):
281
  buffer = io.BytesIO()
 
282
  doc = SimpleDocTemplate(
283
  buffer,
284
+ pagesize=(A4[1] * 2, A4[0]),
285
  leftMargin=36,
286
  rightMargin=36,
287
  topMargin=36,
 
293
  spacer_height = 10
294
  left_column, right_column = markdown_to_pdf_content(markdown_text)
295
 
296
+ total_lines = sum(1 + len(subs) if isinstance(item, list) else 1 for item in left_column + right_column)
297
  if auto_size:
298
+ base_font_size = max(6, min(16, base_font_size * 300 / total_lines))
299
 
300
  item_font_size = base_font_size
301
+ subitem_font_size = base_font_size * 0.85
302
+ section_font_size = base_font_size * 1.1
303
+ title_font_size = min(20, base_font_size * 1.4)
304
 
 
305
  title_style = ParagraphStyle(
306
  'Heading1',
307
  parent=styles['Heading1'],
308
  fontName="Helvetica-Bold",
309
  textColor=colors.darkblue,
310
  alignment=1,
311
+ fontSize=title_font_size,
312
+ leading=title_font_size * 1.2
313
  )
314
 
315
  section_style = ParagraphStyle(
 
327
  parent=styles['Normal'],
328
  fontName="Helvetica",
329
  fontSize=item_font_size,
330
+ leading=item_font_size * 1.15,
331
  spaceAfter=1
332
  )
333
 
 
336
  parent=styles['Normal'],
337
  fontName="Helvetica",
338
  fontSize=subitem_font_size,
339
+ leading=subitem_font_size * 1.15,
340
+ leftIndent=8,
341
  spaceAfter=1
342
  )
343
 
 
344
  story.append(Paragraph(apply_emoji_font("Deities Guide: Mythology and Moral Lessons", selected_font_name), title_style))
345
  story.append(Spacer(1, spacer_height))
346
 
 
347
  left_cells = []
348
  for item in left_column:
349
  if isinstance(item, str) and item.startswith('<b>'):
 
370
  else:
371
  right_cells.append(Paragraph(apply_emoji_font(item, selected_font_name), item_style))
372
 
 
373
  max_cells = max(len(left_cells), len(right_cells))
374
+ left_cells.extend([Paragraph("", item_style)] * (max_cells - len(left_cells)))
375
+ right_cells.extend([Paragraph("", item_style)] * (max_cells - len(right_cells)))
376
 
 
377
  table_data = list(zip(left_cells, right_cells))
378
+ col_width = (A4[1] - 36)
379
  table = Table(table_data, colWidths=[col_width, col_width], hAlign='CENTER')
380
  table.setStyle(TableStyle([
381
  ('VALIGN', (0, 0), (-1, -1), 'TOP'),
382
  ('ALIGN', (0, 0), (-1, -1), 'LEFT'),
383
  ('BACKGROUND', (0, 0), (-1, -1), colors.white),
384
  ('GRID', (0, 0), (-1, -1), 0, colors.white),
385
+ ('LINEAFTER', (0, 0), (0, -1), 0.5, colors.grey),
386
  ('LEFTPADDING', (0, 0), (-1, -1), 2),
387
  ('RIGHTPADDING', (0, 0), (-1, -1), 2),
388
  ('TOPPADDING', (0, 0), (-1, -1), 1),
 
394
  buffer.seek(0)
395
  return buffer.getvalue()
396
 
 
 
397
  def pdf_to_image(pdf_bytes):
398
  try:
399
  doc = fitz.open(stream=pdf_bytes, filetype="pdf")
 
408
  st.error(f"Failed to render PDF preview: {e}")
409
  return None
410
 
 
 
411
  if 'markdown_content' not in st.session_state:
412
  st.session_state.markdown_content = default_markdown
413
 
 
 
414
  with st.spinner("Generating PDF..."):
415
  pdf_bytes = create_main_pdf(st.session_state.markdown_content, base_font_size, auto_size)
416
 
 
417
  with st.container():
418
  pdf_images = pdf_to_image(pdf_bytes)
419
  if pdf_images:
 
422
  else:
423
  st.info("Download the PDF to view it locally.")
424
 
 
425
  st.download_button(
426
  label="Download PDF",
427
  data=pdf_bytes,
 
429
  mime="application/pdf"
430
  )
431
 
 
432
  edited_markdown = st.text_area(
433
  "Modify the markdown content below:",
434
  value=st.session_state.markdown_content,
435
  height=300
436
  )
437
 
 
438
  if st.button("Update PDF"):
439
  st.session_state.markdown_content = edited_markdown
440
  st.rerun()
441
 
 
442
  st.download_button(
443
  label="Save Markdown",
444
  data=st.session_state.markdown_content,