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

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +178 -6
app.py CHANGED
@@ -21,11 +21,11 @@ from reportlab.pdfbase.ttfonts import TTFont
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.
@@ -176,4 +176,176 @@ def create_main_pdf(markdown_text, base_font_size=10, auto_size=False):
176
  for col in (left_column, right_column):
177
  for item in col:
178
  if isinstance(item, list):
179
- main_item, sub_items
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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": "static/NotoEmoji-Bold.ttf",
25
+ "NotoEmoji Light": "static/NotoEmoji-Light.ttf",
26
+ "NotoEmoji Medium": "static/NotoEmoji-Medium.ttf",
27
+ "NotoEmoji Regular": "static/NotoEmoji-Regular.ttf",
28
+ "NotoEmoji SemiBold": "static/NotoEmoji-SemiBold.ttf"
29
  }
30
 
31
  # Sidebar: Let the user choose the desired NotoEmoji font.
 
176
  for col in (left_column, right_column):
177
  for item in col:
178
  if isinstance(item, list):
179
+ main_item, sub_items = item
180
+ total_items += 1 + len(sub_items)
181
+ else:
182
+ total_items += 1
183
+
184
+ if auto_size:
185
+ base_font_size = max(6, min(12, 200 / total_items))
186
+
187
+ item_font_size = base_font_size
188
+ subitem_font_size = base_font_size * 0.9
189
+ section_font_size = base_font_size * 1.2
190
+ title_font_size = min(16, base_font_size * 1.5)
191
+
192
+ # Define styles using the selected NotoEmoji font.
193
+ title_style = ParagraphStyle(
194
+ 'Heading1',
195
+ parent=styles['Heading1'],
196
+ fontName=selected_font_name,
197
+ textColor=colors.darkblue,
198
+ alignment=1,
199
+ fontSize=title_font_size
200
+ )
201
+
202
+ section_style = ParagraphStyle(
203
+ 'SectionStyle',
204
+ parent=styles['Heading2'],
205
+ fontName=selected_font_name,
206
+ textColor=colors.darkblue,
207
+ fontSize=section_font_size,
208
+ leading=section_font_size * 1.2,
209
+ spaceAfter=2
210
+ )
211
+
212
+ item_style = ParagraphStyle(
213
+ 'ItemStyle',
214
+ parent=styles['Normal'],
215
+ fontName=selected_font_name,
216
+ fontSize=item_font_size,
217
+ leading=item_font_size * 1.2,
218
+ spaceAfter=1
219
+ )
220
+
221
+ subitem_style = ParagraphStyle(
222
+ 'SubItemStyle',
223
+ parent=styles['Normal'],
224
+ fontName=selected_font_name,
225
+ fontSize=subitem_font_size,
226
+ leading=subitem_font_size * 1.2,
227
+ leftIndent=10,
228
+ spaceAfter=1
229
+ )
230
+
231
+ story.append(Paragraph("Cutting-Edge ML Outline (ReportLab)", title_style))
232
+ story.append(Spacer(1, spacer_height))
233
+
234
+ left_cells = []
235
+ for item in left_column:
236
+ if isinstance(item, str) and item.startswith('<b>'):
237
+ text = item.replace('<b>', '').replace('</b>', '')
238
+ left_cells.append(Paragraph(text, section_style))
239
+ elif isinstance(item, list):
240
+ main_item, sub_items = item
241
+ left_cells.append(Paragraph(main_item, item_style))
242
+ for sub_item in sub_items:
243
+ left_cells.append(Paragraph(sub_item, subitem_style))
244
+ else:
245
+ left_cells.append(Paragraph(item, item_style))
246
+
247
+ right_cells = []
248
+ for item in right_column:
249
+ if isinstance(item, str) and item.startswith('<b>'):
250
+ text = item.replace('<b>', '').replace('</b>', '')
251
+ right_cells.append(Paragraph(text, section_style))
252
+ elif isinstance(item, list):
253
+ main_item, sub_items = item
254
+ right_cells.append(Paragraph(main_item, item_style))
255
+ for sub_item in sub_items:
256
+ right_cells.append(Paragraph(sub_item, subitem_style))
257
+ else:
258
+ right_cells.append(Paragraph(item, item_style))
259
+
260
+ max_cells = max(len(left_cells), len(right_cells))
261
+ left_cells.extend([""] * (max_cells - len(left_cells)))
262
+ right_cells.extend([""] * (max_cells - len(right_cells)))
263
+
264
+ table_data = list(zip(left_cells, right_cells))
265
+ col_width = (A4[1] - 72) / 2.0
266
+ table = Table(table_data, colWidths=[col_width, col_width], hAlign='CENTER')
267
+ table.setStyle(TableStyle([
268
+ ('VALIGN', (0, 0), (-1, -1), 'TOP'),
269
+ ('ALIGN', (0, 0), (-1, -1), 'LEFT'),
270
+ ('BACKGROUND', (0, 0), (-1, -1), colors.white),
271
+ ('GRID', (0, 0), (-1, -1), 0, colors.white),
272
+ ('LINEAFTER', (0, 0), (0, -1), 0.5, colors.grey),
273
+ ('LEFTPADDING', (0, 0), (-1, -1), 2),
274
+ ('RIGHTPADDING', (0, 0), (-1, -1), 2),
275
+ ('TOPPADDING', (0, 0), (-1, -1), 1),
276
+ ('BOTTOMPADDING', (0, 0), (-1, -1), 1),
277
+ ]))
278
+
279
+ story.append(table)
280
+ doc.build(story)
281
+ buffer.seek(0)
282
+ return buffer.getvalue()
283
+
284
+ # ---------------------------------------------------------------
285
+ # Convert PDF bytes to an image for preview using PyMuPDF.
286
+ def pdf_to_image(pdf_bytes):
287
+ try:
288
+ doc = fitz.open(stream=pdf_bytes, filetype="pdf")
289
+ page = doc[0]
290
+ pix = page.get_pixmap(matrix=fitz.Matrix(2.0, 2.0))
291
+ img = Image.frombytes("RGB", [pix.width, pix.height], pix.samples)
292
+ doc.close()
293
+ return img
294
+ except Exception as e:
295
+ st.error(f"Failed to render PDF preview: {e}")
296
+ return None
297
+
298
+ # ---------------------------------------------------------------
299
+ # Sidebar options for text size.
300
+ with st.sidebar:
301
+ auto_size = st.checkbox("Auto-size text", value=True)
302
+ if not auto_size:
303
+ base_font_size = st.slider("Base Font Size (points)", min_value=6, max_value=16, value=10, step=1)
304
+ else:
305
+ base_font_size = 10
306
+ st.info("Font size will auto-adjust between 6-12 points based on content length.")
307
+
308
+ # Persist markdown content in session state.
309
+ if 'markdown_content' not in st.session_state:
310
+ st.session_state.markdown_content = default_markdown
311
+
312
+ # ---------------------------------------------------------------
313
+ # Generate PDF.
314
+ with st.spinner("Generating PDF..."):
315
+ pdf_bytes = create_main_pdf(st.session_state.markdown_content, base_font_size, auto_size)
316
+
317
+ # Display PDF preview.
318
+ with st.container():
319
+ pdf_image = pdf_to_image(pdf_bytes)
320
+ if pdf_image:
321
+ st.image(pdf_image, use_container_width=True)
322
+ else:
323
+ st.info("Download the PDF to view it locally.")
324
+
325
+ # PDF Download button.
326
+ st.download_button(
327
+ label="Download PDF",
328
+ data=pdf_bytes,
329
+ file_name="ml_outline.pdf",
330
+ mime="application/pdf"
331
+ )
332
+
333
+ # Markdown editor.
334
+ edited_markdown = st.text_area(
335
+ "Modify the markdown content below:",
336
+ value=st.session_state.markdown_content,
337
+ height=300
338
+ )
339
+
340
+ # Update PDF on button click.
341
+ if st.button("Update PDF"):
342
+ st.session_state.markdown_content = edited_markdown
343
+ st.experimental_rerun()
344
+
345
+ # Markdown Download button.
346
+ st.download_button(
347
+ label="Save Markdown",
348
+ data=st.session_state.markdown_content,
349
+ file_name="ml_outline.md",
350
+ mime="text/markdown"
351
+ )