Update app.py
Browse files
app.py
CHANGED
@@ -82,7 +82,11 @@ async def generate_audio(text, voice, filename):
|
|
82 |
def detect_and_convert_links(text):
|
83 |
# Convert Markdown links [text](url) to HTML <a> tags
|
84 |
md_link_pattern = re.compile(r'\[(.*?)\]\((https?://[^\s\[\]()<>{}]+)\)')
|
85 |
-
|
|
|
|
|
|
|
|
|
86 |
|
87 |
# Convert plain URLs to HTML <a> tags, avoiding already tagged links
|
88 |
url_pattern = re.compile(
|
@@ -91,14 +95,14 @@ def detect_and_convert_links(text):
|
|
91 |
)
|
92 |
def replace_url(match):
|
93 |
url = match.group(1)
|
94 |
-
return f'<a href="{url}">{url}</a>'
|
95 |
|
96 |
text = url_pattern.sub(replace_url, text)
|
97 |
return text
|
98 |
|
99 |
def apply_emoji_font(text, emoji_font):
|
100 |
# Preserve links and bold tags
|
101 |
-
link_pattern = re.compile(r'(<a\s+href="[^"]+"
|
102 |
bold_pattern = re.compile(r'(<b>.*?</b>)')
|
103 |
|
104 |
# Split text around links and bold tags
|
@@ -149,11 +153,11 @@ def apply_emoji_font(text, emoji_font):
|
|
149 |
for match in emoji_pattern.finditer(content):
|
150 |
start, end = match.span()
|
151 |
if last_pos < start:
|
152 |
-
parts.append(f'<font face="
|
153 |
parts.append(replace_emoji(match))
|
154 |
last_pos = end
|
155 |
if last_pos < len(content):
|
156 |
-
parts.append(f'<font face="
|
157 |
result.append(''.join(parts))
|
158 |
else:
|
159 |
# Keep links and bold tags unchanged
|
@@ -224,9 +228,7 @@ def create_pdf(markdown_text, base_font_size, render_with_bold, auto_bold_number
|
|
224 |
selected_font_path = next((f for f in available_font_files if "NotoEmoji-Bold" in f), None)
|
225 |
if selected_font_path:
|
226 |
pdfmetrics.registerFont(TTFont("NotoEmoji-Bold", selected_font_path))
|
227 |
-
|
228 |
-
st.error("NotoEmoji-Bold font not found.")
|
229 |
-
return
|
230 |
except Exception as e:
|
231 |
st.error(f"Font registration error: {e}")
|
232 |
return
|
@@ -250,7 +252,7 @@ def create_pdf(markdown_text, base_font_size, render_with_bold, auto_bold_number
|
|
250 |
adjusted_font_size = int(col_width / (avg_line_chars / 10))
|
251 |
adjusted_font_size = max(min_font_size, adjusted_font_size)
|
252 |
item_style = ParagraphStyle(
|
253 |
-
'ItemStyle', parent=styles['Normal'], fontName="
|
254 |
fontSize=adjusted_font_size, leading=adjusted_font_size * 1.15, spaceAfter=1,
|
255 |
linkUnderline=True
|
256 |
)
|
@@ -261,7 +263,7 @@ def create_pdf(markdown_text, base_font_size, render_with_bold, auto_bold_number
|
|
261 |
linkUnderline=True
|
262 |
)
|
263 |
section_style = ParagraphStyle(
|
264 |
-
'SectionStyle', parent=styles['Heading2'], fontName="
|
265 |
textColor=colors.darkblue, fontSize=adjusted_font_size * 1.1, leading=adjusted_font_size * 1.32, spaceAfter=2,
|
266 |
linkUnderline=True
|
267 |
)
|
@@ -287,7 +289,7 @@ def create_pdf(markdown_text, base_font_size, render_with_bold, auto_bold_number
|
|
287 |
heading_style = ParagraphStyle(
|
288 |
f'Heading{level}Style',
|
289 |
parent=styles['Heading1'],
|
290 |
-
fontName="
|
291 |
textColor=colors.darkblue if level == 1 else (colors.black if level > 2 else colors.blue),
|
292 |
fontSize=adjusted_font_size * (1.6 - (level-1)*0.15),
|
293 |
leading=adjusted_font_size * (1.8 - (level-1)*0.15),
|
@@ -303,9 +305,9 @@ def create_pdf(markdown_text, base_font_size, render_with_bold, auto_bold_number
|
|
303 |
else:
|
304 |
column_cells[col_idx].append(Paragraph(apply_emoji_font(content, "NotoEmoji-Bold"), section_style))
|
305 |
else:
|
306 |
-
column_cells[col_idx].append(Paragraph(apply_emoji_font(item, "
|
307 |
else:
|
308 |
-
column_cells[col_idx].append(Paragraph(apply_emoji_font(str(item), "
|
309 |
max_cells = max(len(cells) for cells in column_cells) if column_cells else 0
|
310 |
for cells in column_cells:
|
311 |
cells.extend([Paragraph("", item_style)] * (max_cells - len(cells)))
|
|
|
82 |
def detect_and_convert_links(text):
|
83 |
# Convert Markdown links [text](url) to HTML <a> tags
|
84 |
md_link_pattern = re.compile(r'\[(.*?)\]\((https?://[^\s\[\]()<>{}]+)\)')
|
85 |
+
def replace_md_link(match):
|
86 |
+
text = match.group(1)
|
87 |
+
url = match.group(2)
|
88 |
+
return f'<a href="{url}" color="blue">{text}</a>'
|
89 |
+
text = md_link_pattern.sub(replace_md_link, text)
|
90 |
|
91 |
# Convert plain URLs to HTML <a> tags, avoiding already tagged links
|
92 |
url_pattern = re.compile(
|
|
|
95 |
)
|
96 |
def replace_url(match):
|
97 |
url = match.group(1)
|
98 |
+
return f'<a href="{url}" color="blue">{url}</a>'
|
99 |
|
100 |
text = url_pattern.sub(replace_url, text)
|
101 |
return text
|
102 |
|
103 |
def apply_emoji_font(text, emoji_font):
|
104 |
# Preserve links and bold tags
|
105 |
+
link_pattern = re.compile(r'(<a\s+href="[^"]+"[^>]*>.*?</a>)')
|
106 |
bold_pattern = re.compile(r'(<b>.*?</b>)')
|
107 |
|
108 |
# Split text around links and bold tags
|
|
|
153 |
for match in emoji_pattern.finditer(content):
|
154 |
start, end = match.span()
|
155 |
if last_pos < start:
|
156 |
+
parts.append(f'<font face="DejaVuSans">{content[last_pos:start]}</font>')
|
157 |
parts.append(replace_emoji(match))
|
158 |
last_pos = end
|
159 |
if last_pos < len(content):
|
160 |
+
parts.append(f'<font face="DejaVuSans">{content[last_pos:]}</font>')
|
161 |
result.append(''.join(parts))
|
162 |
else:
|
163 |
# Keep links and bold tags unchanged
|
|
|
228 |
selected_font_path = next((f for f in available_font_files if "NotoEmoji-Bold" in f), None)
|
229 |
if selected_font_path:
|
230 |
pdfmetrics.registerFont(TTFont("NotoEmoji-Bold", selected_font_path))
|
231 |
+
pdfmetrics.registerFont(TTFont("DejaVuSans", "DejaVuSans.ttf"))
|
|
|
|
|
232 |
except Exception as e:
|
233 |
st.error(f"Font registration error: {e}")
|
234 |
return
|
|
|
252 |
adjusted_font_size = int(col_width / (avg_line_chars / 10))
|
253 |
adjusted_font_size = max(min_font_size, adjusted_font_size)
|
254 |
item_style = ParagraphStyle(
|
255 |
+
'ItemStyle', parent=styles['Normal'], fontName="DejaVuSans",
|
256 |
fontSize=adjusted_font_size, leading=adjusted_font_size * 1.15, spaceAfter=1,
|
257 |
linkUnderline=True
|
258 |
)
|
|
|
263 |
linkUnderline=True
|
264 |
)
|
265 |
section_style = ParagraphStyle(
|
266 |
+
'SectionStyle', parent=styles['Heading2'], fontName="DejaVuSans",
|
267 |
textColor=colors.darkblue, fontSize=adjusted_font_size * 1.1, leading=adjusted_font_size * 1.32, spaceAfter=2,
|
268 |
linkUnderline=True
|
269 |
)
|
|
|
289 |
heading_style = ParagraphStyle(
|
290 |
f'Heading{level}Style',
|
291 |
parent=styles['Heading1'],
|
292 |
+
fontName="DejaVuSans",
|
293 |
textColor=colors.darkblue if level == 1 else (colors.black if level > 2 else colors.blue),
|
294 |
fontSize=adjusted_font_size * (1.6 - (level-1)*0.15),
|
295 |
leading=adjusted_font_size * (1.8 - (level-1)*0.15),
|
|
|
305 |
else:
|
306 |
column_cells[col_idx].append(Paragraph(apply_emoji_font(content, "NotoEmoji-Bold"), section_style))
|
307 |
else:
|
308 |
+
column_cells[col_idx].append(Paragraph(apply_emoji_font(item, "DejaVuSans"), item_style))
|
309 |
else:
|
310 |
+
column_cells[col_idx].append(Paragraph(apply_emoji_font(str(item), "DejaVuSans"), item_style))
|
311 |
max_cells = max(len(cells) for cells in column_cells) if column_cells else 0
|
312 |
for cells in column_cells:
|
313 |
cells.extend([Paragraph("", item_style)] * (max_cells - len(cells)))
|