TheAiCollectiveART commited on
Commit
ef5ee52
·
verified ·
1 Parent(s): cc0f1fd

Update/Add WASM_U-Performance_Record/generate_pdf.py for WebAssembly 7.10us record

Browse files
WASM_U-Performance_Record/generate_pdf.py ADDED
@@ -0,0 +1,453 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # -*- coding: utf-8 -*-
2
+ import os
3
+ import re
4
+ import shutil
5
+ from reportlab.lib.pagesizes import letter
6
+ from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle, Image, PageBreak, KeepTogether
7
+ from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
8
+ from reportlab.lib import colors
9
+ from reportlab.pdfgen import canvas
10
+
11
+ class NumberedCanvas(canvas.Canvas):
12
+ def __init__(self, *args, **kwargs):
13
+ super().__init__(*args, **kwargs)
14
+ self._saved_page_states = []
15
+
16
+ def showPage(self):
17
+ self._saved_page_states.append(dict(self.__dict__))
18
+ self._startPage()
19
+
20
+ def save(self):
21
+ num_pages = len(self._saved_page_states)
22
+ for state in self._saved_page_states:
23
+ self.__dict__.update(state)
24
+ self.draw_page_decorations(num_pages)
25
+ super().showPage()
26
+ super().save()
27
+
28
+ def draw_page_decorations(self, page_count):
29
+ self.saveState()
30
+
31
+ # We start headers/footers on page 2 (leaving cover page clean)
32
+ if self._pageNumber > 1:
33
+ # Running Header
34
+ self.setFont("Helvetica-Bold", 8)
35
+ self.setFillColor(colors.HexColor("#0F2D59"))
36
+ self.drawString(54, 755, "LANGUAGE-U SYSTEM TELEMETRY & OPTIMIZATION")
37
+
38
+ self.setFont("Helvetica", 8)
39
+ self.setFillColor(colors.HexColor("#718096"))
40
+ self.drawRightString(558, 755, "WASM MICROSECOND PERFORMANCE WHITE PAPER")
41
+
42
+ # Header line
43
+ self.setStrokeColor(colors.HexColor("#CBD5E0"))
44
+ self.setLineWidth(0.75)
45
+ self.line(54, 747, 558, 747)
46
+
47
+ # Running Footer
48
+ self.setStrokeColor(colors.HexColor("#CBD5E0"))
49
+ self.setLineWidth(0.75)
50
+ self.line(54, 55, 558, 55)
51
+
52
+ self.setFont("Helvetica", 8)
53
+ self.setFillColor(colors.HexColor("#718096"))
54
+ self.drawString(54, 42, "zymatica.space | astronautshe.com | Devs One | We Are TheAiCollective.art")
55
+
56
+ page_text = f"Page {self._pageNumber} of {page_count}"
57
+ self.drawRightString(558, 42, page_text)
58
+
59
+ self.restoreState()
60
+
61
+ def clean_md_text(text):
62
+ # Escape HTML special chars except tags we generate
63
+ text = text.replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;")
64
+
65
+ # Restore specific math tags
66
+ text = text.replace(r"$$\text{Latency}_{\text{WebGPU}} = t_{\text{buffer\_copy}} + t_{\text{command\_compile}} + t_{\text{queue\_dispatch}} + t_{\text{mapAsync}} \approx 0.115 \text{ ms}$$",
67
+ '<i>Latency<sub>WebGPU</sub> = t<sub>buffer_copy</sub> + t<sub>command_compile</sub> + t<sub>queue_dispatch</sub> + t<sub>mapAsync</sub> &asymp; 0.115 ms</i>')
68
+ text = text.replace(r"$$", "")
69
+ text = text.replace(r"$\text{Latency}_{\text{WebGPU}}$", "<i>Latency<sub>WebGPU</sub></i>")
70
+ text = text.replace(r"$t_{\text{buffer\_copy}}$", "<i>t<sub>buffer_copy</sub></i>")
71
+ text = text.replace(r"$t_{\text{command\_compile}}$", "<i>t<sub>command_compile</sub></i>")
72
+ text = text.replace(r"$t_{\text{queue\_dispatch}}$", "<i>t<sub>queue_dispatch</sub></i>")
73
+ text = text.replace(r"$t_{\text{mapAsync}}$", "<i>t<sub>mapAsync</sub></i>")
74
+ text = text.replace(r"$t_{\text{mapAsync}} \approx 0.115 \text{ ms}$", "<i>t<sub>mapAsync</sub> &asymp; 0.115 ms</i>")
75
+ text = text.replace(r"$\approx 0.115 \text{ ms}$", "<i>&asymp; 0.115 ms</i>")
76
+ text = text.replace(r"$\approx 0.12 \text{ ms}$", "<i>&asymp; 0.12 ms</i>")
77
+ text = text.replace(r"$t+1$", "<i>t+1</i>")
78
+ text = text.replace(r"$t$", "<i>t</i>")
79
+
80
+ # Convert bold markdown **text** to <b>text</b>
81
+ text = re.sub(r'\*\*(.*?)\*\*', r'<b>\1</b>', text)
82
+ text = re.sub(r'__(.*?)__', r'<b>\1</b>', text)
83
+
84
+ # Convert italic markdown *text* to <i>text</i>
85
+ text = re.sub(r'\*(.*?)\*', r'<i>\1</i>', text)
86
+
87
+ # Convert `code` to <font name="Courier"><b>code</b></font>
88
+ text = re.sub(r'`(.*?)`', r'<b><font name="Courier" color="#0F2D59">\1</font></b>', text)
89
+
90
+ # Convert links [text](url) to <a href="\2"><font color="#1D4ED8"><b>\1</b></font></a>
91
+ text = re.sub(r'\[(.*?)\]\((.*?)\)', r'<a href="\2"><font color="#1D4ED8"><b>\1</b></font></a>', text)
92
+
93
+ return text
94
+
95
+ def parse_markdown(md_path):
96
+ with open(md_path, 'r', encoding='utf-8') as f:
97
+ content = f.read()
98
+
99
+ lines = content.split('\n')
100
+ elements = []
101
+
102
+ in_code_block = False
103
+ code_lines = []
104
+
105
+ in_table = False
106
+ table_rows = []
107
+
108
+ i = 0
109
+ while i < len(lines):
110
+ line = lines[i]
111
+
112
+ # Code block check
113
+ if line.strip().startswith('```'):
114
+ if in_code_block:
115
+ in_code_block = False
116
+ elements.append({
117
+ 'type': 'code',
118
+ 'content': '\n'.join(code_lines)
119
+ })
120
+ code_lines = []
121
+ else:
122
+ in_code_block = True
123
+ i += 1
124
+ continue
125
+
126
+ if in_code_block:
127
+ code_lines.append(line)
128
+ i += 1
129
+ continue
130
+
131
+ # Table check
132
+ if line.strip().startswith('|') and not in_table:
133
+ if i + 1 < len(lines) and lines[i+1].strip().startswith('|') and '-' in lines[i+1]:
134
+ in_table = True
135
+ table_rows = []
136
+ headers = [cell.strip() for cell in line.split('|')[1:-1]]
137
+ table_rows.append(headers)
138
+ i += 2
139
+ continue
140
+
141
+ if in_table:
142
+ if line.strip().startswith('|'):
143
+ cells = [cell.strip() for cell in line.split('|')[1:-1]]
144
+ table_rows.append(cells)
145
+ i += 1
146
+ continue
147
+ else:
148
+ in_table = False
149
+ elements.append({
150
+ 'type': 'table',
151
+ 'content': table_rows
152
+ })
153
+ table_rows = []
154
+
155
+ # Skip empty lines but keep single Spacers
156
+ if line.strip() == '':
157
+ elements.append({'type': 'spacer', 'content': 8})
158
+ i += 1
159
+ continue
160
+
161
+ # Separator line
162
+ if line.strip() == '---':
163
+ elements.append({'type': 'pagebreak', 'content': None})
164
+ i += 1
165
+ continue
166
+
167
+ # Headers
168
+ if line.startswith('# '):
169
+ elements.append({'type': 'h1', 'content': line[2:].strip()})
170
+ elif line.startswith('## '):
171
+ elements.append({'type': 'h2', 'content': line[3:].strip()})
172
+ elif line.startswith('### '):
173
+ elements.append({'type': 'h3', 'content': line[4:].strip()})
174
+ # Bullet list items
175
+ elif line.strip().startswith('* ') or line.strip().startswith('- '):
176
+ elements.append({'type': 'bullet', 'content': line.strip()[2:].strip()})
177
+ elif re.match(r'^\d+\.\s', line.strip()):
178
+ content_start = line.find('.') + 1
179
+ elements.append({'type': 'bullet', 'content': line[content_start:].strip()})
180
+ # Image
181
+ elif line.strip().startswith('![') and '](' in line:
182
+ caption_match = re.search(r'!\[(.*?)\]', line)
183
+ path_match = re.search(r'\]\(([^)]+)\)', line)
184
+ elements.append({
185
+ 'type': 'image',
186
+ 'caption': caption_match.group(1) if caption_match else '',
187
+ 'path': path_match.group(1) if path_match else ''
188
+ })
189
+ # Plain text
190
+ else:
191
+ elements.append({'type': 'p', 'content': line.strip()})
192
+
193
+ i += 1
194
+
195
+ return elements
196
+
197
+ def build_pdf(md_path, pdf_path):
198
+ elements = parse_markdown(md_path)
199
+
200
+ doc = SimpleDocTemplate(
201
+ pdf_path,
202
+ pagesize=letter,
203
+ leftMargin=54,
204
+ rightMargin=54,
205
+ topMargin=72,
206
+ bottomMargin=72
207
+ )
208
+
209
+ styles = getSampleStyleSheet()
210
+
211
+ # Zymatica Theme Palette
212
+ primary_color = colors.HexColor("#0F2D59") # Deep Navy
213
+ secondary_color = colors.HexColor("#1D4ED8") # Slate Blue
214
+ dark_neutral = colors.HexColor("#111111") # Near Black
215
+
216
+ # Custom Styles
217
+ title_style = ParagraphStyle(
218
+ 'DocTitle',
219
+ parent=styles['Heading1'],
220
+ fontName='Helvetica-Bold',
221
+ fontSize=18,
222
+ leading=22,
223
+ textColor=primary_color,
224
+ spaceAfter=15
225
+ )
226
+
227
+ h1_style = ParagraphStyle(
228
+ 'SecHeading1',
229
+ parent=styles['Heading1'],
230
+ fontName='Helvetica-Bold',
231
+ fontSize=12,
232
+ leading=15,
233
+ textColor=primary_color,
234
+ spaceBefore=14,
235
+ spaceAfter=6,
236
+ keepWithNext=True
237
+ )
238
+
239
+ h2_style = ParagraphStyle(
240
+ 'SecHeading2',
241
+ parent=styles['Heading2'],
242
+ fontName='Helvetica-Bold',
243
+ fontSize=10,
244
+ leading=13,
245
+ textColor=secondary_color,
246
+ spaceBefore=10,
247
+ spaceAfter=4,
248
+ keepWithNext=True
249
+ )
250
+
251
+ body_style = ParagraphStyle(
252
+ 'BodyText',
253
+ parent=styles['Normal'],
254
+ fontName='Helvetica',
255
+ fontSize=9.5,
256
+ leading=13.5,
257
+ textColor=dark_neutral,
258
+ spaceAfter=5
259
+ )
260
+
261
+ bullet_style = ParagraphStyle(
262
+ 'BulletText',
263
+ parent=styles['Normal'],
264
+ fontName='Helvetica',
265
+ fontSize=9,
266
+ leading=13,
267
+ textColor=dark_neutral,
268
+ leftIndent=15,
269
+ firstLineIndent=-10,
270
+ spaceAfter=4
271
+ )
272
+
273
+ code_style = ParagraphStyle(
274
+ 'CodeSnippet',
275
+ parent=styles['Normal'],
276
+ fontName='Courier',
277
+ fontSize=8,
278
+ leading=11,
279
+ textColor=colors.HexColor("#0F2D59"),
280
+ spaceAfter=4
281
+ )
282
+
283
+ table_header_style = ParagraphStyle(
284
+ 'TableHeader',
285
+ parent=styles['Normal'],
286
+ fontName='Helvetica-Bold',
287
+ fontSize=8.5,
288
+ leading=11,
289
+ textColor=colors.white
290
+ )
291
+
292
+ table_cell_style = ParagraphStyle(
293
+ 'TableCell',
294
+ parent=styles['Normal'],
295
+ fontName='Helvetica',
296
+ fontSize=8,
297
+ leading=11,
298
+ textColor=dark_neutral
299
+ )
300
+
301
+ table_cell_bold = ParagraphStyle(
302
+ 'TableCellBold',
303
+ parent=styles['Normal'],
304
+ fontName='Helvetica-Bold',
305
+ fontSize=8,
306
+ leading=11,
307
+ textColor=dark_neutral
308
+ )
309
+
310
+ meta_style = ParagraphStyle(
311
+ 'DocMeta',
312
+ parent=styles['Normal'],
313
+ fontName='Helvetica-Bold',
314
+ fontSize=8.5,
315
+ leading=12,
316
+ textColor=colors.HexColor("#4A5568")
317
+ )
318
+
319
+ story = []
320
+
321
+ # Title Page Header logo block
322
+ logo_path = "Logo.jpg"
323
+ if os.path.exists(logo_path):
324
+ logo_img = Image(logo_path, width=44, height=44)
325
+ header_data = [[logo_img, Paragraph("<b>THE AI COLLECTIVE</b><br/><font color='#4A5568'>Zymatica &bull; astronautshe.com &bull; DevsOne</font>", meta_style)]]
326
+ header_table = Table(header_data, colWidths=[55, 449])
327
+ header_table.setStyle(TableStyle([
328
+ ('VALIGN', (0,0), (-1,-1), 'MIDDLE'),
329
+ ('BOTTOMPADDING', (0,0), (-1,-1), 8),
330
+ ]))
331
+ story.append(header_table)
332
+
333
+ # Header line
334
+ story.append(Table([[ "" ]], colWidths=[504], rowHeights=[1.5], style=TableStyle([
335
+ ('BACKGROUND', (0,0), (-1,-1), primary_color),
336
+ ('BOTTOMPADDING', (0,0), (-1,-1), 0),
337
+ ('TOPPADDING', (0,0), (-1,-1), 0),
338
+ ])))
339
+ story.append(Spacer(1, 15))
340
+
341
+ i = 0
342
+ while i < len(elements):
343
+ elem = elements[i]
344
+
345
+ if elem['type'] == 'pagebreak':
346
+ story.append(PageBreak())
347
+ elif elem['type'] == 'spacer':
348
+ story.append(Spacer(1, elem['content']))
349
+ elif elem['type'] == 'h1':
350
+ title_text = clean_md_text(elem['content'])
351
+ if "Breaking the Browser" in title_text:
352
+ story.append(Paragraph(title_text, title_style))
353
+ else:
354
+ story.append(Paragraph(title_text, h1_style))
355
+ elif elem['type'] == 'h2':
356
+ story.append(Paragraph(clean_md_text(elem['content']), h1_style))
357
+ elif elem['type'] == 'h3':
358
+ story.append(Paragraph(clean_md_text(elem['content']), h2_style))
359
+ elif elem['type'] == 'bullet':
360
+ story.append(Paragraph(f"&bull; {clean_md_text(elem['content'])}", bullet_style))
361
+ elif elem['type'] == 'p':
362
+ p_text = elem['content']
363
+ if p_text.startswith('Published by:') or p_text.startswith('Authors:') or p_text.startswith('License:'):
364
+ story.append(Paragraph(clean_md_text(p_text), meta_style))
365
+ else:
366
+ story.append(Paragraph(clean_md_text(p_text), body_style))
367
+ elif elem['type'] == 'image':
368
+ image_filename = elem['path']
369
+ # Skip cover image in inner sections
370
+ if "Logo.jpg" in image_filename:
371
+ i += 1
372
+ continue
373
+ image_dir = os.path.dirname(md_path)
374
+ full_image_path = os.path.join(image_dir, image_filename)
375
+ if os.path.exists(full_image_path):
376
+ img = Image(full_image_path, width=480, height=280)
377
+ caption = Paragraph(f"<i>Figure: {clean_md_text(elem['caption'])}</i>", body_style)
378
+ img_table = Table([[img]], colWidths=[504])
379
+ img_table.setStyle(TableStyle([
380
+ ('ALIGN', (0,0), (-1,-1), 'CENTER'),
381
+ ('BOTTOMPADDING', (0,0), (-1,-1), 5),
382
+ ]))
383
+ story.append(KeepTogether([img_table, Spacer(1, 4), caption]))
384
+ elif elem['type'] == 'code':
385
+ code_text = elem['content']
386
+ code_text_clean = code_text.replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;")
387
+ code_lines = [Paragraph(line.replace(" ", "&nbsp;"), code_style) for line in code_text_clean.split('\n')]
388
+ code_table_data = [[line] for line in code_lines]
389
+ code_table = Table(code_table_data, colWidths=[504])
390
+ code_table.setStyle(TableStyle([
391
+ ('BACKGROUND', (0,0), (-1,-1), colors.HexColor("#EDF2F7")),
392
+ ('BORDER', (0,0), (-1,-1), 0.5, colors.HexColor("#CBD5E0")),
393
+ ('PADDING', (0,0), (-1,-1), 5),
394
+ ('TOPPADDING', (0,0), (-1,-1), 1),
395
+ ('BOTTOMPADDING', (0,0), (-1,-1), 1),
396
+ ]))
397
+ story.append(code_table)
398
+ elif elem['type'] == 'table':
399
+ table_rows = elem['content']
400
+ pdf_table_data = []
401
+
402
+ headers = [Paragraph(clean_md_text(cell), table_header_style) for cell in table_rows[0]]
403
+ pdf_table_data.append(headers)
404
+
405
+ for r in range(1, len(table_rows)):
406
+ row_cells = []
407
+ for c in range(len(table_rows[r])):
408
+ cell_text = table_rows[r][c]
409
+ if cell_text.startswith('**') and cell_text.endswith('**'):
410
+ row_cells.append(Paragraph(clean_md_text(cell_text), table_cell_bold))
411
+ else:
412
+ row_cells.append(Paragraph(clean_md_text(cell_text), table_cell_style))
413
+ pdf_table_data.append(row_cells)
414
+
415
+ num_cols = len(table_rows[0])
416
+ col_widths = [504 / num_cols] * num_cols
417
+ if num_cols == 4:
418
+ col_widths = [140, 94, 90, 180]
419
+
420
+ pdf_table = Table(pdf_table_data, colWidths=col_widths, repeatRows=1)
421
+ pdf_table.setStyle(TableStyle([
422
+ ('BACKGROUND', (0,0), (-1,0), primary_color),
423
+ ('ALIGN', (0,0), (-1,-1), 'LEFT'),
424
+ ('VALIGN', (0,0), (-1,-1), 'MIDDLE'),
425
+ ('BOTTOMPADDING', (0,0), (-1,-1), 4),
426
+ ('TOPPADDING', (0,0), (-1,-1), 4),
427
+ ('ROWBACKGROUNDS', (0,1), (-1,-1), [colors.white, colors.HexColor("#F7FAFC")]),
428
+ ('GRID', (0,0), (-1,-1), 0.5, colors.HexColor("#E2E8F0")),
429
+ ]))
430
+ story.append(pdf_table)
431
+
432
+ i += 1
433
+
434
+ doc.build(story, canvasmaker=NumberedCanvas)
435
+ print(f"[+] PDF compiled successfully at: {pdf_path}")
436
+
437
+ if __name__ == "__main__":
438
+ md_file = "WASM_PERFORMANCE_RECORD.md"
439
+ pdf_file = "WASM_PERFORMANCE_RECORD.pdf"
440
+ build_pdf(md_file, pdf_file)
441
+
442
+ # Copy PDF to root workspace as well for easy access
443
+ root_pdf = r"j:\Language-U\WASM_PERFORMANCE_RECORD.pdf"
444
+ shutil.copy(pdf_file, root_pdf)
445
+ print(f"[+] PDF copied to root workspace at: {root_pdf}")
446
+
447
+ # Copy PDF to brain artifacts folder
448
+ brain_pdf = r"C:\Users\freed\.gemini\antigravity-ide\brain\217fb20d-ffc1-487f-82c0-643308a2ac3d\WASM_PERFORMANCE_RECORD.pdf"
449
+ try:
450
+ shutil.copy(pdf_file, brain_pdf)
451
+ print(f"[+] PDF copied to brain artifacts folder at: {brain_pdf}")
452
+ except Exception as e:
453
+ print(f"[-] Failed to copy PDF to brain artifacts: {e}")