awacke1 commited on
Commit
7d76447
Β·
verified Β·
1 Parent(s): 6786aba

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +50 -3
app.py CHANGED
@@ -20,13 +20,17 @@ import pytz
20
 
21
  st.set_page_config(layout="wide", initial_sidebar_state="collapsed")
22
 
 
23
  def get_timestamp_prefix():
 
24
  central = pytz.timezone("US/Central")
25
  now = datetime.now(central)
26
  # Format: three-letter day, MMDD, HHMM + AM/PM (all uppercase)
27
  return now.strftime("%a %m%d %I%M%p").upper()
28
 
 
29
  def clean_for_speech(text):
 
30
  # Remove hash marks
31
  text = text.replace("#", "")
32
  # Remove emojis using a regex pattern that covers a wide range
@@ -45,12 +49,20 @@ def clean_for_speech(text):
45
  text = emoji_pattern.sub('', text)
46
  return text
47
 
 
48
  async def generate_audio(text, voice, filename):
 
49
  communicate = edge_tts.Communicate(text, voice)
50
  await communicate.save(filename)
51
  return filename
52
 
 
53
  def apply_emoji_font(text, emoji_font):
 
 
 
 
 
54
  emoji_pattern = re.compile(
55
  r"([\U0001F300-\U0001F5FF"
56
  r"\U0001F600-\U0001F64F"
@@ -65,40 +77,69 @@ def apply_emoji_font(text, emoji_font):
65
  r"\u2600-\u26FF"
66
  r"\u2700-\u27BF]+)"
67
  )
 
68
  def replace_emoji(match):
69
  emoji = match.group(1)
70
  emoji = unicodedata.normalize('NFC', emoji)
71
  return f'<font face="{emoji_font}">{emoji}</font>'
 
72
  segments = []
73
  last_pos = 0
 
74
  for match in emoji_pattern.finditer(text):
75
  start, end = match.span()
76
  if last_pos < start:
77
  segments.append(f'<font face="DejaVuSans">{text[last_pos:start]}</font>')
78
  segments.append(replace_emoji(match))
79
  last_pos = end
 
80
  if last_pos < len(text):
81
  segments.append(f'<font face="DejaVuSans">{text[last_pos:]}</font>')
82
- return ''.join(segments)
 
 
 
 
 
 
 
83
 
 
84
  def markdown_to_pdf_content(markdown_text, render_with_bold, auto_bold_numbers):
 
85
  lines = markdown_text.strip().split('\n')
86
  pdf_content = []
87
  number_pattern = re.compile(r'^\d+\.\s')
 
88
  for line in lines:
89
  line = line.strip()
90
  if not line or line.startswith('# '):
91
  continue
 
 
92
  if render_with_bold:
93
  line = re.sub(r'\*\*(.*?)\*\*', r'<b>\1</b>', line)
 
94
  if auto_bold_numbers and number_pattern.match(line):
 
95
  if not (line.startswith("<b>") and line.endswith("</b>")):
96
- line = f"<b>{line}</b>"
 
 
 
 
 
 
 
 
97
  pdf_content.append(line)
 
98
  total_lines = len(pdf_content)
99
  return pdf_content, total_lines
100
 
 
101
  def create_pdf(markdown_text, base_font_size, render_with_bold, auto_bold_numbers, enlarge_numbered, num_columns):
 
102
  buffer = io.BytesIO()
103
  page_width = A4[0] * 2
104
  page_height = A4[1]
@@ -179,7 +220,9 @@ def create_pdf(markdown_text, base_font_size, render_with_bold, auto_bold_number
179
  buffer.seek(0)
180
  return buffer.getvalue()
181
 
 
182
  def pdf_to_image(pdf_bytes):
 
183
  try:
184
  doc = fitz.open(stream=pdf_bytes, filetype="pdf")
185
  images = []
@@ -197,6 +240,7 @@ def pdf_to_image(pdf_bytes):
197
  md_files = [f for f in glob.glob("*.md") if os.path.basename(f) != "README.md"]
198
  md_options = [os.path.splitext(os.path.basename(f))[0] for f in md_files]
199
 
 
200
  with st.sidebar:
201
  st.markdown("### PDF Options")
202
  if md_options:
@@ -256,9 +300,11 @@ with st.sidebar:
256
  mime="audio/mpeg"
257
  )
258
 
 
259
  with st.spinner("Generating PDF..."):
260
  pdf_bytes = create_pdf(st.session_state.markdown_content, base_font_size, render_with_bold, auto_bold_numbers, enlarge_numbered, num_columns)
261
 
 
262
  with st.container():
263
  pdf_images = pdf_to_image(pdf_bytes)
264
  if pdf_images:
@@ -267,10 +313,11 @@ with st.container():
267
  else:
268
  st.info("Download the PDF to view it locally.")
269
 
 
270
  with st.sidebar:
271
  st.download_button(
272
  label="πŸ’ΎπŸ“„ Save PDF",
273
  data=pdf_bytes,
274
  file_name=f"{prefix} {selected_md}.pdf" if selected_md else f"{prefix} output.pdf",
275
  mime="application/pdf"
276
- )
 
20
 
21
  st.set_page_config(layout="wide", initial_sidebar_state="collapsed")
22
 
23
+ # πŸ•’ Time flies when you're having function calls
24
  def get_timestamp_prefix():
25
+ """πŸ•°οΈ Gets a timestamp that's more reliable than your coworker's ETA estimates"""
26
  central = pytz.timezone("US/Central")
27
  now = datetime.now(central)
28
  # Format: three-letter day, MMDD, HHMM + AM/PM (all uppercase)
29
  return now.strftime("%a %m%d %I%M%p").upper()
30
 
31
+ # 🧹 Because text needs a bath before being spoken
32
  def clean_for_speech(text):
33
+ """🧼 Scrubs your text cleaner than your bathroom will ever be"""
34
  # Remove hash marks
35
  text = text.replace("#", "")
36
  # Remove emojis using a regex pattern that covers a wide range
 
49
  text = emoji_pattern.sub('', text)
50
  return text
51
 
52
+ # 🎀 Making robots talk so you don't have to
53
  async def generate_audio(text, voice, filename):
54
+ """πŸ”Š Turn text into speech, because reading is so last century"""
55
  communicate = edge_tts.Communicate(text, voice)
56
  await communicate.save(filename)
57
  return filename
58
 
59
+ # 🎭 Making emojis wear the right font costume
60
  def apply_emoji_font(text, emoji_font):
61
+ """πŸ¦„ Because emojis deserve their own font fashion show"""
62
+ # First, handle any bold formatting to avoid tag nesting issues
63
+ text = re.sub(r'<b>(.*?)</b>', lambda m: f'###BOLD_START###{m.group(1)}###BOLD_END###', text)
64
+
65
+ # Apply emoji font replacement
66
  emoji_pattern = re.compile(
67
  r"([\U0001F300-\U0001F5FF"
68
  r"\U0001F600-\U0001F64F"
 
77
  r"\u2600-\u26FF"
78
  r"\u2700-\u27BF]+)"
79
  )
80
+
81
  def replace_emoji(match):
82
  emoji = match.group(1)
83
  emoji = unicodedata.normalize('NFC', emoji)
84
  return f'<font face="{emoji_font}">{emoji}</font>'
85
+
86
  segments = []
87
  last_pos = 0
88
+
89
  for match in emoji_pattern.finditer(text):
90
  start, end = match.span()
91
  if last_pos < start:
92
  segments.append(f'<font face="DejaVuSans">{text[last_pos:start]}</font>')
93
  segments.append(replace_emoji(match))
94
  last_pos = end
95
+
96
  if last_pos < len(text):
97
  segments.append(f'<font face="DejaVuSans">{text[last_pos:]}</font>')
98
+
99
+ combined_text = ''.join(segments)
100
+
101
+ # Restore bold tags
102
+ combined_text = combined_text.replace('###BOLD_START###', '</font><b><font face="DejaVuSans">')
103
+ combined_text = combined_text.replace('###BOLD_END###', '</font></b><font face="DejaVuSans">')
104
+
105
+ return combined_text
106
 
107
+ # πŸ“ Converting markdown to PDF content, because PDFs never go out of style
108
  def markdown_to_pdf_content(markdown_text, render_with_bold, auto_bold_numbers):
109
+ """πŸ“‹ Transforms your disorganized thoughts into structured PDF content"""
110
  lines = markdown_text.strip().split('\n')
111
  pdf_content = []
112
  number_pattern = re.compile(r'^\d+\.\s')
113
+
114
  for line in lines:
115
  line = line.strip()
116
  if not line or line.startswith('# '):
117
  continue
118
+
119
+ # Handle bold formatting before any other processing
120
  if render_with_bold:
121
  line = re.sub(r'\*\*(.*?)\*\*', r'<b>\1</b>', line)
122
+
123
  if auto_bold_numbers and number_pattern.match(line):
124
+ # Only apply bold if not already entirely bold
125
  if not (line.startswith("<b>") and line.endswith("</b>")):
126
+ # If there's already some bold formatting inside, we need to handle carefully
127
+ if "<b>" in line and "</b>" in line:
128
+ # Complex case - for simplicity, just make the whole line bold
129
+ # but remove any existing bold tags first
130
+ line = re.sub(r'</?b>', '', line)
131
+ line = f"<b>{line}</b>"
132
+ else:
133
+ line = f"<b>{line}</b>"
134
+
135
  pdf_content.append(line)
136
+
137
  total_lines = len(pdf_content)
138
  return pdf_content, total_lines
139
 
140
+ # πŸ—οΈ Building PDFs like it's your second job
141
  def create_pdf(markdown_text, base_font_size, render_with_bold, auto_bold_numbers, enlarge_numbered, num_columns):
142
+ """πŸ”¨ Constructs a PDF with the precision of a sleep-deprived architect"""
143
  buffer = io.BytesIO()
144
  page_width = A4[0] * 2
145
  page_height = A4[1]
 
220
  buffer.seek(0)
221
  return buffer.getvalue()
222
 
223
+ # πŸ–ΌοΈ Converting PDFs to images, because we can't leave well enough alone
224
  def pdf_to_image(pdf_bytes):
225
+ """πŸ”Ž Turns your PDF into pictures because some people just want to see the world rendered"""
226
  try:
227
  doc = fitz.open(stream=pdf_bytes, filetype="pdf")
228
  images = []
 
240
  md_files = [f for f in glob.glob("*.md") if os.path.basename(f) != "README.md"]
241
  md_options = [os.path.splitext(os.path.basename(f))[0] for f in md_files]
242
 
243
+ # πŸŽͺ The main Streamlit show begins here
244
  with st.sidebar:
245
  st.markdown("### PDF Options")
246
  if md_options:
 
300
  mime="audio/mpeg"
301
  )
302
 
303
+ # πŸš€ Generating the PDF with more complexity than a rocket launch
304
  with st.spinner("Generating PDF..."):
305
  pdf_bytes = create_pdf(st.session_state.markdown_content, base_font_size, render_with_bold, auto_bold_numbers, enlarge_numbered, num_columns)
306
 
307
+ # πŸ“Ί Displaying the preview, because everyone loves to window shop
308
  with st.container():
309
  pdf_images = pdf_to_image(pdf_bytes)
310
  if pdf_images:
 
313
  else:
314
  st.info("Download the PDF to view it locally.")
315
 
316
+ # πŸ’Ύ Last chance to save your masterpiece before it's gone forever
317
  with st.sidebar:
318
  st.download_button(
319
  label="πŸ’ΎπŸ“„ Save PDF",
320
  data=pdf_bytes,
321
  file_name=f"{prefix} {selected_md}.pdf" if selected_md else f"{prefix} output.pdf",
322
  mime="application/pdf"
323
+ )