awacke1 commited on
Commit
ce08b6d
·
verified ·
1 Parent(s): 555f069

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +29 -208
app.py CHANGED
@@ -1,10 +1,9 @@
1
  import os
2
- import urllib.request
3
  import io
4
  import re
5
  import streamlit as st
6
 
7
- # Set the page configuration as the very first Streamlit command.
8
  st.set_page_config(layout="wide", initial_sidebar_state="collapsed")
9
 
10
  from PIL import Image
@@ -17,41 +16,30 @@ from reportlab.lib import colors
17
  from reportlab.pdfbase import pdfmetrics
18
  from reportlab.pdfbase.ttfonts import TTFont
19
 
20
- # --- Step 1: Define and Download Available Emoji Fonts ---
21
- font_files = [
22
- "Noto-COLRv1-emojicompat.ttf",
23
- "Noto-COLRv1-noflags.ttf",
24
- "Noto-COLRv1.ttf",
25
- "NotoColorEmoji-emojicompat.ttf",
26
- "NotoColorEmoji-flagsonly.ttf",
27
- "NotoColorEmoji-noflags.ttf",
28
- "NotoColorEmoji.ttf",
29
- "NotoColorEmoji_WindowsCompatible.ttf"
30
- ]
31
-
32
- base_font_url = "https://github.com/googlefonts/noto-emoji/raw/main/fonts/"
33
-
34
- for font_file in font_files:
35
- if not os.path.exists(font_file):
36
- st.info(f"Downloading {font_file}...")
37
- try:
38
- urllib.request.urlretrieve(base_font_url + font_file, font_file)
39
- st.success(f"Downloaded {font_file}")
40
- except Exception as e:
41
- st.error(f"Failed to download {font_file}: {e}")
42
-
43
- # --- Step 2: Allow User to Select the Emoji Font ---
44
- font_display_names = {f: f.replace(".ttf", "") for f in font_files}
45
- selected_font_file = st.sidebar.selectbox(
46
- "Select Emoji Font",
47
- options=font_files,
48
- format_func=lambda f: font_display_names[f]
49
  )
 
50
 
51
- registered_font_name = font_display_names[selected_font_file]
52
- pdfmetrics.registerFont(TTFont(registered_font_name, selected_font_file))
53
 
54
- # --- Default Markdown Content with Emojis ---
 
55
  default_markdown = """# Cutting-Edge ML Outline
56
 
57
  ## Core ML Techniques
@@ -119,7 +107,8 @@ default_markdown = """# Cutting-Edge ML Outline
119
  - Documentation synthesis
120
  """
121
 
122
- # --- Markdown to PDF Content Processing ---
 
123
  def markdown_to_pdf_content(markdown_text):
124
  lines = markdown_text.strip().split('\n')
125
  pdf_content = []
@@ -133,7 +122,7 @@ def markdown_to_pdf_content(markdown_text):
133
  continue
134
 
135
  if line.startswith('# '):
136
- # Optionally skip main title
137
  pass
138
  elif line.startswith('## '):
139
  if current_item and sub_items:
@@ -164,7 +153,8 @@ def markdown_to_pdf_content(markdown_text):
164
 
165
  return left_column, right_column
166
 
167
- # --- Main PDF Creation ---
 
168
  def create_main_pdf(markdown_text, base_font_size=10, auto_size=False):
169
  buffer = io.BytesIO()
170
  doc = SimpleDocTemplate(
@@ -178,181 +168,12 @@ def create_main_pdf(markdown_text, base_font_size=10, auto_size=False):
178
 
179
  styles = getSampleStyleSheet()
180
  story = []
181
-
182
  spacer_height = 10
183
  left_column, right_column = markdown_to_pdf_content(markdown_text)
184
 
 
185
  total_items = 0
186
  for col in (left_column, right_column):
187
  for item in col:
188
  if isinstance(item, list):
189
- main_item, sub_items = item
190
- total_items += 1 + len(sub_items)
191
- else:
192
- total_items += 1
193
-
194
- if auto_size:
195
- base_font_size = max(6, min(12, 200 / total_items))
196
-
197
- item_font_size = base_font_size
198
- subitem_font_size = base_font_size * 0.9
199
- section_font_size = base_font_size * 1.2
200
- title_font_size = min(16, base_font_size * 1.5)
201
-
202
- title_style = ParagraphStyle(
203
- 'Heading1',
204
- parent=styles['Heading1'],
205
- fontName=registered_font_name,
206
- textColor=colors.darkblue,
207
- alignment=1,
208
- fontSize=title_font_size
209
- )
210
-
211
- section_style = ParagraphStyle(
212
- 'SectionStyle',
213
- parent=styles['Heading2'],
214
- fontName=registered_font_name,
215
- textColor=colors.darkblue,
216
- fontSize=section_font_size,
217
- leading=section_font_size * 1.2,
218
- spaceAfter=2
219
- )
220
-
221
- item_style = ParagraphStyle(
222
- 'ItemStyle',
223
- parent=styles['Normal'],
224
- fontName=registered_font_name,
225
- fontSize=item_font_size,
226
- leading=item_font_size * 1.2,
227
- spaceAfter=1
228
- )
229
-
230
- subitem_style = ParagraphStyle(
231
- 'SubItemStyle',
232
- parent=styles['Normal'],
233
- fontName=registered_font_name,
234
- fontSize=subitem_font_size,
235
- leading=subitem_font_size * 1.2,
236
- leftIndent=10,
237
- spaceAfter=1
238
- )
239
-
240
- story.append(Paragraph("Cutting-Edge ML Outline (ReportLab)", title_style))
241
- story.append(Spacer(1, spacer_height))
242
-
243
- left_cells = []
244
- for item in left_column:
245
- if isinstance(item, str) and item.startswith('<b>'):
246
- text = item.replace('<b>', '').replace('</b>', '')
247
- left_cells.append(Paragraph(text, section_style))
248
- elif isinstance(item, list):
249
- main_item, sub_items = item
250
- left_cells.append(Paragraph(main_item, item_style))
251
- for sub_item in sub_items:
252
- left_cells.append(Paragraph(sub_item, subitem_style))
253
- else:
254
- left_cells.append(Paragraph(item, item_style))
255
-
256
- right_cells = []
257
- for item in right_column:
258
- if isinstance(item, str) and item.startswith('<b>'):
259
- text = item.replace('<b>', '').replace('</b>', '')
260
- right_cells.append(Paragraph(text, section_style))
261
- elif isinstance(item, list):
262
- main_item, sub_items = item
263
- right_cells.append(Paragraph(main_item, item_style))
264
- for sub_item in sub_items:
265
- right_cells.append(Paragraph(sub_item, subitem_style))
266
- else:
267
- right_cells.append(Paragraph(item, item_style))
268
-
269
- max_cells = max(len(left_cells), len(right_cells))
270
- left_cells.extend([""] * (max_cells - len(left_cells)))
271
- right_cells.extend([""] * (max_cells - len(right_cells)))
272
-
273
- table_data = list(zip(left_cells, right_cells))
274
- col_width = (A4[1] - 72) / 2.0
275
-
276
- table = Table(table_data, colWidths=[col_width, col_width], hAlign='CENTER')
277
- table.setStyle(TableStyle([
278
- ('VALIGN', (0, 0), (-1, -1), 'TOP'),
279
- ('ALIGN', (0, 0), (-1, -1), 'LEFT'),
280
- ('BACKGROUND', (0, 0), (-1, -1), colors.white),
281
- ('GRID', (0, 0), (-1, -1), 0, colors.white),
282
- ('LINEAFTER', (0, 0), (0, -1), 0.5, colors.grey),
283
- ('LEFTPADDING', (0, 0), (-1, -1), 2),
284
- ('RIGHTPADDING', (0, 0), (-1, -1), 2),
285
- ('TOPPADDING', (0, 0), (-1, -1), 1),
286
- ('BOTTOMPADDING', (0, 0), (-1, -1), 1),
287
- ]))
288
-
289
- story.append(table)
290
- doc.build(story)
291
- buffer.seek(0)
292
- return buffer.getvalue()
293
-
294
- # --- Function to Convert PDF Bytes to Image (for Preview) ---
295
- def pdf_to_image(pdf_bytes):
296
- try:
297
- doc = fitz.open(stream=pdf_bytes, filetype="pdf")
298
- page = doc[0]
299
- pix = page.get_pixmap(matrix=fitz.Matrix(2.0, 2.0))
300
- img = Image.frombytes("RGB", [pix.width, pix.height], pix.samples)
301
- doc.close()
302
- return img
303
- except Exception as e:
304
- st.error(f"Failed to render PDF preview: {e}")
305
- return None
306
-
307
- # --- Sidebar UI for Additional Settings ---
308
- with st.sidebar:
309
- auto_size = st.checkbox("Auto-size text", value=True)
310
- if not auto_size:
311
- base_font_size = st.slider("Base Font Size (points)", min_value=6, max_value=16, value=10, step=1)
312
- else:
313
- base_font_size = 10
314
- st.info("Font size will auto-adjust between 6-12 points based on content length.")
315
-
316
- # --- Persist Markdown Content in Session State ---
317
- if 'markdown_content' not in st.session_state:
318
- st.session_state.markdown_content = default_markdown
319
-
320
- # --- Generate PDF ---
321
- with st.spinner("Generating PDF..."):
322
- pdf_bytes = create_main_pdf(st.session_state.markdown_content, base_font_size, auto_size)
323
-
324
- # --- Display PDF Preview in UI ---
325
- with st.container():
326
- pdf_image = pdf_to_image(pdf_bytes)
327
- if pdf_image:
328
- st.image(pdf_image, use_container_width=True)
329
- else:
330
- st.info("Download the PDF to view it locally.")
331
-
332
- # --- PDF Download Button ---
333
- st.download_button(
334
- label="Download PDF",
335
- data=pdf_bytes,
336
- file_name="ml_outline.pdf",
337
- mime="application/pdf"
338
- )
339
-
340
- # --- Markdown Editor ---
341
- edited_markdown = st.text_area(
342
- "Modify the markdown content below:",
343
- value=st.session_state.markdown_content,
344
- height=300
345
- )
346
-
347
- # --- Update PDF on Button Click ---
348
- if st.button("Update PDF"):
349
- st.session_state.markdown_content = edited_markdown
350
- st.experimental_rerun()
351
-
352
- # --- Markdown Download Button ---
353
- st.download_button(
354
- label="Save Markdown",
355
- data=st.session_state.markdown_content,
356
- file_name="ml_outline.md",
357
- mime="text/markdown"
358
- )
 
1
  import os
 
2
  import io
3
  import re
4
  import streamlit as st
5
 
6
+ # Must be the first Streamlit command.
7
  st.set_page_config(layout="wide", initial_sidebar_state="collapsed")
8
 
9
  from PIL import Image
 
16
  from reportlab.pdfbase import pdfmetrics
17
  from reportlab.pdfbase.ttfonts import TTFont
18
 
19
+ # ---------------------------------------------------------------
20
+ # Define available NotoEmoji fonts (local files)
21
+ # One font is at the root and others are in the 'static' subdirectory.
22
+ available_fonts = {
23
+ "NotoEmoji Variable": "NotoEmoji-VariableFont_wght.ttf",
24
+ "NotoEmoji Bold": "NotoEmoji-Bold.ttf",
25
+ "NotoEmoji Light": "NotoEmoji-Light.ttf",
26
+ "NotoEmoji Medium": "NotoEmoji-Medium.ttf",
27
+ "NotoEmoji Regular": "NotoEmoji-Regular.ttf",
28
+ "NotoEmoji SemiBold": "NotoEmoji-SemiBold.ttf"
29
+ }
30
+
31
+ # Sidebar: Let the user choose the desired NotoEmoji font.
32
+ selected_font_name = st.sidebar.selectbox(
33
+ "Select NotoEmoji Font",
34
+ options=list(available_fonts.keys())
 
 
 
 
 
 
 
 
 
 
 
 
 
35
  )
36
+ selected_font_path = available_fonts[selected_font_name]
37
 
38
+ # Register the chosen font with ReportLab.
39
+ pdfmetrics.registerFont(TTFont(selected_font_name, selected_font_path))
40
 
41
+ # ---------------------------------------------------------------
42
+ # Default markdown content with emojis.
43
  default_markdown = """# Cutting-Edge ML Outline
44
 
45
  ## Core ML Techniques
 
107
  - Documentation synthesis
108
  """
109
 
110
+ # ---------------------------------------------------------------
111
+ # Process markdown into PDF content.
112
  def markdown_to_pdf_content(markdown_text):
113
  lines = markdown_text.strip().split('\n')
114
  pdf_content = []
 
122
  continue
123
 
124
  if line.startswith('# '):
125
+ # Optionally skip the main title.
126
  pass
127
  elif line.startswith('## '):
128
  if current_item and sub_items:
 
153
 
154
  return left_column, right_column
155
 
156
+ # ---------------------------------------------------------------
157
+ # Create PDF using ReportLab.
158
  def create_main_pdf(markdown_text, base_font_size=10, auto_size=False):
159
  buffer = io.BytesIO()
160
  doc = SimpleDocTemplate(
 
168
 
169
  styles = getSampleStyleSheet()
170
  story = []
 
171
  spacer_height = 10
172
  left_column, right_column = markdown_to_pdf_content(markdown_text)
173
 
174
+ # Count total items to possibly adjust font size.
175
  total_items = 0
176
  for col in (left_column, right_column):
177
  for item in col:
178
  if isinstance(item, list):
179
+ main_item, sub_items