Files
02-ima/scripts/build.mjs
T

123 lines
26 KiB
JavaScript
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.
import fs from 'node:fs/promises';
import path from 'node:path';
import {Presentation,PresentationFile} from '/Users/zhanghailin/.cache/codex-runtimes/codex-primary-runtime/dependencies/node/node_modules/@oai/artifact-tool/dist/artifact_tool.mjs';
process.env.RUNTIME_NODE_MODULES='/Users/zhanghailin/.cache/codex-runtimes/codex-primary-runtime/dependencies/node/node_modules';
const BASE=path.resolve(process.argv[2]||new URL('..',import.meta.url).pathname);
const SKILL='/Users/zhanghailin/.codex/plugins/cache/openai-primary-runtime/presentations/26.1026.10807/skills/presentations';
const PY='/Users/zhanghailin/.cache/codex-runtimes/codex-primary-runtime/dependencies/python/bin/python3';
const C={ink:'#163D35',green:'#276450',mint:'#BDE6D1',lime:'#D9EDAC',white:'#FFFFFF',paper:'#F7FAF8',muted:'#60756D',line:'#D9E3DD',dark:'#102F29',amber:'#A86532',light:'#EAF3EE'};
const FONT='PingFang SC';
const OUTPUT_NAME=process.argv[3]||'知识库与腾讯ima教育应用培训-v2.pptx';
const p=Presentation.create({slideSize:{width:1280,height:720}});
const manifest=[];
function shape(s,g,x,y,w,h,fill,line='none',lw=0){return s.shapes.add({geometry:g,position:{left:x,top:y,width:w,height:h},fill,line:{fill:line,width:lw,style:'solid'}})}
function text(s,t,x,y,w,h,size=26,color=C.ink,bold=false,align='left'){
const o=shape(s,'textbox',x,y,w,h,'none');o.text=t;o.text.style={fontFamily:FONT,typeface:FONT,fontSize:size,color,bold,alignment:align,verticalAlignment:'middle',wrap:true,insets:0};o.text.insets=0;return o;
}
function line(s,x,y,w,h,color=C.line,width=2){return s.shapes.add({geometry:'line',position:{left:Math.min(x,x+w),top:Math.min(y,y+h),width:Math.abs(w),height:Math.abs(h),horizontalFlip:w<0,verticalFlip:h<0},fill:'none',line:{fill:color,width,style:'solid'}})}
function circle(s,x,y,d,fill){return shape(s,'ellipse',x,y,d,d,fill)}
function tag(s,t,x,y,w=160,dark=false){shape(s,'roundRect',x,y,w,34,dark?'#254A3F':C.light);text(s,t,x+12,y+1,w-24,30,16,dark?C.mint:C.green,true)}
function base(title,chapter,notes='',dark=false){
let s=p.slides.add();s.background.fill=dark?C.dark:C.paper;
const n=p.slides.items.length;manifest.push({page:n,title:title||(n===1?'让教学资料用起来':'从一个单元开始'),chapter});
text(s,chapter,64,35,900,28,16,dark?C.mint:C.muted);
if(title)text(s,title,64,89,1152,104,42,dark?C.white:C.ink,true);
text(s,'知识库与腾讯 ima 教育应用',64,670,900,24,13,dark?'#AAC7BA':C.muted);
text(s,String(n).padStart(2,'0')+' / 30',1116,670,100,24,14,dark?'#AAC7BA':C.muted,false,'right');
s.speakerNotes.text=notes;return s;
}
function note(s,t){s.speakerNotes.text += '\n'+t;}
function rows(s,items,x=64,y=220,w=1100,gap=95){items.forEach((a,i)=>{text(s,String(i+1).padStart(2,'0'),x,y+i*gap,60,50,30,C.green,true);text(s,a[0],x+85,y+i*gap,w-85,44,28,C.ink,true);if(a[1])text(s,a[1],x+85,y+i*gap+43,w-85,42,21,C.muted);if(i<items.length-1)line(s,x+85,y+i*gap+88,w-85,0);});}
function cols(s,items,{y=235,h=330,dark=false}={}){const gap=32,w=(1152-gap*(items.length-1))/items.length;items.forEach((a,i)=>{let x=64+i*(w+gap);text(s,String(i+1).padStart(2,'0'),x,y,w,80,58,dark?C.mint:C.green);text(s,a[0],x,y+106,w,58,29,dark?C.white:C.ink,true);text(s,a[1],x,y+182,w,Math.max(70,h-180),23,dark?'#C3D8CE':C.muted);});}
function callout(s,t,y=591,dark=false){text(s,t,64,y,1152,48,23,dark?C.mint:C.green,true)}
function table(s,headers,data,widths,{x=64,y=226,w=1152,h=330,size=22}={}){
const v=[headers,...data];let t=s.tables.add({rows:v.length,columns:headers.length,left:x,top:y,width:w,height:h,columnWidths:widths,values:v});
t.borders.assign({fill:C.line,width:1,style:'solid'});
v.forEach((r,ri)=>{t.rows[ri].height=h/v.length;});
v.forEach((r,ri)=>r.forEach((_,ci)=>{let c=t.getCell(ri,ci);c.fill=ri===0?C.green:(ri%2?C.white:C.light);c.text.style={fontFamily:FONT,typeface:FONT,fontSize:size,color:ri===0?C.white:C.ink,bold:ri===0,verticalAlignment:'middle',insets:14};}));return t;
}
function steps(s,items,y=255){const gap=30,w=(1152-(items.length-1)*gap)/items.length;items.forEach((a,i)=>{let x=64+i*(w+gap);circle(s,x,y,62,i===items.length-1?C.green:C.mint);text(s,''+(i+1),x,y,62,62,27,i===items.length-1?C.white:C.ink,true,'center');text(s,a[0],x,y+90,w,70,28,C.ink,true);text(s,a[1],x,y+175,w,120,22,C.muted);if(i<items.length-1)line(s,x+76,y+31,w-62,0,C.line,3);});}
function prompt(s,t,x=64,y=245,w=1152,h=250){shape(s,'roundRect',x,y,w,h,C.light);text(s,t,x+30,y+23,w-60,h-46,25,C.ink);}
function network(s){let nodes=[[860,145,120,'课程标准'],[1080,335,110,'教学设计'],[950,520,110,'课堂反思'],[720,500,110,'教研经验'],[690,265,90,'课例']];let cx=920,cy=380;nodes.forEach(([x,y,d])=>line(s,cx,cy,x+d/2-cx,y+d/2-cy,'#41685A',2));circle(s,824,290,190,C.mint);text(s,'教学\n知识库',845,323,148,114,35,C.ink,true,'center');nodes.forEach(([x,y,d,t])=>{circle(s,x,y,d,'#244A3E');text(s,t,x+5,y+5,d-10,d-10,19,C.white,false,'center');});}
// 01
{
let s=base('', '教师培训', '开场5分钟。请老师回想最近一次“记得存过,却找不到”的资料。全课120分钟,产品操作25分钟,案例40分钟,练习与交流30分钟。',true);
text(s,'让教学资料\n用起来',64,168,680,206,74,C.white,true);
text(s,'知识库与腾讯 ima 教育应用',68,414,680,64,30,C.mint);
text(s,'从一个单元开始,建立自己的教学资料库',68,518,670,78,25,'#C0D5CA');network(s);
}
//02
{let s=base('资料越来越多,使用依然费劲','从日常问题出发','请举手或口头互动:找不到资料、材料太多读不完、重复备课、成果难共享,哪一项最常见?不承诺具体节省时间。');cols(s,[['散落各处','电脑、微信与网盘\n各自留下一份资料'],['找不到重点','记得看过,却想不起\n文件名和关键段落'],['重复做整理','同一主题的材料\n每次重新阅读比较'],['经验难复用','优秀教案和课堂反思\n还停留在个人手里']]);callout(s,'今天从“保存资料”继续走到“围绕资料解决问题”');}
//03
{let s=base('今天建立一个能回答问题的资料库','今天的成果','先展示目标成果:有资料、有问题、有依据、有教师修改。建议用随附演示材料,全程明确为模拟教学资料。');steps(s,[['几份资料','围绕同一主题\n小范围开始'],['一个问题','来自真实备课\n或日常工作'],['核对依据','返回原文\n检查上下文'],['一份成果','教师修改后\n保存并复用']]);callout(s,'你将带走一个小库、一份成果和一次查证记录');}
//04
{let s=base('知识库,把资料组织成可用的资源','知识库基础','此处知识库是知识管理意义上的集合。带AI问答的知识库增加了内容检索、归纳和问答能力。用“某单元备课库”解释主题、资料、维护与复用。');text(s,'围绕一个主题\n持续积累与使用知识',64,230,650,160,48,C.ink,true);text(s,'资料、笔记、案例与经验\n经过组织,可以查找,也可以反复使用。',64,437,620,112,27,C.muted);let labels=['单元备课库','教研资料库','学校制度库'];labels.forEach((a,i)=>{shape(s,'roundRect',830,232+i*115,355,90,i===0?C.green:C.light);text(s,a,856,244+i*115,305,66,29,i===0?C.white:C.ink,true);});}
//05
{let s=base('资料管理工具,各有适合的问题','知识库基础','这三类工具的能力可能重叠。表格比较常见使用方式,不声称文件夹、网盘或笔记没有搜索或AI功能。');table(s,['常见方式','你通常怎么用','主要帮助'],[['文件夹与网盘','目录、文件名、关键词','找到文件,保存和分发'],['笔记工具','记录、分类、关联','保留理解与思考'],['带 AI 问答的知识库','围绕内容提问、比较、归纳','用资料回答问题、形成初稿']],[245,420,487]);callout(s,'整理资料、标注来源和及时更新,依然重要');}
//06
{let s=base('AI 如何使用你放进去的资料','知识库基础','这是常见检索增强问答的简化解释,并非ima内部技术架构说明。入库通常不是重新训练专属模型。检索可能遗漏,回答仍需要查证。');steps(s,[['解析资料','读取内容\n建立可检索的索引'],['查找片段','根据问题\n寻找相关材料'],['组织回答','结合找到的内容\n归纳与表达'],['回到原文','核对事实\n检查上下文']]);callout(s,'入库后仍需要核对答案与来源');}
//07
{let s=base('知识库进入教师工作的五个环节','知识库基础','讲解价值时结合具体工作:定位课标相关段落、比较两份教案、起草课堂活动、记录实践反思、教研组共用。不要使用未经测量的效率数字。');const a=[['找','定位相关资料'],['读','比较与提取重点'],['用','形成教学初稿'],['留','补充实践反思'],['享','共用教研积累']];a.forEach(([big,t],i)=>{let x=64+i*235;circle(s,x+30,245,140,i%2?C.light:C.mint);text(s,big,x+30,245,140,140,58,C.green,true,'center');text(s,t,x,433,210,90,26,C.ink,true,'center');});}
//08
{let s=base('第一个知识库,从一个具体主题开始','知识库基础','范围越大不代表越好用。举例:八年级物理光学备课、教研组同课异构、学校培训办理。学生使用应由学校与教师按实际要求安排。');table(s,['使用者','适合的主题','先放哪些材料'],[['教师个人','一个单元的备课','教学参考、已有教案、课后反思'],['教研组','一次同课异构教研','多份课例、听评课记录'],['学校管理','一项校务办理','现行制度、流程、常见问题'],['学生学习支持','教师筛选的学习专题','讲义、例题、学习提示']],[200,360,592],{h:350});callout(s,'起步建议:一个主题,3—5 份资料,一个真实问题');}
//09
{let s=base('回答质量,取决于资料质量','知识库基础','请现场比较:清晰命名的文本PDF与缺页扫描件。识别不完整时先修复资料,不要仅靠追问。旧版、新版和矛盾资料需要清晰标注。');rows(s,[['来源可靠','保留出处、发布日期和适用范围'],['版本匹配','检查学科、年级、教材版本与资料时效'],['内容可读','确认没有缺页,扫描件能够正常识别'],['持续维护','处理重复、过期和相互冲突的内容']],64,213,1152,95);}
//10
{let s=base('腾讯 ima,围绕知识库开展搜读写','认识腾讯 ima','来源:https://ima.tencent.com/download;https://ima.qq.com/。核对日期:2026-11-03。此课聚焦知识库基础能力,不讨论动态额度、价格和模型排名。产品功能与入口以授课账号实际版本为准。',true);text(s,'ima',64,211,480,180,135,C.mint,true);text(s,'资料收集、阅读理解\n与内容创作相连接',650,238,550,140,42,C.white,true);text(s,'本次聚焦\n资料入库 / 基于资料问答 / 笔记与共享',650,443,560,112,25,'#C0D5CA');callout(s,'用一个教学专题库,贯穿接下来的操作',596,true);}
//11
{let s=base('一次备课,可以连起五种操作','认识腾讯 ima','能力来源:https://ima.tencent.com/download 与官方应用说明 https://apps.apple.com/cn/app/id6737188438。具体格式及端侧入口因版本而异,不在本页承诺。');rows(s,[['收资料、读资料','把相关文件、文章集中起来,辅助提取重点'],['问资料','针对指定资料范围,查询、比较和归纳'],['写内容','整理教学初稿,并加入教师的判断与修改'],['共用资料','围绕共同主题积累内容,管理成员与权限']],64,213,1152,95);}
//12
{let s=base('先认识知识库入口与提问区域','ima 基础操作','截图来源:https://ima.qq.com/,2026-11-03,未登录Web首页。此截图仅说明可见入口。库内资料、来源、笔记及共享操作需要登录后演示,本次没有使用个人账号实测。');let b=await fs.readFile(path.join(BASE,'assets/ima-official-home.png'));s.images.add({blob:b.buffer.slice(b.byteOffset,b.byteOffset+b.byteLength),contentType:'image/png',alt:'腾讯ima未登录Web首页官方截图',position:{left:64,top:204,width:780,height:439},fit:'contain'});rows(s,[['知识库','添加与管理资料'],['提问区域','描述任务与要求'],['后续演示','登录后查看来源\n笔记与共享入口']],914,232,300,122);text(s,'官方 Web 首页截图,未登录状态',64,643,800,22,14,C.muted);}
//13
{let s=base('建立“光与影”教学专题演示库','ima 基础操作','这里将原大纲“七年级科学”改为不绑定教材版本的“光与影教学专题演示库”。随附3份模拟材料,不能替代真实教材和课程标准。操作:新建库、加入3份Markdown资料、打开检查解析、记下资料名。授课前使用实际账号验证。');cols(s,[['主题说明','01_主题说明.md\n概念、适用范围\n与课堂目标'],['活动建议','02_活动建议.md\n控制变量\n与观察记录'],['课堂反思','03_课堂反思.md\n常见问题\n与改进线索']]);callout(s,'导入后逐份打开,确认内容可读、名称清晰');tag(s,'随附模拟材料',64,194,180);}
//14
{let s=base('具体的问题,让回答更接近任务','ima 基础操作','演示先问“总结一下”,再用完整要求追问。不要伪造产品回答。本页是可复制的提问示例。');text(s,'起点',64,220,160,42,22,C.muted);text(s,'“帮我总结一下。”',64,271,1000,65,37,C.muted);text(s,'补充任务与要求',64,366,800,40,22,C.green,true);prompt(s,'请基于这 3 份资料,整理“光与影”专题的核心概念、\n活动建议和常见问题,用表格呈现,并标明资料名称。\n将资料依据与补充建议分开,缺少依据时明确说明。',64,423,1152,185);}
//15
{let s=base('有引用,还需要回到原文核对','ima 基础操作','示例依据为随附模拟材料02,不是ima实测输出。展示答案中的一句话,然后打开原文,判断它是否受到支持。不要用“有来源”代替“来源支持”。');tag(s,'查证示例',64,219,150);text(s,'待核对的说法',64,291,500,42,23,C.muted);text(s,'“光源越远,影子一定越大。”',64,355,530,125,38,C.ink,true);shape(s,'roundRect',670,254,546,302,C.light);text(s,'原文依据',700,279,486,44,23,C.green,true);text(s,'保持光源与屏幕固定,\n改变物体在二者之间的位置。\n其他条件应保持不变。',700,351,476,150,28,C.ink);callout(s,'原文没有支持这个结论,需要纠正并说明条件');}
//16
{let s=base('把回答继续加工成自己的教学积累','ima 基础操作','建议笔记包含来源、已核对结论、教师修改和课堂反馈。是否保存回库、具体入口请现场验证。强调教师的实践反馈会形成下一次更有价值的资料。');steps(s,[['核对','事实、条件\n与原文来源'],['修改','加入学情\n与教学判断'],['记录','标注出处\n与修改日期'],['更新','补充课堂反馈\n管理共享范围']]);callout(s,'一次回答可以结束,一份教学积累可以继续生长');}
//17
{let s=base('四个场景,把知识库用到工作里','教育典型应用','案例共40分钟,建议单元备课15分钟、练习设计10分钟、教研积累8分钟、校务查询7分钟。案例成果为教学示例,不是实测的产品生成效果。',true);cols(s,[['备课','读懂材料\n组织教学活动'],['练习','明确考查点\n审核题目与答案'],['教研','比较不同课例\n积累实施经验'],['校务','查现行文件\n整理办事清单']],{dark:true});}
//18
{let s=base('案例一:先从材料中提炼备课要点','备课案例','此表是根据随附模拟材料人工整理的示例成果,非课标原文、非ima实测输出。请现场提出问题后与此结构比较。重点检查目标、依据和活动之间的关系。');tag(s,'模拟成果示例',64,202,180);table(s,['备课要点','资料提供的信息','可追溯的依据'],[['核心概念','光沿直线传播,遮挡与影子的形成','01_主题说明'],['课堂观察','固定光源与屏幕,改变物体位置','02_活动建议'],['常见问题','同时改变多个条件,难以比较','03_课堂反思']],[240,570,342],{y:258,h:290});callout(s,'提问:这些资料分别提供了哪些目标、活动和问题线索?');}
//19
{let s=base('案例一:形成可以修改的课堂活动初稿','备课案例','示例课堂40分钟安排:5分钟提出问题、15分钟控制变量观察、10分钟解释、10分钟交流。此为讲师设计建议,不是课标要求。教师需审核实验安全、学情与时间。');table(s,['目标','课堂活动建议','观察学生的表现'],[['解释影子的形成','用光源、物体和屏幕搭建装置','能否说明三者的关系'],['控制一个变化条件','固定光源与屏幕,移动物体','能否指出不变与变化条件'],['根据证据表达','比较观察记录并交流解释','能否用观察支持自己的说法']],[320,470,362],{h:295});callout(s,'补充给 AI:课时、学生已有经验、器材与限制条件');}
//20
{let s=base('案例二:分层练习体现不同思维要求','练习设计案例','以下是基于光与影主题的示例题型,教师正式使用前检查科学性和课程匹配。基础题观察条件,应用题解释,拓展题实验设计。');cols(s,[['基础理解','指出形成影子需要的条件\n\n考查概念与关系'],['情境应用','解释同一装置中\n物体位置改变后的现象\n\n考查条件分析'],['探究设计','设计一个只改变\n物体位置的观察方案\n\n考查实验设计']]);callout(s,'要求同时给出考查点、参考答案、适用前提和设计意图');}
//21
{let s=base('案例二:一道题,展示教师如何审核','练习设计案例','演示修正题干的条件。点光源模型,屏幕垂直光轴,物体在光源与屏幕之间,光源屏幕固定。物体靠近光源,屏幕上的影子通常变大。真实光源有大小时需注意半影,训练中使用理想化描述。');text(s,'初稿中的问题',64,224,520,44,24,C.muted);text(s,'“物体靠近光源,\n影子会怎样?”',64,298,520,150,40,C.ink,true);shape(s,'roundRect',655,219,561,350,C.light);text(s,'教师补充条件',687,249,490,44,26,C.green,true);text(s,'近似点光源与屏幕保持固定。\n物体位于光源和屏幕之间。\n只移动物体,使其靠近光源。',687,326,490,150,28,C.ink);text(s,'参考判断:屏幕上的影子变大。',687,510,490,44,24,C.green,true);callout(s,'审核四项:条件完整、答案正确、范围匹配、难度合适');}
//22
{let s=base('案例三:比较课例,留下适用条件','教研积累案例','A和B为模拟课例,不是效果评估。教师共同讨论适用条件。不要根据两个课例声称一种教法必然更好。');table(s,['比较维度','课例 A:教师演示','课例 B:小组观察'],[['组织方式','教师操作,学生记录','学生分组操作与交流'],['优势与条件','器材少,过程容易统一','需要器材与操作常规'],['需要关注','每位学生是否真正观察到','是否控制变量,记录是否清晰'],['后续改进','增加预测与解释环节','增加角色分工和记录样例']],[230,461,461],{h:360});callout(s,'教研比较表应保留来源、课堂条件和待验证的问题');}
//23
{let s=base('案例三:共享库需要持续维护','教研积累案例','共享功能与权限以授课账号当前版本为准。设置维护人、成员权限与更新规则。示例一个主题库中设置说明、资料、设计、反思四类内容,不承诺某种特定文件夹功能。');cols(s,[['放什么','主题说明与来源\n参考资料与教学设计\n实践反思与改进'],['谁维护','明确维护人与贡献者\n更新后标注日期\n保留适用范围'],['怎样共用','核对成员权限\n先审核再共享\n课堂反馈持续补充']]);callout(s,'共享的价值来自可理解、可追溯、可继续改进的内容');}
//24
{let s=base('案例四:从制度文件整理办事清单','校务查询案例','使用材料04_校务办理模拟指南。全部制度、角色及流程为培训虚构示例,禁止作为学校正式规定。演示问题:校内培训申请需要哪些材料,经过哪些环节?');tag(s,'模拟制度示例',64,202,180);table(s,['办理环节','需要准备或确认','依据'],[['提交申请','主题、时间、参与对象与资源需求','模拟指南第1条'],['审核与沟通','交教研负责人确认,缺项补充','模拟指南第2条'],['活动后归档','活动记录与简要总结','模拟指南第3条']],[270,600,282],{y:256,h:285});callout(s,'实际使用时,列出正式文件名称、发布日期与对应条款');}
//25
{let s=base('案例四:冲突与缺失,需要明确呈现','校务查询案例','这是文件使用习惯,不是法律意见。不能只凭日期自动断言某文件具有更高效力,要看适用范围、发布主体和学校确认。材料04未规定审批时限,回答应明确未找到。');cols(s,[['版本不同','并列文件日期\n核对适用范围\n向负责人确认'],['信息冲突','列出相互矛盾的条款\n说明差异\n暂停确定性结论'],['资料没有','明确“未找到依据”\n不补写审批时限\n列出待确认事项']]);callout(s,'一个可追溯的“待确认”,比编造一个具体答案更有用');}
//26
{let s=base('现场练习:建立自己的教学专题库','现场练习','本环节12分钟独立操作、8分钟分享,最后10分钟使用习惯与答疑,合计30分钟。材料包包含3份光与影模拟资料、1份模拟校务文件和练习单。登录与导入需授课前验证。',true);text(s,'12',64,217,390,180,140,C.mint,true);text(s,'分钟动手操作',70,410,430,60,34,C.white,true);text(s,'再用 8 分钟交流与分享',70,493,460,70,25,'#C0D5CA');let a=['选择一个主题,导入 3—5 份资料','提出一个查询问题和一个综合问题','核对至少两处引用,进行一次修改','保存一份成果与查证记录'];a.forEach((t,i)=>{circle(s,650,235+i*88,36,C.mint);text(s,String(i+1),650,235+i*88,36,36,19,C.ink,true,'center');text(s,t,705,226+i*88,510,62,25,C.white);});}
//27
{let s=base('一段可以反复使用的提问模板','现场练习','邀请老师把年级、学科、任务、资料范围、输出结构填完整。对于资料未涉及的内容不能保证模型一定拒答,必须检查实际回答。');prompt(s,'我正在为【年级/学科/主题】开展【具体任务】。\n请基于【指定资料范围】,完成【具体要求】。\n请用【表格/清单/教学设计初稿】呈现,并注明依据。\n将资料明确说明的内容与补充建议分开。\n没有找到依据的信息,请明确标注。',64,229,1152,328);callout(s,'不必一次问完,可以通过追问逐步补充条件');}
//28
{let s=base('练习完成,能展示这五项成果','现场练习','邀请2至3位教师分享。重点观察查证与修改过程,不能只看生成文本是否流畅。');rows(s,[['资料可读','能打开原文,并说明主题与来源'],['问题明确','能够解释自己要解决的工作问题'],['依据可查','展示两处引用,以及核对后的判断'],['有过修改','至少一次追问或教师修改'],['成果可用','找到并打开保存的最终内容']],64,206,1152,81);}
//29
{let s=base('让资料库保持有用的日常习惯','持续使用','不上传未获授权的敏感资料。按学校要求处理学生信息。共享前检查成员与内容权限。定期清理旧资料与失效内容,保留实践反思。');cols(s,[['范围小一点','围绕一个真实任务\n先积累高质量资料'],['维护勤一点','补充来源与日期\n检查旧版和重复内容'],['使用稳一点','核对正式使用的成果\n处理学生信息与共享权限']]);callout(s,'把自己的课堂反思补回库里,让下一次备课有据可循');}
//30
{let s=base('', '交流与答疑','结尾预留答疑时间。作业:一周内带回一个专题库、一份教师修改后的成果、一次查证记录。培训重点是可持续的使用方法,不对教学效果作未经验证的承诺。',true);text(s,'从一个单元开始',64,160,1152,110,70,C.white,true);text(s,'让下一次备课,多一份可以复用的积累。',68,315,1140,70,34,C.mint);[['一个小库','聚焦一个真实主题'],['一份成果','经过教师检查与修改'],['一次查证','保留依据与核对记录']].forEach((a,i)=>{text(s,a[0],68+i*390,480,360,58,33,C.white,true);text(s,a[1],68+i*390,554,360,55,23,'#C0D5CA');});}
await fs.mkdir(path.join(BASE,'build','previews'),{recursive:true});
await fs.mkdir(path.join(BASE,'outputs'),{recursive:true});
await fs.writeFile(path.join(BASE,'src','pptx-deck.json'),JSON.stringify(manifest,null,2));
const draft=path.join(BASE,'build','candidate.pptx');
await (await PresentationFile.exportPptx(p)).save(draft);
console.log('Draft exported: '+draft);
for(let i=0;i<p.slides.items.length;i++){
let blob=await p.export({slide:p.slides.items[i],format:'png',scale:1});
await fs.writeFile(path.join(BASE,'build','previews',`slide-${String(i+1).padStart(2,'0')}.png`),new Uint8Array(await blob.arrayBuffer()));
console.log('Rendered '+(i+1));
}
const {finalizePresentation}=await import(path.join(SKILL,'container_tools/artifact_tool_utils.mjs'));
await finalizePresentation({workspaceDir:BASE,candidatePath:draft,finalPath:path.join(BASE,'outputs',OUTPUT_NAME),pythonExecutable:PY,integrityValidatorPath:path.join(SKILL,'container_tools/inspect_presentation_package_integrity.py'),layoutValidatorPath:path.join(SKILL,'container_tools/inspect_presentation_layout_geometry.py'),layoutArgs:['--expected-slide-size-emu','12192000,6858000','--validate-bullet-geometry','--validate-heading-fit',...[5,8,18,19,22,24].flatMap(n=>['--require-native-table-slide',String(n)])],explicitTotalSlideCount:30,requiredNativeTableOwnerSlides:[5,8,18,19,22,24],requiredNativeChartOwnerSlides:[],fontPolicy:{basis:'design',families:[FONT]},verifyArtifactToolImport:true,receiptPath:path.join(BASE,'build','validation.json')});
console.log('Finalized');