Update app.py
Browse files
app.py
CHANGED
@@ -3,21 +3,21 @@ import io
|
|
3 |
import re
|
4 |
import streamlit as st
|
5 |
|
6 |
-
#
|
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
|
14 |
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
|
15 |
-
from reportlab.lib import colors
|
16 |
from reportlab.pdfbase import pdfmetrics
|
17 |
from reportlab.pdfbase.ttfonts import TTFont
|
18 |
|
19 |
-
#
|
20 |
-
#
|
21 |
available_fonts = {
|
22 |
"NotoEmoji Variable": "NotoEmoji-VariableFont_wght.ttf",
|
23 |
"NotoEmoji Bold": "NotoEmoji-Bold.ttf",
|
@@ -27,20 +27,20 @@ available_fonts = {
|
|
27 |
"NotoEmoji SemiBold": "NotoEmoji-SemiBold.ttf"
|
28 |
}
|
29 |
|
30 |
-
# Sidebar: Let the user
|
31 |
selected_font_name = st.sidebar.selectbox(
|
32 |
"Select NotoEmoji Font",
|
33 |
options=list(available_fonts.keys())
|
34 |
)
|
35 |
selected_font_path = available_fonts[selected_font_name]
|
36 |
|
37 |
-
# Register the chosen emoji font with ReportLab
|
38 |
pdfmetrics.registerFont(TTFont(selected_font_name, selected_font_path))
|
39 |
|
40 |
-
#
|
41 |
-
#
|
42 |
def apply_emoji_font(text, emoji_font):
|
43 |
-
#
|
44 |
emoji_pattern = re.compile(
|
45 |
r"([\U0001F300-\U0001F5FF"
|
46 |
r"\U0001F600-\U0001F64F"
|
@@ -52,12 +52,12 @@ def apply_emoji_font(text, emoji_font):
|
|
52 |
r"\U0001FA00-\U0001FA6F"
|
53 |
r"\U0001FA70-\U0001FAFF"
|
54 |
r"\u2600-\u26FF"
|
55 |
-
r"\u2700-\u27BF)
|
56 |
)
|
57 |
# Wrap found emoji with a font tag using the selected emoji font.
|
58 |
return emoji_pattern.sub(r'<font face="{}">\1</font>'.format(emoji_font), text)
|
59 |
|
60 |
-
#
|
61 |
# Default markdown content with emojis.
|
62 |
default_markdown = """# Cutting-Edge ML Outline
|
63 |
|
@@ -126,7 +126,7 @@ default_markdown = """# Cutting-Edge ML Outline
|
|
126 |
- Documentation synthesis
|
127 |
"""
|
128 |
|
129 |
-
#
|
130 |
# Process markdown into a two-column layout for the PDF.
|
131 |
def markdown_to_pdf_content(markdown_text):
|
132 |
lines = markdown_text.strip().split('\n')
|
@@ -172,7 +172,7 @@ def markdown_to_pdf_content(markdown_text):
|
|
172 |
|
173 |
return left_column, right_column
|
174 |
|
175 |
-
#
|
176 |
# Create the PDF using ReportLab.
|
177 |
def create_main_pdf(markdown_text, base_font_size=10, auto_size=False):
|
178 |
buffer = io.BytesIO()
|
@@ -207,7 +207,7 @@ def create_main_pdf(markdown_text, base_font_size=10, auto_size=False):
|
|
207 |
section_font_size = base_font_size * 1.2
|
208 |
title_font_size = min(16, base_font_size * 1.5)
|
209 |
|
210 |
-
# Define ParagraphStyles using Helvetica for
|
211 |
title_style = ParagraphStyle(
|
212 |
'Heading1',
|
213 |
parent=styles['Heading1'],
|
@@ -246,13 +246,13 @@ def create_main_pdf(markdown_text, base_font_size=10, auto_size=False):
|
|
246 |
spaceAfter=1
|
247 |
)
|
248 |
|
249 |
-
# Apply emoji font wrapping to the title and each paragraph.
|
250 |
story.append(Paragraph(apply_emoji_font("Cutting-Edge ML Outline (ReportLab)", selected_font_name), title_style))
|
251 |
story.append(Spacer(1, spacer_height))
|
252 |
|
253 |
left_cells = []
|
254 |
for item in left_column:
|
255 |
if isinstance(item, str) and item.startswith('<b>'):
|
|
|
256 |
text = item.replace('<b>', '').replace('</b>', '')
|
257 |
left_cells.append(Paragraph(apply_emoji_font(text, selected_font_name), section_style))
|
258 |
elif isinstance(item, list):
|
@@ -300,7 +300,7 @@ def create_main_pdf(markdown_text, base_font_size=10, auto_size=False):
|
|
300 |
buffer.seek(0)
|
301 |
return buffer.getvalue()
|
302 |
|
303 |
-
#
|
304 |
# Convert PDF bytes to an image for preview using PyMuPDF.
|
305 |
def pdf_to_image(pdf_bytes):
|
306 |
try:
|
@@ -314,7 +314,7 @@ def pdf_to_image(pdf_bytes):
|
|
314 |
st.error(f"Failed to render PDF preview: {e}")
|
315 |
return None
|
316 |
|
317 |
-
#
|
318 |
# Sidebar options for text size.
|
319 |
with st.sidebar:
|
320 |
auto_size = st.checkbox("Auto-size text", value=True)
|
@@ -328,7 +328,7 @@ with st.sidebar:
|
|
328 |
if 'markdown_content' not in st.session_state:
|
329 |
st.session_state.markdown_content = default_markdown
|
330 |
|
331 |
-
#
|
332 |
# Generate the PDF.
|
333 |
with st.spinner("Generating PDF..."):
|
334 |
pdf_bytes = create_main_pdf(st.session_state.markdown_content, base_font_size, auto_size)
|
|
|
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
|
14 |
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
|
15 |
+
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 (all in the base directory now)
|
21 |
available_fonts = {
|
22 |
"NotoEmoji Variable": "NotoEmoji-VariableFont_wght.ttf",
|
23 |
"NotoEmoji Bold": "NotoEmoji-Bold.ttf",
|
|
|
27 |
"NotoEmoji SemiBold": "NotoEmoji-SemiBold.ttf"
|
28 |
}
|
29 |
|
30 |
+
# Sidebar: Let the user choose the desired NotoEmoji font.
|
31 |
selected_font_name = st.sidebar.selectbox(
|
32 |
"Select NotoEmoji Font",
|
33 |
options=list(available_fonts.keys())
|
34 |
)
|
35 |
selected_font_path = available_fonts[selected_font_name]
|
36 |
|
37 |
+
# Register the chosen emoji font with ReportLab.
|
38 |
pdfmetrics.registerFont(TTFont(selected_font_name, selected_font_path))
|
39 |
|
40 |
+
# ---------------------------------------------------------------
|
41 |
+
# Helper function to wrap emoji characters with a font tag.
|
42 |
def apply_emoji_font(text, emoji_font):
|
43 |
+
# This regex attempts to capture many common emoji ranges.
|
44 |
emoji_pattern = re.compile(
|
45 |
r"([\U0001F300-\U0001F5FF"
|
46 |
r"\U0001F600-\U0001F64F"
|
|
|
52 |
r"\U0001FA00-\U0001FA6F"
|
53 |
r"\U0001FA70-\U0001FAFF"
|
54 |
r"\u2600-\u26FF"
|
55 |
+
r"\u2700-\u27BF]+)"
|
56 |
)
|
57 |
# Wrap found emoji with a font tag using the selected emoji font.
|
58 |
return emoji_pattern.sub(r'<font face="{}">\1</font>'.format(emoji_font), text)
|
59 |
|
60 |
+
# ---------------------------------------------------------------
|
61 |
# Default markdown content with emojis.
|
62 |
default_markdown = """# Cutting-Edge ML Outline
|
63 |
|
|
|
126 |
- Documentation synthesis
|
127 |
"""
|
128 |
|
129 |
+
# ---------------------------------------------------------------
|
130 |
# Process markdown into a two-column layout for the PDF.
|
131 |
def markdown_to_pdf_content(markdown_text):
|
132 |
lines = markdown_text.strip().split('\n')
|
|
|
172 |
|
173 |
return left_column, right_column
|
174 |
|
175 |
+
# ---------------------------------------------------------------
|
176 |
# Create the PDF using ReportLab.
|
177 |
def create_main_pdf(markdown_text, base_font_size=10, auto_size=False):
|
178 |
buffer = io.BytesIO()
|
|
|
207 |
section_font_size = base_font_size * 1.2
|
208 |
title_font_size = min(16, base_font_size * 1.5)
|
209 |
|
210 |
+
# Define ParagraphStyles using Helvetica for normal text.
|
211 |
title_style = ParagraphStyle(
|
212 |
'Heading1',
|
213 |
parent=styles['Heading1'],
|
|
|
246 |
spaceAfter=1
|
247 |
)
|
248 |
|
|
|
249 |
story.append(Paragraph(apply_emoji_font("Cutting-Edge ML Outline (ReportLab)", selected_font_name), title_style))
|
250 |
story.append(Spacer(1, spacer_height))
|
251 |
|
252 |
left_cells = []
|
253 |
for item in left_column:
|
254 |
if isinstance(item, str) and item.startswith('<b>'):
|
255 |
+
# Process section headings.
|
256 |
text = item.replace('<b>', '').replace('</b>', '')
|
257 |
left_cells.append(Paragraph(apply_emoji_font(text, selected_font_name), section_style))
|
258 |
elif isinstance(item, list):
|
|
|
300 |
buffer.seek(0)
|
301 |
return buffer.getvalue()
|
302 |
|
303 |
+
# ---------------------------------------------------------------
|
304 |
# Convert PDF bytes to an image for preview using PyMuPDF.
|
305 |
def pdf_to_image(pdf_bytes):
|
306 |
try:
|
|
|
314 |
st.error(f"Failed to render PDF preview: {e}")
|
315 |
return None
|
316 |
|
317 |
+
# ---------------------------------------------------------------
|
318 |
# Sidebar options for text size.
|
319 |
with st.sidebar:
|
320 |
auto_size = st.checkbox("Auto-size text", value=True)
|
|
|
328 |
if 'markdown_content' not in st.session_state:
|
329 |
st.session_state.markdown_content = default_markdown
|
330 |
|
331 |
+
# ---------------------------------------------------------------
|
332 |
# Generate the PDF.
|
333 |
with st.spinner("Generating PDF..."):
|
334 |
pdf_bytes = create_main_pdf(st.session_state.markdown_content, base_font_size, auto_size)
|