feat(learn): add standalone /learn pages backed by Page Data

Serve lightweight child/parent learning assistant pages at /learn without
MindSpace injection, with a rebuild script and Portal static route.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
john
2026-09-15 17:17:18 +08:00
parent b99ddbacee
commit f9e105acd0
6 changed files with 432 additions and 0 deletions
+89
View File
@@ -0,0 +1,89 @@
#!/usr/bin/env python3
"""Build lightweight /learn/* pages without MindSpace injection."""
import re
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
SRC = ROOT / 'MindSpace/a70ff537-8908-486e-9b6c-042e07cc25db/public'
OUT = ROOT / 'public/learn'
VER = '20260915j'
CHILD_PAGE = 'dcb1f3f0-db96-4dab-a009-7a9c393ebe77'
PARENT_PAGE = 'f9c80392-9417-46fd-af89-a91a239d3bfc'
def extract_style(html: str) -> str:
m = re.search(r'<style>([\s\S]*?)</style>', html)
return m.group(1) if m else ''
def extract_app_script(html: str) -> str:
m = re.search(r'<script>\s*(var state=[\s\S]*?\)\(\);)\s*</script>', html)
if not m:
raise ValueError('app script not found')
return m.group(1)
def shell(title: str, style: str, page_id: str, access: str, body: str, script: str) -> str:
access_json = '{"pageId":"%s","accessMode":"%s"}' % (page_id, access)
return f'''<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1,viewport-fit=cover">
<title>{title}</title>
<meta name="mindspace-page-data-page-id" content="{page_id}">
<script>window.__MINDSPACE_PAGE_DATA__={access_json};</script>
<style>{style}</style>
<script src="/assets/page-data-client.js?v={VER}"></script>
<script src="/learn/learning-assistant-data.js?v={VER}"></script>
<link rel="icon" type="image/png" href="/brand/tkmind-icon.png">
</head>
{body}
<script>
{script}
</script>
</body>
</html>
'''
def main():
OUT.mkdir(parents=True, exist_ok=True)
child_src = (SRC / 'learning-assistant.html').read_text(encoding='utf-8')
parent_src = (SRC / 'learning-assistant-parent.html').read_text(encoding='utf-8')
child_style = extract_style(child_src)
parent_style = extract_style(parent_src)
child_script = extract_app_script(child_src)
parent_script = extract_app_script(parent_src)
child_script = child_script.replace('learning-assistant-parent.html', '/learn/parent.html')
parent_script = parent_script.replace('learning-assistant.html', '/learn/')
child_body = '''<body>
<div class="wrap" id="app"><div class="card"><div class="empty">加载中…</div></div></div>
<div class="tabbar" id="tabbar"></div>
'''
parent_body = '''<body>
<div class="wrap pl" id="app"><div class="card"><div class="empty">加载中…</div></div></div>
'''
(OUT / 'index.html').write_text(
shell('我的学习小助手', child_style, CHILD_PAGE, 'public', child_body, child_script),
encoding='utf-8',
)
(OUT / 'parent.html').write_text(
shell('家长后台', parent_style, PARENT_PAGE, 'password', parent_body, parent_script),
encoding='utf-8',
)
data_js = (SRC / 'learning-assistant-data.js').read_text(encoding='utf-8')
data_js = re.sub(r'DATA_VER="[^"]+"', f'DATA_VER="{VER}"', data_js)
(OUT / 'learning-assistant-data.js').write_text(data_js, encoding='utf-8')
print('built', OUT)
print(' index.html', (OUT / 'index.html').stat().st_size, 'bytes')
print(' parent.html', (OUT / 'parent.html').stat().st_size, 'bytes')
if __name__ == '__main__':
main()
+42
View File
@@ -0,0 +1,42 @@
#!/usr/bin/env python3
from pathlib import Path
p = Path("/Users/john/Project/Memind/server.mjs")
text = p.read_text()
if '"/learn"' in text and "public/learn" in text:
print("ALREADY_PATCHED")
raise SystemExit(0)
needle = """ app2.use(
"/assets",
staticMiddleware(
pathApi.join(h5Root, "public/assets"),
{ maxAge: "1d" }
)
);
app2.get(
"/dev/wechat-share-preview","""
insert = """ app2.use(
"/assets",
staticMiddleware(
pathApi.join(h5Root, "public/assets"),
{ maxAge: "1d" }
)
);
app2.use(
"/learn",
staticMiddleware(
pathApi.join(h5Root, "public/learn"),
{ maxAge: "5m", index: "index.html" }
)
);
app2.get(
"/dev/wechat-share-preview","""
if needle not in text:
print("NEEDLE_NOT_FOUND")
raise SystemExit(1)
p.write_text(text.replace(needle, insert, 1))
print("PATCHED_OK")