本文件写给会写代码、能生成 HTML的 AI 助手。读完后你应该能:
- 理解 CourseForge 与 AI 的分工边界;
- 通过本地 WebSocket 接收生成请求、回传互动 HTML;
- 产出一个符合 Widget Spec 的、可离线运行的互动组件。
完整通信协议见仓库
course-editor/README.md第四节;组件规范见course-editor/WIDGET_SPEC.md。
CourseForge 是离线条编辑器,负责 PPT 解析、页面拖拽排版、课件保存 / 导出。AI(WorkBuddy)只做一件事:根据老师的自然语言需求,生成一个自包含的互动 HTML 片段。
- AI 不解析 PPT、不改动课件基础层、不持有完整课件。
- 编辑器通过本地 WebSocket 把
prompt + 主题 + 容器尺寸发给 AI,AI 只回传html片段。 - 生成结果是「预览态」:编辑器先展示,老师确认后才回填容器。老师可随时删除 / 重生成。
- 地址:
ws://127.0.0.1:7788(编辑器「连接」按钮可改;仅本机回环,数据不上云) - 全双工,单连接多请求,用
requestId关联
编辑器 → AI(请求)
{
"type": "generate",
"requestId": 1,
"prompt": "做一个浮力知识点的选择题小测验,3道题",
"theme": { "primary": "#2563eb", "bodyFont": "Microsoft YaHei" },
"size": { "w": 340, "h": 200 }
}AI → 编辑器(进度 / 结果 / 错误)
{ "type": "progress", "requestId": 1, "message": "正在生成…" }
{ "type": "result", "requestId": 1, "title": "浮力小测验", "html": "<!doctype html>…完整自包含HTML…" }
{ "type": "error", "requestId": 1, "message": "生成失败:…" }workbuddy-bridge.js(仓库根 course-editor/)是该协议的服务端参考实现,内含调用 LLM 的占位,开发者据此把真实 WorkBuddy 接进来。
生成的 html 必须是完整自包含的单页 HTML(内联 CSS/JS,不引用任何外部资源),以便编辑器用 iframe srcdoc 离线加载。
:root{
--cf-primary:#2563eb; /* 跟随全局统一样式 */
--cf-bg:#ffffff;
--cf-text:#1f2937;
--cf-radius:12px;
--cf-body-font:"Microsoft YaHei",system-ui,sans-serif;
}window.addEventListener('message', e=>{
const d = e.data;
if(d && d.type==='cf:activate') {/* 开始动画 / 重置状态 */}
if(d && d.type==='cf:deactivate') {/* 暂停计时器 / 清理 */}
});parent.postMessage({ type:'cf:ready' }, '*');
parent.postMessage({ type:'cf:event', name:'answered', data:{ correct:true } }, '*');
parent.postMessage({ type:'cf:error', message:'...' }, '*');- 默认不需要摄像头 / 麦克风,不要主动申请。
- 仅在确需时(如人脸检测、语音评测)才要求老师开启「摄像头 / 麦克风 / 允许同源」;开启后浏览器才允许
getUserMedia。file://直接双击打开时浏览器可能仍会限制音视频,导出课件建议在受支持的本地位点或 https/localhost 下运行。
<!doctype html><html><head><meta charset="utf-8">
<style>
:root{--cf-primary:#2563eb;--cf-bg:#fff;--cf-text:#1f2937;--cf-radius:12px;
--cf-body-font:system-ui,"Microsoft YaHei",sans-serif}
body{margin:0;font-family:var(--cf-body-font);color:var(--cf-text);background:var(--cf-bg)}
.btn{background:var(--cf-primary);color:#fff;border:0;border-radius:var(--cf-radius);padding:8px 14px;cursor:pointer}
</style></head><body>
<h3>小测验</h3><button class="btn" id="go">开始</button>
<script>
parent.postMessage({type:'cf:ready'},'*');
document.getElementById('go').onclick=()=>parent.postMessage({type:'cf:event',name:'start'},'*');
window.addEventListener('message',e=>{ if(e.data?.type==='cf:activate') console.log('activated'); });
</script>
</body></html>帮老师生成组件时,按这个结构理清需求(仓库 course-editor/widgets/PROMPT_FRAMEWORK.md 有完整版):
- 学科 / 知识点:数学?物理?语文?具体哪个知识点?
- 互动类型:答题 / 投票 / 拖拽排序 / 仿真 / 实验 / 检测(摄像头)?
- 题量 / 数据:几道题?用什么素材?
- 反馈方式:即时判分?答对高亮?结束后汇总?
- 视觉:对齐全局
--cf-*主题,不写死颜色。
仓库 course-editor/widgets/ 提供三个可运行范例,生成前先对照它们的结构与体量:
quiz.html—— 答题vote.html—— 投票drag.html—— 拖拽
Bento 之类的项目会让 AI 直接读写文档 JSON(window.bento.doc / loadDoc())。CourseForge 当前通过 WebSocket 让 AI 只生成互动片段,是最稳妥的边界。后续可能新增只读的 window.courseforge 表面(doc / loadDoc / validate)以支持「按章节批量编排整本课件」——届时以 course-editor/README.md 与本文档的更新为准。