awacke1 commited on
Commit
6e92a2d
Β·
verified Β·
1 Parent(s): 7d76447

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +109 -5
app.py CHANGED
@@ -56,10 +56,76 @@ async def generate_audio(text, voice, filename):
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
@@ -102,6 +168,23 @@ def apply_emoji_font(text, emoji_font):
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
@@ -115,8 +198,11 @@ def markdown_to_pdf_content(markdown_text, render_with_bold, auto_bold_numbers):
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
 
@@ -147,19 +233,26 @@ def create_pdf(markdown_text, base_font_size, render_with_bold, auto_bold_number
147
  styles = getSampleStyleSheet()
148
  spacer_height = 10
149
  pdf_content, total_lines = markdown_to_pdf_content(markdown_text, render_with_bold, auto_bold_numbers)
 
 
150
  item_style = ParagraphStyle(
151
  'ItemStyle', parent=styles['Normal'], fontName="DejaVuSans",
152
- fontSize=base_font_size, leading=base_font_size * 1.15, spaceAfter=1
 
153
  )
154
  numbered_bold_style = ParagraphStyle(
155
  'NumberedBoldStyle', parent=styles['Normal'], fontName="NotoEmoji-Bold",
156
  fontSize=base_font_size + 1 if enlarge_numbered else base_font_size,
157
- leading=(base_font_size + 1) * 1.15 if enlarge_numbered else base_font_size * 1.15, spaceAfter=1
 
158
  )
159
  section_style = ParagraphStyle(
160
  'SectionStyle', parent=styles['Heading2'], fontName="DejaVuSans",
161
- textColor=colors.darkblue, fontSize=base_font_size * 1.1, leading=base_font_size * 1.32, spaceAfter=2
 
162
  )
 
 
163
  try:
164
  available_font_files = glob.glob("*.ttf")
165
  if not available_font_files:
@@ -176,17 +269,22 @@ def create_pdf(markdown_text, base_font_size, render_with_bold, auto_bold_number
176
  except Exception as e:
177
  st.error(f"Font registration error: {e}")
178
  return
 
 
179
  columns = [[] for _ in range(num_columns)]
180
  lines_per_column = total_lines / num_columns if num_columns > 0 else total_lines
181
  current_line_count = 0
182
  current_column = 0
183
  number_pattern = re.compile(r'^\d+\.\s')
 
184
  for item in pdf_content:
185
  if current_line_count >= lines_per_column and current_column < num_columns - 1:
186
  current_column += 1
187
  current_line_count = 0
188
  columns[current_column].append(item)
189
  current_line_count += 1
 
 
190
  column_cells = [[] for _ in range(num_columns)]
191
  for col_idx, column in enumerate(columns):
192
  for item in column:
@@ -198,9 +296,13 @@ def create_pdf(markdown_text, base_font_size, render_with_bold, auto_bold_number
198
  column_cells[col_idx].append(Paragraph(apply_emoji_font(content, "NotoEmoji-Bold"), section_style))
199
  else:
200
  column_cells[col_idx].append(Paragraph(apply_emoji_font(item, "DejaVuSans"), item_style))
 
 
201
  max_cells = max(len(cells) for cells in column_cells) if column_cells else 0
202
  for cells in column_cells:
203
  cells.extend([Paragraph("", item_style)] * (max_cells - len(cells)))
 
 
204
  col_width = (page_width - 72) / num_columns if num_columns > 0 else page_width - 72
205
  table_data = list(zip(*column_cells)) if column_cells else [[]]
206
  table = Table(table_data, colWidths=[col_width] * num_columns, hAlign='CENTER')
@@ -215,6 +317,8 @@ def create_pdf(markdown_text, base_font_size, render_with_bold, auto_bold_number
215
  ('TOPPADDING', (0, 0), (-1, -1), 1),
216
  ('BOTTOMPADDING', (0, 0), (-1, -1), 1),
217
  ]))
 
 
218
  story = [Spacer(1, spacer_height), table]
219
  doc.build(story)
220
  buffer.seek(0)
 
56
  await communicate.save(filename)
57
  return filename
58
 
59
+ # πŸ”— Detecting links like a digital bloodhound
60
+ def detect_and_convert_links(text):
61
+ """πŸ•ΈοΈ Finds URLs in your text and turns them into actual clickable links"""
62
+ # Pattern to find URLs (http/https/ftp/www)
63
+ url_pattern = re.compile(
64
+ r'(https?://|www\.)[^\s\[\]()<>{}]+(\.[^\s\[\]()<>{}]+)+(/[^\s\[\]()<>{}]*)?',
65
+ re.IGNORECASE
66
+ )
67
+
68
+ # Pattern to find markdown links [text](url)
69
+ md_link_pattern = re.compile(r'\[(.*?)\]\((https?://[^\s\[\]()<>{}]+)\)')
70
+
71
+ # First convert markdown links
72
+ text = md_link_pattern.sub(r'<a href="\2">\1</a>', text)
73
+
74
+ # Then find and convert plain URLs not already in tags
75
+ start_idx = 0
76
+ result = []
77
+
78
+ while start_idx < len(text):
79
+ # Find the next URL
80
+ match = url_pattern.search(text, start_idx)
81
+ if not match:
82
+ # No more URLs, add the remaining text
83
+ result.append(text[start_idx:])
84
+ break
85
+
86
+ # Check if the URL is already inside an <a> tag
87
+ # This is a simplified check. A more robust approach might use an HTML parser
88
+ prev_text = text[start_idx:match.start()]
89
+ tag_balance = prev_text.count('<a') - prev_text.count('</a')
90
+
91
+ if tag_balance > 0:
92
+ # URL is likely inside a tag, skip this match
93
+ result.append(text[start_idx:match.end()])
94
+ else:
95
+ # Add text before the URL
96
+ result.append(text[start_idx:match.start()])
97
+
98
+ # Get the URL
99
+ url = match.group(0)
100
+
101
+ # Add proper URL prefix if needed
102
+ if url.startswith('www.'):
103
+ url_with_prefix = 'http://' + url
104
+ else:
105
+ url_with_prefix = url
106
+
107
+ # Add the URL as a link
108
+ result.append(f'<a href="{url_with_prefix}">{url}</a>')
109
+
110
+ start_idx = match.end()
111
+
112
+ return ''.join(result)
113
+
114
  # 🎭 Making emojis wear the right font costume
115
  def apply_emoji_font(text, emoji_font):
116
  """πŸ¦„ Because emojis deserve their own font fashion show"""
117
+ # First handle links - temporarily replace them with placeholders
118
+ link_pattern = re.compile(r'<a\s+href="([^"]+)">(.*?)</a>')
119
+ links = []
120
+
121
+ def save_link(match):
122
+ link_idx = len(links)
123
+ links.append((match.group(1), match.group(2)))
124
+ return f"###LINK_{link_idx}###"
125
+
126
+ text = link_pattern.sub(save_link, text)
127
+
128
+ # Now handle bold formatting
129
  text = re.sub(r'<b>(.*?)</b>', lambda m: f'###BOLD_START###{m.group(1)}###BOLD_END###', text)
130
 
131
  # Apply emoji font replacement
 
168
  combined_text = combined_text.replace('###BOLD_START###', '</font><b><font face="DejaVuSans">')
169
  combined_text = combined_text.replace('###BOLD_END###', '</font></b><font face="DejaVuSans">')
170
 
171
+ # Restore links
172
+ for i, (url, label) in enumerate(links):
173
+ placeholder = f"###LINK_{i}###"
174
+ if placeholder in combined_text:
175
+ # If the link is within a font tag, we need to close and reopen it
176
+ parts = combined_text.split(placeholder)
177
+ if len(parts) == 2:
178
+ before, after = parts
179
+ # Check if we're inside a font tag
180
+ if before.rfind('<font') > before.rfind('</font>'):
181
+ # Close font tag before link, reopen after
182
+ link_html = f'</font><a href="{url}">{label}</a><font face="DejaVuSans">'
183
+ combined_text = before + link_html + after
184
+ else:
185
+ # Simple replacement
186
+ combined_text = before + f'<a href="{url}">{label}</a>' + after
187
+
188
  return combined_text
189
 
190
  # πŸ“ Converting markdown to PDF content, because PDFs never go out of style
 
198
  line = line.strip()
199
  if not line or line.startswith('# '):
200
  continue
201
+
202
+ # Process links before any other formatting
203
+ line = detect_and_convert_links(line)
204
 
205
+ # Handle bold formatting
206
  if render_with_bold:
207
  line = re.sub(r'\*\*(.*?)\*\*', r'<b>\1</b>', line)
208
 
 
233
  styles = getSampleStyleSheet()
234
  spacer_height = 10
235
  pdf_content, total_lines = markdown_to_pdf_content(markdown_text, render_with_bold, auto_bold_numbers)
236
+
237
+ # Define styles for different text types
238
  item_style = ParagraphStyle(
239
  'ItemStyle', parent=styles['Normal'], fontName="DejaVuSans",
240
+ fontSize=base_font_size, leading=base_font_size * 1.15, spaceAfter=1,
241
+ linkUnderline=True # Enable underline for links
242
  )
243
  numbered_bold_style = ParagraphStyle(
244
  'NumberedBoldStyle', parent=styles['Normal'], fontName="NotoEmoji-Bold",
245
  fontSize=base_font_size + 1 if enlarge_numbered else base_font_size,
246
+ leading=(base_font_size + 1) * 1.15 if enlarge_numbered else base_font_size * 1.15, spaceAfter=1,
247
+ linkUnderline=True # Enable underline for links
248
  )
249
  section_style = ParagraphStyle(
250
  'SectionStyle', parent=styles['Heading2'], fontName="DejaVuSans",
251
+ textColor=colors.darkblue, fontSize=base_font_size * 1.1, leading=base_font_size * 1.32, spaceAfter=2,
252
+ linkUnderline=True # Enable underline for links
253
  )
254
+
255
+ # Register fonts
256
  try:
257
  available_font_files = glob.glob("*.ttf")
258
  if not available_font_files:
 
269
  except Exception as e:
270
  st.error(f"Font registration error: {e}")
271
  return
272
+
273
+ # Distribute content across columns
274
  columns = [[] for _ in range(num_columns)]
275
  lines_per_column = total_lines / num_columns if num_columns > 0 else total_lines
276
  current_line_count = 0
277
  current_column = 0
278
  number_pattern = re.compile(r'^\d+\.\s')
279
+
280
  for item in pdf_content:
281
  if current_line_count >= lines_per_column and current_column < num_columns - 1:
282
  current_column += 1
283
  current_line_count = 0
284
  columns[current_column].append(item)
285
  current_line_count += 1
286
+
287
+ # Format columns into Paragraph objects
288
  column_cells = [[] for _ in range(num_columns)]
289
  for col_idx, column in enumerate(columns):
290
  for item in column:
 
296
  column_cells[col_idx].append(Paragraph(apply_emoji_font(content, "NotoEmoji-Bold"), section_style))
297
  else:
298
  column_cells[col_idx].append(Paragraph(apply_emoji_font(item, "DejaVuSans"), item_style))
299
+
300
+ # Ensure columns have the same number of cells
301
  max_cells = max(len(cells) for cells in column_cells) if column_cells else 0
302
  for cells in column_cells:
303
  cells.extend([Paragraph("", item_style)] * (max_cells - len(cells)))
304
+
305
+ # Create the table layout
306
  col_width = (page_width - 72) / num_columns if num_columns > 0 else page_width - 72
307
  table_data = list(zip(*column_cells)) if column_cells else [[]]
308
  table = Table(table_data, colWidths=[col_width] * num_columns, hAlign='CENTER')
 
317
  ('TOPPADDING', (0, 0), (-1, -1), 1),
318
  ('BOTTOMPADDING', (0, 0), (-1, -1), 1),
319
  ]))
320
+
321
+ # Build the PDF
322
  story = [Spacer(1, spacer_height), table]
323
  doc.build(story)
324
  buffer.seek(0)