Files
sincos.cc-website/blog/build.py
T
admin 678cbf98f8 feat: 首页改版为研究优先的博客风;新增 Serial Terminal / Enthalpy Diagram;下架三个工具;品牌与结构更新
- 首页:主力项目 Sequence-Diagram 大图展示 + 前沿研究三卡 + 工具矩阵(去彩色渐变块)
- 新增工具页:串口调试助手(Android)与湿空气焓湿图(Android),含实机截图
- 下架 Engineer Craft / Five Phases / UniTouch(保留页面与路由)
- 全站品牌 Easy Data Collection → Easy Design Collection(EDC 总品牌)
- 资源中心更名「内部研究」,仅保留 footer 入口
- 导航下拉更新;产品线统计更新为 6
2026-10-10 11:45:30 +08:00

427 lines
16 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# -*- coding: utf-8 -*-
"""
博客构建脚本:blog/posts/*.md -> website/static/blog/(列表 + 文章页)+ website/static/home.html(首页)
front matter 格式:
---
title: 文章标题
date: 2026-08-13
tags: 工业软件, ResLib
---
"""
import re
from datetime import datetime
from pathlib import Path
import markdown
BASE = Path(__file__).resolve().parent
POSTS_DIR = BASE / "posts"
OUT_BLOG = BASE.parent / "website" / "static" / "blog"
OUT_HOME = BASE.parent / "website" / "static" / "home.html"
OUT_ABOUT = BASE.parent / "website" / "static" / "about.html"
SITE_NAME = "Easy Design Collection"
SEO_NAME = "人工智能工程技术研究-江北的渔夫"
NAV_ITEMS = [
{
"key": "research",
"href": "/research/",
"label": "前沿技术研究",
"children": [
("http://124.220.63.9:25000", "Research Digest"),
("/research/neural/", "Neural Research"),
("/research/reslib/", "ResLib"),
],
},
{
"key": "tools",
"href": "/tools/",
"label": "工具开发",
"children": [
("/tools/sequence-diagram/", "Sequence-Diagram"),
("/tools/uni-viewer/", "Uni-Viewer"),
("/tools/serial-terminal/", "Serial Terminal"),
("/tools/enthalpy-diagram/", "Enthalpy Diagram"),
("/tools/edc-lite-erp/", "EDC Lite ERP"),
("/tools/physics-ai-fluent/", "Physics AI Fluent"),
],
},
{
"key": "license",
"href": "/license/",
"label": "License",
"children": [
("/license/apply", "申请 License"),
("/license/status", "查询 / 下载"),
("/license/package", "资源包获取"),
],
},
{
"key": "blog",
"href": "/blog/",
"label": "博客",
"children": [],
},
]
def nav_html(active: str = "") -> str:
parts = []
for item in NAV_ITEMS:
if not item["children"]:
cls = "nav-link active" if item["key"] == active else "nav-link"
parts.append(f' <a class="{cls}" href="{item["href"]}">{item["label"]}</a>')
continue
parent_cls = "nav-link active" if item["key"] == active else "nav-link"
links = "\n".join(
f' <a href="{href}">{label}</a>'
for href, label in item["children"]
)
parts.append(
f""" <div class="nav-item has-dropdown">
<a class="{parent_cls}" href="{item['href']}">{item['label']}</a>
<button class="nav-caret" type="button" aria-label="展开{item['label']}">▾</button>
<div class="dropdown">
{links}
</div>
</div>"""
)
return "\n".join(parts)
def page_header(active: str = "", title: str = "") -> str:
seo_title = f"{title} - {SEO_NAME}" if title else SEO_NAME
return f"""<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{seo_title}</title>
<meta name="description" content="{SEO_NAME} —— 工业软件、标准件库与数字化实践分享">
<meta name="keywords" content="{SEO_NAME}, {SITE_NAME}, ResLib, 资源中心管理器, Creo, 标准零部件库, 数字孪生, 深度学习">
<link rel="stylesheet" href="/static/css/style.css">
<link rel="icon" href="/static/img/logo.svg" type="image/svg+xml">
<script src="/static/js/nav.js"></script>
</head>
<body>
<header class="site-header">
<div class="container header-inner">
<a class="brand" href="/">
<img src="/static/img/logo.svg" alt="{SITE_NAME}">
<span class="brand-name">EDC|江北的渔夫</span>
</a>
<nav class="main-nav" id="mainNav">
{nav_html(active)}
</nav>
<button class="nav-toggle" id="navToggle" aria-label="菜单">☰</button>
</div>
</header>
<main>"""
def page_footer() -> str:
return f"""</main>
<footer class="site-footer">
<div class="container footer-inner">
<div class="footer-brand">
<img src="/static/img/logo.svg" alt="">
<span>{SITE_NAME}</span>
</div>
<span>Copyright &copy; 2026 {SITE_NAME}. All rights reserved.</span>
<span class="footer-links">
<a href="/resources/">内部研究</a><span class="sep">·</span>
<a href="/license/">License</a><span class="sep">·</span>
<a href="/admin">管理页面</a><span class="sep">·</span>
<a href="https://beian.miit.gov.cn/" target="_blank" rel="noopener">苏ICP备2026056863号</a>
</span>
</div>
</footer>
</body>
</html>"""
def parse_post(path: Path) -> dict:
text = path.read_text(encoding="utf-8")
m = re.match(r"^---\s*\n(.*?)\n---\s*\n?(.*)$", text, re.S)
front, body = ("", text)
if m:
front, body = m.group(1), m.group(2)
meta = {}
for line in front.splitlines():
if ":" in line:
k, _, v = line.partition(":")
meta[k.strip()] = v.strip()
html = markdown.markdown(
body,
extensions=["extra", "toc", "sane_lists", "attr_list", "admonition"],
)
return {
"slug": path.stem,
"title": meta.get("title", path.stem),
"date": meta.get("date", ""),
"tags": [t.strip() for t in meta.get("tags", "").split(",") if t.strip()],
"html": html,
}
def summary(html: str, length: int = 120) -> str:
text = re.sub(r"<[^>]+>", "", html)
text = re.sub(r"\s+", " ", text).strip()
if len(text) > length:
text = text[:length] + "…"
return text
def fmt_date(s: str) -> str:
try:
return datetime.strptime(s, "%Y-%m-%d").strftime("%Y年%m月%d日")
except ValueError:
return s
PRODUCT_CARDS = """
<a class="product-card" href="/tools/sequence-diagram/">
<div class="product-icon">◷</div>
<span class="product-meta">主力项目 · Flutter / Android</span>
<h3>Sequence-Diagram</h3>
<p>PLC 流程节拍与相位角设计:条形 / 圆周 / 流程图三视图,泳道加宽与 drawio 导出。</p>
<span class="product-link">了解详情 →</span>
</a>
<a class="product-card" href="/tools/uni-viewer/">
<div class="product-icon">◉</div>
<span class="product-meta">Web Component</span>
<h3>Uni-Viewer</h3>
<p>纯前端、不出网的文件预览组件,271 个扩展名、47 条预览链路。</p>
<span class="product-link">了解详情 →</span>
</a>
<a class="product-card" href="/tools/serial-terminal/">
<div class="product-icon">⇄</div>
<span class="product-meta">Kotlin · Jetpack Compose</span>
<h3>Serial Terminal</h3>
<p>串口调试助手:USB-OTG / 蓝牙 SPP / TCP / UDP 调试,12 种自动校验位。</p>
<span class="product-link">了解详情 →</span>
</a>
<a class="product-card" href="/tools/enthalpy-diagram/">
<div class="product-icon">焓</div>
<span class="product-meta">Kotlin · Jetpack Compose</span>
<h3>Enthalpy Diagram</h3>
<p>湿空气焓湿图:11 项参数任选两个求解全量结果,交互式焓湿图,纯离线零权限。</p>
<span class="product-link">了解详情 →</span>
</a>
<a class="product-card" href="/tools/edc-lite-erp/">
<div class="product-icon">▣</div>
<span class="product-meta">Electron · MySQL</span>
<h3>EDC Lite ERP</h3>
<p>轻量资源计划与制造管理系统:物料编码、进销存、扫码称配全链路。</p>
<span class="product-link">了解详情 →</span>
</a>
<a class="product-card" href="/tools/physics-ai-fluent/">
<div class="product-icon">◍</div>
<span class="product-meta">Python · GPU LBM</span>
<h3>Physics AI Fluent</h3>
<p>GPU 格子玻尔兹曼流场仿真:流化床空床流场分钟级求解,AI for Science 数据工厂。</p>
<span class="product-link">了解详情 →</span>
</a>"""
def build():
posts = [parse_post(p) for p in sorted(POSTS_DIR.glob("*.md"), reverse=True)]
posts.sort(key=lambda p: p["date"], reverse=True)
OUT_BLOG.mkdir(parents=True, exist_ok=True)
# ---------- 博客列表页 ----------
cards = []
for p in posts:
tags = "".join(f'<span class="tag">{t}</span>' for t in p["tags"])
cards.append(f"""
<a class="post-card" href="/blog/{p['slug']}/">
<div class="post-meta"><span class="post-date">{fmt_date(p['date'])}</span>{tags}</div>
<h3 class="post-title">{p['title']}</h3>
<p class="post-excerpt">{summary(p['html'])}</p>
</a>""")
if not cards:
cards.append('<p class="section-desc">暂无文章,敬请期待。</p>')
blog_list = f"""{page_header("blog")}
<section class="page-hero">
<div class="container">
<p class="hero-eyebrow">BLOG · 博客</p>
<h1>工程实践与研究记录</h1>
<p class="page-hero-sub">工业软件、标准件库、深度学习与工具开发的过程记录。</p>
</div>
</section>
<section class="section">
<div class="container">
<div class="post-list">
{''.join(cards)}
</div>
</div>
</section>
{page_footer()}"""
(OUT_BLOG / "index.html").write_text(blog_list, encoding="utf-8")
# ---------- 文章详情页 ----------
for p in posts:
tags = "".join(f'<span class="tag">{t}</span>' for t in p["tags"])
html = f"""{page_header("blog", p['title'])}
<section class="section">
<div class="container narrow">
<nav class="breadcrumb"><a href="/">首页</a> / <a href="/blog/">博客</a></nav>
<h2 class="section-title">{p['title']}</h2>
<div class="post-meta"><span class="post-date">{fmt_date(p['date'])}</span>{tags}</div>
<article class="article">
{p['html']}
</article>
</div>
</section>
{page_footer()}"""
(OUT_BLOG / p["slug"]).mkdir(parents=True, exist_ok=True)
(OUT_BLOG / p["slug"] / "index.html").write_text(html, encoding="utf-8")
# ---------- 首页 ----------
recent = "".join(f"""
<a class="post-card" href="/blog/{p['slug']}/">
<div class="post-meta"><span class="post-date">{fmt_date(p['date'])}</span></div>
<h3 class="post-title">{p['title']}</h3>
<p class="post-excerpt">{summary(p['html'], 90)}</p>
</a>""" for p in posts[:3])
if not recent:
recent = '<p class="section-desc">暂无文章,敬请期待。</p>'
home = f"""{page_header("")}
<section class="hero">
<div class="container">
<h1>人工智能研究与工程实施</h1>
<p class="hero-sub">Ai时代,所有项目都值得重构</p>
<div class="hero-actions">
<a href="/tools/" class="btn btn-light">探索工具开发</a>
<a href="/research/" class="btn btn-outline-light">前沿技术研究</a>
</div>
</div>
</section>
<section class="section">
<div class="container">
<div class="feature" style="padding-top: 0;">
<div class="feature-copy">
<span class="feature-tag">主力项目</span>
<h2>时序图设计 · Sequence Diagram Studio</h2>
<p>面向 PLC 流程节拍与相位角设计的专业软件:条形节拍、圆周节拍、流程图三视图共享同一份数据,泳道加宽、依赖关系与关键路径清晰可见。</p>
<ul class="feature-list">
<li>三视图一份数据 · 泳道 1–5 槽位加宽</li>
<li>drawio / SVG / PNG 导出,Windows 与 Android 双端</li>
</ul>
<div class="feature-actions">
<a href="/tools/sequence-diagram/" class="btn btn-primary">了解主力项目</a>
</div>
</div>
<div class="feature-visual has-image">
<img src="/static/img/sequence/circular-timing.jpg" alt="Sequence Diagram Studio 圆周节拍视图">
</div>
</div>
</div>
</section>
<section class="section section-alt">
<div class="container">
<div class="section-head">
<h2 class="section-title">前沿技术研究</h2>
<p class="section-desc">以研究为主、工具为辅 —— 正在持续投入的三个方向。</p>
</div>
<div class="grid">
<a class="card card-link" href="http://124.220.63.9:25000">
<span class="feature-tag">RESEARCH DIGEST</span>
<h3>国际顶尖科研热榜</h3>
<p>自动检索国际顶尖期刊与权威机构最新成果,AI 输出中文摘要、技术突破总结与 0-5 突破度评分。</p>
<span class="more">31 信源 · 21 领域 · 每日 06:00 更新 →</span>
</a>
<a class="card card-link" href="/research/neural/">
<span class="feature-tag">NEURAL RESEARCH</span>
<h3>NeuralMix AI 混合终点判断</h3>
<p>ModbusRTU 采集 → Redis 缓冲 → TimescaleDB 存储 → 1D-CNN 实时评估混合均匀度,稳定即判定完成。</p>
<span class="more">1D-CNN · 边缘部署 · 开放 API →</span>
</a>
<a class="card card-link" href="/research/reslib/">
<span class="feature-tag">RESLIB</span>
<h3>资源中心管理器</h3>
<p>面向 Creo 7.0+ 的企业级标准零部件管理库:3D 实时预览、快速装配与 LIC 授权体系。</p>
<span class="more">Creo 7.0 - 10.0 · MAC 绑定授权 →</span>
</a>
</div>
</div>
</section>
<section class="section">
<div class="container">
<div class="section-head">
<h2 class="section-title">工具开发</h2>
<p class="section-desc">每一款工具都来自真实项目,独立研发、私有部署、持续迭代。</p>
</div>
<div class="product-grid">{PRODUCT_CARDS}
</div>
<div class="text-center mt-32">
<a href="/tools/" class="btn btn-ghost">查看全部工具</a>
</div>
</div>
</section>
<section class="section section-alt">
<div class="container">
<h2 class="section-title">最新文章</h2>
<div class="post-list">
{recent}
</div>
<div class="text-center mt-32">
<a href="/blog/" class="btn btn-ghost">查看全部文章</a>
</div>
</div>
</section>
{page_footer()}"""
OUT_HOME.write_text(home, encoding="utf-8")
# ---------- 关于页 ----------
about = f"""{page_header("")}
<section class="page-hero">
<div class="container">
<p class="hero-eyebrow">ABOUT</p>
<h1>关于</h1>
<p class="page-hero-sub">Easy Design Collection —— 工业软件与数据产品的独立开发实践。</p>
</div>
</section>
<section class="section">
<div class="container narrow">
<div class="article">
<h3>SinCos</h3>
<p>工业软件方向开发者,专注流程工业的数字化与智能化实践。</p>
<h3>正在做</h3>
<ul>
<li><b>ResLib</b>:资源中心管理器 —— Creo 7.0+ 标准零部件管理库(Pro/TOOLKIT DLL 插件),支持 License 在线申请与审批</li>
<li><b>Neural Research</b>:NeuralMix AI 混合终点判断与算法研究</li>
<li><b>工具开发</b>:Sequence-Diagram、Uni-Viewer、Serial Terminal、Enthalpy Diagram、Physics AI Fluent、EDC Lite ERP 等自研产品</li>
<li><b>Research Digest</b>:国际顶尖科研热榜与 AI 突破度分析</li>
</ul>
<h3>联系方式</h3>
<ul>
<li>博客:<a href="/">sincos.cc</a></li>
<li>License 申请:<a href="/license/apply">/license/apply</a></li>
</ul>
</div>
</div>
</section>
{page_footer()}"""
OUT_ABOUT.write_text(about, encoding="utf-8")
print(f"构建完成:{len(posts)} 篇文章 -> {OUT_BLOG} / home.html / about.html")
if __name__ == "__main__":
build()