Prathamesh Sarjerao Vaidya commited on
Commit
330512b
·
1 Parent(s): aaaa4c6

update main and check.yml

Browse files
Files changed (2) hide show
  1. .github/workflows/check.yml +400 -432
  2. .github/workflows/main.yml +398 -429
.github/workflows/check.yml CHANGED
@@ -16,7 +16,7 @@ jobs:
16
  with:
17
  filesizelimit: 1073741824 # 1GB
18
 
19
- sync-to-drive-on-pr:
20
  runs-on: ubuntu-latest
21
  needs: check-file-size
22
  if: github.event_name == 'pull_request'
@@ -31,453 +31,422 @@ jobs:
31
  git lfs install
32
  git lfs pull
33
 
34
- # Install pandoc and fonts for proper Unicode/emoji support
35
- - name: Install pandoc and dependencies
 
 
 
 
 
 
36
  run: |
37
  sudo apt-get update
38
  sudo apt-get install -y \
39
- pandoc \
40
  texlive-xetex \
41
- texlive-fonts-recommended \
42
- texlive-fonts-extra \
43
- fonts-dejavu \
44
- fonts-liberation \
45
- python3-pip
46
-
47
- # Install weasyprint as fallback
48
- pip install weasyprint
 
49
 
50
- # Improved MD to PDF Conversion with proper image handling and mermaid support
51
- name: Convert Markdown to PDF
 
 
 
52
 
53
- on:
54
- push:
55
- branches: [ main ]
56
- pull_request:
57
- branches: [ main ]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
58
 
59
- jobs:
60
- convert-to-pdf:
61
- runs-on: ubuntu-latest
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
62
 
63
- steps:
64
- - name: Checkout repository
65
- uses: actions/checkout@v4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
66
 
67
- - name: Setup Python
68
- uses: actions/setup-python@v4
69
- with:
70
- python-version: '3.11'
71
-
72
- - name: Install system dependencies
73
- run: |
74
- sudo apt-get update
75
- sudo apt-get install -y \
76
- texlive-full \
77
- texlive-xetex \
78
- texlive-luatex \
79
- pandoc \
80
- librsvg2-bin \
81
- python3-pip \
82
- nodejs \
83
- npm \
84
- imagemagick \
85
- ghostscript \
86
- wkhtmltopdf
87
-
88
- - name: Install Node.js dependencies for Mermaid
89
- run: |
90
- npm install -g @mermaid-js/mermaid-cli
91
- npm install -g puppeteer
92
-
93
- - name: Install Python dependencies
94
- run: |
95
- pip install --upgrade pip
96
- pip install \
97
- weasyprint \
98
- markdown \
99
- pymdown-extensions \
100
- pillow \
101
- cairosvg \
102
- pdfkit
103
-
104
- - name: Create LaTeX header for better image handling
105
- run: |
106
- cat > latex-header.tex << 'EOF'
107
- \usepackage{graphicx}
108
- \usepackage{float}
109
- \usepackage{adjustbox}
110
- \usepackage{caption}
111
- \usepackage{subcaption}
112
- \usepackage{geometry}
113
- \usepackage{fancyhdr}
114
- \usepackage{xcolor}
115
- \usepackage{hyperref}
116
-
117
- % Better image positioning and scaling
118
- \floatplacement{figure}{H}
119
- \renewcommand{\includegraphics}[2][]{\adjustbox{max width=\textwidth,center}{\oldincludegraphics[#1]{#2}}}
120
- \let\oldincludegraphics\includegraphics
121
-
122
- % Set margins
123
- \geometry{margin=1in}
124
-
125
- % Hyperlink colors
126
- \hypersetup{
127
- colorlinks=true,
128
- linkcolor=blue,
129
- urlcolor=blue,
130
- citecolor=blue
131
- }
132
- EOF
133
-
134
- - name: Create enhanced CSS for HTML conversion
135
- run: |
136
- cat > styles.css << 'EOF'
137
- body {
138
- font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
139
- max-width: 210mm;
140
- margin: 0 auto;
141
- padding: 20mm;
142
- line-height: 1.6;
143
- color: #333;
144
- background: white;
145
- }
146
-
147
- img {
148
- max-width: 100%;
149
- height: auto;
150
- display: block;
151
- margin: 1em auto;
152
- border-radius: 4px;
153
- box-shadow: 0 2px 8px rgba(0,0,0,0.1);
154
- }
155
-
156
- pre {
157
- background: #f8f9fa;
158
- padding: 1em;
159
- border-radius: 6px;
160
- border-left: 4px solid #007acc;
161
- overflow-x: auto;
162
- font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
163
- font-size: 0.9em;
164
- }
165
-
166
- code {
167
- background: #f1f3f4;
168
- padding: 0.2em 0.4em;
169
- border-radius: 3px;
170
- font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
171
- font-size: 0.9em;
172
- }
173
-
174
- h1, h2, h3, h4, h5, h6 {
175
- color: #2c3e50;
176
- margin-top: 2em;
177
- margin-bottom: 1em;
178
- page-break-after: avoid;
179
- }
180
-
181
- h1 {
182
- border-bottom: 3px solid #3498db;
183
- padding-bottom: 0.5em;
184
- }
185
-
186
- h2 {
187
- border-bottom: 2px solid #95a5a6;
188
- padding-bottom: 0.3em;
189
- }
190
-
191
- table {
192
- border-collapse: collapse;
193
- width: 100%;
194
- margin: 1em 0;
195
- }
196
-
197
- th, td {
198
- border: 1px solid #ddd;
199
- padding: 0.75em;
200
- text-align: left;
201
- }
202
-
203
- th {
204
- background-color: #f8f9fa;
205
- font-weight: bold;
206
- }
207
-
208
- blockquote {
209
- border-left: 4px solid #3498db;
210
- margin: 1em 0;
211
- padding: 0.5em 1em;
212
- background: #f8f9fa;
213
- border-radius: 0 4px 4px 0;
214
- }
215
-
216
- .mermaid-container {
217
- text-align: center;
218
- margin: 2em 0;
219
- page-break-inside: avoid;
220
- }
221
-
222
- .mermaid-container img {
223
- max-width: 100%;
224
- height: auto;
225
- }
226
-
227
- @media print {
228
- body {
229
- margin: 0;
230
- padding: 15mm;
231
- }
232
-
233
- img {
234
- max-height: 80vh;
235
- page-break-inside: avoid;
236
- }
237
-
238
- h1, h2, h3, h4, h5, h6 {
239
- page-break-after: avoid;
240
- }
241
-
242
- pre, blockquote {
243
- page-break-inside: avoid;
244
- }
245
- }
246
- EOF
247
-
248
- - name: Create preprocessing script
249
- run: |
250
- cat > preprocess_markdown.py << 'EOF'
251
- #!/usr/bin/env python3
252
- import re
253
- import os
254
- import sys
255
- import subprocess
256
- from pathlib import Path
257
-
258
- def process_mermaid_diagrams(content, file_dir):
259
- """Convert mermaid diagrams to images"""
260
- mermaid_pattern = r'```mermaid\n(.*?)\n```'
261
-
262
- def replace_mermaid(match):
263
- mermaid_code = match.group(1)
264
- # Create a unique filename for this diagram
265
- diagram_hash = str(abs(hash(mermaid_code)))
266
- mermaid_file = f"{file_dir}/mermaid_{diagram_hash}.mmd"
267
- svg_file = f"{file_dir}/mermaid_{diagram_hash}.svg"
268
- png_file = f"{file_dir}/mermaid_{diagram_hash}.png"
269
-
270
- # Write mermaid code to file
271
- with open(mermaid_file, 'w') as f:
272
- f.write(mermaid_code)
273
-
274
- try:
275
- # Convert to SVG first
276
- subprocess.run([
277
- 'mmdc', '-i', mermaid_file, '-o', svg_file,
278
- '--theme', 'default', '--backgroundColor', 'white'
279
- ], check=True, capture_output=True)
280
-
281
- # Convert SVG to PNG for better PDF compatibility
282
- subprocess.run([
283
- 'rsvg-convert', '-f', 'png', '-o', png_file,
284
- '--width', '1200', '--height', '800', svg_file
285
- ], check=True, capture_output=True)
286
-
287
- # Clean up intermediate files
288
- os.remove(mermaid_file)
289
- if os.path.exists(svg_file):
290
- os.remove(svg_file)
291
-
292
- # Return markdown image syntax
293
- return f'\n<div class="mermaid-container">\n\n![Architecture Diagram]({os.path.basename(png_file)})\n\n</div>\n'
294
-
295
- except subprocess.CalledProcessError as e:
296
- print(f"Error converting mermaid diagram: {e}")
297
- return f'\n```\n{mermaid_code}\n```\n'
298
- except Exception as e:
299
- print(f"Unexpected error with mermaid: {e}")
300
- return f'\n```\n{mermaid_code}\n```\n'
301
-
302
- return re.sub(mermaid_pattern, replace_mermaid, content, flags=re.DOTALL)
303
-
304
- def fix_image_paths(content, file_dir):
305
- """Fix image paths and add proper sizing"""
306
- # Pattern to match markdown images
307
- img_pattern = r'!\[([^\]]*)\]\(([^)]+)\)'
308
-
309
- def replace_image(match):
310
- alt_text = match.group(1)
311
- img_path = match.group(2)
312
-
313
- # Handle relative paths
314
- if not img_path.startswith(('http://', 'https://', '/')):
315
- # Make path relative to the markdown file
316
- abs_img_path = os.path.join(file_dir, img_path)
317
- if os.path.exists(abs_img_path):
318
- img_path = os.path.relpath(abs_img_path, file_dir)
319
-
320
- # Add HTML img tag with better control
321
- return f'<img src="{img_path}" alt="{alt_text}" style="max-width: 100%; height: auto; display: block; margin: 1em auto;" />'
322
-
323
- # Also handle HTML img tags and ensure they have proper styling
324
- content = re.sub(img_pattern, replace_image, content)
325
-
326
- # Fix existing HTML img tags
327
- content = re.sub(
328
- r'<img\s+([^>]*?)\s*/?>',
329
- lambda m: f'<img {m.group(1)} style="max-width: 100%; height: auto; display: block; margin: 1em auto;" />',
330
- content
331
- )
332
-
333
- return content
334
-
335
- def main():
336
- if len(sys.argv) != 2:
337
- print("Usage: python preprocess_markdown.py <markdown_file>")
338
- sys.exit(1)
339
-
340
- md_file = sys.argv[1]
341
- file_dir = os.path.dirname(os.path.abspath(md_file))
342
-
343
- with open(md_file, 'r', encoding='utf-8') as f:
344
- content = f.read()
345
-
346
- # Process mermaid diagrams
347
- content = process_mermaid_diagrams(content, file_dir)
348
-
349
- # Fix image paths and sizing
350
- content = fix_image_paths(content, file_dir)
351
-
352
- # Write processed content
353
- processed_file = md_file.replace('.md', '_processed.md')
354
- with open(processed_file, 'w', encoding='utf-8') as f:
355
- f.write(content)
356
-
357
- print(f"Processed file saved as: {processed_file}")
358
- return processed_file
359
-
360
- if __name__ == "__main__":
361
- main()
362
- EOF
363
-
364
- chmod +x preprocess_markdown.py
365
-
366
- - name: Convert MD to PDF with enhanced processing
367
- run: |
368
- find . -name "*.md" -not -path "./.git/*" | while read file; do
369
- # Get the directory and filename
370
- dir="$(dirname "$file")"
371
- filename="$(basename "$file" .md)"
372
- pdf_path="$dir/$filename.pdf"
373
-
374
- echo "Processing $file..."
375
-
376
- # Preprocess the markdown file
377
- cd "$dir"
378
- processed_file=$(python3 "$GITHUB_WORKSPACE/preprocess_markdown.py" "$(basename "$file")")
379
-
380
- if [ ! -f "$processed_file" ]; then
381
- echo "Preprocessing failed for $file, using original"
382
- processed_file="$(basename "$file")"
383
- fi
384
 
385
- echo "Converting $processed_file to $pdf_path"
 
 
386
 
387
- # Method 1: Try XeLaTeX with enhanced settings
388
- pandoc "$processed_file" \
389
- -o "$pdf_path" \
390
- --pdf-engine=xelatex \
391
- --include-in-header="$GITHUB_WORKSPACE/latex-header.tex" \
392
- --variable mainfont="DejaVu Sans" \
393
- --variable sansfont="DejaVu Sans" \
394
- --variable monofont="DejaVu Sans Mono" \
395
- --variable geometry:margin=1in \
396
- --variable colorlinks=true \
397
- --variable linkcolor=blue \
398
- --variable urlcolor=blue \
399
- --variable toccolor=gray \
400
- --resource-path="$dir:$GITHUB_WORKSPACE" \
401
- --standalone \
402
- --toc \
403
- --number-sections \
404
- --highlight-style=github \
405
- --wrap=auto \
406
- --dpi=300 \
407
- --verbose 2>/dev/null || {
408
-
409
- echo "XeLaTeX failed, trying HTML->PDF conversion..."
410
-
411
- # Method 2: HTML to PDF conversion with WeasyPrint
412
- pandoc "$processed_file" \
413
- -t html5 \
414
- --standalone \
415
- --embed-resources \
416
- --css="$GITHUB_WORKSPACE/styles.css" \
417
- --toc \
418
- --number-sections \
419
- --highlight-style=github \
420
- -o "$dir/$filename.html"
421
-
422
- if [ -f "$dir/$filename.html" ]; then
423
- weasyprint "$dir/$filename.html" "$pdf_path" --presentational-hints || {
424
- echo "WeasyPrint failed, trying wkhtmltopdf..."
425
-
426
- # Method 3: wkhtmltopdf as final fallback
427
- wkhtmltopdf \
428
- --page-size A4 \
429
- --margin-top 0.75in \
430
- --margin-right 0.75in \
431
- --margin-bottom 0.75in \
432
- --margin-left 0.75in \
433
- --encoding UTF-8 \
434
- --no-outline \
435
- --enable-local-file-access \
436
- "$dir/$filename.html" "$pdf_path" || {
437
- echo "All conversion methods failed for $file"
438
- continue
439
- }
440
- }
441
 
442
- # Clean up HTML file
443
- rm -f "$dir/$filename.html"
444
- fi
445
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
446
 
447
- # Clean up processed file
448
- if [ "$processed_file" != "$(basename "$file")" ]; then
449
- rm -f "$processed_file"
450
- fi
 
 
451
 
452
- # Clean up generated mermaid images
453
- rm -f mermaid_*.png mermaid_*.svg mermaid_*.mmd
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
454
 
455
- if [ -f "$pdf_path" ]; then
456
- echo "✅ Successfully converted $file to $pdf_path"
457
- else
458
- echo "❌ Failed to convert $file"
459
- fi
460
- done
 
 
 
 
 
 
 
 
 
461
 
462
- - name: Upload PDF artifacts
463
- uses: actions/upload-artifact@v4
464
- with:
465
- name: converted-pdfs
466
- path: "**/*.pdf"
467
- retention-days: 30
468
-
469
- # Set up Python for Google Drive upload
470
- - name: Set up Python
471
- uses: actions/setup-python@v4
472
- with:
473
- python-version: '3.9'
 
 
 
 
 
 
 
474
 
475
- # Install Python dependencies
476
- - name: Install Python dependencies
477
- run: |
478
- pip install google-auth google-auth-oauthlib google-auth-httplib2 google-api-python-client
 
 
 
479
 
480
- # Create and run upload script
481
  - name: Upload to Google Drive
482
  env:
483
  GOOGLE_OAUTH_TOKEN: ${{ secrets.GOOGLE_OAUTH_TOKEN }}
@@ -621,5 +590,4 @@ jobs:
621
  print("Upload completed - MD files were skipped, PDFs were uploaded!")
622
  EOF
623
 
624
- python upload_to_drive.py
625
-
 
16
  with:
17
  filesizelimit: 1073741824 # 1GB
18
 
19
+ convert-and-sync:
20
  runs-on: ubuntu-latest
21
  needs: check-file-size
22
  if: github.event_name == 'pull_request'
 
31
  git lfs install
32
  git lfs pull
33
 
34
+ # Setup Python
35
+ - name: Setup Python
36
+ uses: actions/setup-python@v4
37
+ with:
38
+ python-version: '3.11'
39
+
40
+ # Install system dependencies
41
+ - name: Install system dependencies
42
  run: |
43
  sudo apt-get update
44
  sudo apt-get install -y \
45
+ texlive-full \
46
  texlive-xetex \
47
+ texlive-luatex \
48
+ pandoc \
49
+ librsvg2-bin \
50
+ python3-pip \
51
+ nodejs \
52
+ npm \
53
+ imagemagick \
54
+ ghostscript \
55
+ wkhtmltopdf
56
 
57
+ # Install Node.js dependencies for Mermaid
58
+ - name: Install Node.js dependencies for Mermaid
59
+ run: |
60
+ npm install -g @mermaid-js/mermaid-cli
61
+ npm install -g puppeteer
62
 
63
+ # Install Python dependencies
64
+ - name: Install Python dependencies
65
+ run: |
66
+ pip install --upgrade pip
67
+ pip install \
68
+ weasyprint \
69
+ markdown \
70
+ pymdown-extensions \
71
+ pillow \
72
+ cairosvg \
73
+ pdfkit \
74
+ google-auth \
75
+ google-auth-oauthlib \
76
+ google-auth-httplib2 \
77
+ google-api-python-client
78
+
79
+ # Create LaTeX header for better image handling
80
+ - name: Create LaTeX header for better image handling
81
+ run: |
82
+ cat > latex-header.tex << 'EOF'
83
+ \usepackage{graphicx}
84
+ \usepackage{float}
85
+ \usepackage{adjustbox}
86
+ \usepackage{caption}
87
+ \usepackage{subcaption}
88
+ \usepackage{geometry}
89
+ \usepackage{fancyhdr}
90
+ \usepackage{xcolor}
91
+ \usepackage{hyperref}
92
+
93
+ % Better image positioning and scaling
94
+ \floatplacement{figure}{H}
95
+ \renewcommand{\includegraphics}[2][]{\adjustbox{max width=\textwidth,center}{\oldincludegraphics[#1]{#2}}}
96
+ \let\oldincludegraphics\includegraphics
97
+
98
+ % Set margins
99
+ \geometry{margin=1in}
100
+
101
+ % Hyperlink colors
102
+ \hypersetup{
103
+ colorlinks=true,
104
+ linkcolor=blue,
105
+ urlcolor=blue,
106
+ citecolor=blue
107
+ }
108
+ EOF
109
 
110
+ # Create enhanced CSS for HTML conversion
111
+ - name: Create enhanced CSS for HTML conversion
112
+ run: |
113
+ cat > styles.css << 'EOF'
114
+ body {
115
+ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
116
+ max-width: 210mm;
117
+ margin: 0 auto;
118
+ padding: 20mm;
119
+ line-height: 1.6;
120
+ color: #333;
121
+ background: white;
122
+ }
123
+
124
+ img {
125
+ max-width: 100%;
126
+ height: auto;
127
+ display: block;
128
+ margin: 1em auto;
129
+ border-radius: 4px;
130
+ box-shadow: 0 2px 8px rgba(0,0,0,0.1);
131
+ }
132
+
133
+ pre {
134
+ background: #f8f9fa;
135
+ padding: 1em;
136
+ border-radius: 6px;
137
+ border-left: 4px solid #007acc;
138
+ overflow-x: auto;
139
+ font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
140
+ font-size: 0.9em;
141
+ }
142
+
143
+ code {
144
+ background: #f1f3f4;
145
+ padding: 0.2em 0.4em;
146
+ border-radius: 3px;
147
+ font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
148
+ font-size: 0.9em;
149
+ }
150
+
151
+ h1, h2, h3, h4, h5, h6 {
152
+ color: #2c3e50;
153
+ margin-top: 2em;
154
+ margin-bottom: 1em;
155
+ page-break-after: avoid;
156
+ }
157
+
158
+ h1 {
159
+ border-bottom: 3px solid #3498db;
160
+ padding-bottom: 0.5em;
161
+ }
162
+
163
+ h2 {
164
+ border-bottom: 2px solid #95a5a6;
165
+ padding-bottom: 0.3em;
166
+ }
167
 
168
+ table {
169
+ border-collapse: collapse;
170
+ width: 100%;
171
+ margin: 1em 0;
172
+ }
173
+
174
+ th, td {
175
+ border: 1px solid #ddd;
176
+ padding: 0.75em;
177
+ text-align: left;
178
+ }
179
+
180
+ th {
181
+ background-color: #f8f9fa;
182
+ font-weight: bold;
183
+ }
184
+
185
+ blockquote {
186
+ border-left: 4px solid #3498db;
187
+ margin: 1em 0;
188
+ padding: 0.5em 1em;
189
+ background: #f8f9fa;
190
+ border-radius: 0 4px 4px 0;
191
+ }
192
+
193
+ .mermaid-container {
194
+ text-align: center;
195
+ margin: 2em 0;
196
+ page-break-inside: avoid;
197
+ }
198
+
199
+ .mermaid-container img {
200
+ max-width: 100%;
201
+ height: auto;
202
+ }
203
+
204
+ @media print {
205
+ body {
206
+ margin: 0;
207
+ padding: 15mm;
208
+ }
209
 
210
+ img {
211
+ max-height: 80vh;
212
+ page-break-inside: avoid;
213
+ }
214
+
215
+ h1, h2, h3, h4, h5, h6 {
216
+ page-break-after: avoid;
217
+ }
218
+
219
+ pre, blockquote {
220
+ page-break-inside: avoid;
221
+ }
222
+ }
223
+ EOF
224
+
225
+ # Create preprocessing script
226
+ - name: Create preprocessing script
227
+ run: |
228
+ cat > preprocess_markdown.py << 'EOF'
229
+ #!/usr/bin/env python3
230
+ import re
231
+ import os
232
+ import sys
233
+ import subprocess
234
+ from pathlib import Path
235
+
236
+ def process_mermaid_diagrams(content, file_dir):
237
+ """Convert mermaid diagrams to images"""
238
+ mermaid_pattern = r'```mermaid\n(.*?)\n```'
239
+
240
+ def replace_mermaid(match):
241
+ mermaid_code = match.group(1)
242
+ # Create a unique filename for this diagram
243
+ diagram_hash = str(abs(hash(mermaid_code)))
244
+ mermaid_file = f"{file_dir}/mermaid_{diagram_hash}.mmd"
245
+ svg_file = f"{file_dir}/mermaid_{diagram_hash}.svg"
246
+ png_file = f"{file_dir}/mermaid_{diagram_hash}.png"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
247
 
248
+ # Write mermaid code to file
249
+ with open(mermaid_file, 'w') as f:
250
+ f.write(mermaid_code)
251
 
252
+ try:
253
+ # Convert to SVG first
254
+ subprocess.run([
255
+ 'mmdc', '-i', mermaid_file, '-o', svg_file,
256
+ '--theme', 'default', '--backgroundColor', 'white'
257
+ ], check=True, capture_output=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
258
 
259
+ # Convert SVG to PNG for better PDF compatibility
260
+ subprocess.run([
261
+ 'rsvg-convert', '-f', 'png', '-o', png_file,
262
+ '--width', '1200', '--height', '800', svg_file
263
+ ], check=True, capture_output=True)
264
+
265
+ # Clean up intermediate files
266
+ os.remove(mermaid_file)
267
+ if os.path.exists(svg_file):
268
+ os.remove(svg_file)
269
+
270
+ # Return markdown image syntax
271
+ return f'\n<div class="mermaid-container">\n\n![Architecture Diagram]({os.path.basename(png_file)})\n\n</div>\n'
272
+
273
+ except subprocess.CalledProcessError as e:
274
+ print(f"Error converting mermaid diagram: {e}")
275
+ return f'\n```\n{mermaid_code}\n```\n'
276
+ except Exception as e:
277
+ print(f"Unexpected error with mermaid: {e}")
278
+ return f'\n```\n{mermaid_code}\n```\n'
279
+
280
+ return re.sub(mermaid_pattern, replace_mermaid, content, flags=re.DOTALL)
281
+
282
+ def fix_image_paths(content, file_dir):
283
+ """Fix image paths and add proper sizing"""
284
+ # Pattern to match markdown images
285
+ img_pattern = r'!\[([^\]]*)\]\(([^)]+)\)'
286
+
287
+ def replace_image(match):
288
+ alt_text = match.group(1)
289
+ img_path = match.group(2)
290
 
291
+ # Handle relative paths
292
+ if not img_path.startswith(('http://', 'https://', '/')):
293
+ # Make path relative to the markdown file
294
+ abs_img_path = os.path.join(file_dir, img_path)
295
+ if os.path.exists(abs_img_path):
296
+ img_path = os.path.relpath(abs_img_path, file_dir)
297
 
298
+ # Add HTML img tag with better control
299
+ return f'<img src="{img_path}" alt="{alt_text}" style="max-width: 100%; height: auto; display: block; margin: 1em auto;" />'
300
+
301
+ # Also handle HTML img tags and ensure they have proper styling
302
+ content = re.sub(img_pattern, replace_image, content)
303
+
304
+ # Fix existing HTML img tags
305
+ content = re.sub(
306
+ r'<img\s+([^>]*?)\s*/?>',
307
+ lambda m: f'<img {m.group(1)} style="max-width: 100%; height: auto; display: block; margin: 1em auto;" />',
308
+ content
309
+ )
310
+
311
+ return content
312
+
313
+ def main():
314
+ if len(sys.argv) != 2:
315
+ print("Usage: python preprocess_markdown.py <markdown_file>")
316
+ sys.exit(1)
317
+
318
+ md_file = sys.argv[1]
319
+ file_dir = os.path.dirname(os.path.abspath(md_file))
320
+
321
+ with open(md_file, 'r', encoding='utf-8') as f:
322
+ content = f.read()
323
+
324
+ # Process mermaid diagrams
325
+ content = process_mermaid_diagrams(content, file_dir)
326
+
327
+ # Fix image paths and sizing
328
+ content = fix_image_paths(content, file_dir)
329
+
330
+ # Write processed content
331
+ processed_file = md_file.replace('.md', '_processed.md')
332
+ with open(processed_file, 'w', encoding='utf-8') as f:
333
+ f.write(content)
334
+
335
+ print(f"Processed file saved as: {processed_file}")
336
+ return processed_file
337
+
338
+ if __name__ == "__main__":
339
+ main()
340
+ EOF
341
+
342
+ chmod +x preprocess_markdown.py
343
+
344
+ # Convert MD to PDF with enhanced processing
345
+ - name: Convert MD to PDF with enhanced processing
346
+ run: |
347
+ find . -name "*.md" -not -path "./.git/*" | while read file; do
348
+ # Get the directory and filename
349
+ dir="$(dirname "$file")"
350
+ filename="$(basename "$file" .md)"
351
+ pdf_path="$dir/$filename.pdf"
352
+
353
+ echo "Processing $file..."
354
+
355
+ # Preprocess the markdown file
356
+ cd "$dir"
357
+ processed_file=$(python3 "$GITHUB_WORKSPACE/preprocess_markdown.py" "$(basename "$file")")
358
+
359
+ if [ ! -f "$processed_file" ]; then
360
+ echo "Preprocessing failed for $file, using original"
361
+ processed_file="$(basename "$file")"
362
+ fi
363
+
364
+ echo "Converting $processed_file to $pdf_path"
365
+
366
+ # Method 1: Try XeLaTeX with enhanced settings
367
+ pandoc "$processed_file" \
368
+ -o "$pdf_path" \
369
+ --pdf-engine=xelatex \
370
+ --include-in-header="$GITHUB_WORKSPACE/latex-header.tex" \
371
+ --variable mainfont="DejaVu Sans" \
372
+ --variable sansfont="DejaVu Sans" \
373
+ --variable monofont="DejaVu Sans Mono" \
374
+ --variable geometry:margin=1in \
375
+ --variable colorlinks=true \
376
+ --variable linkcolor=blue \
377
+ --variable urlcolor=blue \
378
+ --variable toccolor=gray \
379
+ --resource-path="$dir:$GITHUB_WORKSPACE" \
380
+ --standalone \
381
+ --toc \
382
+ --number-sections \
383
+ --highlight-style=github \
384
+ --wrap=auto \
385
+ --dpi=300 \
386
+ --verbose 2>/dev/null || {
387
+
388
+ echo "XeLaTeX failed, trying HTML->PDF conversion..."
389
+
390
+ # Method 2: HTML to PDF conversion with WeasyPrint
391
+ pandoc "$processed_file" \
392
+ -t html5 \
393
+ --standalone \
394
+ --embed-resources \
395
+ --css="$GITHUB_WORKSPACE/styles.css" \
396
+ --toc \
397
+ --number-sections \
398
+ --highlight-style=github \
399
+ -o "$dir/$filename.html"
400
+
401
+ if [ -f "$dir/$filename.html" ]; then
402
+ weasyprint "$dir/$filename.html" "$pdf_path" --presentational-hints || {
403
+ echo "WeasyPrint failed, trying wkhtmltopdf..."
404
 
405
+ # Method 3: wkhtmltopdf as final fallback
406
+ wkhtmltopdf \
407
+ --page-size A4 \
408
+ --margin-top 0.75in \
409
+ --margin-right 0.75in \
410
+ --margin-bottom 0.75in \
411
+ --margin-left 0.75in \
412
+ --encoding UTF-8 \
413
+ --no-outline \
414
+ --enable-local-file-access \
415
+ "$dir/$filename.html" "$pdf_path" || {
416
+ echo "All conversion methods failed for $file"
417
+ continue
418
+ }
419
+ }
420
 
421
+ # Clean up HTML file
422
+ rm -f "$dir/$filename.html"
423
+ fi
424
+ }
425
+
426
+ # Clean up processed file
427
+ if [ "$processed_file" != "$(basename "$file")" ]; then
428
+ rm -f "$processed_file"
429
+ fi
430
+
431
+ # Clean up generated mermaid images
432
+ rm -f mermaid_*.png mermaid_*.svg mermaid_*.mmd
433
+
434
+ if [ -f "$pdf_path" ]; then
435
+ echo "✅ Successfully converted $file to $pdf_path"
436
+ else
437
+ echo "❌ Failed to convert $file"
438
+ fi
439
+ done
440
 
441
+ # Upload PDF artifacts
442
+ - name: Upload PDF artifacts
443
+ uses: actions/upload-artifact@v4
444
+ with:
445
+ name: converted-pdfs
446
+ path: "**/*.pdf"
447
+ retention-days: 30
448
 
449
+ # Upload to Google Drive
450
  - name: Upload to Google Drive
451
  env:
452
  GOOGLE_OAUTH_TOKEN: ${{ secrets.GOOGLE_OAUTH_TOKEN }}
 
590
  print("Upload completed - MD files were skipped, PDFs were uploaded!")
591
  EOF
592
 
593
+ python upload_to_drive.py
 
.github/workflows/main.yml CHANGED
@@ -19,453 +19,422 @@ jobs:
19
  git lfs install
20
  git lfs pull
21
 
22
- # Install pandoc and fonts for proper Unicode/emoji support
23
- - name: Install pandoc and dependencies
 
 
 
 
 
 
24
  run: |
25
  sudo apt-get update
26
  sudo apt-get install -y \
27
- pandoc \
28
  texlive-xetex \
29
- texlive-fonts-recommended \
30
- texlive-fonts-extra \
31
- fonts-dejavu \
32
- fonts-liberation \
33
- python3-pip
34
-
35
- # Install weasyprint as fallback
36
- pip install weasyprint
 
37
 
38
- # Improved MD to PDF Conversion with proper image handling and mermaid support
39
- name: Convert Markdown to PDF
 
 
 
40
 
41
- on:
42
- push:
43
- branches: [ main ]
44
- pull_request:
45
- branches: [ main ]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
46
 
47
- jobs:
48
- convert-to-pdf:
49
- runs-on: ubuntu-latest
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
50
 
51
- steps:
52
- - name: Checkout repository
53
- uses: actions/checkout@v4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
54
 
55
- - name: Setup Python
56
- uses: actions/setup-python@v4
57
- with:
58
- python-version: '3.11'
59
-
60
- - name: Install system dependencies
61
- run: |
62
- sudo apt-get update
63
- sudo apt-get install -y \
64
- texlive-full \
65
- texlive-xetex \
66
- texlive-luatex \
67
- pandoc \
68
- librsvg2-bin \
69
- python3-pip \
70
- nodejs \
71
- npm \
72
- imagemagick \
73
- ghostscript \
74
- wkhtmltopdf
75
-
76
- - name: Install Node.js dependencies for Mermaid
77
- run: |
78
- npm install -g @mermaid-js/mermaid-cli
79
- npm install -g puppeteer
80
-
81
- - name: Install Python dependencies
82
- run: |
83
- pip install --upgrade pip
84
- pip install \
85
- weasyprint \
86
- markdown \
87
- pymdown-extensions \
88
- pillow \
89
- cairosvg \
90
- pdfkit
91
-
92
- - name: Create LaTeX header for better image handling
93
- run: |
94
- cat > latex-header.tex << 'EOF'
95
- \usepackage{graphicx}
96
- \usepackage{float}
97
- \usepackage{adjustbox}
98
- \usepackage{caption}
99
- \usepackage{subcaption}
100
- \usepackage{geometry}
101
- \usepackage{fancyhdr}
102
- \usepackage{xcolor}
103
- \usepackage{hyperref}
104
-
105
- % Better image positioning and scaling
106
- \floatplacement{figure}{H}
107
- \renewcommand{\includegraphics}[2][]{\adjustbox{max width=\textwidth,center}{\oldincludegraphics[#1]{#2}}}
108
- \let\oldincludegraphics\includegraphics
109
-
110
- % Set margins
111
- \geometry{margin=1in}
112
-
113
- % Hyperlink colors
114
- \hypersetup{
115
- colorlinks=true,
116
- linkcolor=blue,
117
- urlcolor=blue,
118
- citecolor=blue
119
- }
120
- EOF
121
-
122
- - name: Create enhanced CSS for HTML conversion
123
- run: |
124
- cat > styles.css << 'EOF'
125
- body {
126
- font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
127
- max-width: 210mm;
128
- margin: 0 auto;
129
- padding: 20mm;
130
- line-height: 1.6;
131
- color: #333;
132
- background: white;
133
- }
134
-
135
- img {
136
- max-width: 100%;
137
- height: auto;
138
- display: block;
139
- margin: 1em auto;
140
- border-radius: 4px;
141
- box-shadow: 0 2px 8px rgba(0,0,0,0.1);
142
- }
143
-
144
- pre {
145
- background: #f8f9fa;
146
- padding: 1em;
147
- border-radius: 6px;
148
- border-left: 4px solid #007acc;
149
- overflow-x: auto;
150
- font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
151
- font-size: 0.9em;
152
- }
153
-
154
- code {
155
- background: #f1f3f4;
156
- padding: 0.2em 0.4em;
157
- border-radius: 3px;
158
- font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
159
- font-size: 0.9em;
160
- }
161
-
162
- h1, h2, h3, h4, h5, h6 {
163
- color: #2c3e50;
164
- margin-top: 2em;
165
- margin-bottom: 1em;
166
- page-break-after: avoid;
167
- }
168
-
169
- h1 {
170
- border-bottom: 3px solid #3498db;
171
- padding-bottom: 0.5em;
172
- }
173
-
174
- h2 {
175
- border-bottom: 2px solid #95a5a6;
176
- padding-bottom: 0.3em;
177
- }
178
-
179
- table {
180
- border-collapse: collapse;
181
- width: 100%;
182
- margin: 1em 0;
183
- }
184
-
185
- th, td {
186
- border: 1px solid #ddd;
187
- padding: 0.75em;
188
- text-align: left;
189
- }
190
-
191
- th {
192
- background-color: #f8f9fa;
193
- font-weight: bold;
194
- }
195
-
196
- blockquote {
197
- border-left: 4px solid #3498db;
198
- margin: 1em 0;
199
- padding: 0.5em 1em;
200
- background: #f8f9fa;
201
- border-radius: 0 4px 4px 0;
202
- }
203
-
204
- .mermaid-container {
205
- text-align: center;
206
- margin: 2em 0;
207
- page-break-inside: avoid;
208
- }
209
-
210
- .mermaid-container img {
211
- max-width: 100%;
212
- height: auto;
213
- }
214
-
215
- @media print {
216
- body {
217
- margin: 0;
218
- padding: 15mm;
219
- }
220
-
221
- img {
222
- max-height: 80vh;
223
- page-break-inside: avoid;
224
- }
225
-
226
- h1, h2, h3, h4, h5, h6 {
227
- page-break-after: avoid;
228
- }
229
-
230
- pre, blockquote {
231
- page-break-inside: avoid;
232
- }
233
- }
234
- EOF
235
-
236
- - name: Create preprocessing script
237
- run: |
238
- cat > preprocess_markdown.py << 'EOF'
239
- #!/usr/bin/env python3
240
- import re
241
- import os
242
- import sys
243
- import subprocess
244
- from pathlib import Path
245
-
246
- def process_mermaid_diagrams(content, file_dir):
247
- """Convert mermaid diagrams to images"""
248
- mermaid_pattern = r'```mermaid\n(.*?)\n```'
249
-
250
- def replace_mermaid(match):
251
- mermaid_code = match.group(1)
252
- # Create a unique filename for this diagram
253
- diagram_hash = str(abs(hash(mermaid_code)))
254
- mermaid_file = f"{file_dir}/mermaid_{diagram_hash}.mmd"
255
- svg_file = f"{file_dir}/mermaid_{diagram_hash}.svg"
256
- png_file = f"{file_dir}/mermaid_{diagram_hash}.png"
257
-
258
- # Write mermaid code to file
259
- with open(mermaid_file, 'w') as f:
260
- f.write(mermaid_code)
261
-
262
- try:
263
- # Convert to SVG first
264
- subprocess.run([
265
- 'mmdc', '-i', mermaid_file, '-o', svg_file,
266
- '--theme', 'default', '--backgroundColor', 'white'
267
- ], check=True, capture_output=True)
268
-
269
- # Convert SVG to PNG for better PDF compatibility
270
- subprocess.run([
271
- 'rsvg-convert', '-f', 'png', '-o', png_file,
272
- '--width', '1200', '--height', '800', svg_file
273
- ], check=True, capture_output=True)
274
-
275
- # Clean up intermediate files
276
- os.remove(mermaid_file)
277
- if os.path.exists(svg_file):
278
- os.remove(svg_file)
279
-
280
- # Return markdown image syntax
281
- return f'\n<div class="mermaid-container">\n\n![Architecture Diagram]({os.path.basename(png_file)})\n\n</div>\n'
282
-
283
- except subprocess.CalledProcessError as e:
284
- print(f"Error converting mermaid diagram: {e}")
285
- return f'\n```\n{mermaid_code}\n```\n'
286
- except Exception as e:
287
- print(f"Unexpected error with mermaid: {e}")
288
- return f'\n```\n{mermaid_code}\n```\n'
289
-
290
- return re.sub(mermaid_pattern, replace_mermaid, content, flags=re.DOTALL)
291
-
292
- def fix_image_paths(content, file_dir):
293
- """Fix image paths and add proper sizing"""
294
- # Pattern to match markdown images
295
- img_pattern = r'!\[([^\]]*)\]\(([^)]+)\)'
296
-
297
- def replace_image(match):
298
- alt_text = match.group(1)
299
- img_path = match.group(2)
300
-
301
- # Handle relative paths
302
- if not img_path.startswith(('http://', 'https://', '/')):
303
- # Make path relative to the markdown file
304
- abs_img_path = os.path.join(file_dir, img_path)
305
- if os.path.exists(abs_img_path):
306
- img_path = os.path.relpath(abs_img_path, file_dir)
307
-
308
- # Add HTML img tag with better control
309
- return f'<img src="{img_path}" alt="{alt_text}" style="max-width: 100%; height: auto; display: block; margin: 1em auto;" />'
310
-
311
- # Also handle HTML img tags and ensure they have proper styling
312
- content = re.sub(img_pattern, replace_image, content)
313
-
314
- # Fix existing HTML img tags
315
- content = re.sub(
316
- r'<img\s+([^>]*?)\s*/?>',
317
- lambda m: f'<img {m.group(1)} style="max-width: 100%; height: auto; display: block; margin: 1em auto;" />',
318
- content
319
- )
320
-
321
- return content
322
-
323
- def main():
324
- if len(sys.argv) != 2:
325
- print("Usage: python preprocess_markdown.py <markdown_file>")
326
- sys.exit(1)
327
-
328
- md_file = sys.argv[1]
329
- file_dir = os.path.dirname(os.path.abspath(md_file))
330
-
331
- with open(md_file, 'r', encoding='utf-8') as f:
332
- content = f.read()
333
-
334
- # Process mermaid diagrams
335
- content = process_mermaid_diagrams(content, file_dir)
336
-
337
- # Fix image paths and sizing
338
- content = fix_image_paths(content, file_dir)
339
-
340
- # Write processed content
341
- processed_file = md_file.replace('.md', '_processed.md')
342
- with open(processed_file, 'w', encoding='utf-8') as f:
343
- f.write(content)
344
-
345
- print(f"Processed file saved as: {processed_file}")
346
- return processed_file
347
-
348
- if __name__ == "__main__":
349
- main()
350
- EOF
351
-
352
- chmod +x preprocess_markdown.py
353
-
354
- - name: Convert MD to PDF with enhanced processing
355
- run: |
356
- find . -name "*.md" -not -path "./.git/*" | while read file; do
357
- # Get the directory and filename
358
- dir="$(dirname "$file")"
359
- filename="$(basename "$file" .md)"
360
- pdf_path="$dir/$filename.pdf"
361
-
362
- echo "Processing $file..."
363
-
364
- # Preprocess the markdown file
365
- cd "$dir"
366
- processed_file=$(python3 "$GITHUB_WORKSPACE/preprocess_markdown.py" "$(basename "$file")")
367
-
368
- if [ ! -f "$processed_file" ]; then
369
- echo "Preprocessing failed for $file, using original"
370
- processed_file="$(basename "$file")"
371
- fi
372
 
373
- echo "Converting $processed_file to $pdf_path"
 
 
374
 
375
- # Method 1: Try XeLaTeX with enhanced settings
376
- pandoc "$processed_file" \
377
- -o "$pdf_path" \
378
- --pdf-engine=xelatex \
379
- --include-in-header="$GITHUB_WORKSPACE/latex-header.tex" \
380
- --variable mainfont="DejaVu Sans" \
381
- --variable sansfont="DejaVu Sans" \
382
- --variable monofont="DejaVu Sans Mono" \
383
- --variable geometry:margin=1in \
384
- --variable colorlinks=true \
385
- --variable linkcolor=blue \
386
- --variable urlcolor=blue \
387
- --variable toccolor=gray \
388
- --resource-path="$dir:$GITHUB_WORKSPACE" \
389
- --standalone \
390
- --toc \
391
- --number-sections \
392
- --highlight-style=github \
393
- --wrap=auto \
394
- --dpi=300 \
395
- --verbose 2>/dev/null || {
396
-
397
- echo "XeLaTeX failed, trying HTML->PDF conversion..."
398
-
399
- # Method 2: HTML to PDF conversion with WeasyPrint
400
- pandoc "$processed_file" \
401
- -t html5 \
402
- --standalone \
403
- --embed-resources \
404
- --css="$GITHUB_WORKSPACE/styles.css" \
405
- --toc \
406
- --number-sections \
407
- --highlight-style=github \
408
- -o "$dir/$filename.html"
409
-
410
- if [ -f "$dir/$filename.html" ]; then
411
- weasyprint "$dir/$filename.html" "$pdf_path" --presentational-hints || {
412
- echo "WeasyPrint failed, trying wkhtmltopdf..."
413
-
414
- # Method 3: wkhtmltopdf as final fallback
415
- wkhtmltopdf \
416
- --page-size A4 \
417
- --margin-top 0.75in \
418
- --margin-right 0.75in \
419
- --margin-bottom 0.75in \
420
- --margin-left 0.75in \
421
- --encoding UTF-8 \
422
- --no-outline \
423
- --enable-local-file-access \
424
- "$dir/$filename.html" "$pdf_path" || {
425
- echo "All conversion methods failed for $file"
426
- continue
427
- }
428
- }
429
 
430
- # Clean up HTML file
431
- rm -f "$dir/$filename.html"
432
- fi
433
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
434
 
435
- # Clean up processed file
436
- if [ "$processed_file" != "$(basename "$file")" ]; then
437
- rm -f "$processed_file"
438
- fi
 
 
439
 
440
- # Clean up generated mermaid images
441
- rm -f mermaid_*.png mermaid_*.svg mermaid_*.mmd
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
442
 
443
- if [ -f "$pdf_path" ]; then
444
- echo "✅ Successfully converted $file to $pdf_path"
445
- else
446
- echo "❌ Failed to convert $file"
447
- fi
448
- done
 
 
 
 
 
 
 
 
 
449
 
450
- - name: Upload PDF artifacts
451
- uses: actions/upload-artifact@v4
452
- with:
453
- name: converted-pdfs
454
- path: "**/*.pdf"
455
- retention-days: 30
456
-
457
- # Set up Python for Google Drive upload
458
- - name: Set up Python
459
- uses: actions/setup-python@v4
460
- with:
461
- python-version: '3.9'
 
 
 
 
 
 
 
462
 
463
- # Install Python dependencies
464
- - name: Install Python dependencies
465
- run: |
466
- pip install google-auth google-auth-oauthlib google-auth-httplib2 google-api-python-client
 
 
 
467
 
468
- # Create and run upload script
469
  - name: Upload to Google Drive
470
  env:
471
  GOOGLE_OAUTH_TOKEN: ${{ secrets.GOOGLE_OAUTH_TOKEN }}
 
19
  git lfs install
20
  git lfs pull
21
 
22
+ # Setup Python
23
+ - name: Setup Python
24
+ uses: actions/setup-python@v4
25
+ with:
26
+ python-version: '3.11'
27
+
28
+ # Install system dependencies
29
+ - name: Install system dependencies
30
  run: |
31
  sudo apt-get update
32
  sudo apt-get install -y \
33
+ texlive-full \
34
  texlive-xetex \
35
+ texlive-luatex \
36
+ pandoc \
37
+ librsvg2-bin \
38
+ python3-pip \
39
+ nodejs \
40
+ npm \
41
+ imagemagick \
42
+ ghostscript \
43
+ wkhtmltopdf
44
 
45
+ # Install Node.js dependencies for Mermaid
46
+ - name: Install Node.js dependencies for Mermaid
47
+ run: |
48
+ npm install -g @mermaid-js/mermaid-cli
49
+ npm install -g puppeteer
50
 
51
+ # Install Python dependencies
52
+ - name: Install Python dependencies
53
+ run: |
54
+ pip install --upgrade pip
55
+ pip install \
56
+ weasyprint \
57
+ markdown \
58
+ pymdown-extensions \
59
+ pillow \
60
+ cairosvg \
61
+ pdfkit \
62
+ google-auth \
63
+ google-auth-oauthlib \
64
+ google-auth-httplib2 \
65
+ google-api-python-client
66
+
67
+ # Create LaTeX header for better image handling
68
+ - name: Create LaTeX header for better image handling
69
+ run: |
70
+ cat > latex-header.tex << 'EOF'
71
+ \usepackage{graphicx}
72
+ \usepackage{float}
73
+ \usepackage{adjustbox}
74
+ \usepackage{caption}
75
+ \usepackage{subcaption}
76
+ \usepackage{geometry}
77
+ \usepackage{fancyhdr}
78
+ \usepackage{xcolor}
79
+ \usepackage{hyperref}
80
+
81
+ % Better image positioning and scaling
82
+ \floatplacement{figure}{H}
83
+ \renewcommand{\includegraphics}[2][]{\adjustbox{max width=\textwidth,center}{\oldincludegraphics[#1]{#2}}}
84
+ \let\oldincludegraphics\includegraphics
85
+
86
+ % Set margins
87
+ \geometry{margin=1in}
88
+
89
+ % Hyperlink colors
90
+ \hypersetup{
91
+ colorlinks=true,
92
+ linkcolor=blue,
93
+ urlcolor=blue,
94
+ citecolor=blue
95
+ }
96
+ EOF
97
 
98
+ # Create enhanced CSS for HTML conversion
99
+ - name: Create enhanced CSS for HTML conversion
100
+ run: |
101
+ cat > styles.css << 'EOF'
102
+ body {
103
+ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
104
+ max-width: 210mm;
105
+ margin: 0 auto;
106
+ padding: 20mm;
107
+ line-height: 1.6;
108
+ color: #333;
109
+ background: white;
110
+ }
111
+
112
+ img {
113
+ max-width: 100%;
114
+ height: auto;
115
+ display: block;
116
+ margin: 1em auto;
117
+ border-radius: 4px;
118
+ box-shadow: 0 2px 8px rgba(0,0,0,0.1);
119
+ }
120
+
121
+ pre {
122
+ background: #f8f9fa;
123
+ padding: 1em;
124
+ border-radius: 6px;
125
+ border-left: 4px solid #007acc;
126
+ overflow-x: auto;
127
+ font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
128
+ font-size: 0.9em;
129
+ }
130
+
131
+ code {
132
+ background: #f1f3f4;
133
+ padding: 0.2em 0.4em;
134
+ border-radius: 3px;
135
+ font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
136
+ font-size: 0.9em;
137
+ }
138
+
139
+ h1, h2, h3, h4, h5, h6 {
140
+ color: #2c3e50;
141
+ margin-top: 2em;
142
+ margin-bottom: 1em;
143
+ page-break-after: avoid;
144
+ }
145
+
146
+ h1 {
147
+ border-bottom: 3px solid #3498db;
148
+ padding-bottom: 0.5em;
149
+ }
150
+
151
+ h2 {
152
+ border-bottom: 2px solid #95a5a6;
153
+ padding-bottom: 0.3em;
154
+ }
155
 
156
+ table {
157
+ border-collapse: collapse;
158
+ width: 100%;
159
+ margin: 1em 0;
160
+ }
161
+
162
+ th, td {
163
+ border: 1px solid #ddd;
164
+ padding: 0.75em;
165
+ text-align: left;
166
+ }
167
+
168
+ th {
169
+ background-color: #f8f9fa;
170
+ font-weight: bold;
171
+ }
172
+
173
+ blockquote {
174
+ border-left: 4px solid #3498db;
175
+ margin: 1em 0;
176
+ padding: 0.5em 1em;
177
+ background: #f8f9fa;
178
+ border-radius: 0 4px 4px 0;
179
+ }
180
+
181
+ .mermaid-container {
182
+ text-align: center;
183
+ margin: 2em 0;
184
+ page-break-inside: avoid;
185
+ }
186
+
187
+ .mermaid-container img {
188
+ max-width: 100%;
189
+ height: auto;
190
+ }
191
+
192
+ @media print {
193
+ body {
194
+ margin: 0;
195
+ padding: 15mm;
196
+ }
197
 
198
+ img {
199
+ max-height: 80vh;
200
+ page-break-inside: avoid;
201
+ }
202
+
203
+ h1, h2, h3, h4, h5, h6 {
204
+ page-break-after: avoid;
205
+ }
206
+
207
+ pre, blockquote {
208
+ page-break-inside: avoid;
209
+ }
210
+ }
211
+ EOF
212
+
213
+ # Create preprocessing script
214
+ - name: Create preprocessing script
215
+ run: |
216
+ cat > preprocess_markdown.py << 'EOF'
217
+ #!/usr/bin/env python3
218
+ import re
219
+ import os
220
+ import sys
221
+ import subprocess
222
+ from pathlib import Path
223
+
224
+ def process_mermaid_diagrams(content, file_dir):
225
+ """Convert mermaid diagrams to images"""
226
+ mermaid_pattern = r'```mermaid\n(.*?)\n```'
227
+
228
+ def replace_mermaid(match):
229
+ mermaid_code = match.group(1)
230
+ # Create a unique filename for this diagram
231
+ diagram_hash = str(abs(hash(mermaid_code)))
232
+ mermaid_file = f"{file_dir}/mermaid_{diagram_hash}.mmd"
233
+ svg_file = f"{file_dir}/mermaid_{diagram_hash}.svg"
234
+ png_file = f"{file_dir}/mermaid_{diagram_hash}.png"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
235
 
236
+ # Write mermaid code to file
237
+ with open(mermaid_file, 'w') as f:
238
+ f.write(mermaid_code)
239
 
240
+ try:
241
+ # Convert to SVG first
242
+ subprocess.run([
243
+ 'mmdc', '-i', mermaid_file, '-o', svg_file,
244
+ '--theme', 'default', '--backgroundColor', 'white'
245
+ ], check=True, capture_output=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
246
 
247
+ # Convert SVG to PNG for better PDF compatibility
248
+ subprocess.run([
249
+ 'rsvg-convert', '-f', 'png', '-o', png_file,
250
+ '--width', '1200', '--height', '800', svg_file
251
+ ], check=True, capture_output=True)
252
+
253
+ # Clean up intermediate files
254
+ os.remove(mermaid_file)
255
+ if os.path.exists(svg_file):
256
+ os.remove(svg_file)
257
+
258
+ # Return markdown image syntax
259
+ return f'\n<div class="mermaid-container">\n\n![Architecture Diagram]({os.path.basename(png_file)})\n\n</div>\n'
260
+
261
+ except subprocess.CalledProcessError as e:
262
+ print(f"Error converting mermaid diagram: {e}")
263
+ return f'\n```\n{mermaid_code}\n```\n'
264
+ except Exception as e:
265
+ print(f"Unexpected error with mermaid: {e}")
266
+ return f'\n```\n{mermaid_code}\n```\n'
267
+
268
+ return re.sub(mermaid_pattern, replace_mermaid, content, flags=re.DOTALL)
269
+
270
+ def fix_image_paths(content, file_dir):
271
+ """Fix image paths and add proper sizing"""
272
+ # Pattern to match markdown images
273
+ img_pattern = r'!\[([^\]]*)\]\(([^)]+)\)'
274
+
275
+ def replace_image(match):
276
+ alt_text = match.group(1)
277
+ img_path = match.group(2)
278
 
279
+ # Handle relative paths
280
+ if not img_path.startswith(('http://', 'https://', '/')):
281
+ # Make path relative to the markdown file
282
+ abs_img_path = os.path.join(file_dir, img_path)
283
+ if os.path.exists(abs_img_path):
284
+ img_path = os.path.relpath(abs_img_path, file_dir)
285
 
286
+ # Add HTML img tag with better control
287
+ return f'<img src="{img_path}" alt="{alt_text}" style="max-width: 100%; height: auto; display: block; margin: 1em auto;" />'
288
+
289
+ # Also handle HTML img tags and ensure they have proper styling
290
+ content = re.sub(img_pattern, replace_image, content)
291
+
292
+ # Fix existing HTML img tags
293
+ content = re.sub(
294
+ r'<img\s+([^>]*?)\s*/?>',
295
+ lambda m: f'<img {m.group(1)} style="max-width: 100%; height: auto; display: block; margin: 1em auto;" />',
296
+ content
297
+ )
298
+
299
+ return content
300
+
301
+ def main():
302
+ if len(sys.argv) != 2:
303
+ print("Usage: python preprocess_markdown.py <markdown_file>")
304
+ sys.exit(1)
305
+
306
+ md_file = sys.argv[1]
307
+ file_dir = os.path.dirname(os.path.abspath(md_file))
308
+
309
+ with open(md_file, 'r', encoding='utf-8') as f:
310
+ content = f.read()
311
+
312
+ # Process mermaid diagrams
313
+ content = process_mermaid_diagrams(content, file_dir)
314
+
315
+ # Fix image paths and sizing
316
+ content = fix_image_paths(content, file_dir)
317
+
318
+ # Write processed content
319
+ processed_file = md_file.replace('.md', '_processed.md')
320
+ with open(processed_file, 'w', encoding='utf-8') as f:
321
+ f.write(content)
322
+
323
+ print(f"Processed file saved as: {processed_file}")
324
+ return processed_file
325
+
326
+ if __name__ == "__main__":
327
+ main()
328
+ EOF
329
+
330
+ chmod +x preprocess_markdown.py
331
+
332
+ # Convert MD to PDF with enhanced processing
333
+ - name: Convert MD to PDF with enhanced processing
334
+ run: |
335
+ find . -name "*.md" -not -path "./.git/*" | while read file; do
336
+ # Get the directory and filename
337
+ dir="$(dirname "$file")"
338
+ filename="$(basename "$file" .md)"
339
+ pdf_path="$dir/$filename.pdf"
340
+
341
+ echo "Processing $file..."
342
+
343
+ # Preprocess the markdown file
344
+ cd "$dir"
345
+ processed_file=$(python3 "$GITHUB_WORKSPACE/preprocess_markdown.py" "$(basename "$file")")
346
+
347
+ if [ ! -f "$processed_file" ]; then
348
+ echo "Preprocessing failed for $file, using original"
349
+ processed_file="$(basename "$file")"
350
+ fi
351
+
352
+ echo "Converting $processed_file to $pdf_path"
353
+
354
+ # Method 1: Try XeLaTeX with enhanced settings
355
+ pandoc "$processed_file" \
356
+ -o "$pdf_path" \
357
+ --pdf-engine=xelatex \
358
+ --include-in-header="$GITHUB_WORKSPACE/latex-header.tex" \
359
+ --variable mainfont="DejaVu Sans" \
360
+ --variable sansfont="DejaVu Sans" \
361
+ --variable monofont="DejaVu Sans Mono" \
362
+ --variable geometry:margin=1in \
363
+ --variable colorlinks=true \
364
+ --variable linkcolor=blue \
365
+ --variable urlcolor=blue \
366
+ --variable toccolor=gray \
367
+ --resource-path="$dir:$GITHUB_WORKSPACE" \
368
+ --standalone \
369
+ --toc \
370
+ --number-sections \
371
+ --highlight-style=github \
372
+ --wrap=auto \
373
+ --dpi=300 \
374
+ --verbose 2>/dev/null || {
375
+
376
+ echo "XeLaTeX failed, trying HTML->PDF conversion..."
377
+
378
+ # Method 2: HTML to PDF conversion with WeasyPrint
379
+ pandoc "$processed_file" \
380
+ -t html5 \
381
+ --standalone \
382
+ --embed-resources \
383
+ --css="$GITHUB_WORKSPACE/styles.css" \
384
+ --toc \
385
+ --number-sections \
386
+ --highlight-style=github \
387
+ -o "$dir/$filename.html"
388
+
389
+ if [ -f "$dir/$filename.html" ]; then
390
+ weasyprint "$dir/$filename.html" "$pdf_path" --presentational-hints || {
391
+ echo "WeasyPrint failed, trying wkhtmltopdf..."
392
 
393
+ # Method 3: wkhtmltopdf as final fallback
394
+ wkhtmltopdf \
395
+ --page-size A4 \
396
+ --margin-top 0.75in \
397
+ --margin-right 0.75in \
398
+ --margin-bottom 0.75in \
399
+ --margin-left 0.75in \
400
+ --encoding UTF-8 \
401
+ --no-outline \
402
+ --enable-local-file-access \
403
+ "$dir/$filename.html" "$pdf_path" || {
404
+ echo "All conversion methods failed for $file"
405
+ continue
406
+ }
407
+ }
408
 
409
+ # Clean up HTML file
410
+ rm -f "$dir/$filename.html"
411
+ fi
412
+ }
413
+
414
+ # Clean up processed file
415
+ if [ "$processed_file" != "$(basename "$file")" ]; then
416
+ rm -f "$processed_file"
417
+ fi
418
+
419
+ # Clean up generated mermaid images
420
+ rm -f mermaid_*.png mermaid_*.svg mermaid_*.mmd
421
+
422
+ if [ -f "$pdf_path" ]; then
423
+ echo "✅ Successfully converted $file to $pdf_path"
424
+ else
425
+ echo "❌ Failed to convert $file"
426
+ fi
427
+ done
428
 
429
+ # Upload PDF artifacts
430
+ - name: Upload PDF artifacts
431
+ uses: actions/upload-artifact@v4
432
+ with:
433
+ name: converted-pdfs
434
+ path: "**/*.pdf"
435
+ retention-days: 30
436
 
437
+ # Upload to Google Drive
438
  - name: Upload to Google Drive
439
  env:
440
  GOOGLE_OAUTH_TOKEN: ${{ secrets.GOOGLE_OAUTH_TOKEN }}