@zhouchangui/math-ati 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.local.example +6 -0
- package/AGENTS.md +273 -0
- package/README.md +34 -0
- package/bin/math-ati.js +194 -0
- package/dist/assets/index-BYFoutza.js +22 -0
- package/dist/assets/index-Bk2WFPoL.css +1 -0
- package/dist/index.html +13 -0
- package/package.json +72 -0
- package/prompts/grading.system.md +129 -0
- package/prompts/knowledge-extract.system.md +123 -0
- package/prompts/knowledge-summarize.system.md +127 -0
- package/prompts/learning-summary.system.md +123 -0
- package/prompts/pdf-grading.system.md +80 -0
- package/prompts/pdf-page-extract.system.md +52 -0
- package/prompts/pdf-recheck.system.md +43 -0
- package/prompts/practice-generate.system.md +161 -0
- package/prompts/practice-review.system.md +65 -0
- package/prompts/practice-revise.system.md +56 -0
- package/server/abilityService.js +259 -0
- package/server/agentClient.js +202 -0
- package/server/env.js +4 -0
- package/server/fileStore.js +726 -0
- package/server/grading.js +116 -0
- package/server/index.js +655 -0
- package/server/jobStore.js +169 -0
- package/server/knowledgeBase.js +30 -0
- package/server/knowledgeExtractor.js +360 -0
- package/server/knowledgeFeedback.js +299 -0
- package/server/llmConfig.js +96 -0
- package/server/mistakeLifecycle.js +251 -0
- package/server/pdfSubmissionGrader.js +846 -0
- package/server/practiceGenerator.js +908 -0
- package/server/practicePaperHtml.js +313 -0
- package/server/practiceReviewer.js +307 -0
- package/server/practiceService.js +331 -0
- package/server/promptStore.js +16 -0
- package/server/submissionService.js +184 -0
- package/templates/workspace/.env.local.example +6 -0
- package/templates/workspace/data/global/ability_index.json +5 -0
- package/templates/workspace/data/global/chapters.json +621 -0
- package/templates/workspace/data/global/mastery_index.json +6 -0
- package/templates/workspace/data/global/mistakes_index.json +7 -0
- package/templates/workspace/data/global/student_profile.json +11 -0
- package/templates/workspace/data/knowledge_points.json +1264 -0
- package/templates/workspace/data/mistakes.json +1 -0
- package/vite.config.js +21 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
:root{color:#17201c;background:#eef2ef;font-family:Inter,PingFang SC,Microsoft YaHei,Arial,sans-serif;font-size:16px;--surface: #fffdf8;--surface-muted: #f5f7f2;--surface-cool: #edf4f0;--border: #d4ddd5;--border-strong: #b9c6be;--text-soft: #5f6c64;--text-muted: #738077;--green: #1f6455;--green-dark: #16483d;--green-soft: #dcece5;--rust: #91442f;--rust-soft: #f4ded1;--yellow-soft: #ece7bd;--danger: #872d23;--danger-soft: #f8d8d2}*{box-sizing:border-box}body{margin:0}button,input,textarea,select{font:inherit}button{min-height:38px;border:1px solid var(--border-strong);border-radius:6px;background:var(--surface);color:#17201c;padding:0 12px;display:inline-flex;align-items:center;justify-content:center;gap:8px;cursor:pointer;transition:background .14s ease,border-color .14s ease,color .14s ease,box-shadow .14s ease}.button-link,.entry-action-button{min-height:38px;border:1px solid var(--border-strong);border-radius:6px;color:#17201c;text-decoration:none;display:inline-flex;align-items:center;justify-content:center;gap:8px;padding:0 12px}button.primary{color:#fff;background:var(--green);border-color:var(--green)}button:hover:not(:disabled),.button-link:hover,.entry-action-button:hover{border-color:var(--green);background:var(--surface-cool)}button.primary:hover:not(:disabled){background:var(--green-dark);border-color:var(--green-dark)}button:focus-visible,.button-link:focus-visible,.entry-action-button:focus-visible,input:focus-visible,textarea:focus-visible,select:focus-visible{outline:2px solid rgba(31,100,85,.28);outline-offset:2px}button:disabled,input:disabled,textarea:disabled,select:disabled{opacity:.55;cursor:not-allowed}input,textarea,select{width:100%;border:1px solid var(--border-strong);border-radius:6px;background:#fff;color:#17201c;min-height:38px;padding:8px 10px}textarea{min-height:72px;resize:vertical}h1,h2,h3,h4,p{margin:0}h1{font-size:32px;line-height:1.15}h2{font-size:22px}h3{font-size:18px}h4{font-size:15px}.app-shell{max-width:1480px;margin:0 auto;padding:24px}.app-header{display:flex;justify-content:space-between;align-items:center;gap:18px;margin-bottom:18px}.app-title-button{min-height:0;border:0;background:transparent;padding:0;color:inherit;justify-content:flex-start;text-align:left}.app-title-button:hover:not(:disabled){background:transparent;color:var(--green)}.profile-open-button{flex:0 0 auto}.settings-menu-wrap{position:relative;flex:0 0 auto}.settings-menu{position:absolute;top:calc(100% + 8px);right:0;z-index:40;min-width:150px;display:grid;gap:4px;border:1px solid var(--border-strong);border-radius:8px;background:var(--surface);box-shadow:0 18px 42px #16221d2e;padding:6px}.settings-menu button{width:100%;justify-content:flex-start;border-color:transparent;background:transparent}.settings-menu button:hover{border-color:var(--border);background:var(--surface-cool)}.app-header p,.workflow-head p,.section-heading p,.card-note{color:var(--text-muted);margin-top:5px}.eyebrow{color:var(--rust);font-size:12px;text-transform:uppercase;letter-spacing:0;font-weight:700}.toast{background:var(--green-dark);color:#fff;border-radius:6px;padding:10px 12px;margin-bottom:14px}.workspace{display:grid;grid-template-columns:292px minmax(0,1fr);gap:18px;align-items:start}.nav-collapsed .workspace{grid-template-columns:64px minmax(0,1fr)}.chapter-nav{position:sticky;top:16px;height:calc(100vh - 48px);overflow:hidden;border:1px solid var(--border);border-radius:8px;background:var(--surface);display:flex;flex-direction:column;box-shadow:0 10px 24px #24312a0f}.chapter-nav-head{min-height:54px;padding:10px;border-bottom:1px solid var(--border);display:flex;align-items:center;justify-content:space-between;gap:8px}.chapter-nav-list{padding:8px;overflow:auto;display:grid;gap:5px}.chapter-nav-item{width:100%;justify-content:flex-start;min-height:42px;padding:6px 8px;background:transparent;border-color:transparent}.chapter-nav.collapsed .chapter-nav-head,.chapter-nav.collapsed .chapter-nav-item{justify-content:center}.chapter-nav-item.selected{border-color:var(--green);background:var(--green-soft)}.chapter-index{width:24px;flex:0 0 auto;color:var(--rust);font-weight:700;font-size:12px}.chapter-name{flex:1;min-width:0;text-align:left;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.chapter-status,.flow-status{flex:0 0 auto;border-radius:999px;background:#e4e9e2;color:#536057;padding:3px 8px;font-size:12px;white-space:nowrap}.chapter-status.in_progress,.flow-status.generated,.flow-status.previewed,.flow-status.printed,.flow-status.submitted,.flow-status.pdf_received{background:#f2d9c8;color:#7f3a23}.chapter-status.review_due,.flow-status.graded,.flow-status.needs_review{background:var(--yellow-soft);color:#645600}.chapter-status.mastered,.flow-status.archived{background:#cfe8da;color:var(--green)}.flow-status.failed,.flow-status.failed_generate,.flow-status.failed_grade{background:var(--danger-soft);color:var(--danger)}.flow-status.available{background:var(--green-soft);color:var(--green)}.flow-status.missing{background:#fff6d7;color:#7a5a0f}.flow-status.missing_source,.flow-status.unavailable{background:#e7ece8;color:var(--text-muted)}.icon-button{width:38px;padding:0}.chapter-workspace{min-width:0}.panel{background:var(--surface);border:1px solid var(--border);border-radius:8px;padding:18px;margin-bottom:16px;box-shadow:0 10px 24px #24312a0d}.chapter-summary{display:grid;grid-template-columns:minmax(250px,1fr) minmax(400px,1.2fr);gap:16px;align-items:end}.stats-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:10px}.stats-grid.compact{grid-template-columns:repeat(5,minmax(0,1fr))}.stat-tile{border:1px solid var(--border);border-radius:6px;background:var(--surface-muted);padding:12px}.stat-tile span{color:var(--text-muted);font-size:13px}.stat-tile strong{display:block;margin-top:6px;font-size:22px}.knowledge-map-panel{display:grid;gap:16px}.knowledge-map-head{display:flex;justify-content:space-between;gap:16px;align-items:start}.knowledge-view-tabs{display:inline-flex;gap:4px;padding:4px;border:1px solid var(--border);border-radius:8px;background:var(--surface-muted)}.knowledge-view-tabs button{min-height:34px;border-color:transparent;background:transparent;white-space:nowrap}.knowledge-view-tabs button.selected{color:var(--green);border-color:var(--green);background:#fff;font-weight:700}.knowledge-map-summary{display:flex;flex-wrap:wrap;gap:10px;color:var(--text-soft);font-size:13px}.knowledge-map-summary span{display:inline-flex;align-items:center;gap:6px}.knowledge-filter-group{display:inline-flex;gap:4px;padding:2px;border:1px solid var(--border);border-radius:999px;background:var(--surface-muted)}.knowledge-filter-group button{min-height:26px;border-radius:999px;border-color:transparent;background:transparent;padding:0 10px;font-size:12px}.knowledge-filter-group button.selected{color:#fff;background:var(--green);border-color:var(--green)}.legend-dot{width:10px;height:10px;border:1px solid var(--border-strong);border-radius:999px;background:#fff}.legend-dot.mastered{background:#bfe1cf;border-color:var(--green)}.legend-dot.needs_review{background:var(--yellow-soft);border-color:#c6b85d}.knowledge-wall{display:grid;grid-template-columns:repeat(auto-fill,minmax(210px,1fr));gap:10px}.knowledge-card{min-height:132px;display:grid;align-content:space-between;gap:10px;border:1px solid var(--border);border-radius:8px;padding:12px;background:#fff}.knowledge-card.mastered{border-color:#94bca8;background:#edf7f1}.knowledge-card.needs_review{border-color:#d7cb76;background:#fff9d9}.knowledge-card.uncovered{background:#fff}.knowledge-card strong{display:block;line-height:1.35}.knowledge-card span{color:var(--text-muted);font-size:12px}.knowledge-card p{color:var(--text-soft);font-size:13px;line-height:1.55}.knowledge-card-foot{display:flex;justify-content:space-between;gap:8px;align-items:center}.knowledge-card-foot small{color:var(--text-muted)}.knowledge-market-layout{display:block}.knowledge-market-board{position:relative;display:grid;grid-template-columns:repeat(auto-fill,minmax(82px,1fr));grid-auto-flow:dense;gap:1px;padding:4px;border:0;border-radius:8px;background:#20342e}.knowledge-market-tile{--tile-bg: #fffdf8;--tile-fg: #17201c;--tile-muted: #627167;position:relative;min-height:54px;display:grid;place-items:center;gap:2px;padding:6px;border-radius:3px;text-align:center;color:var(--tile-fg);background:var(--tile-bg);border:0;box-shadow:none}.knowledge-market-tile:hover:not(:disabled){z-index:40;background:var(--tile-bg);border-color:transparent;filter:brightness(.96)}.knowledge-market-tile:focus-visible{z-index:40;outline:2px solid rgba(31,100,85,.42);outline-offset:1px}.knowledge-market-tile strong{width:100%;font-size:12.5px;line-height:1.22;display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;overflow:hidden}.knowledge-hover-card span{color:var(--tile-muted);font-size:11px;line-height:1.1}.knowledge-market-tile.mastered{--tile-bg: #1f9d5b;--tile-fg: #ffffff;--tile-muted: rgba(255, 255, 255, .82)}.knowledge-market-tile.needs_review{--tile-bg: #f3dc61;--tile-fg: #17201c;--tile-muted: #5d612f}.knowledge-market-tile.review-low{--tile-bg: #f8e986;--tile-muted: #667044}.knowledge-market-tile.review-mid{--tile-bg: #efd347;--tile-muted: #5b5f2b}.knowledge-market-tile.review-high{--tile-bg: #d49a22;--tile-muted: #443a17}.knowledge-market-tile.uncovered{--tile-bg: #fffdf8;--tile-fg: #17201c;--tile-muted: #738077}.knowledge-hover-card{position:absolute;left:0;top:calc(100% + 6px);z-index:80;width:min(320px,70vw);display:none;gap:7px;border:1px solid var(--border-strong);border-radius:8px;background:#fffdf8;color:#17201c;box-shadow:0 18px 46px #16221d42;padding:12px;text-align:left}.knowledge-market-tile:hover .knowledge-hover-card,.knowledge-market-tile:focus-visible .knowledge-hover-card{display:grid}.knowledge-hover-card strong{font-size:15px;line-height:1.35;display:block}.knowledge-hover-card em{color:var(--text-soft);font-style:normal;font-size:13px;line-height:1.55}.knowledge-hover-card>span{color:var(--text-muted);font-size:12px}.knowledge-image-board{display:grid;grid-template-columns:repeat(auto-fill,minmax(300px,1fr));gap:12px}.knowledge-page-card{display:grid;grid-template-columns:110px minmax(0,1fr);gap:12px;border:1px solid var(--border);border-radius:8px;background:#fff;padding:10px}.knowledge-page-card img{width:100%;height:150px;object-fit:cover;object-position:top;border:1px solid var(--border);border-radius:6px;background:var(--surface-muted)}.knowledge-page-card strong{display:block;margin-bottom:3px}.knowledge-page-card p{color:var(--text-muted);font-size:13px;margin-bottom:8px}.page-point-list{display:flex;flex-wrap:wrap;gap:6px}.point-pill{border:1px solid var(--border-strong);border-radius:999px;background:#fff;padding:4px 8px;color:var(--text-soft);font-size:12px}.point-pill.mastered{border-color:#94bca8;background:#edf7f1;color:var(--green)}.point-pill.needs_review{border-color:#d7cb76;background:#fff9d9;color:#645600}.flow-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(210px,1fr));gap:10px}.active-paper-panel,.result-panel{display:grid;gap:14px;align-content:start}.workflow-entry-card{width:100%;min-height:72px;display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:center;justify-content:stretch;text-align:left;padding:12px 14px;gap:14px;background:#fff;border:1px solid var(--border-strong);border-radius:6px}.workflow-entry-card.disabled{background:#f1f4f0;border-color:var(--border)}.workflow-head,.section-heading{display:flex;align-items:flex-start;justify-content:space-between;gap:12px}.section-heading{justify-content:flex-start;margin-bottom:12px}.section-heading svg{color:var(--green);margin-top:1px}.subtle-icon-button{width:34px;min-height:34px;margin-left:auto;padding:0;border-color:transparent;background:transparent;color:var(--text-muted)}.subtle-icon-button:hover:not(:disabled){border-color:var(--border);background:var(--surface-cool);color:var(--green)}.overview-actions{display:grid;gap:12px}.practice-entry-strip{display:grid;gap:10px;padding:14px}.practice-entry-strip .section-heading{margin-bottom:0}.practice-entry-strip .workflow-entry-card{min-height:60px;padding:12px;background:#fbfdf9}.practice-entry-strip .workflow-entry-card>div:first-child strong{font-size:15px}.practice-entry-strip .workflow-entry-card small{display:none}.practice-overview-progress{display:grid;gap:12px;border:1px solid var(--border);border-radius:6px;background:var(--surface-muted);padding:14px}.progress-copy{display:flex;align-items:baseline;justify-content:space-between;gap:12px}.progress-copy span,.workflow-entry-card small{color:var(--text-muted);font-size:13px}.progress-copy strong{font-size:18px}.progress-track{height:8px;overflow:hidden;border-radius:999px;background:#dfe7e1}.progress-track span{display:block;height:100%;border-radius:inherit;background:var(--green)}.progress-stat-grid{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:10px}.progress-stat-grid .stat-tile{padding:10px}.progress-stat-grid .stat-tile strong{font-size:20px}.practice-stat-line{display:flex;flex-wrap:wrap;gap:8px}.practice-stat-line span{border:1px solid var(--border);border-radius:999px;background:#fff;color:var(--text-soft);font-size:12px;padding:5px 9px}.workflow-entry-card>div:first-child{min-width:0;display:grid;gap:3px}.workflow-entry-card>div:first-child strong{font-size:16px}.entry-action-cluster{min-width:max-content;display:flex;align-items:center;justify-content:flex-end;gap:10px}.entry-action-button{min-width:104px;color:#fff;background:var(--green);border-color:var(--green);font-weight:700;white-space:nowrap;padding:0 12px 0 14px;box-shadow:0 4px 10px #1f645524;transition:background .14s ease,border-color .14s ease,color .14s ease,box-shadow .14s ease,transform .14s ease}.entry-action-button svg{margin-right:-3px}.entry-action-button:hover{color:#fff;background:var(--green-dark);border-color:var(--green-dark);box-shadow:0 6px 14px #1f645533;transform:translateY(-1px)}.entry-action-button.disabled{color:var(--text-muted);background:#e7ece8;border-color:var(--border);box-shadow:none;pointer-events:none}.extract-workspace{display:grid;gap:16px;scroll-margin-top:16px}.extract-compact-panel{display:flex;flex-wrap:wrap;align-items:center;gap:10px;padding:12px 14px}.extract-hero-panel{display:flex;align-items:center;gap:14px}.extract-hero-panel p,.extract-status-panel p,.extract-source-panel p{color:var(--text-muted);margin-top:5px}.extract-status-panel,.extract-source-panel{display:grid;gap:14px}.extract-profile-summary{display:flex;flex-wrap:wrap;gap:8px}.extract-profile-summary span{border:1px solid var(--border);border-radius:999px;background:#fff;color:var(--text-soft);font-size:12px;padding:5px 9px}.extract-actions{display:flex;flex-wrap:wrap;align-items:center;gap:10px}.extract-source-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(140px,1fr));gap:10px}.extract-source-grid a{display:grid;gap:7px;color:inherit;text-decoration:none;border:1px solid var(--border);border-radius:8px;background:var(--surface-muted);padding:8px}.extract-source-grid img{width:100%;aspect-ratio:3 / 4;object-fit:cover;object-position:top;border:1px solid var(--border);border-radius:6px;background:#fff}.extract-source-grid span{overflow:hidden;color:var(--text-soft);font-size:12px;white-space:nowrap;text-overflow:ellipsis}.extract-profile-dialog{width:min(720px,calc(100vw - 40px))}.extract-profile-fields{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:12px}.extract-focus-list{display:flex;flex-wrap:wrap;gap:8px;margin-top:12px}.extract-focus-list>.field-label{flex:0 0 100%}.check-pill,.check-row{display:inline-flex;align-items:center;gap:7px;border:1px solid var(--border);border-radius:999px;background:#fff;padding:7px 10px;color:#17201c;font-size:13px}.check-row{width:fit-content;margin-top:12px;border-radius:6px}.check-pill input,.check-row input{width:auto;min-height:0}.destructive-note{margin-top:12px;border:1px solid #d8aaa2;border-radius:6px;background:#fff7f5;color:var(--danger);padding:10px 12px;font-size:13px;line-height:1.55}.practice-workspace{display:grid;gap:16px}.workspace-title-panel{display:flex;align-items:center;gap:14px;min-height:96px}.workspace-title-panel button{flex:0 0 auto}.workspace-title-panel p{color:var(--text-muted);margin-top:5px}.paper-workspace-grid{display:grid;grid-template-columns:minmax(0,1fr) minmax(300px,360px);gap:18px;align-items:start}.paper-main-column,.practice-side-rail{display:grid;gap:16px;align-content:start}.practice-side-rail{position:sticky;top:18px}.paper-toolbar{display:flex;align-items:flex-start;justify-content:space-between;gap:12px}.paper-toolbar p{color:var(--text-muted);margin-top:5px}.paper-toolbar-side{display:grid;gap:10px;justify-items:end;flex:0 0 auto}.paper-mode-switch{display:inline-grid;grid-template-columns:repeat(2,minmax(72px,1fr));gap:4px;padding:4px;border:1px solid var(--border);border-radius:8px;background:var(--surface-muted)}.paper-mode-switch button{min-height:32px;border-color:transparent;background:transparent;padding:0 10px;white-space:nowrap}.paper-mode-switch button.selected{border-color:var(--green);background:#fff;color:var(--green);font-weight:700}.paper-preview-frame{height:min(78vh,900px);min-height:620px;border:1px solid var(--border);border-radius:8px;background:#f8faf7;overflow:hidden}.paper-preview-frame iframe{width:100%;height:100%;border:0;display:block;background:#fff}.create-practice-panel,.workflow-controls{display:grid;gap:12px}.workflow-controls{grid-template-columns:minmax(320px,1fr) minmax(150px,210px);align-items:end;border:1px solid var(--border);border-radius:8px;background:var(--surface-muted);padding:12px}label{display:grid;gap:6px;color:#4b574f;font-size:13px}.field-hint{color:var(--text-muted);font-size:12px}.duration-field{display:grid;gap:6px}.field-label{color:#4b574f;font-size:13px;font-weight:700}.duration-options{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:8px}.duration-option{min-height:40px;padding:0 8px;white-space:nowrap;background:#fff}.duration-option.selected{border-color:var(--green);background:var(--green-soft);color:var(--green);font-weight:700}.first-round-progress{display:grid;gap:8px;padding:11px 12px;border:1px solid var(--border);border-radius:8px;background:var(--surface-muted)}.first-round-progress .progress-copy strong{font-size:16px}.first-round-progress p{color:var(--text-muted);font-size:12px;line-height:1.5}.practice-links{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px}.paper-action-bar{display:grid;grid-template-columns:minmax(280px,1.35fr) minmax(150px,1fr) minmax(170px,1fr);gap:8px}.paper-page-switch{display:grid;grid-template-columns:minmax(0,1fr) auto minmax(0,1fr);gap:6px;align-items:center;min-height:38px}.paper-page-switch button{min-height:38px;padding:0 10px}.paper-page-switch span{color:var(--text-muted);font-size:13px;font-weight:700;white-space:nowrap}.upload-strip{display:grid;gap:10px;padding:12px;border:1px solid var(--border);border-radius:8px;background:#fff}.upload-strip p{color:var(--text-muted);font-size:13px;margin-top:3px}.upload-strip .button-link{justify-self:start}.upload-file-actions{display:flex;flex-wrap:wrap;gap:8px}.upload-strip .danger-subtle{justify-self:start;color:var(--danger);border-color:#d8aaa2;background:#fff7f5}.upload-strip .danger-subtle:hover:not(:disabled){color:var(--danger);border-color:var(--danger);background:var(--danger-soft)}.full-width{width:100%}.card-note{border-left:3px solid var(--border-strong);padding-left:10px;font-size:13px}.job-line{display:grid;gap:8px;border:1px solid var(--border);border-radius:6px;background:var(--surface-muted);padding:9px 10px;color:#4b574f}.job-line-current{display:flex;align-items:center;gap:8px;min-width:0}.job-line-current span{min-width:0;overflow-wrap:anywhere}.job-events{display:grid;gap:5px;margin:0;padding-left:24px;color:#6c746c;font-size:12px;line-height:1.45}.job-events li{overflow-wrap:anywhere}.job-line.failed{background:#fff0ed;color:var(--danger)}.spin{animation:spin 1s linear infinite}@keyframes spin{to{transform:rotate(360deg)}}.result-button,.result-actions{justify-self:start}.result-actions{display:flex;flex-wrap:wrap;gap:8px}.modal-backdrop{position:fixed;inset:0;z-index:50;display:grid;place-items:center;background:#17201c5c;padding:24px}.modal-panel{width:min(920px,100%);max-height:min(820px,calc(100vh - 48px));overflow:auto;border:1px solid var(--border-strong);border-radius:8px;background:var(--surface);box-shadow:0 24px 70px #15251f47;padding:16px}.modal-head{display:flex;align-items:flex-start;justify-content:space-between;gap:16px;margin-bottom:12px}.modal-panel .result-panel{border:0;box-shadow:none;padding:0}.profile-dialog{width:min(720px,100%);display:grid;gap:12px}.settings-dialog{width:min(680px,100%);display:grid;gap:12px}.profile-form-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px}.profile-dialog label,.settings-dialog label{display:grid;gap:6px}.profile-dialog textarea{min-height:82px}.inline-check{display:flex!important;grid-template-columns:none;align-items:center;gap:8px;color:var(--text-muted)}.inline-check input{width:auto}.settings-status,.settings-path,.form-error{border:1px solid var(--border);border-radius:6px;padding:9px 10px;font-size:14px}.settings-status.configured{background:var(--green-soft);color:var(--green-dark)}.settings-status.missing,.form-error{background:var(--peach);color:var(--rust)}.settings-path{background:var(--surface-muted);color:var(--text-muted);word-break:break-all}.modal-actions{display:flex;justify-content:flex-end;gap:8px;padding-top:4px}.artifact-links{margin-top:12px;border:1px solid var(--border);border-radius:6px;background:var(--surface-muted);padding:10px}.artifact-links h4{margin-bottom:8px}.artifact-links div{display:flex;flex-wrap:wrap;gap:8px}.artifact-links a{border:1px solid var(--border-strong);border-radius:999px;color:var(--green);background:var(--surface);padding:5px 10px;text-decoration:none;font-size:13px}.history-list{display:grid;gap:8px}.history-select-row{width:100%;display:grid;grid-template-columns:auto minmax(0,1fr);gap:8px 10px;justify-content:stretch;text-align:left;border:1px solid var(--border);background:var(--surface-muted);padding:10px;min-height:62px}.history-select-row.selected{border-color:var(--green);background:var(--green-soft)}.history-select-row .flow-status{align-self:start}.history-select-row strong,.history-select-row span,.history-select-row small{min-width:0}.history-select-row strong,.history-select-row div>span{display:block;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.history-select-row small{grid-column:2;color:var(--text-muted)}.history-row{display:grid;grid-template-columns:minmax(0,1fr) auto auto auto;gap:8px;align-items:center;border:1px solid var(--border);border-radius:6px;background:var(--surface-muted);padding:10px}.history-row strong,.history-row span{display:block}.history-row div>span{color:var(--text-muted);overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.empty-state{border:1px dashed var(--border-strong);border-radius:6px;color:var(--text-muted);padding:18px;background:var(--surface-muted)}.grading-table{display:grid;gap:8px;margin-top:12px}.grading-row{display:grid;grid-template-columns:60px 90px minmax(0,1fr);gap:10px;align-items:start;border:1px solid var(--border);border-radius:6px;background:var(--surface-muted);padding:10px;text-align:left;width:100%}.grading-row p{color:#4b574f}.grading-row.selected{border-color:var(--green);background:var(--green-soft)}.grading-detail-card{display:grid;gap:8px;margin-top:12px;border:1px solid var(--border-strong);border-radius:8px;background:#fff;padding:12px}.grading-detail-card p{color:#4b574f}.weak-points{margin-top:14px;display:flex;flex-wrap:wrap;gap:8px;align-items:center}.weak-points h4{width:100%}.weak-points span{border-radius:999px;background:var(--rust-soft);color:#7f3a23;padding:4px 9px;font-size:12px}.weak-points p{color:var(--text-muted)}@media(max-width:1080px){.workspace,.nav-collapsed .workspace,.chapter-summary,.flow-grid,.paper-workspace-grid{grid-template-columns:1fr}.practice-side-rail{position:static}.chapter-nav{position:static;height:auto;max-height:320px}.chapter-nav.collapsed{max-height:54px}.chapter-nav.collapsed .chapter-nav-list{display:none}}@media(max-width:760px){.app-shell{padding:14px}.app-header,.workflow-head,.paper-toolbar,.workspace-title-panel{display:grid}.stats-grid,.stats-grid.compact,.practice-links,.paper-action-bar,.workflow-controls,.history-row,.profile-form-grid,.grading-row,.progress-copy,.workflow-entry-card{grid-template-columns:1fr}.progress-stat-grid{grid-template-columns:repeat(2,minmax(0,1fr))}.progress-copy{display:grid}.history-select-row small{grid-column:1}}
|
package/dist/index.html
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="zh-CN">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<title>周子烊数学提分 Agent</title>
|
|
7
|
+
<script type="module" crossorigin src="/assets/index-BYFoutza.js"></script>
|
|
8
|
+
<link rel="stylesheet" crossorigin href="/assets/index-Bk2WFPoL.css">
|
|
9
|
+
</head>
|
|
10
|
+
<body>
|
|
11
|
+
<div id="root"></div>
|
|
12
|
+
</body>
|
|
13
|
+
</html>
|
package/package.json
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@zhouchangui/math-ati",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Local ATI math learning loop for printable practice, PDF grading, and mastery tracking.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"math-ati": "bin/math-ati.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"bin",
|
|
11
|
+
"dist",
|
|
12
|
+
"server",
|
|
13
|
+
"prompts",
|
|
14
|
+
"templates",
|
|
15
|
+
".env.local.example",
|
|
16
|
+
"AGENTS.md",
|
|
17
|
+
"README.md",
|
|
18
|
+
"vite.config.js"
|
|
19
|
+
],
|
|
20
|
+
"publishConfig": {
|
|
21
|
+
"access": "public"
|
|
22
|
+
},
|
|
23
|
+
"engines": {
|
|
24
|
+
"node": ">=20"
|
|
25
|
+
},
|
|
26
|
+
"scripts": {
|
|
27
|
+
"dev": "concurrently \"npm:dev:server\" \"npm:dev:client\"",
|
|
28
|
+
"dev:client": "vite --host 127.0.0.1",
|
|
29
|
+
"dev:server": "node --watch server/index.js",
|
|
30
|
+
"build": "vite build",
|
|
31
|
+
"prepack": "npm run build",
|
|
32
|
+
"pack:local": "npm pack --dry-run",
|
|
33
|
+
"release:npm": "node scripts/release-npm.js",
|
|
34
|
+
"preview": "vite preview --host 127.0.0.1",
|
|
35
|
+
"extract:knowledge": "node scripts/extract-knowledge.js",
|
|
36
|
+
"pipeline:check": "node scripts/pipeline-check.js",
|
|
37
|
+
"generate:coverage": "node scripts/generate-coverage.js",
|
|
38
|
+
"combine:coverage": "node scripts/combine-coverage.js",
|
|
39
|
+
"probe:knowledge-point": "node scripts/probe-knowledge-point.js",
|
|
40
|
+
"generate:mistakes": "node scripts/generate-mistakes.js",
|
|
41
|
+
"grade:coverage": "node scripts/grade-practice.js --mode coverage",
|
|
42
|
+
"grade:pdf": "node scripts/grade-submission-pdf.js",
|
|
43
|
+
"grade:mistakes": "node scripts/grade-practice.js --mode mistakes",
|
|
44
|
+
"regenerate:coverage": "node scripts/regenerate-coverage.js",
|
|
45
|
+
"regenerate:mistakes": "node scripts/regenerate-mistakes.js",
|
|
46
|
+
"verify:ui": "node scripts/verify-ui-workflow.js",
|
|
47
|
+
"verify:knowledge-extract": "node scripts/verify-knowledge-extract-workflow.js",
|
|
48
|
+
"verify:knowledge-extract:acceptance": "node scripts/verify-knowledge-extract-workflow.js --fixture-server --acceptance",
|
|
49
|
+
"verify:coverage-state": "node scripts/verify-coverage-state.js",
|
|
50
|
+
"verify:mistake-lifecycle": "node scripts/verify-mistake-lifecycle.js",
|
|
51
|
+
"verify:ability-config": "node scripts/verify-ability-config.js",
|
|
52
|
+
"verify:ability-loop": "node scripts/verify-ability-loop.js",
|
|
53
|
+
"verify:practice-flows": "node scripts/verify-practice-flows.js",
|
|
54
|
+
"smoke:mistake-repair": "npm run verify:mistake-lifecycle",
|
|
55
|
+
"smoke:ability": "npm run verify:ability-loop",
|
|
56
|
+
"smoke": "node scripts/smoke-api.js",
|
|
57
|
+
"smoke:full": "node scripts/smoke-full-loop.js"
|
|
58
|
+
},
|
|
59
|
+
"dependencies": {
|
|
60
|
+
"@vitejs/plugin-react": "^5.1.1",
|
|
61
|
+
"concurrently": "^9.2.1",
|
|
62
|
+
"dotenv": "^17.2.3",
|
|
63
|
+
"express": "^5.2.1",
|
|
64
|
+
"katex": "^0.16.25",
|
|
65
|
+
"lucide-react": "^0.562.0",
|
|
66
|
+
"multer": "^2.0.2",
|
|
67
|
+
"vite": "^7.3.1",
|
|
68
|
+
"react": "^19.2.3",
|
|
69
|
+
"react-dom": "^19.2.3"
|
|
70
|
+
},
|
|
71
|
+
"devDependencies": {}
|
|
72
|
+
}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
# Prompt Contract: 作答图片批改 Agent
|
|
2
|
+
|
|
3
|
+
## 1. Mission
|
|
4
|
+
|
|
5
|
+
读取学生作答图片,根据练习题干、标准答案、解题步骤、rubric 和知识点标签生成结构化批改结果,并提炼可用于下次出题的知识点掌握信号和错因。
|
|
6
|
+
|
|
7
|
+
## 2. Inputs
|
|
8
|
+
|
|
9
|
+
调用方会提供:
|
|
10
|
+
|
|
11
|
+
- `context.student`:学生画像,来自 `data/student_profile.json`。
|
|
12
|
+
- `context.practice`:练习卷 JSON,来自 `data/chapters/<chapter-id>/practices/<practice-id>.json`。
|
|
13
|
+
- `context.uploadedFiles`:作答图片路径。
|
|
14
|
+
- `context.notes`:家长备注。
|
|
15
|
+
- 当前请求附带 1 张或多张作答图片。
|
|
16
|
+
|
|
17
|
+
输出会写入:
|
|
18
|
+
|
|
19
|
+
- `data/chapters/<chapter-id>/submissions/<submission-id>/metadata.json`
|
|
20
|
+
- `data/chapters/<chapter-id>/reports/<submission-id>.md`
|
|
21
|
+
- `data/chapters/<chapter-id>/mastery.json`
|
|
22
|
+
- `data/chapters/<chapter-id>/mistakes.json`
|
|
23
|
+
|
|
24
|
+
## 3. Context Reading Order
|
|
25
|
+
|
|
26
|
+
1. 先读 `context.practice.questions`,确定题号、题干、题型、知识点 ID、知识点名称和预期错因。
|
|
27
|
+
2. 再读作答图片,按题号定位学生答案。
|
|
28
|
+
3. 再读 `context.notes`,处理家长备注中的补充信息。
|
|
29
|
+
4. 最后结合 `context.student` 调整反馈语气。
|
|
30
|
+
|
|
31
|
+
练习卷 JSON 是评分的 Source of Truth。题目必须提供 `answer`、`solutionSteps`、`rubric`,并以这些字段作为参考标准。图片看不清时不要猜。
|
|
32
|
+
|
|
33
|
+
## 4. Operating Principles
|
|
34
|
+
|
|
35
|
+
- 不臆造看不清的手写内容。
|
|
36
|
+
- 每题都必须返回一个状态。
|
|
37
|
+
- 每题都必须输出 `referenceAnswer`;正确题可以简短,错误/部分正确题要能支撑讲解。
|
|
38
|
+
- 错因要具体,能驱动下一次出题。
|
|
39
|
+
- 分数不能超过该题 `maxScore`。
|
|
40
|
+
- 公式使用 LaTeX,放在 `$...$` 中。
|
|
41
|
+
|
|
42
|
+
## 5. SOP
|
|
43
|
+
|
|
44
|
+
1. 对每题找到学生作答区域。
|
|
45
|
+
2. 识别学生答案;无法识别时标记 `unrecognized`。
|
|
46
|
+
3. 优先读取题目自带标准答案;缺失时根据题干独立解出参考答案。
|
|
47
|
+
4. 对照参考答案和题目要求评分。
|
|
48
|
+
5. 判断状态:`correct`、`partial`、`wrong`、`unrecognized`、`needs_review`。
|
|
49
|
+
6. 写出 `errorTypes` 和具体 `comment`。
|
|
50
|
+
7. 错误、部分正确、无法识别但可讲解的题,输出 `solutionMethod` 和 `teachingHint`;正确题可以留空数组。
|
|
51
|
+
8. 汇总本次表现,写 `summary`、`masterySignals`、`nextPracticeSuggestion`。
|
|
52
|
+
9. 输出 JSON。
|
|
53
|
+
|
|
54
|
+
## 6. Few-shot Example
|
|
55
|
+
|
|
56
|
+
练习题:
|
|
57
|
+
|
|
58
|
+
```text
|
|
59
|
+
写出 $-7$ 和 $0$ 的相反数。
|
|
60
|
+
答案:$7$,$0$
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
学生作答识别为:`7,没有`
|
|
64
|
+
|
|
65
|
+
正确输出片段:
|
|
66
|
+
|
|
67
|
+
```json
|
|
68
|
+
{
|
|
69
|
+
"grading": [
|
|
70
|
+
{
|
|
71
|
+
"questionId": "q1",
|
|
72
|
+
"recognizedAnswer": "$7$,没有",
|
|
73
|
+
"status": "partial",
|
|
74
|
+
"score": 3,
|
|
75
|
+
"maxScore": 6,
|
|
76
|
+
"errorTypes": ["特殊值遗漏"],
|
|
77
|
+
"comment": "$-7$ 的相反数写对了,但 $0$ 的相反数应为 $0$,不是没有。",
|
|
78
|
+
"referenceAnswer": "$7$,$0$",
|
|
79
|
+
"solutionMethod": ["相反数是只有符号不同的两个数。", "$0$ 的相反数仍然是 $0$。"],
|
|
80
|
+
"teachingHint": "讲解时重点强调 $0$ 是特殊值,但不是“没有相反数”。"
|
|
81
|
+
}
|
|
82
|
+
],
|
|
83
|
+
"masterySignals": ["相反数基本概念部分掌握", "$0$ 的特殊情况需要复习"],
|
|
84
|
+
"nextPracticeSuggestion": "继续生成包含 $0$ 的相反数选择题或填空题。"
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## 7. Output Schema
|
|
89
|
+
|
|
90
|
+
只输出 JSON,不输出 Markdown,不输出解释性前后缀。
|
|
91
|
+
|
|
92
|
+
```json
|
|
93
|
+
{
|
|
94
|
+
"summary": "string",
|
|
95
|
+
"masterySignals": ["string"],
|
|
96
|
+
"nextPracticeSuggestion": "string",
|
|
97
|
+
"grading": [
|
|
98
|
+
{
|
|
99
|
+
"questionId": "q1",
|
|
100
|
+
"recognizedAnswer": "string",
|
|
101
|
+
"status": "correct|partial|wrong|unrecognized|needs_review",
|
|
102
|
+
"score": 0,
|
|
103
|
+
"maxScore": 6,
|
|
104
|
+
"errorTypes": ["string"],
|
|
105
|
+
"comment": "string",
|
|
106
|
+
"referenceAnswer": "string",
|
|
107
|
+
"solutionMethod": ["string"],
|
|
108
|
+
"teachingHint": "string"
|
|
109
|
+
}
|
|
110
|
+
]
|
|
111
|
+
}
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## 8. Self-check Rubric
|
|
115
|
+
|
|
116
|
+
输出前确认:
|
|
117
|
+
|
|
118
|
+
- 是否每题都有 grading 记录?
|
|
119
|
+
- `questionId` 是否存在于练习卷?
|
|
120
|
+
- 看不清的内容是否没有猜测?
|
|
121
|
+
- 是否优先使用题目自带答案,或在缺失时给出了可靠 `referenceAnswer`?
|
|
122
|
+
- 错因是否具体到知识点或步骤?
|
|
123
|
+
- `nextPracticeSuggestion` 是否能驱动下次生成?
|
|
124
|
+
|
|
125
|
+
## 9. Failure Policy
|
|
126
|
+
|
|
127
|
+
- 图片完全看不清:所有题标记 `unrecognized`,分数为 0,说明需要重拍。
|
|
128
|
+
- 题号无法对应:标记 `needs_review`,说明需要家长确认。
|
|
129
|
+
- 家长备注与图片冲突:优先图片,但在 comment 中提示冲突。
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# Prompt Contract: 知识点逐页提取 Agent
|
|
2
|
+
|
|
3
|
+
## 1. Mission
|
|
4
|
+
|
|
5
|
+
从单页章节图片中提取可教学、可检测、可追溯的初中数学知识内容,输出结构化 JSON,供章节汇总 Agent 后续合并。
|
|
6
|
+
|
|
7
|
+
## 2. Inputs
|
|
8
|
+
|
|
9
|
+
调用方会提供:
|
|
10
|
+
|
|
11
|
+
- `context.chapter.id`:章节 ID,例如 `chapter-01`。
|
|
12
|
+
- `context.chapter.title`:章节标题,例如 `第一章 有理数`。
|
|
13
|
+
- `context.chapter.track`:学习主线,例如 `计算与代数地基`。
|
|
14
|
+
- 当前请求附带 1 张章节图片。
|
|
15
|
+
|
|
16
|
+
参考文件位置:
|
|
17
|
+
|
|
18
|
+
- 原始章节图片:`output/images/初中数学_提分笔记_按章节/<chapter-folder>/*.png`
|
|
19
|
+
- 本 Agent 输出:`data/knowledge_extracts/<chapter-id>/<page>.json`
|
|
20
|
+
|
|
21
|
+
## 3. Context Reading Order
|
|
22
|
+
|
|
23
|
+
1. 先读图片中的主标题、章节位置和视觉结构。
|
|
24
|
+
2. 再读定义、公式、性质、方法、例题提示和易错提醒。
|
|
25
|
+
3. 最后结合 `context.chapter` 判断这些内容属于哪个章节和主线。
|
|
26
|
+
|
|
27
|
+
图片内容是最高优先级。不要用外部知识补充图片没有出现的内容。
|
|
28
|
+
|
|
29
|
+
## 4. Operating Principles
|
|
30
|
+
|
|
31
|
+
- 忠实提取,不扩展教材外知识。
|
|
32
|
+
- 例子不等于知识点;例子放入 `examples`。
|
|
33
|
+
- 公式使用 LaTeX,放在 `$...$` 中。
|
|
34
|
+
- 易错点要能转化为后续错题练习方向。
|
|
35
|
+
- 不确定时写入 `rawOutline` 或在 summary 中保持保守表达。
|
|
36
|
+
|
|
37
|
+
## 5. SOP
|
|
38
|
+
|
|
39
|
+
1. OCR/理解页面文字与结构。
|
|
40
|
+
2. 提取页面中的概念、性质、公式、方法、题型,形成 `knowledgePoints`。
|
|
41
|
+
3. 提取页面中出现的限制条件、特殊值、常见误判,形成 `easyMistakes`。
|
|
42
|
+
4. 为每个知识点写一句适合 14 岁学生理解的 `summary`。
|
|
43
|
+
5. 为后续出题写 `exerciseHints`,只写方向,不写完整答案。
|
|
44
|
+
6. 输出前执行自检。
|
|
45
|
+
|
|
46
|
+
## 6. Few-shot Example
|
|
47
|
+
|
|
48
|
+
输入图片内容摘要:
|
|
49
|
+
|
|
50
|
+
```text
|
|
51
|
+
相反数:只有符号不同的两个数互为相反数,0 的相反数是 0。
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
正确输出片段:
|
|
55
|
+
|
|
56
|
+
```json
|
|
57
|
+
{
|
|
58
|
+
"knowledgePoints": [
|
|
59
|
+
{
|
|
60
|
+
"title": "相反数的概念",
|
|
61
|
+
"summary": "只有符号不同的两个数互为相反数,$0$ 的相反数是 $0$。",
|
|
62
|
+
"formulas": ["$a$ 的相反数是 $-a$"],
|
|
63
|
+
"examples": ["$3$ 与 $-3$"],
|
|
64
|
+
"prerequisite": "正数、负数和 0 的意义",
|
|
65
|
+
"difficulty": "basic"
|
|
66
|
+
}
|
|
67
|
+
],
|
|
68
|
+
"easyMistakes": [
|
|
69
|
+
{
|
|
70
|
+
"title": "漏掉 0 的特殊情况",
|
|
71
|
+
"errorType": "特殊值遗漏",
|
|
72
|
+
"description": "学生容易认为 $0$ 没有相反数。",
|
|
73
|
+
"correction": "$0$ 的相反数是 $0$。"
|
|
74
|
+
}
|
|
75
|
+
]
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## 7. Output Schema
|
|
80
|
+
|
|
81
|
+
只输出 JSON,不输出 Markdown,不输出解释性前后缀。
|
|
82
|
+
|
|
83
|
+
```json
|
|
84
|
+
{
|
|
85
|
+
"pageTitle": "string",
|
|
86
|
+
"rawOutline": ["string"],
|
|
87
|
+
"knowledgePoints": [
|
|
88
|
+
{
|
|
89
|
+
"title": "string",
|
|
90
|
+
"summary": "string",
|
|
91
|
+
"formulas": ["string with LaTeX"],
|
|
92
|
+
"examples": ["short example or expression"],
|
|
93
|
+
"prerequisite": "string",
|
|
94
|
+
"difficulty": "basic|medium|challenge"
|
|
95
|
+
}
|
|
96
|
+
],
|
|
97
|
+
"easyMistakes": [
|
|
98
|
+
{
|
|
99
|
+
"title": "string",
|
|
100
|
+
"errorType": "string",
|
|
101
|
+
"description": "string",
|
|
102
|
+
"correction": "string"
|
|
103
|
+
}
|
|
104
|
+
],
|
|
105
|
+
"exerciseHints": ["string"]
|
|
106
|
+
}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## 8. Self-check Rubric
|
|
110
|
+
|
|
111
|
+
输出前确认:
|
|
112
|
+
|
|
113
|
+
- 是否遗漏页面中的定义、公式、性质、方法或题型?
|
|
114
|
+
- 是否把例子误当成知识点?
|
|
115
|
+
- 是否把教材没有出现的知识扩写进来了?
|
|
116
|
+
- 是否保留了易错点和特殊值?
|
|
117
|
+
- JSON 是否可解析?
|
|
118
|
+
|
|
119
|
+
## 9. Failure Policy
|
|
120
|
+
|
|
121
|
+
- 如果图片局部看不清:在 `rawOutline` 写明不确定区域,能确定的内容照常提取。
|
|
122
|
+
- 如果整页无法识别:返回空 `knowledgePoints`,并在 `rawOutline` 说明原因。
|
|
123
|
+
- 不要编造看不清的文字。
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
# Prompt Contract: 章节知识点汇总审校 Agent
|
|
2
|
+
|
|
3
|
+
## 1. Mission
|
|
4
|
+
|
|
5
|
+
把同一章节的逐页提取结果合并、去重、压缩为可教学、可逐点检测、可归档追踪的章节知识点文档。
|
|
6
|
+
|
|
7
|
+
## 2. Inputs
|
|
8
|
+
|
|
9
|
+
调用方会提供:
|
|
10
|
+
|
|
11
|
+
- `context.chapter`:章节元信息。
|
|
12
|
+
- `context.pageExtracts`:逐页提取 JSON 数组,来自 `data/knowledge_extracts/<chapter-id>/*.json`。
|
|
13
|
+
- `context.localDraft`:本地程序初步合并草稿。
|
|
14
|
+
|
|
15
|
+
输出会写入:
|
|
16
|
+
|
|
17
|
+
- `data/knowledge_points.json`
|
|
18
|
+
- `data/knowledge_docs/<chapter-id>.md`
|
|
19
|
+
- `data/mastery.json`
|
|
20
|
+
|
|
21
|
+
## 3. Context Reading Order
|
|
22
|
+
|
|
23
|
+
1. 先读 `context.pageExtracts`,它是主要来源。
|
|
24
|
+
2. 再读 `context.localDraft`,只作为辅助草稿。
|
|
25
|
+
3. 最后读 `context.chapter`,用于章节命名、主线和 id 前缀。
|
|
26
|
+
|
|
27
|
+
逐页提取内容优先于 localDraft。不要依赖外部教材知识补写。
|
|
28
|
+
|
|
29
|
+
## 4. Operating Principles
|
|
30
|
+
|
|
31
|
+
- 合并同义知识点,避免重复。
|
|
32
|
+
- 普通知识点和易错点分区。
|
|
33
|
+
- 知识点颗粒度要适合逐个检测。
|
|
34
|
+
- 每个知识点必须能生成选择题、填空题或问答题。
|
|
35
|
+
- 每个知识点都要保留来源页 `sources`。
|
|
36
|
+
|
|
37
|
+
## 5. SOP
|
|
38
|
+
|
|
39
|
+
1. 通读所有逐页 JSON,列出候选知识点。
|
|
40
|
+
2. 合并同义、过小、重复候选。
|
|
41
|
+
3. 将核心知识放入 `知识点覆盖` section。
|
|
42
|
+
4. 将常见误判、特殊值、限制条件放入 `易错题专项` section。
|
|
43
|
+
5. 给每个 point 生成稳定 id。
|
|
44
|
+
6. 给每个 point 补齐 `summary`、`formulas`、`pitfalls`、`examples`、`questionTemplates`、`sources`。
|
|
45
|
+
7. 在 `review` 中说明合并情况、疑似遗漏和是否通过。
|
|
46
|
+
|
|
47
|
+
## 6. Few-shot Example
|
|
48
|
+
|
|
49
|
+
输入候选:
|
|
50
|
+
|
|
51
|
+
```text
|
|
52
|
+
- 相反数:只有符号不同的两个数互为相反数。
|
|
53
|
+
- 0 的相反数是 0。
|
|
54
|
+
- 易错:把 0 当作没有相反数。
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
正确合并:
|
|
58
|
+
|
|
59
|
+
```json
|
|
60
|
+
{
|
|
61
|
+
"sections": [
|
|
62
|
+
{
|
|
63
|
+
"title": "知识点覆盖",
|
|
64
|
+
"points": [
|
|
65
|
+
{
|
|
66
|
+
"id": "chapter-01-kp-05",
|
|
67
|
+
"title": "相反数的概念",
|
|
68
|
+
"summary": "只有符号不同的两个数互为相反数,$0$ 的相反数是 $0$。",
|
|
69
|
+
"formulas": ["$a$ 的相反数是 $-a$"],
|
|
70
|
+
"pitfalls": ["漏掉 $0$ 的相反数"],
|
|
71
|
+
"examples": ["$7$ 与 $-7$"],
|
|
72
|
+
"questionTemplates": [["写出 $-7$ 和 $0$ 的相反数。", "$7$,$0$", "特殊值遗漏"]],
|
|
73
|
+
"sources": ["page-001.png"]
|
|
74
|
+
}
|
|
75
|
+
]
|
|
76
|
+
}
|
|
77
|
+
]
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## 7. Output Schema
|
|
82
|
+
|
|
83
|
+
只输出 JSON,不输出 Markdown,不输出解释性前后缀。
|
|
84
|
+
|
|
85
|
+
```json
|
|
86
|
+
{
|
|
87
|
+
"sections": [
|
|
88
|
+
{
|
|
89
|
+
"title": "知识点覆盖",
|
|
90
|
+
"points": [
|
|
91
|
+
{
|
|
92
|
+
"id": "chapter-01-kp-01",
|
|
93
|
+
"title": "string",
|
|
94
|
+
"summary": "string",
|
|
95
|
+
"formulas": ["string with LaTeX"],
|
|
96
|
+
"pitfalls": ["string"],
|
|
97
|
+
"examples": ["string"],
|
|
98
|
+
"questionTemplates": [["stem", "answer", "expectedErrorType"]],
|
|
99
|
+
"sources": ["image filename"]
|
|
100
|
+
}
|
|
101
|
+
]
|
|
102
|
+
}
|
|
103
|
+
],
|
|
104
|
+
"review": {
|
|
105
|
+
"passed": true,
|
|
106
|
+
"coverageSummary": "string",
|
|
107
|
+
"missingOrWeak": ["string"],
|
|
108
|
+
"duplicateMerged": ["string"]
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## 8. Self-check Rubric
|
|
114
|
+
|
|
115
|
+
输出前确认:
|
|
116
|
+
|
|
117
|
+
- 是否把同义知识点合并?
|
|
118
|
+
- 是否把易错点放入专项 section?
|
|
119
|
+
- 是否控制在可教学颗粒度?
|
|
120
|
+
- 每个 point 是否有稳定 id 和 questionTemplates?
|
|
121
|
+
- `sources` 是否保留?
|
|
122
|
+
|
|
123
|
+
## 9. Failure Policy
|
|
124
|
+
|
|
125
|
+
- 如果逐页提取质量差:在 `review.missingOrWeak` 写明需要人工复核。
|
|
126
|
+
- 如果无法判断是否重复:保守合并,并在 `duplicateMerged` 记录。
|
|
127
|
+
- 不要为了凑数量创造教材外知识点。
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# Prompt Contract: 学习档案总结 Agent
|
|
2
|
+
|
|
3
|
+
## 1. Mission
|
|
4
|
+
|
|
5
|
+
把一次批改结果转化为下次出题可用的结构化学习总结,更新知识点掌握判断、错因优先级和下一轮练习建议。
|
|
6
|
+
|
|
7
|
+
## 2. Inputs
|
|
8
|
+
|
|
9
|
+
调用方会提供:
|
|
10
|
+
|
|
11
|
+
- `context.practice`:练习卷 JSON,来自 `data/chapters/<chapter-id>/practices/<practice-id>.json`。
|
|
12
|
+
- `context.grading`:批改结果,来自 `data/chapters/<chapter-id>/submissions/<submission-id>/metadata.json`。
|
|
13
|
+
- `context.knowledgeDoc`:知识点字典,来自 `data/knowledge_points.json`。
|
|
14
|
+
- `context.mastery`:当前掌握状态,来自 `data/mastery.json`。
|
|
15
|
+
- `context.mistakes`:历史错题,来自 `data/mistakes.json`。
|
|
16
|
+
|
|
17
|
+
输出会用于更新:
|
|
18
|
+
|
|
19
|
+
- `data/chapters/<chapter-id>/reports/<submission-id>.md`
|
|
20
|
+
- `data/mastery.json`
|
|
21
|
+
- `data/mistakes.json`
|
|
22
|
+
|
|
23
|
+
## 3. Context Reading Order
|
|
24
|
+
|
|
25
|
+
1. 先读 `context.practice.questions`,建立题目到知识点 ID 的映射。
|
|
26
|
+
2. 再读 `context.grading`,统计每个知识点表现。
|
|
27
|
+
3. 再读 `context.mastery`,判断是否首次覆盖、继续错误或已经稳定掌握。
|
|
28
|
+
4. 再读 `context.mistakes`,识别重复错因。
|
|
29
|
+
5. 最后读 `context.knowledgeDoc`,补充知识点标题和易错点说明。
|
|
30
|
+
|
|
31
|
+
`practice.questions[].knowledgePointIds` 是知识点归档的 Source of Truth。
|
|
32
|
+
|
|
33
|
+
## 4. Operating Principles
|
|
34
|
+
|
|
35
|
+
- 不用泛泛鼓励代替诊断。
|
|
36
|
+
- 每条建议都必须能驱动下一次出题。
|
|
37
|
+
- 错因要可复用,例如“特殊值遗漏”“相反数与倒数混淆”。
|
|
38
|
+
- 连续出错的知识点要提高优先级。
|
|
39
|
+
|
|
40
|
+
## 5. SOP
|
|
41
|
+
|
|
42
|
+
1. 按 knowledgePointId 聚合题目结果。
|
|
43
|
+
2. 根据正确率和状态判断 `mastered`、`covered` 或 `needs_review`。
|
|
44
|
+
3. 提炼每个知识点的主要错因。
|
|
45
|
+
4. 推荐下一次题型:`choice`、`blank`、`short_answer`。
|
|
46
|
+
5. 给出章节级下一步计划。
|
|
47
|
+
6. 输出 JSON。
|
|
48
|
+
|
|
49
|
+
## 6. Few-shot Example
|
|
50
|
+
|
|
51
|
+
输入摘要:
|
|
52
|
+
|
|
53
|
+
```text
|
|
54
|
+
knowledgePointId: chapter-01-kp-05
|
|
55
|
+
status: partial
|
|
56
|
+
errorTypes: [特殊值遗漏]
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
正确输出片段:
|
|
60
|
+
|
|
61
|
+
```json
|
|
62
|
+
{
|
|
63
|
+
"knowledgeUpdates": [
|
|
64
|
+
{
|
|
65
|
+
"knowledgePointId": "chapter-01-kp-05",
|
|
66
|
+
"status": "needs_review",
|
|
67
|
+
"reason": "能写出非零数的相反数,但漏掉 $0$ 的相反数。",
|
|
68
|
+
"nextQuestionKind": "blank",
|
|
69
|
+
"priority": "high"
|
|
70
|
+
}
|
|
71
|
+
],
|
|
72
|
+
"mistakeSummary": [
|
|
73
|
+
{
|
|
74
|
+
"knowledgePointId": "chapter-01-kp-05",
|
|
75
|
+
"errorType": "特殊值遗漏",
|
|
76
|
+
"suggestion": "下次继续生成包含 $0$ 的相反数填空题。"
|
|
77
|
+
}
|
|
78
|
+
]
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## 7. Output Schema
|
|
83
|
+
|
|
84
|
+
只输出 JSON,不输出 Markdown,不输出解释性前后缀。
|
|
85
|
+
|
|
86
|
+
```json
|
|
87
|
+
{
|
|
88
|
+
"summary": "string",
|
|
89
|
+
"knowledgeUpdates": [
|
|
90
|
+
{
|
|
91
|
+
"knowledgePointId": "chapter-01-kp-05",
|
|
92
|
+
"status": "mastered|covered|needs_review",
|
|
93
|
+
"reason": "string",
|
|
94
|
+
"nextQuestionKind": "choice|blank|short_answer",
|
|
95
|
+
"priority": "low|medium|high"
|
|
96
|
+
}
|
|
97
|
+
],
|
|
98
|
+
"mistakeSummary": [
|
|
99
|
+
{
|
|
100
|
+
"knowledgePointId": "chapter-01-kp-05",
|
|
101
|
+
"errorType": "string",
|
|
102
|
+
"suggestion": "string"
|
|
103
|
+
}
|
|
104
|
+
],
|
|
105
|
+
"nextPracticePlan": ["string"]
|
|
106
|
+
}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## 8. Self-check Rubric
|
|
110
|
+
|
|
111
|
+
输出前确认:
|
|
112
|
+
|
|
113
|
+
- 是否每个知识点更新都有合法 ID?
|
|
114
|
+
- 是否明确说明为什么掌握或未掌握?
|
|
115
|
+
- 是否推荐了下一题型?
|
|
116
|
+
- 是否识别重复错因?
|
|
117
|
+
- 是否能直接用于下一次生成题目?
|
|
118
|
+
|
|
119
|
+
## 9. Failure Policy
|
|
120
|
+
|
|
121
|
+
- 如果缺少知识点 ID:使用题目中的知识点标题辅助说明,但在 reason 中标记“缺少稳定 ID”。
|
|
122
|
+
- 如果批改结果全是 `unrecognized`:不要判断掌握,只建议重拍或人工确认。
|
|
123
|
+
- 如果历史数据为空:只基于本次结果生成建议。
|