TheAiCollectiveART commited on
Commit
3e3073a
·
verified ·
1 Parent(s): df78959

Publish expanded 23-language matrix across all 20 inventions (460 codebases total)

Browse files
.gitattributes CHANGED
@@ -36,3 +36,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
36
  architecture.png filter=lfs diff=lfs merge=lfs -text
37
  Logo.jpg filter=lfs diff=lfs merge=lfs -text
38
  Logo_Zymatica_Voice.png filter=lfs diff=lfs merge=lfs -text
 
 
36
  architecture.png filter=lfs diff=lfs merge=lfs -text
37
  Logo.jpg filter=lfs diff=lfs merge=lfs -text
38
  Logo_Zymatica_Voice.png filter=lfs diff=lfs merge=lfs -text
39
+ Zymatica_Voice_Lora_Guide.pdf filter=lfs diff=lfs merge=lfs -text
README.md CHANGED
@@ -66,6 +66,7 @@ Each invention is isolated in its own folder and contains a complete academic **
66
  | **08** | [EPAUP Weight Projection](08_EPAUP_Weight_Projection) | Projects weights onto word embedding matrices. | [Whitepaper](08_EPAUP_Weight_Projection/WHITEPAPER.md) | [run_proof.py](08_EPAUP_Weight_Projection/run_proof.py) |
67
  | **09** | [Tokenizer Varint Coding](09_Tokenizer_Varint_Coding) | Prefix-suffix varint differential token coder. | [Whitepaper](09_Tokenizer_Varint_Coding/WHITEPAPER.md) | [run_proof.py](09_Tokenizer_Varint_Coding/run_proof.py) |
68
  | **10** | [Multi-Language Runtimes](10_Multi_Language_Runtimes) | Native runtimes (C++, Rust, Go, Swift, Java). | [Whitepaper](10_Multi_Language_Runtimes/WHITEPAPER.md) | [run_proof.py](10_Multi_Language_Runtimes/run_proof.py) |
 
69
  | **11** | [RCRA Resonance Alignment](11_RCRA_Resonance_Alignment) | Fine-tuning using radical resonance loss. | [Whitepaper](11_RCRA_Resonance_Alignment/WHITEPAPER.md) | [run_proof.py](11_RCRA_Resonance_Alignment/run_proof.py) |
70
  | **12** | [Brand Assets Artwork](12_Brand_Assets_Artwork) | Official branding, logos, and design assets. | [Whitepaper](12_Brand_Assets_Artwork/WHITEPAPER.md) | [run_proof.py](12_Brand_Assets_Artwork/run_proof.py) |
71
  | **13** | [Multi-Centroid Steering](13_Multi_Centroid_Steering) | Dynamic English/CJK hidden state steering. | [Whitepaper](13_Multi_Centroid_Steering/WHITEPAPER.md) | [run_proof.py](13_Multi_Centroid_Steering/run_proof.py) |
 
66
  | **08** | [EPAUP Weight Projection](08_EPAUP_Weight_Projection) | Projects weights onto word embedding matrices. | [Whitepaper](08_EPAUP_Weight_Projection/WHITEPAPER.md) | [run_proof.py](08_EPAUP_Weight_Projection/run_proof.py) |
67
  | **09** | [Tokenizer Varint Coding](09_Tokenizer_Varint_Coding) | Prefix-suffix varint differential token coder. | [Whitepaper](09_Tokenizer_Varint_Coding/WHITEPAPER.md) | [run_proof.py](09_Tokenizer_Varint_Coding/run_proof.py) |
68
  | **10** | [Multi-Language Runtimes](10_Multi_Language_Runtimes) | Native runtimes (C++, Rust, Go, Swift, Java). | [Whitepaper](10_Multi_Language_Runtimes/WHITEPAPER.md) | [run_proof.py](10_Multi_Language_Runtimes/run_proof.py) |
69
+ | **05/10** | [Zymatica Voice LoRa Guide](Zymatica_Voice_Lora_Guide.md) | AI Agent integration guide for physical LoRa hardware verification. | [MD Version](Zymatica_Voice_Lora_Guide.md) | [PDF Version](Zymatica_Voice_Lora_Guide.pdf) |
70
  | **11** | [RCRA Resonance Alignment](11_RCRA_Resonance_Alignment) | Fine-tuning using radical resonance loss. | [Whitepaper](11_RCRA_Resonance_Alignment/WHITEPAPER.md) | [run_proof.py](11_RCRA_Resonance_Alignment/run_proof.py) |
71
  | **12** | [Brand Assets Artwork](12_Brand_Assets_Artwork) | Official branding, logos, and design assets. | [Whitepaper](12_Brand_Assets_Artwork/WHITEPAPER.md) | [run_proof.py](12_Brand_Assets_Artwork/run_proof.py) |
72
  | **13** | [Multi-Centroid Steering](13_Multi_Centroid_Steering) | Dynamic English/CJK hidden state steering. | [Whitepaper](13_Multi_Centroid_Steering/WHITEPAPER.md) | [run_proof.py](13_Multi_Centroid_Steering/run_proof.py) |
Zymatica_Voice_Lora_Guide.pdf ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:0dfb390f971cd0b154f0b22aec196d9ec1ae320a7924df0470975883bd902d3f
3
+ size 917954
generate_voice_guide_pdf.py ADDED
@@ -0,0 +1,684 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # -*- coding: utf-8 -*-
2
+ import os
3
+ import re
4
+ import sys
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
32
+ if self._pageNumber > 1:
33
+ # Running Header
34
+ self.setFont("Helvetica-Bold", 8)
35
+ self.setFillColor(colors.HexColor("#1A365D"))
36
+ self.drawString(54, 755, "ZYMATICA VOICE: A GUIDE TO LORA FOR AI AGENTS")
37
+
38
+ self.setFont("Helvetica", 8)
39
+ self.setFillColor(colors.HexColor("#718096"))
40
+ self.drawRightString(558, 755, "IP CLASS 05/10 - TECHNICAL SPECIFICATION")
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, "© 2026 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 md_to_html(text):
62
+ # Escape '&' but avoid double escaping if it's already an entity
63
+ # A simple way is to replace '&' with '&' except for <, >, &, •, –, —
64
+ # Let's replace '&' first
65
+ text = text.replace("&", "&")
66
+ text = text.replace("&", "&")
67
+ text = text.replace("•", "•")
68
+ text = text.replace("–", "–")
69
+ text = text.replace("—", "—")
70
+
71
+ # Replace '<' and '>' except when they look like HTML tags we want to support:
72
+ # <b>, </b>, <i>, </i>, <font ...>, </font>, <a>, </a>, <br/>, <br>
73
+ # We can temporarily hide our tags, clean the rest, and restore them, or just use regular expressions carefully.
74
+
75
+ # Let's do markdown replacement
76
+ # Bold **text**
77
+ text = re.sub(r'\*\*(.*?)\*\*', r'<b>\1</b>', text)
78
+ # Italic *text*
79
+ text = re.sub(r'\*(.*?)\*', r'<i>\1</i>', text)
80
+ # Inline code `text`
81
+ text = re.sub(r'`(.*?)`', r'<font face="Courier" color="#2C5282">\1</font>', text)
82
+ # Links [text](url)
83
+ text = re.sub(r'\[(.*?)\]\((.*?)\)', r'<a href="\2"><font color="#2B6CB0"><u>\1</u></font></a>', text)
84
+
85
+ return text
86
+
87
+ def parse_markdown(filepath):
88
+ if not os.path.exists(filepath):
89
+ print(f"Error: {filepath} not found.")
90
+ sys.exit(1)
91
+
92
+ with open(filepath, 'r', encoding='utf-8') as f:
93
+ lines = f.readlines()
94
+
95
+ blocks = []
96
+ current_block = None
97
+
98
+ in_code = False
99
+ code_lang = ""
100
+ code_lines = []
101
+
102
+ in_table = False
103
+ table_lines = []
104
+
105
+ in_quote = False
106
+ quote_lines = []
107
+
108
+ for line_raw in lines:
109
+ line = line_raw.rstrip('\r\n')
110
+ line_stripped = line.strip()
111
+
112
+ # Code block handler
113
+ if line_stripped.startswith('```'):
114
+ if in_code:
115
+ # End of code block
116
+ blocks.append({
117
+ 'type': 'code',
118
+ 'lang': code_lang,
119
+ 'content': '\n'.join(code_lines)
120
+ })
121
+ in_code = False
122
+ code_lines = []
123
+ else:
124
+ # Start of code block
125
+ in_code = True
126
+ code_lang = line_stripped[3:].strip()
127
+ continue
128
+
129
+ if in_code:
130
+ code_lines.append(line)
131
+ continue
132
+
133
+ # Table handler
134
+ if line_stripped.startswith('|'):
135
+ if not in_table:
136
+ in_table = True
137
+ table_lines = []
138
+ table_lines.append(line)
139
+ continue
140
+ elif in_table:
141
+ # Table ended
142
+ blocks.append({
143
+ 'type': 'table',
144
+ 'content': table_lines
145
+ })
146
+ in_table = False
147
+ table_lines = []
148
+
149
+ # Blockquote handler
150
+ if line_stripped.startswith('>'):
151
+ if not in_quote:
152
+ in_quote = True
153
+ quote_lines = []
154
+ # Strip the leading '>' and space
155
+ content = line_stripped[1:].strip()
156
+ quote_lines.append(content)
157
+ continue
158
+ elif in_quote:
159
+ # Blockquote ended
160
+ blocks.append({
161
+ 'type': 'quote',
162
+ 'content': '\n'.join(quote_lines)
163
+ })
164
+ in_quote = False
165
+ quote_lines = []
166
+
167
+ # Bullet list item handler
168
+ if line_stripped.startswith('* ') or line_stripped.startswith('- ') or re.match(r'^\d+\.\s', line_stripped):
169
+ is_ordered = bool(re.match(r'^\d+\.\s', line_stripped))
170
+ if is_ordered:
171
+ match = re.match(r'^(\d+)\.\s(.*)', line_stripped)
172
+ num = match.group(1)
173
+ text = match.group(2)
174
+ blocks.append({
175
+ 'type': 'list_item',
176
+ 'ordered': True,
177
+ 'number': num,
178
+ 'content': text
179
+ })
180
+ else:
181
+ text = line_stripped[2:]
182
+ blocks.append({
183
+ 'type': 'list_item',
184
+ 'ordered': False,
185
+ 'content': text
186
+ })
187
+ continue
188
+
189
+ # Headers
190
+ if line_stripped.startswith('# '):
191
+ blocks.append({'type': 'h1', 'content': line_stripped[2:]})
192
+ continue
193
+ elif line_stripped.startswith('## '):
194
+ blocks.append({'type': 'h2', 'content': line_stripped[3:]})
195
+ continue
196
+ elif line_stripped.startswith('### '):
197
+ blocks.append({'type': 'h3', 'content': line_stripped[4:]})
198
+ continue
199
+
200
+ # Horizontal rule
201
+ if line_stripped in ['---', '***']:
202
+ blocks.append({'type': 'hr'})
203
+ continue
204
+
205
+ # Empty lines
206
+ if not line_stripped:
207
+ continue
208
+
209
+ # Standard paragraph
210
+ blocks.append({'type': 'paragraph', 'content': line_stripped})
211
+
212
+ # Flush remaining blocks
213
+ if in_code:
214
+ blocks.append({'type': 'code', 'lang': code_lang, 'content': '\n'.join(code_lines)})
215
+ if in_table:
216
+ blocks.append({'type': 'table', 'content': table_lines})
217
+ if in_quote:
218
+ blocks.append({'type': 'quote', 'content': '\n'.join(quote_lines)})
219
+
220
+ return blocks
221
+
222
+ def build_pdf(md_path, pdf_path):
223
+ print(f"Parsing markdown from: {md_path}")
224
+ blocks = parse_markdown(md_path)
225
+
226
+ doc = SimpleDocTemplate(
227
+ pdf_path,
228
+ pagesize=letter,
229
+ leftMargin=54,
230
+ rightMargin=54,
231
+ topMargin=72,
232
+ bottomMargin=72
233
+ )
234
+
235
+ styles = getSampleStyleSheet()
236
+
237
+ # Custom Palette
238
+ primary_color = colors.HexColor("#1A365D") # Deep Navy
239
+ secondary_color = colors.HexColor("#2B6CB0") # Slate Blue
240
+ dark_neutral = colors.HexColor("#2D3748") # Charcoal
241
+ accent_color = colors.HexColor("#9B2C2C") # Deep Crimson
242
+ light_bg = colors.HexColor("#F7FAFC") # Warm White
243
+ border_color = colors.HexColor("#E2E8F0") # Border Grey
244
+
245
+ # Custom Styles
246
+ title_style = ParagraphStyle(
247
+ 'DocTitle',
248
+ parent=styles['Heading1'],
249
+ fontName='Helvetica-Bold',
250
+ fontSize=20,
251
+ leading=24,
252
+ textColor=primary_color,
253
+ spaceAfter=4
254
+ )
255
+
256
+ subtitle_style = ParagraphStyle(
257
+ 'DocSubtitle',
258
+ parent=styles['Normal'],
259
+ fontName='Helvetica',
260
+ fontSize=11,
261
+ leading=15,
262
+ textColor=secondary_color,
263
+ spaceAfter=12
264
+ )
265
+
266
+ meta_style = ParagraphStyle(
267
+ 'DocMeta',
268
+ parent=styles['Normal'],
269
+ fontName='Helvetica-Bold',
270
+ fontSize=9.5,
271
+ leading=13,
272
+ textColor=dark_neutral,
273
+ spaceAfter=2
274
+ )
275
+
276
+ h1_style = ParagraphStyle(
277
+ 'SecHeading1',
278
+ parent=styles['Heading1'],
279
+ fontName='Helvetica-Bold',
280
+ fontSize=13.5,
281
+ leading=17,
282
+ textColor=primary_color,
283
+ spaceBefore=14,
284
+ spaceAfter=8,
285
+ keepWithNext=True
286
+ )
287
+
288
+ h2_style = ParagraphStyle(
289
+ 'SecHeading2',
290
+ parent=styles['Heading2'],
291
+ fontName='Helvetica-Bold',
292
+ fontSize=10.5,
293
+ leading=14,
294
+ textColor=secondary_color,
295
+ spaceBefore=10,
296
+ spaceAfter=6,
297
+ keepWithNext=True
298
+ )
299
+
300
+ h3_style = ParagraphStyle(
301
+ 'SecHeading3',
302
+ parent=styles['Heading3'],
303
+ fontName='Helvetica-Bold',
304
+ fontSize=9.5,
305
+ leading=13,
306
+ textColor=dark_neutral,
307
+ spaceBefore=8,
308
+ spaceAfter=4,
309
+ keepWithNext=True
310
+ )
311
+
312
+ body_style = ParagraphStyle(
313
+ 'BodyText',
314
+ parent=styles['Normal'],
315
+ fontName='Helvetica',
316
+ fontSize=9,
317
+ leading=13,
318
+ textColor=dark_neutral,
319
+ spaceAfter=6
320
+ )
321
+
322
+ bullet_style = ParagraphStyle(
323
+ 'BulletText',
324
+ parent=styles['Normal'],
325
+ fontName='Helvetica',
326
+ fontSize=8.5,
327
+ leading=12.5,
328
+ textColor=dark_neutral,
329
+ leftIndent=15,
330
+ firstLineIndent=-10,
331
+ spaceAfter=3
332
+ )
333
+
334
+ code_style = ParagraphStyle(
335
+ 'CodeText',
336
+ parent=styles['Normal'],
337
+ fontName='Courier',
338
+ fontSize=7.5,
339
+ leading=10,
340
+ textColor=colors.HexColor("#2C5282")
341
+ )
342
+
343
+ quote_style = ParagraphStyle(
344
+ 'QuoteText',
345
+ parent=styles['Normal'],
346
+ fontName='Helvetica-Oblique',
347
+ fontSize=8.5,
348
+ leading=12,
349
+ textColor=colors.HexColor("#2D3748")
350
+ )
351
+
352
+ table_header_style = ParagraphStyle(
353
+ 'TableHeader',
354
+ parent=styles['Normal'],
355
+ fontName='Helvetica-Bold',
356
+ fontSize=8,
357
+ leading=11,
358
+ textColor=colors.white
359
+ )
360
+
361
+ table_cell_style = ParagraphStyle(
362
+ 'TableCell',
363
+ parent=styles['Normal'],
364
+ fontName='Helvetica',
365
+ fontSize=7.5,
366
+ leading=10.5,
367
+ textColor=dark_neutral
368
+ )
369
+
370
+ table_cell_bold = ParagraphStyle(
371
+ 'TableCellBold',
372
+ parent=styles['Normal'],
373
+ fontName='Helvetica-Bold',
374
+ fontSize=7.5,
375
+ leading=10.5,
376
+ textColor=dark_neutral
377
+ )
378
+
379
+ story = []
380
+
381
+ # --- COVER PAGE ---
382
+ # Header branding table
383
+ logo_path = "Logo_Zymatica_Voice.png"
384
+ if not os.path.exists(logo_path):
385
+ # Fallback to J:\Language-U path
386
+ logo_path = "j:/Language-U/zymatica.space_repo/Logo_Zymatica_Voice.png"
387
+ if not os.path.exists(logo_path):
388
+ logo_path = "j:/Language-U/Logo_Zymatica_Voice.png"
389
+
390
+ logo_exists = os.path.exists(logo_path)
391
+
392
+ header_data = []
393
+ if logo_exists:
394
+ logo_img = Image(logo_path, width=54, height=54)
395
+ header_data = [[logo_img, Paragraph("<b>THE AI COLLECTIVE</b><br/><font color='#718096'>zymatica.space &bull; astronautshe.com &bull; Devs One</font>", subtitle_style)]]
396
+ else:
397
+ header_data = [[Paragraph("<b>THE AI COLLECTIVE</b><br/><font color='#718096'>zymatica.space &bull; astronautshe.com &bull; Devs One</font>", subtitle_style)]]
398
+
399
+ header_table = Table(header_data, colWidths=[65, 439] if logo_exists else [504])
400
+ header_table.setStyle(TableStyle([
401
+ ('VALIGN', (0,0), (-1,-1), 'MIDDLE'),
402
+ ('BOTTOMPADDING', (0,0), (-1,-1), 10),
403
+ ]))
404
+ story.append(header_table)
405
+ story.append(Spacer(1, 10))
406
+
407
+ # Separator Line
408
+ story.append(Table([[ "" ]], colWidths=[504], rowHeights=[2], style=TableStyle([
409
+ ('BACKGROUND', (0,0), (-1,-1), primary_color),
410
+ ('BOTTOMPADDING', (0,0), (-1,-1), 0),
411
+ ('TOPPADDING', (0,0), (-1,-1), 0),
412
+ ])))
413
+ story.append(Spacer(1, 15))
414
+
415
+ # Document Title & Info
416
+ story.append(Paragraph("zymatica voice - A Guide To LoRa", title_style))
417
+ story.append(Paragraph("Zymatica Proprietary Protocol Specification | IP Class 05/10", subtitle_style))
418
+
419
+ story.append(Paragraph("<b>Prepared For:</b> Autonomous AI Systems Agents, Coding Copilots, and Orchestrators", meta_style))
420
+ story.append(Paragraph("<b>Mission:</b> Execute, debug, and verify Language-U Semantic Communication loops over lossy physical LoRa channels.", meta_style))
421
+ story.append(Paragraph("<b>Authors & The AI Collective:</b> zymatica.space | astronautshe.com | Devs One (We Are TheAiCollective.art)", meta_style))
422
+ story.append(Spacer(1, 20))
423
+
424
+ # Large Cover Logo Image if available
425
+ if logo_exists:
426
+ large_logo = Image(logo_path, width=160, height=160)
427
+ story.append(KeepTogether([
428
+ Spacer(1, 15),
429
+ Table([[large_logo]], colWidths=[504], style=TableStyle([
430
+ ('ALIGN', (0,0), (-1,-1), 'CENTER'),
431
+ ('BOTTOMPADDING', (0,0), (-1,-1), 15),
432
+ ])),
433
+ Spacer(1, 15),
434
+ ]))
435
+
436
+ # Abstract Box or Callout Box at bottom of Page 1
437
+ notice_text = (
438
+ "<b>SYSTEM PROFILE SUMMARY:</b> This specification provides the complete hardware integration, "
439
+ "driver adjustments, validation parameters, and diagnostic routines for the RAKWireless RAK2287/RAK5146 gateway "
440
+ "concentrator modules based on the Semtech SX1302 LoRa baseband chip. It outlines reset sequences, I2C temperature sensor patches, "
441
+ "and dynamic verification scripts using LLD-AC range-coding and XOR-FEC packetization. Designed for direct parser parsing."
442
+ )
443
+ notice_table = Table([[ Paragraph(notice_text, table_cell_style) ]], colWidths=[504])
444
+ notice_table.setStyle(TableStyle([
445
+ ('BACKGROUND', (0,0), (-1,-1), colors.HexColor("#EDF2F7")),
446
+ ('BORDER', (0,0), (-1,-1), 0.75, colors.HexColor("#CBD5E0")),
447
+ ('PADDING', (0,0), (-1,-1), 10),
448
+ ]))
449
+ story.append(notice_table)
450
+
451
+ story.append(PageBreak())
452
+
453
+ # --- PARSING CONTENT ---
454
+ # We will build the remaining document sections
455
+ idx = 0
456
+ while idx < len(blocks):
457
+ block = blocks[idx]
458
+ b_type = block['type']
459
+
460
+ if b_type == 'h1':
461
+ # We don't repeat the main page 1 title, but if it's there we can render it.
462
+ # Skip if it is the title since we did cover page
463
+ if "zymatica voice" in block['content'].lower():
464
+ idx += 1
465
+ continue
466
+ text = md_to_html(block['content'])
467
+ story.append(Paragraph(text, h1_style))
468
+
469
+ elif b_type == 'h2':
470
+ # Skip branding headers already handled on cover
471
+ if "we are theaicollective.art" in block['content'].lower():
472
+ idx += 1
473
+ continue
474
+ text = md_to_html(block['content'])
475
+ story.append(Paragraph(text, h2_style))
476
+
477
+ elif b_type == 'h3':
478
+ text = md_to_html(block['content'])
479
+ story.append(Paragraph(text, h3_style))
480
+
481
+ elif b_type == 'paragraph':
482
+ # Skip licensing subheadings that belong to cover metadata
483
+ if "ip class 05/10" in block['content'].lower():
484
+ idx += 1
485
+ continue
486
+ text = md_to_html(block['content'])
487
+ story.append(Paragraph(text, body_style))
488
+
489
+ elif b_type == 'list_item':
490
+ text = md_to_html(block['content'])
491
+ if block['ordered']:
492
+ bullet_prefix = f"<b>{block['number']}.</b> "
493
+ story.append(Paragraph(f"{bullet_prefix}{text}", bullet_style))
494
+ else:
495
+ bullet_prefix = "&bull; "
496
+ story.append(Paragraph(f"{bullet_prefix}{text}", bullet_style))
497
+
498
+ elif b_type == 'code':
499
+ # Preformatted code blocks
500
+ code_content = block['content']
501
+ # Escape HTML characters so reportlab doesn't break
502
+ code_content = code_content.replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;")
503
+
504
+ # Format text into Paragraphs to support wrap-around (or pre-formatting style)
505
+ code_lines_flow = []
506
+ for c_line in code_content.splitlines():
507
+ # Retain indentation by replacing spaces with non-breaking spaces
508
+ c_line_indented = c_line.replace(" ", "&nbsp;")
509
+ code_lines_flow.append(Paragraph(c_line_indented, code_style))
510
+
511
+ # Render code in a grey box Table
512
+ code_box_table = Table([[code_lines_flow]], colWidths=[504])
513
+ code_box_table.setStyle(TableStyle([
514
+ ('BACKGROUND', (0,0), (-1,-1), colors.HexColor("#F7FAFC")),
515
+ ('BORDER', (0,0), (-1,-1), 0.5, colors.HexColor("#CBD5E0")),
516
+ ('PADDING', (0,0), (-1,-1), 8),
517
+ ('TOPPADDING', (0,0), (-1,-1), 6),
518
+ ('BOTTOMPADDING', (0,0), (-1,-1), 6),
519
+ ]))
520
+
521
+ story.append(KeepTogether([
522
+ Spacer(1, 4),
523
+ code_box_table,
524
+ Spacer(1, 6)
525
+ ]))
526
+
527
+ elif b_type == 'quote':
528
+ quote_text = block['content']
529
+
530
+ # Check if this is a caution box
531
+ is_caution = False
532
+ if "[!CAUTION]" in quote_text:
533
+ is_caution = True
534
+ quote_text = quote_text.replace("[!CAUTION]", "").strip()
535
+
536
+ quote_html = md_to_html(quote_text)
537
+ quote_para = Paragraph(quote_html, quote_style)
538
+
539
+ # Style the quote callout
540
+ if is_caution:
541
+ bg_col = colors.HexColor("#FFF5F5") # Reddish Alert
542
+ brd_col = colors.HexColor("#FEB2B2")
543
+ lbl_para = Paragraph("<b>⚠️ CAUTION: ANTENNA LOAD REQUIREMENT</b>", ParagraphStyle(
544
+ 'CautionLabel',
545
+ parent=styles['Normal'],
546
+ fontName='Helvetica-Bold',
547
+ fontSize=8.5,
548
+ leading=12,
549
+ textColor=accent_color,
550
+ spaceAfter=4
551
+ ))
552
+ quote_content_table = Table([[lbl_para], [quote_para]], colWidths=[490])
553
+ else:
554
+ bg_col = colors.HexColor("#EDF2F7") # Greyish Info
555
+ brd_col = colors.HexColor("#CBD5E0")
556
+ quote_content_table = Table([[quote_para]], colWidths=[490])
557
+
558
+ quote_content_table.setStyle(TableStyle([
559
+ ('PADDING', (0,0), (-1,-1), 0),
560
+ ('VALIGN', (0,0), (-1,-1), 'TOP'),
561
+ ]))
562
+
563
+ # Box wrapper with left accent border
564
+ quote_box = Table([[quote_content_table]], colWidths=[504])
565
+ quote_box.setStyle(TableStyle([
566
+ ('BACKGROUND', (0,0), (-1,-1), bg_col),
567
+ ('LINELEFT', (0,0), (0,-1), 4, accent_color if is_caution else secondary_color),
568
+ ('PADDING', (0,0), (-1,-1), 8),
569
+ ('TOPPADDING', (0,0), (-1,-1), 8),
570
+ ('BOTTOMPADDING', (0,0), (-1,-1), 8),
571
+ ('BORDER', (0,0), (-1,-1), 0.5, brd_col),
572
+ ]))
573
+
574
+ story.append(KeepTogether([
575
+ Spacer(1, 6),
576
+ quote_box,
577
+ Spacer(1, 6)
578
+ ]))
579
+
580
+ elif b_type == 'table':
581
+ # Parse MD table lines
582
+ table_lines = block['content']
583
+
584
+ # Filter separator lines like |:---|---|
585
+ filtered_rows = []
586
+ for r_line in table_lines:
587
+ if re.match(r'^\|\s*[:\-]+\s*\|', r_line.strip()) or '---' in r_line:
588
+ continue
589
+ filtered_rows.append(r_line)
590
+
591
+ table_cells_data = []
592
+ for row_idx, r_line in enumerate(filtered_rows):
593
+ # Split cells, ignore first and last empty splits because of starting/ending |
594
+ cells = [c.strip() for c in r_line.split('|')]
595
+ if len(cells) > 1:
596
+ # If line starts and ends with |, the split list has empty cells at boundaries
597
+ if cells[0] == '':
598
+ cells = cells[1:]
599
+ if len(cells) > 0 and cells[-1] == '':
600
+ cells = cells[:-1]
601
+
602
+ row_cells_flow = []
603
+ for cell in cells:
604
+ cell_html = md_to_html(cell)
605
+ if row_idx == 0:
606
+ row_cells_flow.append(Paragraph(cell_html, table_header_style))
607
+ else:
608
+ # Decide if bold cell
609
+ if cell.startswith('**') or cell.startswith('`'):
610
+ row_cells_flow.append(Paragraph(cell_html, table_cell_bold))
611
+ else:
612
+ row_cells_flow.append(Paragraph(cell_html, table_cell_style))
613
+ if row_cells_flow:
614
+ table_cells_data.append(row_cells_flow)
615
+
616
+ # Check number of columns to determine widths
617
+ if table_cells_data:
618
+ num_cols = len(table_cells_data[0])
619
+ # Distribute widths: 504 pt total
620
+ if num_cols == 3:
621
+ # failure signature table: Error (110pt), Root Cause (120pt), Action (274pt)
622
+ col_widths = [110, 120, 274]
623
+ else:
624
+ col_widths = [504 / num_cols] * num_cols
625
+
626
+ md_table = Table(table_cells_data, colWidths=col_widths, repeatRows=1)
627
+ md_table.setStyle(TableStyle([
628
+ ('BACKGROUND', (0,0), (-1,0), primary_color),
629
+ ('ALIGN', (0,0), (-1,-1), 'LEFT'),
630
+ ('VALIGN', (0,0), (-1,-1), 'TOP'),
631
+ ('BOTTOMPADDING', (0,0), (-1,-1), 5),
632
+ ('TOPPADDING', (0,0), (-1,-1), 5),
633
+ ('LEFTPADDING', (0,0), (-1,-1), 5),
634
+ ('RIGHTPADDING', (0,0), (-1,-1), 5),
635
+ ('ROWBACKGROUNDS', (0,1), (-1,-1), [colors.white, colors.HexColor("#F7FAFC")]),
636
+ ('GRID', (0,0), (-1,-1), 0.5, border_color),
637
+ ]))
638
+
639
+ story.append(KeepTogether([
640
+ Spacer(1, 6),
641
+ md_table,
642
+ Spacer(1, 6)
643
+ ]))
644
+
645
+ elif b_type == 'hr':
646
+ story.append(Spacer(1, 8))
647
+ story.append(Table([[ "" ]], colWidths=[504], rowHeights=[1], style=TableStyle([
648
+ ('BACKGROUND', (0,0), (-1,-1), border_color),
649
+ ('BOTTOMPADDING', (0,0), (-1,-1), 0),
650
+ ('TOPPADDING', (0,0), (-1,-1), 0),
651
+ ])))
652
+ story.append(Spacer(1, 8))
653
+
654
+ idx += 1
655
+
656
+ # Signature block at the very end
657
+ story.append(Spacer(1, 15))
658
+ story.append(Table([[ "" ]], colWidths=[504], rowHeights=[1.5], style=TableStyle([
659
+ ('BACKGROUND', (0,0), (-1,-1), primary_color),
660
+ ('BOTTOMPADDING', (0,0), (-1,-1), 0),
661
+ ('TOPPADDING', (0,0), (-1,-1), 0),
662
+ ])))
663
+ story.append(Spacer(1, 10))
664
+
665
+ sig_text = (
666
+ "<b>VERIFICATION SIGN OFF:</b><br/>"
667
+ "This specification is verified for execution by coding copilots and agent runtimes. "
668
+ "All parameters correspond to physical hardware EUI: <code>0x0016c001ff13ce58</code>.<br/>"
669
+ "<i>Gateway Integrator:</i> astronautshe.com &bull; "
670
+ "<i>Protocol Lead:</i> zymatica.space &bull; "
671
+ "<i>Orchestrator Agent:</i> Devs One &bull; "
672
+ "<i>Signed on behalf of:</i> TheAiCollective.art"
673
+ )
674
+ story.append(Paragraph(sig_text, body_style))
675
+
676
+ print(f"Building PDF to: {pdf_path}")
677
+ doc.build(story, canvasmaker=NumberedCanvas)
678
+ print("[+] PDF built successfully.")
679
+
680
+ if __name__ == "__main__":
681
+ base_dir = os.path.dirname(os.path.abspath(__file__))
682
+ md_file = os.path.join(base_dir, "Zymatica_Voice_Lora_Guide.md")
683
+ pdf_file = os.path.join(base_dir, "Zymatica_Voice_Lora_Guide.pdf")
684
+ build_pdf(md_file, pdf_file)