""" Convert knowledge.md → interactive index.html for each Group folder. Uses Tailwind CSS (CDN), Mermaid.js, Dark Mode, collapsible sections. """ import re import html import sys from pathlib import Path WORKSPACE = Path(r"d:\WORK\AI_ML小組新進人員教育訓練簡報") GROUPS = [ ("Group1_Weather_Climate_Prediction", "天氣與氣候預報模型開發", "🌦️"), ("Group2_Marine_Climate_Tech", "海象與氣候應用技術", "🌊"), ("Group3_Warning_Forecasting", "天氣預報與預警應用技術", "⚡"), ("Group4_Earthquake_Warning", "地震預警應用技術", "🔔"), ("Group5_Weather_Monitoring", "天氣監測與應用技術", "📡"), ("Group7_IT_OpenSource", "資訊系統與開源環境", "🖥️"), ("Group8_AI_Talent_Cultivation", "AI 人才培育", "🎓"), ] HTML_TEMPLATE = r"""
{content}\n') bq_lines = [] in_blockquote = False def inline(text: str) -> str: """Handle inline markdown: bold, italic, code, links, KaTeX.""" t = html.escape(text) # bold t = re.sub(r'\*\*(.+?)\*\*', r'\1', t) # italic t = re.sub(r'(?\1', t) # inline code t = re.sub(r'`([^`]+)`', r'
\1', t)
# links
t = re.sub(r'\[([^\]]+)\]\(([^)]+)\)', r'\1', t)
# strikethrough
t = re.sub(r'~~(.+?)~~', r'')
else:
if in_mermaid:
mermaid_content = '\n'.join(mermaid_lines)
html_parts.append(f'\n{mermaid_content}\n\n')
in_mermaid = False
else:
html_parts.append('\n')
in_code = False
continue
if in_code:
html_parts.append(html.escape(line) + '\n')
continue
if in_mermaid:
mermaid_lines.append(line)
continue
# Table
if '|' in stripped and stripped.startswith('|'):
if not in_table:
flush_list()
flush_blockquote()
in_table = True
table_rows.append(stripped)
continue
elif in_table:
flush_table()
# List
if re.match(r'^[-*+]\s', stripped) or re.match(r'^\d+\.\s', stripped):
if not in_list:
flush_table()
flush_blockquote()
in_list = True
item = re.sub(r'^[-*+\d.]+\s*', '', stripped)
list_items.append(item)
continue
elif in_list and stripped == '':
flush_list()
continue
elif in_list and stripped:
flush_list()
# Blockquote
if stripped.startswith('>'):
if not in_blockquote:
flush_table()
flush_list()
in_blockquote = True
bq_lines.append(stripped.lstrip('> '))
continue
elif in_blockquote:
flush_blockquote()
# Headings
if stripped.startswith('# ') and not stripped.startswith('## '):
flush_table(); flush_list(); flush_blockquote()
text = stripped[2:]
html_parts.append(f'{inline(stripped)}
\n') # Flush remaining flush_table() flush_list() flush_blockquote() return ''.join(html_parts) def build_html(folder_name: str, title: str, emoji: str): md_path = WORKSPACE / folder_name / "knowledge.md" if not md_path.exists(): print(f" SKIP {folder_name} (no knowledge.md)") return False md_text = md_path.read_text(encoding='utf-8') content = md_to_html_content(md_text) short_title = title page_html = HTML_TEMPLATE.format( title=title, short_title=short_title, emoji=emoji, content=content, ) out_path = WORKSPACE / folder_name / "index.html" out_path.write_text(page_html, encoding='utf-8') print(f" ✓ {out_path}") return True def main(): print("=== Phase 3: knowledge.md → index.html ===") count = 0 for folder, title, emoji in GROUPS: if build_html(folder, title, emoji): count += 1 print(f"\nDone: {count} HTML files generated.") if __name__ == "__main__": main()