Spaces:
Running
Running
Download index.html from YVES28/learningos: direct link, hf CLI and curl.
- Browser
- Download file 36.9 kB
-
https://huggingface.co/spaces/YVES28/learningos/resolve/main/index.html
- Command line
-
hf download hf://spaces/YVES28/learningos/index.html
-
curl -L -o index.html https://huggingface.co/spaces/YVES28/learningos/resolve/main/index.html
36.9 kB
| <html lang="zh-CN"> | |
| <head> | |
| <meta charset="UTF-8" /> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0" /> | |
| <title>LearningOS V3.0 · 儿童学习能力 AI 操作系统</title> | |
| <script src="https://cdn.plot.ly/plotly-2.35.2.min.js" charset="utf-8"></script> | |
| <style> | |
| :root{ | |
| --blue:#2E86DE; --blue-d:#1f5fa8; --bg:#f5f8fc; --card:#fff; | |
| --line:#e2e8f0; --text:#1f2d3d; --muted:#6b7a8d; --red:#E74C3C; --green:#27ae60; | |
| } | |
| *{box-sizing:border-box} | |
| body{margin:0;font-family:-apple-system,"PingFang SC","Microsoft YaHei",Segoe UI,Roboto,sans-serif; | |
| background:var(--bg);color:var(--text);line-height:1.6} | |
| header{background:linear-gradient(135deg,var(--blue),var(--blue-d));color:#fff;padding:18px 24px} | |
| header h1{margin:0;font-size:20px} | |
| header p{margin:4px 0 0;font-size:13px;opacity:.9} | |
| .tabs{display:flex;flex-wrap:wrap;background:#fff;border-bottom:1px solid var(--line)} | |
| .tab{padding:12px 16px;cursor:pointer;font-size:14px;color:var(--muted);border-bottom:3px solid transparent} | |
| .tab.active{color:var(--blue);border-bottom-color:var(--blue);font-weight:600} | |
| .page{display:none;padding:20px 24px;max-width:980px;margin:0 auto} | |
| .page.active{display:block} | |
| .card{background:var(--card);border:1px solid var(--line);border-radius:10px;padding:16px 18px;margin-bottom:16px; | |
| box-shadow:0 1px 3px rgba(0,0,0,.04)} | |
| h2{font-size:18px;margin:0 0 10px} | |
| h3{font-size:15px;margin:14px 0 6px;color:var(--blue-d)} | |
| label{display:block;font-size:13px;margin:10px 0 4px;color:var(--text)} | |
| .row{display:flex;gap:14px;flex-wrap:wrap} | |
| .row > *{flex:1;min-width:200px} | |
| button{background:var(--blue);color:#fff;border:none;padding:10px 18px;border-radius:8px; | |
| font-size:14px;cursor:pointer;margin-top:10px} | |
| button:hover{background:var(--blue-d)} | |
| button.ghost{background:#fff;color:var(--blue);border:1px solid var(--blue)} | |
| .opt{display:flex;gap:8px;flex-wrap:wrap;margin:6px 0} | |
| .opt label{margin:0;padding:6px 12px;border:1px solid var(--line);border-radius:20px;cursor:pointer;font-size:13px} | |
| .opt input{display:none} | |
| .opt input:checked + span{font-weight:600} | |
| .opt label:has(input:checked){background:var(--blue);color:#fff;border-color:var(--blue)} | |
| input[type=number],textarea,select{width:100%;padding:8px 10px;border:1px solid var(--line);border-radius:8px;font-size:14px} | |
| .pill{display:inline-block;padding:2px 10px;border-radius:12px;font-size:12px;background:#eef4fb;color:var(--blue)} | |
| .warn{color:var(--red);font-weight:600} | |
| .ok{color:var(--green);font-weight:600} | |
| .muted{color:var(--muted);font-size:13px} | |
| .plot{width:100%;height:440px} | |
| details{border:1px solid var(--line);border-radius:8px;padding:8px 12px;margin:10px 0;background:#fff} | |
| summary{cursor:pointer;font-weight:600;font-size:14px} | |
| .banner{background:#fff7e6;border:1px solid #ffe1a8;color:#8a5a00;padding:10px 14px;border-radius:8px;font-size:13px;margin-bottom:14px} | |
| .qcard{border:1px solid var(--line);border-radius:8px;padding:10px 12px;margin:8px 0} | |
| pre{white-space:pre-wrap;word-break:break-word;background:#f8fafc;border:1px solid var(--line);padding:12px;border-radius:8px;font-size:13px} | |
| table{width:100%;border-collapse:collapse;font-size:13px;margin-top:6px} | |
| th,td{border:1px solid var(--line);padding:6px 8px;text-align:left} | |
| th{background:#f1f6fc} | |
| </style> | |
| </head> | |
| <body> | |
| <header> | |
| <h1>🧠 LearningOS V3.0 — 儿童学习能力 AI 操作系统(原型演示)</h1> | |
| <p>AI筛查 · 能力评估 · 学习数字孪生 · 智能解释(LearningGPT) · 个性化干预 · 报告导出</p> | |
| </header> | |
| <div class="tabs" id="tabs"> | |
| <div class="tab active" data-t="home">🏠 概览</div> | |
| <div class="tab" data-t="screen">🔍 AI 筛查</div> | |
| <div class="tab" data-t="assess">📝 能力评估</div> | |
| <div class="tab" data-t="twin">👤 学习数字孪生</div> | |
| <div class="tab" data-t="explain">🤖 智能解释</div> | |
| <div class="tab" data-t="intervene">🎯 个性化干预</div> | |
| <div class="tab" data-t="report">📤 报告导出</div> | |
| </div> | |
| <!-- 概览 --> | |
| <div class="page active" id="home"> | |
| <div class="banner">⚠️ 本应用为<b>演示原型</b>:题目、常模、算法均为平台自研原创演示内容,<b>不构成任何临床或教育诊断结论</b>。WIAT-III/WISC-V 仅作为维度设计的学术参考框架。</div> | |
| <div class="card"> | |
| <h2>平台定位</h2> | |
| <p>基于儿童神经发育科学 + AI 主动智能体 + 多模态行为分析 + 标准化学习能力评估体系 + 数字化干预, | |
| 打造覆盖 <b>AI筛查—能力评估—智能解释—个性化干预—家庭管理—医疗协同—科研数据库</b> 的儿童学习脑健康数字生态平台。</p> | |
| <h3>可体验的完整闭环</h3> | |
| <ol> | |
| <li><b>AI 筛查</b>:家长/教师 8 项行为问卷 → 风险预警</li> | |
| <li><b>能力评估</b>:自研分测验(阅读/数学/语言/书写/执行功能)→ 组合分标准分</li> | |
| <li><b>学习数字孪生</b>:10 维能力雷达 + 成长时间轴 + 6 个月趋势投影</li> | |
| <li><b>智能解释 LearningGPT</b>:可解释地追溯底层认知因素,支持问答</li> | |
| <li><b>个性化干预</b>:自适应干预引擎(ZPD 动态调参)</li> | |
| <li><b>报告导出</b>:面向医/教/家三端的报告</li> | |
| </ol> | |
| <button id="demoBtn">🚀 一键加载演示档案(快速体验)</button> | |
| <button class="ghost" id="resetBtn">🧹 清空并重新开始</button> | |
| <p class="muted" id="homeStatus">尚未生成画像,请先完成筛查与评估,或点击一键演示。</p> | |
| </div> | |
| </div> | |
| <!-- AI 筛查 --> | |
| <div class="page" id="screen"> | |
| <div class="card"> | |
| <h2>AI 筛查(家长/教师版)</h2> | |
| <p class="muted">请按孩子近一个月的真实表现评分:1=从不,5=总是</p> | |
| <div id="screenItems"></div> | |
| <button id="saveScreen">保存筛查结果</button> | |
| <div id="screenOut" class="muted"></div> | |
| </div> | |
| </div> | |
| <!-- 能力评估 --> | |
| <div class="page" id="assess"> | |
| <div class="card"> | |
| <h2>能力评估(自研分测验)</h2> | |
| <p class="muted">完成以下任务,系统将计算分测验 → 组合分标准分(均值100 / 标准差15)。</p> | |
| <details open><summary>📖 阅读理解</summary> | |
| <p id="rcPassage" class="muted"></p> | |
| <div id="rcQuestions"></div> | |
| </details> | |
| <details open><summary>🔢 数学计算</summary> | |
| <div id="mcQuestions"></div> | |
| </details> | |
| <details open><summary>🧩 数学应用</summary> | |
| <div id="maQuestions"></div> | |
| </details> | |
| <details open><summary>🔤 词汇</summary> | |
| <div id="vocQuestions"></div> | |
| </details> | |
| <details open><summary>✏️ 句子结构</summary> | |
| <div id="sentQuestions"></div> | |
| </details> | |
| <details><summary>🔡 字词识读(自评)</summary> | |
| <label>能流利识读以下 16 个字的数量:<span id="wrVal">12</span></label> | |
| <input type="range" id="wordReading" min="0" max="16" value="12" /> | |
| <p class="muted" id="wrChars"></p> | |
| </details> | |
| <details><summary>✍️ 书写流畅(自评)</summary> | |
| <label>抄写参考句耗时(秒)</label> | |
| <input type="number" id="writtenSec" value="45" /> | |
| <p class="muted" id="wfPrompt"></p> | |
| </details> | |
| <details><summary>🟥 Stroop 抑制控制(自评)</summary> | |
| <p class="muted" id="stroopDemo"></p> | |
| <label>正确点击数 (0-10):<span id="scVal">8</span></label> | |
| <input type="range" id="stroopCorrect" min="0" max="10" value="8" /> | |
| <label>平均反应时 (ms)</label> | |
| <input type="number" id="stroopRt" value="900" /> | |
| </details> | |
| <details><summary>🎯 CPT 持续注意(自评)</summary> | |
| <p class="muted" id="cptDemo"></p> | |
| <label>漏点 X 的次数 (0-4):<span id="coVal">1</span></label> | |
| <input type="range" id="cptOmis" min="0" max="4" value="1" /> | |
| <label>误点非 X 的次数 (0-10):<span id="ccVal">1</span></label> | |
| <input type="range" id="cptComm" min="0" max="10" value="1" /> | |
| </details> | |
| <button id="submitAssess">📊 提交并生成能力画像</button> | |
| <div id="assessOut"></div> | |
| </div> | |
| </div> | |
| <!-- 数字孪生 --> | |
| <div class="page" id="twin"> | |
| <div class="card"> | |
| <h2>学习数字孪生 (Learning Digital Twin)</h2> | |
| <label><input type="checkbox" id="intervene" checked /> 已启动自适应干预(影响未来斜率)</label> | |
| <div class="row"> | |
| <div><div id="radar" class="plot"></div></div> | |
| <div><div id="timeline" class="plot"></div></div> | |
| </div> | |
| <button id="refreshTwin">🔄 刷新数字孪生</button> | |
| <p class="muted" id="twinHint"></p> | |
| </div> | |
| </div> | |
| <!-- 智能解释 --> | |
| <div class="page" id="explain"> | |
| <div class="card"> | |
| <h2>智能解释 · LearningGPT(可解释 AI)</h2> | |
| <div id="exSummary"></div> | |
| <hr/> | |
| <label>向 LearningGPT 提问(如:为什么孩子阅读理解下降?)</label> | |
| <textarea id="exQuestion" rows="2" placeholder="输入您关心的问题…"></textarea> | |
| <button id="askBtn">💡 获取解释</button> | |
| <div id="exAnswer" style="margin-top:10px"></div> | |
| </div> | |
| </div> | |
| <!-- 个性化干预 --> | |
| <div class="page" id="intervene"> | |
| <div class="card"> | |
| <h2>个性化干预(自适应干预引擎)</h2> | |
| <button id="ivBtn">🔄 生成/刷新干预方案</button> | |
| <div id="ivPlan" style="margin-top:10px"></div> | |
| </div> | |
| </div> | |
| <!-- 报告导出 --> | |
| <div class="page" id="report"> | |
| <div class="card"> | |
| <h2>报告导出(医/教/家三端)</h2> | |
| <button id="rpBtn">📄 生成报告</button> | |
| <button class="ghost" id="rpDownload">⬇️ 下载报告 (.md)</button> | |
| <button class="ghost" id="rpPrint">🖨️ 打印 / 另存 PDF</button> | |
| <div id="rpMD" style="margin-top:12px"></div> | |
| </div> | |
| </div> | |
| <script> | |
| /* ===================== 数据与常模(自研原创演示) ===================== */ | |
| const SS_MEAN=100, SS_SD=15, SCALED_MEAN=10, SCALED_SD=3; | |
| const AGE_BANDS=["4-6岁(幼小衔接)","7-9岁(小学低段)","10-12岁(小学高段)","13-15岁(初中)"]; | |
| const DIMENSIONS=[ | |
| ["info","基础信息",false],["neuro","神经发育",true],["cognitive","认知能力",true], | |
| ["language","语言沟通",true],["reading","阅读素养",true],["math","数学计算",true], | |
| ["executive","执行功能",true],["family","家庭环境",false],["school","学校表现",false], | |
| ["ai_history","AI训练历史",false] | |
| ]; | |
| const COMPOSITES={ | |
| reading:{name:"阅读素养 (Reading)",subtests:["word_reading","reading_comp"]}, | |
| math:{name:"数学能力 (Math)",subtests:["math_calc","math_applied"]}, | |
| written:{name:"书写表达 (Written)",subtests:["written_fluency"]}, | |
| oral:{name:"口头语言 (Oral Language)",subtests:["vocabulary","sentence"]}, | |
| executive:{name:"执行功能/注意力 (Executive)",subtests:["stroop","cpt"]} | |
| }; | |
| const ITEMS={ | |
| reading_comp:{ | |
| passage:"小猫和小狗是好朋友。一天,它们一起去公园玩球。小狗把球抛得很高,小猫跳起来接住了。回家的路上,下起了小雨,它们躲进树叶下,开心地笑了。", | |
| questions:[ | |
| {q:"谁把球抛得很高?",options:["小猫","小狗","小鸟"],answer:1}, | |
| {q:"它们为什么躲起来?",options:["累了","下雨了","天黑了"],answer:1}, | |
| {q:"这个故事主要讲什么?",options:["两个朋友玩耍","下雨天真好","接球比赛"],answer:0} | |
| ]}, | |
| math_calc:{problems:[ | |
| {q:"12 + 7 = ?",answer:19},{q:"35 - 18 = ?",answer:17},{q:"6 × 8 = ?",answer:48}, | |
| {q:"72 ÷ 9 = ?",answer:8},{q:"45 + 29 = ?",answer:74}]}, | |
| math_applied:{questions:[ | |
| {q:"小明有8颗糖,妈妈又给了5颗,他现在有几颗?",options:["12","13","14"],answer:1}, | |
| {q:"一盒铅笔有12支,平均分给3个同学,每人几支?",options:["3","4","6"],answer:1}]}, | |
| vocabulary:{questions:[ | |
| {q:"「迅速」的意思最接近?",options:["快速","缓慢","安静"],answer:0}, | |
| {q:"「美丽」的意思最接近?",options:["好看","难看","高大"],answer:0}, | |
| {q:"「寒冷」的意思最接近?",options:["冷","热","甜"],answer:0}, | |
| {q:"「巨大」的意思最接近?",options:["大","小","轻"],answer:0}]}, | |
| sentence:{questions:[ | |
| {q:"下列哪个句子语序正确?",options:["我吃饭了","饭吃了我","吃了饭我"],answer:0}, | |
| {q:"「因为…所以…」使用正确的是?",options:["因为下雨,所以比赛取消","因为比赛取消,所以下雨","下雨因为,所以取消"],answer:0}, | |
| {q:"量词使用正确的是?",options:["一只猫","一条猫","一个猫"],answer:0}]}, | |
| word_reading:{chars:["蝴","蝶","螃","蟹","蘑","菇","蜻","蜓","鸬","鹚","鼹","鼠","蜈","蚣","蝙","蝠"]}, | |
| written_fluency:{prompt:"今天天气真好,我们去公园放风筝。",ref:16}, | |
| stroop:{stimuli:[["红","绿"],["蓝","红"],["绿","蓝"],["黄","红"],["红","蓝"],["绿","黄"],["蓝","绿"],["黄","绿"],["红","黄"],["绿","红"]],colors:["红","绿","蓝","黄"]}, | |
| cpt:{sequence:["K","J","F","X","L","S","D","X","P","A","X","M","R","T","X","B","N","X","C","V"],target:"X"} | |
| }; | |
| const SCREENING=[ | |
| {q:"写作业时容易分心、走神",domain:"attention"}, | |
| {q:"阅读时经常跳行、漏字或重复读",domain:"reading"}, | |
| {q:"记不住多步口头指令",domain:"executive"}, | |
| {q:"完成功课极慢,明显超出同龄人",domain:"speed"}, | |
| {q:"数学计算常因粗心出错",domain:"math"}, | |
| {q:"字迹潦草、握笔姿势别扭",domain:"written"}, | |
| {q:"遇到挫折容易情绪波动",domain:"emotion"}, | |
| {q:"与同伴交往存在困难",domain:"social"} | |
| ]; | |
| const SCREEN_DOMAINS=["attention","reading","executive","speed","math","written","emotion","social"]; | |
| const DOMAIN_CN={attention:"注意力",reading:"阅读",executive:"执行功能",speed:"加工速度",math:"数学",written:"书写",emotion:"情绪",social:"社交"}; | |
| const FACTOR_MAP={ | |
| reading:{low_word_high_comp:["工作记忆负载 (Working Memory Load)","字词识读尚可但阅读理解偏弱,提示信息保持与整合环节负载阶段性超载,而非识字能力本身倒退。"], | |
| general:["阅读流畅性与解码效率","阅读相关分测验整体处于临界区间,建议优先排查视觉-语音转换与眼动回视模式。"]}, | |
| math:["计算策略表型与程序性知识","数学分测验偏低,常见瓶颈为计算策略固化与工作记忆在多位运算中的负载。"], | |
| written:["精细动作与加工速度","书写流畅性偏弱,通常与手部精细动作协调及视觉-动作整合速度相关。"], | |
| oral:["词汇提取与句法工作记忆","口头语言分测验反映词汇量与句法工作记忆,偏低时影响课堂理解与表达。"], | |
| executive:["抑制控制与持续注意","执行功能/注意力分测验提示抑制控制或持续注意存在波动,易表现为分心与冲动。"] | |
| }; | |
| const MODULE_CATALOG={ | |
| "工作记忆负载 (Working Memory Load)":{module:"工作记忆双任务训练",modality:"Child APP · 游戏化(数字广度+视觉矩阵)",freq:"每周 4 次",dur:"每次 12 分钟",goal:"提升信息保持与整合容量,缓解阅读理解加工瓶颈"}, | |
| "阅读流畅性与解码效率":{module:"眼动-语音整合训练",modality:"Child APP · 眼动追踪+跟读",freq:"每周 5 次",dur:"每次 10 分钟",goal:"降低回视概率、提升阅读流畅性"}, | |
| "计算策略表型与程序性知识":{module:"计算策略多样化训练",modality:"Child APP · 分步解题+策略提示",freq:"每周 4 次",dur:"每次 15 分钟",goal:"丰富计算策略、降低程序性错误"}, | |
| "精细动作与加工速度":{module:"书写自动化训练",modality:"Child APP · 压感笔迹+抄写节奏",freq:"每周 3 次",dur:"每次 10 分钟",goal:"提升书写速率与视觉-动作整合"}, | |
| "词汇提取与句法工作记忆":{module:"语义网络拓展训练",modality:"Child APP · 词汇联想+造句",freq:"每周 3 次",dur:"每次 12 分钟",goal:"扩充词汇量与句法工作记忆"}, | |
| "抑制控制与持续注意":{module:"Go/No-Go 与持续注意训练",modality:"Child APP · 反应抑制+信号检测",freq:"每周 5 次",dur:"每次 8 分钟",goal:"提升抑制控制与持续注意力时长"} | |
| }; | |
| /* ===================== 工具函数 ===================== */ | |
| const clamp=(v,lo=1,hi=19)=>Math.max(lo,Math.min(hi,v)); | |
| function classifySS(ss){if(ss>=115)return"高于平均";if(ss>=85)return"平均水平";if(ss>=70)return"临界偏低";return"显著偏低";} | |
| function scaledFromCorrect(correct,total){if(total<=0)return 10;const center=total/2;return clamp(Math.round(SCALED_MEAN+(correct-center)/center*SCALED_SD));} | |
| function compositeSS(list){if(!list.length)return 100;const avg=list.reduce((a,b)=>a+b,0)/list.length;return Math.round(SS_MEAN+(avg-SCALED_MEAN)*(SS_SD/SCALED_SD));} | |
| function readingFactor(profile){ | |
| const sub=profile.sub_scaled||{};const wr=sub.word_reading,rc=sub.reading_comp;const rd=FACTOR_MAP.reading; | |
| if(wr!=null&&rc!=null&&wr-rc>=2)return rd.low_word_high_comp;return rd.general; | |
| } | |
| function factorOf(key,profile){ | |
| const f=FACTOR_MAP[key]; | |
| if(Array.isArray(f))return f; | |
| if(f&&typeof f==="object")return readingFactor(profile); | |
| return ["待评估因素",""]; | |
| } | |
| /* ===================== 状态 ===================== */ | |
| let state={profile:null,screening:{},meta:{name:"待测儿童",age_band:AGE_BANDS[1]}}; | |
| /* ===================== 页面切换 ===================== */ | |
| document.querySelectorAll('.tab').forEach(t=>t.onclick=()=>{ | |
| document.querySelectorAll('.tab').forEach(x=>x.classList.remove('active')); | |
| document.querySelectorAll('.page').forEach(x=>x.classList.remove('active')); | |
| t.classList.add('active'); | |
| document.getElementById(t.dataset.t).classList.add('active'); | |
| if(t.dataset.t==="twin")refreshTwin(); | |
| }); | |
| /* ===================== 构建评估 UI ===================== */ | |
| function buildAssessUI(){ | |
| document.getElementById('rcPassage').textContent="短文:"+ITEMS.reading_comp.passage; | |
| const rc=document.getElementById('rcQuestions'); | |
| ITEMS.reading_comp.questions.forEach((q,i)=>{ | |
| rc.appendChild(qCard(`阅读 ${i+1}. ${q.q}`,q.options,`rc${i}`)); | |
| }); | |
| const mc=document.getElementById('mcQuestions'); | |
| ITEMS.math_calc.problems.forEach((p,i)=>{ | |
| const d=document.createElement('div');d.className='qcard'; | |
| d.innerHTML=`<label>计算 ${i+1}. ${p.q}</label><input type="number" id="mc${i}" />`; | |
| mc.appendChild(d); | |
| }); | |
| const ma=document.getElementById('maQuestions'); | |
| ITEMS.math_applied.questions.forEach((q,i)=>ma.appendChild(qCard(`应用 ${i+1}. ${q.q}`,q.options,`ma${i}`))); | |
| const voc=document.getElementById('vocQuestions'); | |
| ITEMS.vocabulary.questions.forEach((q,i)=>voc.appendChild(qCard(`词汇 ${i+1}. ${q.q}`,q.options,`voc${i}`))); | |
| const sent=document.getElementById('sentQuestions'); | |
| ITEMS.sentence.questions.forEach((q,i)=>sent.appendChild(qCard(`句子 ${i+1}. ${q.q}`,q.options,`sent${i}`))); | |
| document.getElementById('wrChars').textContent="演示字表:"+ITEMS.word_reading.chars.join("、"); | |
| document.getElementById('wfPrompt').textContent="参考句:"+ITEMS.written_fluency.prompt; | |
| document.getElementById('stroopDemo').textContent="演示刺激(字≠墨色),需点击墨色:"+ | |
| ITEMS.stroop.stimuli.map(s=>`${s[0]}(墨:${s[1]})`).join("、"); | |
| document.getElementById('cptDemo').textContent="刺激序列(出现 X 需点击):"+ITEMS.cpt.sequence.join(" "); | |
| // 滑块实时数值 | |
| bindRange('wordReading','wrVal');bindRange('stroopCorrect','scVal'); | |
| bindRange('cptOmis','coVal');bindRange('cptComm','ccVal'); | |
| } | |
| function qCard(title,options,name){ | |
| const d=document.createElement('div');d.className='qcard'; | |
| let html=`<label>${title}</label><div class="opt">`; | |
| options.forEach((o,i)=>{html+=`<label><input type="radio" name="${name}" value="${i}"><span>${o}</span></label>`;}); | |
| html+='</div>';d.innerHTML=html;return d; | |
| } | |
| function bindRange(id,lab){const el=document.getElementById(id);el.oninput=()=>document.getElementById(lab).textContent=el.value;} | |
| /* ===================== 筛查 UI ===================== */ | |
| function buildScreenUI(){ | |
| const box=document.getElementById('screenItems'); | |
| SCREENING.forEach((it,i)=>{ | |
| const d=document.createElement('div');d.className='qcard'; | |
| let opts='';for(let v=1;v<=5;v++)opts+=`<label><input type="radio" name="scr${i}" value="${v}" ${v===3?'checked':''}><span>${v}</span></label>`; | |
| d.innerHTML=`<label>${i+1}. ${it.q}</label><div class="opt">${opts}</div>`; | |
| box.appendChild(d); | |
| }); | |
| } | |
| /* ===================== 评分 ===================== */ | |
| function getRadio(name){const el=document.querySelector(`input[name="${name}"]:checked`);return el?parseInt(el.value):null;} | |
| function scoreScreening(){ | |
| const ratings={}; | |
| SCREENING.forEach((it,i)=>{const v=getRadio(`scr${i}`);if(v)ratings[it.domain]=ratings[it.domain]||[];if(v)ratings[it.domain].push(v);}); | |
| const out={}; | |
| SCREEN_DOMAINS.forEach(dom=>{const vals=ratings[dom]||[];const avg=vals.length?vals.reduce((a,b)=>a+b,0)/vals.length:0;out[dom]={avg:Math.round(avg*100)/100,flag:avg>=4};}); | |
| return out; | |
| } | |
| function buildProfile(responses){ | |
| const sub={}; | |
| // 阅读 | |
| const rcA=ITEMS.reading_comp.questions.map(q=>q.answer); | |
| sub.reading_comp=scaledFromCorrect(rcA.filter((a,i)=>a===responses.rc[i]).length,rcA.length); | |
| sub.word_reading=scaledFromCorrect(responses.wordReading,16); | |
| // 数学 | |
| const mcA=ITEMS.math_calc.problems.map(p=>String(p.answer)); | |
| const mcCorrect=mcA.filter((a,i)=>String(responses.mc[i])===a).length; | |
| let sCalc=scaledFromCorrect(mcCorrect,5); | |
| const per=responses.mcTime/5;if(per<4)sCalc=clamp(sCalc+1);else if(per>9)sCalc=clamp(sCalc-1); | |
| sub.math_calc=sCalc; | |
| const maA=ITEMS.math_applied.questions.map(q=>q.answer); | |
| sub.math_applied=scaledFromCorrect(maA.filter((a,i)=>a===responses.ma[i]).length,maA.length); | |
| // 词汇/句子 | |
| const vocA=ITEMS.vocabulary.questions.map(q=>q.answer); | |
| sub.vocabulary=scaledFromCorrect(vocA.filter((a,i)=>a===responses.voc[i]).length,vocA.length); | |
| const sentA=ITEMS.sentence.questions.map(q=>q.answer); | |
| sub.sentence=scaledFromCorrect(sentA.filter((a,i)=>a===responses.sent[i]).length,sentA.length); | |
| // 书写 | |
| const elapsed=responses.writtenSec||45;const cpm=16/(elapsed/60); | |
| sub.written_fluency=clamp(Math.round(SCALED_MEAN+(cpm-22)/22*SCALED_SD*3)); | |
| // Stroop / CPT | |
| sub.stroop=clamp(13-responses.stroopErrors*2-(responses.stroopRt>1500?1:0)); | |
| sub.cpt=clamp(13-(responses.cptOmis+responses.cptComm)*2); | |
| const composites={}; | |
| for(const k in COMPOSITES){const scales=COMPOSITES[k].subtests.map(s=>sub[s]);const ss=compositeSS(scales); | |
| composites[k]={name:COMPOSITES[k].name,ss,level:classifySS(ss),subtests:Object.fromEntries(COMPOSITES[k].subtests.map(s=>[s,sub[s]]))};} | |
| const dim={};DIMENSIONS.forEach(d=>dim[d[0]]=null); | |
| dim.reading=composites.reading.ss;dim.math=composites.math.ss;dim.language=composites.oral.ss; | |
| dim.executive=composites.executive.ss;dim.cognitive=Math.round((composites.written.ss+composites.executive.ss)/2); | |
| dim.neuro=dim.cognitive;dim.family=72;dim.school=68;dim.ai_history=25;dim.info=100; | |
| return {meta:state.meta,sub_scaled:sub,composites,dim_scores:dim,screening:state.screening}; | |
| } | |
| function demoProfile(){ | |
| const base={reading:78,math:96,written:92,oral:104,executive:88}; | |
| const composites={}; | |
| for(const k in base){const ss=Math.max(60,Math.min(130,base[k]+(Math.random()*12-6)|0));composites[k]={name:COMPOSITES[k].name,ss,level:classifySS(ss)};} | |
| const dim={};DIMENSIONS.forEach(d=>dim[d[0]]=null); | |
| dim.reading=composites.reading.ss;dim.math=composites.math.ss;dim.language=composites.oral.ss; | |
| dim.executive=composites.executive.ss;dim.cognitive=composites.written.ss;dim.neuro=composites.written.ss; | |
| dim.family=72;dim.school=68;dim.ai_history=25;dim.info=100; | |
| const scr={};SCREEN_DOMAINS.forEach(d=>{const avg=Math.round((2+Math.random()*2.6)*100)/100;scr[d]={avg,flag:avg>=4};}); | |
| scr.reading={avg:4.3,flag:true};scr.attention={avg:4.1,flag:true}; | |
| return {meta:{name:"演示儿童",age_band:AGE_BANDS[1],demo:true},sub_scaled:{},composites,dim_scores:dim,screening:scr}; | |
| } | |
| /* ===================== 数字孪生 ===================== */ | |
| function ssToIndex(ss){return Math.max(0,Math.min(100,(ss-60)/(130-60)*100));} | |
| function normalizedDims(p){const d=p.dim_scores||{};const o={};DIMENSIONS.forEach(([k,_,ab])=>{const v=d[k];if(v==null){o[k]=50;return;}o[k]=ab?ssToIndex(v):Math.max(0,Math.min(100,v));});return o;} | |
| function refreshTwin(){ | |
| if(!state.profile||!state.profile.composites){document.getElementById('twinHint').textContent="请先生成能力画像(评估页或一键演示)。";return;} | |
| const nd=normalizedDims(state.profile); | |
| const labels=DIMENSIONS.map(d=>d[1]);const vals=DIMENSIONS.map(d=>nd[d[0]]); | |
| Plotly.newPlot('radar',[{type:'scatterpolar',r:[...vals,vals[0]],theta:[...labels,labels[0]],fill:'toself', | |
| name:'当前能力画像',line:{color:'#2E86DE'},fillcolor:'rgba(46,134,222,0.25)'}, | |
| {type:'scatterpolar',r:Array(labels.length+1).fill(65),theta:[...labels,labels[0]],name:'同龄参考',line:{color:'#888',dash:'dot'}}], | |
| {polar:{radialaxis:{visible:true,range:[0,100]}},showlegend:true,height:430, | |
| margin:{l:40,r:40,t:30,b:30},legend:{orientation:'h',y:-0.15}}); | |
| // 时间轴 | |
| const intervene=document.getElementById('intervene').checked; | |
| const abilityKeys=DIMENSIONS.filter(d=>d[2]).map(d=>d[0]); | |
| const base=abilityKeys.reduce((a,k)=>a+nd[k],0)/abilityKeys.length; | |
| const scr=state.profile.screening||{};const readingFlag=scr.reading&&scr.reading.flag; | |
| const aiHist=state.profile.dim_scores.ai_history||25; | |
| let drift=0.15;if(aiHist>=40)drift+=0.25;if(readingFlag&&!intervene)drift-=0.35;if(intervene)drift+=0.45; | |
| const past=[];let val=base;for(let i=12;i>0;i--){val+=0.2+(Math.random()*2-1)*1.2;past.push(Math.round(val*10)/10);} | |
| const future=[];val=base;for(let i=1;i<=26;i++){val+=drift+(Math.random()*2-1)*0.6;future.push(Math.max(0,Math.min(100,val)));} | |
| const weeks=[];for(let i=-12;i<0;i++)weeks.push(i);weeks.push(0);for(let i=1;i<=26;i++)weeks.push(i); | |
| const series=[...past,base,...future];const upper=[],lower=[]; | |
| weeks.forEach(w=>{const band=w<=0?1.5:1.5+w*0.25;upper.push(Math.min(100,series[weeks.indexOf(w)]+band));lower.push(Math.max(0,series[weeks.indexOf(w)]-band));}); | |
| const traces=[ | |
| {x:weeks,y:upper,mode:'lines',line:{width:0},showlegend:false,hoverinfo:'skip'}, | |
| {x:weeks,y:lower,mode:'lines',line:{width:0},fill:'tonexty',fillcolor:'rgba(46,134,222,0.15)',name:'不确定区间',hoverinfo:'skip'} | |
| ]; | |
| weeks.forEach((w,i)=>{const phase=w<0?'历史':(w===0?'当前':'预测');if(!traces.find(t=>t.name===phase))traces.push({x:[weeks[i]],y:[series[i]],mode:'lines+markers',name:phase,line:{color:{历史:'#95A5A6',当前:'#E74C3C',预测:'#2E86DE'}[phase],width:3},marker:{size:5}});else{const t=traces.find(t=>t.name===phase);t.x.push(weeks[i]);t.y.push(series[i]);}}); | |
| Plotly.newPlot('timeline',traces,{title:`学习成长时间轴 · 6个月预测斜率≈${drift>=0?'+':''}${drift.toFixed(2)}/周${intervene?' · 已启动自适应干预':' · 未干预'}`, | |
| xaxis:{title:'周(负数=过去,正数=未来)'},yaxis:{title:'综合能力指数',range:[0,100]},height:430, | |
| legend:{orientation:'h',y:-0.25},margin:{l:40,r:40,t:50,b:40}}); | |
| document.getElementById('twinHint').textContent="数字孪生已更新。"; | |
| } | |
| /* ===================== 解释 ===================== */ | |
| function analyze(p){ | |
| const comps=p.composites||{};const scr=p.screening||{};const findings=[];const risks=[];const strengths=[]; | |
| for(const k in comps){const c=comps[k];if(c.ss<85){const[fname,fdesc]=factorOf(k,p);findings.push({dimension:c.name,ss:c.ss,level:c.level,factor:fname,detail:fdesc});risks.push(c.name);}else if(c.ss>=110)strengths.push(c.name);} | |
| const flags=SCREEN_DOMAINS.filter(d=>scr[d]&&scr[d].flag).map(d=>DOMAIN_CN[d]); | |
| const n=findings.length; | |
| const overall=n===0?"当前各项能力处于平均水平或更高,未见明显偏低组合分,建议保持规律随访与能力拓展。":`共发现 ${n} 项能力组合分处于临界/显著偏低区间,主要关注:${risks.join("、")}。`; | |
| let summary=`【总体结论】${overall}\n\n【能力组合分】\n`; | |
| for(const k in comps)summary+=`· ${comps[k].name}:标准分 ${comps[k].ss}(${comps[k].level})\n`; | |
| summary+=`\n【筛查预警】${flags.length?'存在:'+flags.join("、"):'无明显预警信号'}\n`; | |
| summary+=`【相对优势】${strengths.length?strengths.join("、"):'暂未显现明显优势项'}`; | |
| return {overall,findings,risks,strengths,flags,summary}; | |
| } | |
| function explainQuestion(p,q){ | |
| if(!q)return "请输入您关心的问题。"; | |
| const a=analyze(p);const comps=p.composites||{};let target=null; | |
| if(/阅读|理解|识字|读书/.test(q))target="reading"; | |
| else if(/数学|计算|应用题/.test(q))target="math"; | |
| else if(/写字|书写|字迹|握笔/.test(q))target="written"; | |
| else if(/注意|分心|专注|走神|冲动/.test(q))target="executive"; | |
| else if(/语言|表达|说话|词汇/.test(q))target="oral"; | |
| if(!target)return "我结合孩子的多模态能力画像为您解读:\n\n"+a.overall+"\n\n您可以就具体维度继续追问,例如:「为什么孩子阅读理解下降?」「数学计算总粗心怎么办?」「注意力为什么不持久?」"; | |
| const c=comps[target]||{};const[fname,fdesc]=factorOf(target,p); | |
| return `关于您提到的「${COMPOSITES[target].name}」问题:\n\n系统追踪到该维度标准分为 **${c.ss}(${c.level})**。\n底层认知因素指向 **${fname}**:${fdesc}\n\n💡 建议:基于上述机制,可优先安排针对性的认知训练模块(如工作记忆/抑制控制/加工速度训练),并在家庭端降低任务时长、提升即时反馈频率,使孩子始终处于最优学习发展区(ZPD)。`; | |
| } | |
| /* ===================== 干预 ===================== */ | |
| function recommend(p){ | |
| const a=analyze(p);const aiHist=(p.dim_scores||{}).ai_history||25;const mods=[];const seen=new Set(); | |
| a.findings.forEach(f=>{const factor=f.factor;if(MODULE_CATALOG[factor]&&!seen.has(factor)){seen.add(factor);const m={...MODULE_CATALOG[factor]}; | |
| if(aiHist>=40)m.adapt="既往完成度高,初始难度上调一档,步进更快"; | |
| else if(aiHist<20)m.adapt="训练史较短,从基础档起步,强化即时反馈与激励"; | |
| else m.adapt="维持标准难度曲线,按实时表现动态变频"; | |
| m.target=f.dimension;mods.push(m);}}); | |
| if(!mods.length)mods.push({module:"能力拓展与预防训练",modality:"Child APP · 综合游戏化挑战",freq:"每周 2 次",dur:"每次 10 分钟",goal:"巩固优势、预防能力滑坡",adapt:"无显著风险,维持拓展性训练",target:"综合"}); | |
| return mods; | |
| } | |
| function planHTML(p){ | |
| const mods=recommend(p);let h='<h3>个性化干预方案(自适应)</h3>'; | |
| mods.forEach((m,i)=>{h+=`<p><b>${i+1}. ${m.module}</b> → 目标维度:${m.target}</p> | |
| <p class="muted">干预形态:${m.modality} | 频次/时长:${m.freq} · ${m.dur}</p> | |
| <p class="muted">训练目标:${m.goal}</p><p class="muted">自适应策略:${m.adapt}</p>`;}); | |
| return h; | |
| } | |
| /* ===================== 报告 ===================== */ | |
| function genMarkdown(p){ | |
| const meta=p.meta||{};const a=analyze(p);const d=p.dim_scores||{};const scr=p.screening||{}; | |
| let md=`# 儿童学习能力评估与干预报告(LearningOS V3.0 原型)\n\n`; | |
| md+=`## 一、基本信息\n- 姓名/代号:${meta.name||'—'}\n- 年龄段:${meta.age_band||'—'}\n- 报告性质:演示原型(非诊断)\n\n`; | |
| md+=`## 二、能力组合分(Subtests → Composites)\n| 组合分 | 标准分 | 等级 |\n| --- | --- | --- |\n`; | |
| for(const k in p.composites)md+=`| ${p.composites[k].name} | ${p.composites[k].ss} | ${p.composites[k].level} |\n`; | |
| md+=`\n## 三、学习数字孪生 · 十维画像\n| 维度 | 指数/分值 |\n| --- | --- |\n`; | |
| DIMENSIONS.forEach(dm=>md+=`| ${dm[1]} | ${d[dm[0]]??'—'} |\n`); | |
| md+=`\n## 四、AI 筛查预警\n| 维度 | 平均分(1-5) | 状态 |\n| --- | --- | --- |\n`; | |
| SCREEN_DOMAINS.forEach(dom=>{const v=scr[dom];md+=`| ${DOMAIN_CN[dom]} | ${v?v.avg:'—'} | ${v&&v.flag?'⚠️ 预警':'正常'} |\n`;}); | |
| md+=`\n## 五、智能解释(LearningGPT)\n${a.summary}\n\n## 六、个性化干预方案\n`; | |
| recommend(p).forEach((m,i)=>{md+=`### ${i+1}. ${m.module} → ${m.target}\n- 形态:${m.modality}\n- 频次/时长:${m.freq} · ${m.dur}\n- 目标:${m.goal}\n- 自适应:${m.adapt}\n`;}); | |
| md+=`\n---\n> ⚠️ 本报告显示范性原型输出,所用题目、常模与算法均为平台自研演示内容,不构成任何临床诊断或教育鉴定结论。WIAT-III/WISC-V 仅作为维度设计的学术参考框架。`; | |
| return md; | |
| } | |
| /* ===================== 事件绑定 ===================== */ | |
| function syncAll(p,statusText){ | |
| if(!p||!p.composites){document.getElementById('twinHint').textContent="请先生成能力画像。"; | |
| document.getElementById('exSummary').textContent="请先生成能力画像。";document.getElementById('ivPlan').textContent="请先生成能力画像。";return;} | |
| document.getElementById('exSummary').textContent=analyze(p).summary; | |
| document.getElementById('ivPlan').innerHTML=planHTML(p);refreshTwin(); | |
| } | |
| document.getElementById('demoBtn').onclick=()=>{state.profile=demoProfile();document.getElementById('homeStatus').textContent="✅ 已加载演示档案,请前往『学习数字孪生 / 智能解释 / 个性化干预 / 报告导出』查看。";syncAll(state.profile);}; | |
| document.getElementById('resetBtn').onclick=()=>{state.profile=null;document.getElementById('homeStatus').textContent="已清空,请重新评估。";syncAll(null);}; | |
| document.getElementById('saveScreen').onclick=()=>{state.screening=scoreScreening();let h='<h3>筛查结果</h3>';SCREEN_DOMAINS.forEach(d=>{const v=state.screening[d];h+=`<p>${DOMAIN_CN[d]}:均分 ${v.avg} → ${v.flag?'<span class="warn">⚠️ 预警</span>':'<span class="ok">✅ 正常</span>'}</p>`;});document.getElementById('screenOut').innerHTML=h;}; | |
| document.getElementById('submitAssess').onclick=()=>{ | |
| const responses={rc:ITEMS.reading_comp.questions.map((_,i)=>getRadio(`rc${i}`)), | |
| mc:ITEMS.math_calc.problems.map((_,i)=>document.getElementById(`mc${i}`).value),mcTime:30, | |
| ma:ITEMS.math_applied.questions.map((_,i)=>getRadio(`ma${i}`)), | |
| voc:ITEMS.vocabulary.questions.map((_,i)=>getRadio(`voc${i}`)), | |
| sent:ITEMS.sentence.questions.map((_,i)=>getRadio(`sent${i}`)), | |
| wordReading:parseInt(document.getElementById('wordReading').value), | |
| writtenSec:parseFloat(document.getElementById('writtenSec').value)||45, | |
| stroopErrors:10-parseInt(document.getElementById('stroopCorrect').value), | |
| stroopRt:parseFloat(document.getElementById('stroopRt').value)||900, | |
| cptOmis:parseInt(document.getElementById('cptOmis').value), | |
| cptComm:parseInt(document.getElementById('cptComm').value)}; | |
| state.profile=buildProfile(responses); | |
| let h='<h3>✅ 能力画像已生成(组合分标准分,均值100/标准差15)</h3><ul>'; | |
| for(const k in state.profile.composites)h+=`<li><b>${state.profile.composites[k].name}</b>:${state.profile.composites[k].ss}(${state.profile.composites[k].level})</li>`; | |
| h+='</ul>';document.getElementById('assessOut').innerHTML=h;syncAll(state.profile); | |
| }; | |
| document.getElementById('refreshTwin').onclick=refreshTwin; | |
| document.getElementById('askBtn').onclick=()=>{if(!state.profile){document.getElementById('exAnswer').textContent="请先生成能力画像再提问。";return;}document.getElementById('exAnswer').textContent=explainQuestion(state.profile,document.getElementById('exQuestion').value);}; | |
| document.getElementById('ivBtn').onclick=()=>{if(!state.profile){document.getElementById('ivPlan').textContent="请先生成能力画像。";return;}document.getElementById('ivPlan').innerHTML=planHTML(state.profile);}; | |
| let lastMD=""; | |
| document.getElementById('rpBtn').onclick=()=>{if(!state.profile){document.getElementById('rpMD').textContent="请先生成能力画像。";return;}lastMD=genMarkdown(state.profile);document.getElementById('rpMD').textContent=lastMD;}; | |
| document.getElementById('rpDownload').onclick=()=>{if(!lastMD)lastMD=genMarkdown(state.profile);const blob=new Blob([lastMD],{type:'text/markdown'});const a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download='LearningOS_报告.md';a.click();}; | |
| document.getElementById('rpPrint').onclick=()=>{const w=window.open();w.document.write('<pre>'+genMarkdown(state.profile).replace(/</g,'<')+'</pre>');w.document.close();w.print();}; | |
| /* ===================== 初始化 ===================== */ | |
| buildAssessUI();buildScreenUI(); | |
| </script> | |
| </body> | |
| </html> | |