cotutor 0.3.0 → 0.4.1
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/LICENSE +9 -7
- package/NOTICE +3 -3
- package/README.md +65 -18
- package/avatars/chinese.webp +0 -0
- package/avatars/english.webp +0 -0
- package/avatars/math.webp +0 -0
- package/bin/cotutor.js +13 -3
- package/cards/photo/card.css +10 -3
- package/cards/photo/card.md +2 -2
- package/cards/tutor/card.css +13 -0
- package/cards/tutor/card.md +2 -1
- package/cards//346/235/277/344/271/246/346/200/216/344/271/210/345/206/231.md +1 -1
- package/dist/app/activity-eval.js +3 -2
- package/dist/app/cli/activities.d.ts +8 -1
- package/dist/app/cli/activities.js +42 -4
- package/dist/app/cli/cert.d.ts +11 -0
- package/dist/app/cli/cert.js +36 -9
- package/dist/app/cli/chalk/browser.d.ts +2 -2
- package/dist/app/cli/chalk/browser.js +22 -7
- package/dist/app/cli/chalk/main.js +3 -2
- package/dist/app/cli/doctor.d.ts +11 -5
- package/dist/app/cli/doctor.js +156 -181
- package/dist/app/cli/firewall.d.ts +24 -0
- package/dist/app/cli/firewall.js +79 -0
- package/dist/app/cli/init.js +8 -5
- package/dist/app/cli/main.js +379 -27
- package/dist/app/cli/migrate.d.ts +2 -11
- package/dist/app/cli/migrate.js +1 -59
- package/dist/app/cli/port-holder.d.ts +16 -0
- package/dist/app/cli/port-holder.js +34 -0
- package/dist/app/cli/port.d.ts +37 -0
- package/dist/app/cli/port.js +116 -0
- package/dist/app/cli/sandbox.d.ts +25 -0
- package/dist/app/cli/sandbox.js +166 -0
- package/dist/app/cli/serve-log.d.ts +13 -0
- package/dist/app/cli/serve-log.js +90 -0
- package/dist/app/cli/serve.d.ts +18 -4
- package/dist/app/cli/serve.js +78 -8
- package/dist/app/cli/service-windows.d.ts +50 -0
- package/dist/app/cli/service-windows.js +117 -0
- package/dist/app/cli/service.d.ts +152 -0
- package/dist/app/cli/service.js +443 -0
- package/dist/app/cli/skeleton.d.ts +1 -1
- package/dist/app/cli/skeleton.js +13 -13
- package/dist/app/cli/skills.d.ts +5 -1
- package/dist/app/cli/skills.js +14 -4
- package/dist/app/cli/tray-icons.d.ts +11 -0
- package/dist/app/cli/tray-icons.js +87 -0
- package/dist/app/cli/tray-ids.d.ts +6 -0
- package/dist/app/cli/tray-ids.js +6 -0
- package/dist/app/cli/tray-mac.d.ts +8 -0
- package/dist/app/cli/tray-mac.js +140 -0
- package/dist/app/cli/tray-run.d.ts +1 -0
- package/dist/app/cli/tray-run.js +42 -0
- package/dist/app/cli/tray-windows.d.ts +5 -0
- package/dist/app/cli/tray-windows.js +166 -0
- package/dist/app/cli/tray.d.ts +236 -0
- package/dist/app/cli/tray.js +670 -0
- package/dist/app/cli/usage.d.ts +1 -1
- package/dist/app/cli/usage.js +11 -6
- package/dist/app/dictation/route.js +3 -2
- package/dist/app/http/app.d.ts +5 -10
- package/dist/app/http/app.js +47 -98
- package/dist/app/http/avatars.d.ts +17 -0
- package/dist/app/http/avatars.js +35 -0
- package/dist/app/http/dev-tutor-files.js +1 -1
- package/dist/app/http/parent-home.d.ts +14 -0
- package/dist/app/http/parent-home.js +69 -6
- package/dist/app/http/parent-look.d.ts +2 -0
- package/dist/app/http/parent-look.js +151 -0
- package/dist/app/http/raw-view.js +3 -3
- package/dist/app/http/voice-preview.d.ts +4 -0
- package/dist/app/http/voice-preview.js +34 -0
- package/dist/app/machine/bailian.d.ts +0 -2
- package/dist/app/machine/bailian.js +5 -6
- package/dist/app/machine/update.d.ts +25 -0
- package/dist/app/machine/update.js +88 -0
- package/dist/app/mock/mock-live.js +1 -1
- package/dist/app/mock/mock.d.ts +4 -2
- package/dist/app/mock/mock.js +20 -12
- package/dist/app/replay.js +4 -4
- package/dist/app/skills/home-doc.js +1 -1
- package/dist/app/workspace.d.ts +9 -4
- package/dist/app/workspace.js +33 -10
- package/dist/app/ws/route.d.ts +8 -2
- package/dist/app/ws/route.js +7 -3
- package/dist/board/parse.d.ts +0 -2
- package/dist/board/parse.js +0 -6
- package/dist/board/presentation.d.ts +9 -15
- package/dist/board/presentation.js +8 -10
- package/dist/brain/api-tools.js +2 -1
- package/dist/brain/api.d.ts +12 -17
- package/dist/brain/api.js +16 -33
- package/dist/brain/index.d.ts +23 -71
- package/dist/brain/index.js +6 -69
- package/dist/brain/log.d.ts +5 -0
- package/dist/brain/log.js +22 -0
- package/dist/brain/runtime.d.ts +30 -0
- package/dist/brain/runtime.js +23 -0
- package/dist/brain/{cli/stream-json.d.ts → stream-json.d.ts} +2 -4
- package/dist/brain/{cli/stream-json.js → stream-json.js} +0 -4
- package/dist/brain/stream.d.ts +5 -5
- package/dist/brain/stream.js +7 -7
- package/dist/brain/transcript.d.ts +3 -3
- package/dist/brain/transcript.js +6 -6
- package/dist/brain/{cli/types.d.ts → types.d.ts} +3 -48
- package/dist/brain/types.js +14 -0
- package/dist/chalk/glyphs/skeleton.d.ts +3 -3
- package/dist/chalk/glyphs/skeleton.js +1 -1
- package/dist/lib/index.d.ts +1 -1
- package/dist/lib/index.js +1 -1
- package/dist/memory/diary.js +3 -3
- package/dist/realtime/bailian.d.ts +1 -1
- package/dist/realtime/bailian.js +3 -2
- package/dist/realtime/preview.js +1 -1
- package/dist/realtime/voices.d.ts +2 -0
- package/dist/realtime/voices.js +57 -57
- package/dist/runtime/activities.d.ts +13 -1
- package/dist/runtime/activities.js +28 -2
- package/dist/runtime/activity-state.js +2 -2
- package/dist/runtime/agent-file.d.ts +3 -3
- package/dist/runtime/agent-file.js +3 -3
- package/dist/runtime/context/tutor-rules.d.ts +2 -2
- package/dist/runtime/context/tutor-rules.js +3 -3
- package/dist/runtime/home/home.d.ts +12 -1
- package/dist/runtime/home/home.js +8 -1
- package/dist/runtime/home/store.d.ts +1 -1
- package/dist/runtime/home/store.js +36 -21
- package/dist/runtime/journal/mix.d.ts +15 -6
- package/dist/runtime/journal/mix.js +60 -19
- package/dist/runtime/journal/recorder.d.ts +58 -13
- package/dist/runtime/journal/recorder.js +106 -16
- package/dist/runtime/journal/store.d.ts +4 -4
- package/dist/runtime/journal/store.js +6 -6
- package/dist/runtime/kid-input.js +2 -3
- package/dist/runtime/live/call.d.ts +12 -0
- package/dist/runtime/live/call.js +51 -18
- package/dist/runtime/live/turns.js +1 -1
- package/dist/runtime/runner.d.ts +9 -55
- package/dist/runtime/runner.js +52 -173
- package/dist/scenes/paint/painter.js +4 -3
- package/dist/schema/config.d.ts +43 -22
- package/dist/schema/config.js +45 -47
- package/dist/schema/conversation.d.ts +6 -0
- package/dist/schema/home.d.ts +11 -1
- package/dist/schema/home.js +7 -2
- package/dist/schema/workspace.d.ts +27 -0
- package/dist/schema/workspace.js +28 -0
- package/dist/shared/default-port.d.ts +2 -0
- package/dist/shared/default-port.js +2 -0
- package/dist/shared/qianwen.d.ts +14 -10
- package/dist/shared/qianwen.js +26 -22
- package/dist/shared/site-url.d.ts +2 -0
- package/dist/shared/site-url.js +5 -0
- package/dist/shared/upgrade.d.ts +9 -0
- package/dist/shared/upgrade.js +23 -0
- package/dist/ui/dev/dev-page.js +25 -252
- package/dist/ui/dev/dev-theme.d.ts +1 -1
- package/dist/ui/dev/dev-theme.js +1 -1
- package/dist/ui/dev/voice-gallery-page.js +1 -1
- package/dist/ui/kid/board-mark.d.ts +2 -2
- package/dist/ui/kid/board-mark.js +2 -2
- package/dist/ui/kid/home-tiles.d.ts +14 -0
- package/dist/ui/kid/home-tiles.js +44 -0
- package/dist/ui/kid/kid-page.js +68 -103
- package/dist/ui/kid/voice-ui.d.ts +1 -1
- package/dist/ui/kid/voice-ui.js +1 -1
- package/dist/ui/kid/word-emoji.js +5 -3
- package/dist/ui/parent/parent-home-page.js +337 -7
- package/dist/ui/parent/parent-page.js +6 -2
- package/dist/ui/parent/parent-settings-page.d.ts +1 -0
- package/dist/ui/parent/parent-settings-page.js +133 -0
- package/dist/ui/{dev → parent}/qr-page.d.ts +2 -2
- package/dist/ui/{dev → parent}/qr-page.js +19 -14
- package/dist/ui/shared/brand.d.ts +3 -1
- package/dist/ui/shared/brand.js +3 -1
- package/grades/grade-2/README.md +1 -1
- package/grades/grade-2/VALIDATION.md +1 -1
- package/grades/grade-2/agents/chinese-tutor/activities//345/244/215/344/271/240.md +1 -1
- package/grades/grade-2/agents/chinese-tutor/activities//346/{211/271/346/224/271.md → 243/200/346/237/245/344/275/234/344/270/232.md} +4 -4
- package/grades/grade-2/agents/chinese-tutor/activities//346/{211/271/346/224/271. → 243/200/346/237/245/344/275/234/344/270/232.}/344/276/213/345/255/220.md +2 -2
- package/grades/grade-2/agents/chinese-tutor/activities//351/242/204/344/271/240.md +1 -1
- package/grades/grade-2/agents/english-tutor/activities//345/244/215/344/271/240.md +1 -1
- package/grades/grade-2/agents/english-tutor/activities//346/{211/271/346/224/271.md → 243/200/346/237/245/344/275/234/344/270/232.md} +4 -4
- package/grades/grade-2/agents/english-tutor/activities//346/{211/271/346/224/271. → 243/200/346/237/245/344/275/234/344/270/232.}/344/276/213/345/255/220.md +2 -2
- package/grades/grade-2/agents/english-tutor/activities//351/242/204/344/271/240.md +1 -1
- package/grades/grade-2/agents/math-tutor/activities//345/244/215/344/271/240.md +1 -1
- package/grades/grade-2/agents/math-tutor/activities//346/{211/271/346/224/271.md → 243/200/346/237/245/344/275/234/344/270/232.md} +4 -4
- package/grades/grade-2/agents/math-tutor/activities//346/{211/271/346/224/271. → 243/200/346/237/245/344/275/234/344/270/232.}/344/276/213/345/255/220.md +2 -2
- package/grades/grade-2/agents/math-tutor/activities//351/242/204/344/271/240.md +1 -1
- package/package.json +6 -2
- package/skills/cotutor-analyze/references//345/221/275/344/273/244/344/270/216/346/226/207/344/273/266.md +2 -2
- package/skills/cotutor-board/references/photo.md +2 -2
- package/skills/cotutor-home/SKILL.md +1 -0
- package/skills/cotutor-home/references/tutor.md +2 -1
- package/skills/cotutor-home/references//351/246/226/351/241/265/350/257/255/346/263/225.md +2 -1
- package/skills/cotutor-tune/references//345/255/227/346/256/265.md +6 -3
- package/skills/cotutor-tutor/SKILL.md +5 -13
- package/dist/brain/cli/adapters.d.ts +0 -60
- package/dist/brain/cli/adapters.js +0 -91
- package/dist/brain/cli/qwen.d.ts +0 -11
- package/dist/brain/cli/qwen.js +0 -141
- package/dist/brain/cli/run-plan.d.ts +0 -59
- package/dist/brain/cli/run-plan.js +0 -71
- package/dist/brain/cli/run.d.ts +0 -35
- package/dist/brain/cli/run.js +0 -256
- package/dist/brain/cli/types.js +0 -3
- package/dist/brain/cli/warm.d.ts +0 -53
- package/dist/brain/cli/warm.js +0 -103
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 家长端「设置」(/parent/settings):设一次就不常动的。现在只有一项——孩子的平板上,按住说话那一栏放哪边(cotutor.json 的 kid.hand)。
|
|
3
|
+
* 两张示意图(不是截图,页面现画的 SVG):横着的平板,窄的一栏是老师头像 + 按住说话,宽的一边是写字的白纸;点一张就存。
|
|
4
|
+
* 孩子端首页的接口带着它(/api/kid/home 的 hand),孩子下次进老师页就换过来;画板那一列工具跟着一起挪。
|
|
5
|
+
* 零依赖内联脚本,只走 /api/parent/settings(GET 读,PATCH {kid: {hand}} 改)。
|
|
6
|
+
* 用 String.raw:脚本里的反斜杠原样留着;脚本里不写反引号和 ${。
|
|
7
|
+
*/
|
|
8
|
+
import { faviconLinks } from "../shared/favicon.js";
|
|
9
|
+
import { BRAND_CSS, BRAND_FOOTER, BRAND_JS, titleLogo } from "../shared/brand.js";
|
|
10
|
+
import { pageDomJs } from "../shared/page-dom.js";
|
|
11
|
+
export const PARENT_SETTINGS_PAGE = String.raw `<!doctype html>
|
|
12
|
+
<html lang="zh-CN"><head><meta charset="utf-8">
|
|
13
|
+
<meta name="viewport" content="width=device-width,initial-scale=1,viewport-fit=cover">
|
|
14
|
+
<meta name="apple-mobile-web-app-capable" content="yes">
|
|
15
|
+
<link rel="manifest" href="/parent/manifest.webmanifest">
|
|
16
|
+
${faviconLinks()}
|
|
17
|
+
<title>家长 · 设置</title>
|
|
18
|
+
<style>
|
|
19
|
+
:root { --paper:#f6f5f1; --ink:#2b2b2b; --dim:#6b675f; --mute:#8a8781; --line:#efece5; --card:#fff; --accent:#b4531f; }
|
|
20
|
+
* { box-sizing:border-box; }
|
|
21
|
+
html,body { margin:0; background:var(--paper); color:var(--ink); font:16px/1.5 -apple-system,"PingFang SC","Hiragino Sans GB",sans-serif; -webkit-text-size-adjust:100%; }
|
|
22
|
+
button { font:inherit; color:inherit; }
|
|
23
|
+
.wrap { max-width:640px; margin:0 auto; padding:calc(env(safe-area-inset-top) + 20px) 16px calc(env(safe-area-inset-bottom) + 40px); display:flex; flex-direction:column; gap:16px; }
|
|
24
|
+
.top { display:flex; flex-wrap:wrap; align-items:center; gap:12px 20px; }
|
|
25
|
+
.top b { font-size:20px; }
|
|
26
|
+
.top .ttl { display:inline-flex; align-items:center; gap:10px; }
|
|
27
|
+
#ct-mark { display:flex; }
|
|
28
|
+
${BRAND_CSS}
|
|
29
|
+
.devl { flex:none; display:inline-flex; align-items:center; gap:4px; height:32px; padding:0 10px; border:1px solid #e2dfd6; border-radius:10px; background:#fff; color:var(--dim); font-size:13px; text-decoration:none; margin-left:auto; }
|
|
30
|
+
.top .seg { order:3; flex:1 0 100%; }
|
|
31
|
+
.seg { display:flex; padding:3px; border-radius:12px; background:#e9e6de; }
|
|
32
|
+
.seg > * { flex:1; height:36px; border-radius:9px; font-size:15px; color:var(--dim); display:flex; align-items:center; justify-content:center; text-decoration:none; }
|
|
33
|
+
.seg > .on { background:#fff; color:var(--ink); font-weight:600; box-shadow:0 1px 2px rgba(0,0,0,.08); }
|
|
34
|
+
.gh { font-size:13px; color:var(--mute); padding:8px 16px 6px; }
|
|
35
|
+
.grp { background:var(--card); border-radius:14px; padding:14px; display:flex; flex-direction:column; gap:12px; }
|
|
36
|
+
.q { font-size:16px; font-weight:500; padding:0 2px; }
|
|
37
|
+
.hands { display:grid; grid-template-columns:1fr 1fr; gap:12px; }
|
|
38
|
+
.hand { position:relative; display:flex; flex-direction:column; align-items:center; gap:8px; padding:10px 10px 12px; border:2px solid var(--line); border-radius:14px; background:#fff; cursor:pointer; -webkit-tap-highlight-color:transparent; }
|
|
39
|
+
.hand svg { display:block; width:100%; height:auto; }
|
|
40
|
+
.hand .lb { font-size:15px; color:var(--dim); }
|
|
41
|
+
.hand .lb small { display:block; font-size:12px; color:var(--mute); text-align:center; }
|
|
42
|
+
.hand.on { border-color:var(--accent); }
|
|
43
|
+
.hand.on .lb { color:var(--ink); font-weight:600; }
|
|
44
|
+
.hand .ck { position:absolute; top:-9px; right:-9px; width:22px; height:22px; border-radius:50%; background:var(--accent); color:#fff; display:none; place-items:center; }
|
|
45
|
+
.hand.on .ck { display:grid; }
|
|
46
|
+
.hand:disabled { cursor:default; opacity:.6; }
|
|
47
|
+
.note { font-size:13px; color:var(--mute); line-height:1.55; padding:0 2px; }
|
|
48
|
+
#toast { position:fixed; left:50%; bottom:calc(env(safe-area-inset-bottom) + 24px); transform:translateX(-50%); max-width:min(560px,calc(100% - 32px)); padding:12px 18px; border-radius:16px; background:#2b2b2bee; color:#fff; font-size:15px; display:none; z-index:20; white-space:pre-line; }
|
|
49
|
+
#toast.on { display:block; }
|
|
50
|
+
@media (min-width:1000px) {
|
|
51
|
+
.wrap { padding-top:calc(env(safe-area-inset-top) + 22px); gap:20px; }
|
|
52
|
+
.top .seg { order:0; flex:0 0 260px; }
|
|
53
|
+
.gh { padding:8px 6px 6px; }
|
|
54
|
+
}
|
|
55
|
+
</style></head><body>
|
|
56
|
+
<div class="wrap">
|
|
57
|
+
<div class="top"><span class="ttl"><span id="ct-mark" class="ct-draw ct-hover">${titleLogo(true)}</span><b id="title">家长</b></span><nav class="seg"><a href="/parent/home">首页</a><a href="/parent">记录</a><a class="on" href="/parent/settings">设置</a></nav><a class="devl" href="/dev" target="_blank" title="工作台:细调老师文件、activity(新窗口)">工作台<svg width="11" height="11" viewBox="0 0 12 12" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" aria-hidden="true"><path d="M4 2h6v6"/><path d="M10 2 3 9"/></svg></a></div>
|
|
58
|
+
<div>
|
|
59
|
+
<div class="gh">孩子的平板</div>
|
|
60
|
+
<div class="grp">
|
|
61
|
+
<div class="q" id="hand-q">按住说话那一栏放哪边</div>
|
|
62
|
+
<div class="hands" id="hands" role="radiogroup" aria-labelledby="hand-q"></div>
|
|
63
|
+
<div class="note">平板横着用的时候,老师页上那一栏(老师的头像、按住说话)放在这边,另一边留给写字;画板上那一列工具也跟着放这边。孩子下次进老师页就换过来。</div>
|
|
64
|
+
</div>
|
|
65
|
+
</div>
|
|
66
|
+
${BRAND_FOOTER}
|
|
67
|
+
</div>
|
|
68
|
+
<div id="toast"></div>
|
|
69
|
+
<script>
|
|
70
|
+
(() => {
|
|
71
|
+
${BRAND_JS}
|
|
72
|
+
// $ / h / toast / api(page-dom.ts,几页共用)
|
|
73
|
+
${pageDomJs(3200)}
|
|
74
|
+
const CHECK = '<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12.5l4.5 4.5L19 7.5"></path></svg>';
|
|
75
|
+
/** 示意图:横着的平板;col = 窄的那一栏在哪边('left' / 'right')。窄栏里是老师的头像与按住说话的胶囊,宽的一边是白纸上写着几行字 */
|
|
76
|
+
const sketch = (col) => {
|
|
77
|
+
const W = 240, H = 168, sx = 10, sy = 10, sw = 220, sh = 148, cw = 66;
|
|
78
|
+
const cx = col === 'left' ? sx : sx + sw - cw;
|
|
79
|
+
const px = col === 'left' ? sx + cw + 12 : sx + 12;
|
|
80
|
+
const pw = sw - cw - 24;
|
|
81
|
+
const mid = cx + cw / 2;
|
|
82
|
+
const id = 'scr-' + col;
|
|
83
|
+
const lines = [0.78, 0.6, 0.7].map((k, i) => '<path d="M' + (px + 12) + ' ' + (sy + 30 + i * 15) + 'h' + Math.round((pw - 24) * k) + '" stroke="#ddd8cc" stroke-width="4" stroke-linecap="round"></path>').join('');
|
|
84
|
+
const wx = px + 14, wy = sy + 104;
|
|
85
|
+
const ink = '<path d="M' + wx + ' ' + wy + 'c6-14 12-14 14 0s8 14 14 0 8-14 14 0 8 14 14 0" fill="none" stroke="#7a4fc9" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"></path>';
|
|
86
|
+
return '<svg viewBox="0 0 ' + W + ' ' + H + '" aria-hidden="true">'
|
|
87
|
+
+ '<defs><clipPath id="' + id + '"><rect x="' + sx + '" y="' + sy + '" width="' + sw + '" height="' + sh + '" rx="9"></rect></clipPath></defs>'
|
|
88
|
+
+ '<rect x="2" y="2" width="' + (W - 4) + '" height="' + (H - 4) + '" rx="16" fill="#34312c"></rect>'
|
|
89
|
+
+ '<g clip-path="url(#' + id + ')">'
|
|
90
|
+
+ '<rect x="' + sx + '" y="' + sy + '" width="' + sw + '" height="' + sh + '" fill="#f4f1ea"></rect>'
|
|
91
|
+
+ '<rect x="' + cx + '" y="' + sy + '" width="' + cw + '" height="' + sh + '" fill="#fffdf8"></rect>'
|
|
92
|
+
+ '<path d="M' + (col === 'left' ? cx + cw : cx) + ' ' + sy + 'v' + sh + '" stroke="#e6e1d6" stroke-width="1.5"></path>'
|
|
93
|
+
+ '</g>'
|
|
94
|
+
+ '<rect x="' + px + '" y="' + (sy + 12) + '" width="' + pw + '" height="' + (sh - 24) + '" rx="6" fill="#fff" stroke="#e6e1d6"></rect>'
|
|
95
|
+
+ lines + ink
|
|
96
|
+
+ '<circle cx="' + mid + '" cy="' + (sy + 62) + '" r="18" fill="#f6e6da" stroke="#b4531f" stroke-width="3"></circle>'
|
|
97
|
+
+ '<circle cx="' + (mid - 6) + '" cy="' + (sy + 59) + '" r="2.2" fill="#6b4a36"></circle><circle cx="' + (mid + 6) + '" cy="' + (sy + 59) + '" r="2.2" fill="#6b4a36"></circle>'
|
|
98
|
+
+ '<path d="M' + (mid - 6) + ' ' + (sy + 67) + 'q6 5 12 0" fill="none" stroke="#6b4a36" stroke-width="2" stroke-linecap="round"></path>'
|
|
99
|
+
+ '<rect x="' + (mid - 24) + '" y="' + (sy + 96) + '" width="48" height="20" rx="10" fill="#b4531f"></rect>'
|
|
100
|
+
+ '<rect x="' + (mid - 3) + '" y="' + (sy + 100) + '" width="6" height="9" rx="3" fill="#fff"></rect>'
|
|
101
|
+
+ '<path d="M' + (mid - 6) + ' ' + (sy + 106) + 'a6 6 0 0 0 12 0M' + mid + ' ' + (sy + 112) + 'v2" fill="none" stroke="#fff" stroke-width="1.6" stroke-linecap="round"></path>'
|
|
102
|
+
+ '</svg>';
|
|
103
|
+
};
|
|
104
|
+
// hand(cotutor.json 的键)→ 那一栏在哪边:right(缺省)= 栏在左边;left = 栏在右边
|
|
105
|
+
const CHOICES = [{ hand: 'right', col: 'left', label: '在左边', sub: '缺省' }, { hand: 'left', col: 'right', label: '在右边', sub: '' }];
|
|
106
|
+
let S = null; let busy = false;
|
|
107
|
+
const draw = () => {
|
|
108
|
+
const box = $('#hands');
|
|
109
|
+
box.replaceChildren(...CHOICES.map((c) => {
|
|
110
|
+
const on = S && S.hand === c.hand;
|
|
111
|
+
return h('button', { type: 'button', class: 'hand' + (on ? ' on' : ''), role: 'radio', 'aria-checked': on ? 'true' : 'false', 'aria-label': '按住说话' + c.label, disabled: busy || !S, on: { click: () => pick(c) } },
|
|
112
|
+
h('span', { class: 'ck', html: CHECK }), h('span', { style: 'display:block;width:100%', html: sketch(c.col) }),
|
|
113
|
+
h('span', { class: 'lb' }, '按住说话' + c.label, c.sub ? h('small', {}, c.sub) : null));
|
|
114
|
+
}));
|
|
115
|
+
};
|
|
116
|
+
const pick = async (c) => {
|
|
117
|
+
if (!S || busy || S.hand === c.hand) return;
|
|
118
|
+
busy = true; draw();
|
|
119
|
+
try { await api('PATCH', '/api/parent/settings', { kid: { hand: c.hand } }); S.hand = c.hand; toast('存好了:按住说话' + c.label + '。孩子下次进老师页就换过来'); }
|
|
120
|
+
catch (e) { toast('没改成:' + e.message); }
|
|
121
|
+
busy = false; draw();
|
|
122
|
+
};
|
|
123
|
+
const load = async () => {
|
|
124
|
+
try { S = await api('GET', '/api/parent/settings'); } catch (e) { toast('读不到:' + e.message); }
|
|
125
|
+
if (S) { document.title = S.title + ' · 家长 · 设置'; $('#title').textContent = S.title; }
|
|
126
|
+
draw();
|
|
127
|
+
};
|
|
128
|
+
draw();
|
|
129
|
+
load();
|
|
130
|
+
})();
|
|
131
|
+
</script>
|
|
132
|
+
</body></html>
|
|
133
|
+
`;
|
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* 二维码的打印页 /parent/qr:家长端「扫码打开」那块的「打印 ›」开它。每次请求现画,不落文件。
|
|
3
3
|
* 编什么由服务端定(ListenInfo,listen 之后才知道真端口),不看请求的 Host——家长多半是从 localhost 打开这一页的,照抄就编成了 localhost。
|
|
4
4
|
* 默认编 <本机名>.local(不随 Wi-Fi 变);个别设备会把它解析到走不通的 IPv6(一直转圈),页脚有一条换成局域网 IP 的退路(?via=ip)。
|
|
5
5
|
* 两张码:孩子端 `/`(缺省)与家长端 `/parent`(?to=parent),页脚互相换。
|
|
6
|
-
* 没有脚本;打印(⌘P)
|
|
6
|
+
* 没有脚本;打印(⌘P)只留卡面与页脚的品牌标记,可以贴书桌。不在孩子端的入口里。色板同家长端各页。
|
|
7
7
|
*/
|
|
8
8
|
import { qrNotes, qrSvg } from "../shared/qr-svg.js";
|
|
9
9
|
import { faviconLinks } from "../shared/favicon.js";
|
|
10
|
-
import {
|
|
10
|
+
import { BRAND_FOOTER } from "../shared/brand.js";
|
|
11
11
|
const esc = (s) => s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"');
|
|
12
12
|
export function qrPage(title, info, via = 'name', to = 'kid') {
|
|
13
13
|
const useIp = via === 'ip' && info.ip !== null;
|
|
14
14
|
const base = useIp ? info.ip : info.name;
|
|
15
15
|
const url = to === 'parent' ? `${base}parent` : base;
|
|
16
16
|
const svg = qrSvg(url) ?? '<p>地址太长,编不进二维码</p>';
|
|
17
|
-
const q = (v, t) => `/
|
|
17
|
+
const q = (v, t) => `/parent/qr${v === 'ip' ? '?via=ip' : ''}${t === 'parent' ? (v === 'ip' ? '&' : '?') + 'to=parent' : ''}`;
|
|
18
18
|
const other = useIp
|
|
19
19
|
? `<a href="${q('name', to)}">换回主机名那张</a>(不随 Wi-Fi 变,适合打印)`
|
|
20
20
|
: info.ip
|
|
@@ -23,8 +23,8 @@ export function qrPage(title, info, via = 'name', to = 'kid') {
|
|
|
23
23
|
// 换到另一张时带上现在真用的那种地址(要了 ip 但没连网 → 仍是主机名,不给 via=ip 的退路)
|
|
24
24
|
const cur = useIp ? 'ip' : 'name';
|
|
25
25
|
const swap = to === 'parent'
|
|
26
|
-
?
|
|
27
|
-
:
|
|
26
|
+
? `这张是家长用的:看记录、排首页。<a href="${q(cur, 'kid')}">孩子那张</a>`
|
|
27
|
+
: `家长自己的手机扫另一张:<a href="${q(cur, 'parent')}">家长那张</a>`;
|
|
28
28
|
return `<!doctype html>
|
|
29
29
|
<html lang="zh-CN">
|
|
30
30
|
<head>
|
|
@@ -33,17 +33,21 @@ export function qrPage(title, info, via = 'name', to = 'kid') {
|
|
|
33
33
|
${faviconLinks()}
|
|
34
34
|
<title>扫码打开 · ${esc(title)}${to === 'parent' ? ' · 家长' : ''}</title>
|
|
35
35
|
<style>
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
36
|
+
:root { --paper:#f6f5f1; --ink:#2b2b2b; --dim:#6b675f; --mute:#8a8781; --line:#efece5; --card:#fff; --accent:#b4531f; }
|
|
37
|
+
* { box-sizing:border-box; }
|
|
38
|
+
html, body { margin:0; background:var(--paper); color:var(--ink); font:15px/1.6 -apple-system,"PingFang SC","Hiragino Sans GB",sans-serif; }
|
|
39
|
+
body { min-height:100vh; display:flex; flex-direction:column; align-items:center; justify-content:center; padding:16px; }
|
|
40
|
+
main { background:var(--card); border-radius:16px; padding:32px 36px 28px; max-width:440px; width:100%; box-shadow:0 1px 3px #0000000d, 0 0 0 1px var(--line); }
|
|
39
41
|
h1 { margin:0 0 16px; font-size:24px; font-weight:650; text-align:center; letter-spacing:-.01em; }
|
|
40
|
-
h1 small { display:block; font-size:13.5px; font-weight:400; color:var(--
|
|
42
|
+
h1 small { display:block; font-size:13.5px; font-weight:400; color:var(--mute); letter-spacing:0; }
|
|
41
43
|
.qr svg { display:block; width:100%; max-width:340px; height:auto; margin:0 auto; }
|
|
42
|
-
.url { margin:10px 0 18px; text-align:center; font:500 14px/1.4
|
|
43
|
-
ul { margin:0; padding-left:20px; font-size:13.5px; color:var(--
|
|
44
|
+
.url { margin:10px 0 18px; text-align:center; font:500 14px/1.4 ui-monospace,"SF Mono",Menlo,monospace; word-break:break-all; background:var(--paper); border-radius:8px; padding:8px 12px; }
|
|
45
|
+
ul { margin:0; padding-left:20px; font-size:13.5px; color:var(--dim); }
|
|
44
46
|
li + li { margin-top:4px; }
|
|
45
|
-
.other { margin:16px 0 0; font-size:13px; color:var(--
|
|
46
|
-
|
|
47
|
+
.other { margin:16px 0 0; font-size:13px; color:var(--mute); text-align:center; }
|
|
48
|
+
.other a { color:var(--accent); }
|
|
49
|
+
.ct-brand { margin-top:20px; }
|
|
50
|
+
@media print { html, body { background:#fff; } body { min-height:0; } main { box-shadow:none; margin:0 auto; } .url { background:none; } .other { display:none; } }
|
|
47
51
|
</style>
|
|
48
52
|
</head>
|
|
49
53
|
<body>
|
|
@@ -55,6 +59,7 @@ ${DEV_CSS}
|
|
|
55
59
|
<p class="other">${swap}</p>
|
|
56
60
|
${other ? `<p class="other">${other}</p>` : ''}
|
|
57
61
|
</main>
|
|
62
|
+
${BRAND_FOOTER}
|
|
58
63
|
</body>
|
|
59
64
|
</html>
|
|
60
65
|
`;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* cotutor 的品牌标记(LICENSE 附加条件第 2 条):logo、名字、仓库链接,只在这里定义一份。
|
|
3
|
-
* 家长端各页的页脚用 BRAND_FOOTER,工作台的页头用 brandLogo + BRAND_CSS;「XX的老师们」前面的那颗用 titleLogo(孩子端首页、家长端记录与首页,
|
|
3
|
+
* 家长端各页的页脚用 BRAND_FOOTER,工作台的页头用 brandLogo + BRAND_CSS(logo 点了回概览,仓库链接是它下面那条「GitHub · 好用就点个 ★」);「XX的老师们」前面的那颗用 titleLogo(孩子端首页、家长端记录与首页,
|
|
4
4
|
* ):家长端彩色;孩子端跟标题同色、不带链接(首页的颜色是分给老师的,孩子端也没有外链)。
|
|
5
5
|
* 孩子端回首页的胶囊「‹ logo」用 BACK_LOGO:单色、不带链接、不动。
|
|
6
6
|
* 听写的录像页(/parent/dictation/reel)是全屏播放器,不放。
|
|
@@ -11,6 +11,8 @@
|
|
|
11
11
|
*/
|
|
12
12
|
export declare const BRAND_NAME = "cotutor";
|
|
13
13
|
export declare const BRAND_URL = "https://github.com/TarsLab/cotutor";
|
|
14
|
+
/** GitHub 的标(Octicons mark-github,16×16):工作台页头「GitHub · 好用就点个 ★」那条仓库链接用 */
|
|
15
|
+
export declare const GITHUB_MARK = "<svg width=\"15\" height=\"15\" viewBox=\"0 0 16 16\" aria-hidden=\"true\"><path fill=\"currentColor\" d=\"M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0 0 16 8c0-4.42-3.58-8-8-8z\"/></svg>";
|
|
14
16
|
export interface BrandLogoOpts {
|
|
15
17
|
/** 边长(px) */
|
|
16
18
|
size?: number;
|
package/dist/ui/shared/brand.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* cotutor 的品牌标记(LICENSE 附加条件第 2 条):logo、名字、仓库链接,只在这里定义一份。
|
|
3
|
-
* 家长端各页的页脚用 BRAND_FOOTER,工作台的页头用 brandLogo + BRAND_CSS;「XX的老师们」前面的那颗用 titleLogo(孩子端首页、家长端记录与首页,
|
|
3
|
+
* 家长端各页的页脚用 BRAND_FOOTER,工作台的页头用 brandLogo + BRAND_CSS(logo 点了回概览,仓库链接是它下面那条「GitHub · 好用就点个 ★」);「XX的老师们」前面的那颗用 titleLogo(孩子端首页、家长端记录与首页,
|
|
4
4
|
* ):家长端彩色;孩子端跟标题同色、不带链接(首页的颜色是分给老师的,孩子端也没有外链)。
|
|
5
5
|
* 孩子端回首页的胶囊「‹ logo」用 BACK_LOGO:单色、不带链接、不动。
|
|
6
6
|
* 听写的录像页(/parent/dictation/reel)是全屏播放器,不放。
|
|
@@ -12,6 +12,8 @@
|
|
|
12
12
|
import { LOGO_CLAY, LOGO_INK, logoBody, logoGeom } from "./logo.js";
|
|
13
13
|
export const BRAND_NAME = 'cotutor';
|
|
14
14
|
export const BRAND_URL = 'https://github.com/TarsLab/cotutor';
|
|
15
|
+
/** GitHub 的标(Octicons mark-github,16×16):工作台页头「GitHub · 好用就点个 ★」那条仓库链接用 */
|
|
16
|
+
export const GITHUB_MARK = '<svg width="15" height="15" viewBox="0 0 16 16" aria-hidden="true"><path fill="currentColor" d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0 0 16 8c0-4.42-3.58-8-8-8z"/></svg>';
|
|
15
17
|
/** logo 的 SVG(几何在 src/ui/shared/logo.ts,网页图标与主屏幕图标同一份) */
|
|
16
18
|
export function brandLogo({ size = 18, outer = 'currentColor', inner = outer, innerOpacity = 1 } = {}) {
|
|
17
19
|
return `<svg class="ct-logo" width="${size}" height="${size}" viewBox="0 0 100 100" aria-hidden="true">${logoBody(logoGeom(size), { outer, inner, innerOpacity })}</svg>`;
|
package/grades/grade-2/README.md
CHANGED
|
@@ -6,6 +6,6 @@
|
|
|
6
6
|
|
|
7
7
|
安装: `cotutor init ming --grade 2`。文件拷进 workspace 后属于家长;upgrade 只换未修改的。老师 ID 与现有 activity 名称保持稳定,看图说话的按钮可显示为「看图写话」。
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
三科提供预习、检查作业、复习(孩子端老师牌上常驻三块方砖);语文另有看图说话、写话、听写与表达活动;英语另有口语课、听写;小课堂继续使用提前做好的课包,看完再问。典型题型的完整示例见 `examples/数学平均分.md`。
|
|
10
10
|
|
|
11
11
|
验证:所有 activity 及例子必须通过静态检查;真实模型的评估结果见 [验证记录](VALIDATION.md),命令见仓库 `docs/年级教学包.md`。静态通过不表示教学效果已经验证。
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
- 英语:qwen3.8-flash;早期试跑用 low,最终默认采用 medium。
|
|
20
20
|
- 模拟孩子:qwen3.8-flash。
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
三科预习、批改(2026-11-03 改名检查作业,教法没改,只改了名字和开场那句「带孩子检查作业」)、复习与语文写话均跑过缺材料/给定范围多轮/结束边界。口语课验证了按给定词表热身;平均分小课堂验证了看懂就收、主动要求练一道后的互动。口语通话后半段沿用原有流程,本次没有进行真人音频通话验收。
|
|
23
23
|
|
|
24
24
|
完整批次每个例子跑 1 次,两项复习修正后的完整例子各跑 3 次,九个共性 activity 的缺材料开场各跑 3 次。轮次上限只是评估停止条件,不代表孩子已经完成学习。
|
|
25
25
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
name:
|
|
2
|
+
name: 检查作业
|
|
3
3
|
description: 看已完成的语文作业,一次订正一处
|
|
4
4
|
cards: photo image read tianzige
|
|
5
5
|
---
|
|
@@ -7,7 +7,7 @@ cards: photo image read tianzige
|
|
|
7
7
|
<!-- 给人看
|
|
8
8
|
谁读:「老师怎么带」是独立系统提示,不读老师文件。
|
|
9
9
|
能改:家长自己的文件;upgrade 保留改过的。
|
|
10
|
-
改了:cotutor activity check chinese-tutor
|
|
10
|
+
改了:cotutor activity check chinese-tutor 检查作业;再跑同名例子。
|
|
11
11
|
-->
|
|
12
12
|
|
|
13
13
|
## 家长填的
|
|
@@ -19,7 +19,7 @@ cards: photo image read tianzige
|
|
|
19
19
|
|
|
20
20
|
## 老师怎么带
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
你是这个家的语文老师,带孩子检查作业。默认面向中国大陆小学二年级。
|
|
23
23
|
教材版本、已学内容和孩子基础看档案与学科入口文件。
|
|
24
24
|
|
|
25
25
|
第一句: 本次材料不足时,照下面的开场示例回复。材料齐了就从第一步开始。
|
|
@@ -78,4 +78,4 @@ cards: photo image read tianzige
|
|
|
78
78
|
|
|
79
79
|
## 怎么挂
|
|
80
80
|
|
|
81
|
-
|
|
81
|
+
孩子端这位老师的牌上常驻一块「检查作业」方砖(家长端首页「每天都在」里能关),点了不带参数,老师先请孩子拍材料。要带范围,首页老师卡里写 `activity 检查作业`,下面填「范围:」和「重点:」。
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
name:
|
|
2
|
+
name: 检查作业
|
|
3
3
|
description: 核对已完成的英语作业,用词句示例帮助订正
|
|
4
4
|
cards: photo image word read choice
|
|
5
5
|
---
|
|
@@ -7,7 +7,7 @@ cards: photo image word read choice
|
|
|
7
7
|
<!-- 给人看
|
|
8
8
|
谁读:「老师怎么带」是独立系统提示,不读老师文件。
|
|
9
9
|
能改:家长自己的文件;upgrade 保留改过的。
|
|
10
|
-
改了:cotutor activity check english-tutor
|
|
10
|
+
改了:cotutor activity check english-tutor 检查作业;再跑同名例子。
|
|
11
11
|
-->
|
|
12
12
|
|
|
13
13
|
## 家长填的
|
|
@@ -19,7 +19,7 @@ cards: photo image word read choice
|
|
|
19
19
|
|
|
20
20
|
## 老师怎么带
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
你是这个家的英语老师,带孩子检查作业。默认面向中国大陆小学二年级。
|
|
23
23
|
教材版本、已学内容和孩子基础看档案与学科入口文件。
|
|
24
24
|
|
|
25
25
|
第一句: 本次材料不足时,照下面的开场示例回复。材料齐了就从第一步开始。
|
|
@@ -77,4 +77,4 @@ cards: photo image word read choice
|
|
|
77
77
|
|
|
78
78
|
## 怎么挂
|
|
79
79
|
|
|
80
|
-
|
|
80
|
+
孩子端这位老师的牌上常驻一块「检查作业」方砖(家长端首页「每天都在」里能关),点了不带参数,老师先请孩子拍材料。要带范围,首页老师卡里写 `activity 检查作业`,下面填「范围:」和「重点:」。
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
name:
|
|
2
|
+
name: 检查作业
|
|
3
3
|
description: 核对已完成的数学作业,找到并订正一个具体问题
|
|
4
4
|
cards: photo image canvas choice
|
|
5
5
|
---
|
|
@@ -7,7 +7,7 @@ cards: photo image canvas choice
|
|
|
7
7
|
<!-- 给人看
|
|
8
8
|
谁读:「老师怎么带」是独立系统提示,不读老师文件。
|
|
9
9
|
能改:家长自己的文件;upgrade 保留改过的。
|
|
10
|
-
改了:cotutor activity check math-tutor
|
|
10
|
+
改了:cotutor activity check math-tutor 检查作业;再跑同名例子。
|
|
11
11
|
-->
|
|
12
12
|
|
|
13
13
|
## 家长填的
|
|
@@ -19,7 +19,7 @@ cards: photo image canvas choice
|
|
|
19
19
|
|
|
20
20
|
## 老师怎么带
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
你是这个家的数学老师,带孩子检查作业。默认面向中国大陆小学二年级。
|
|
23
23
|
教材版本、已学内容和孩子基础看档案与学科入口文件。
|
|
24
24
|
|
|
25
25
|
第一句: 本次材料不足时,照下面的开场示例回复。材料齐了就从第一步开始。
|
|
@@ -77,4 +77,4 @@ cards: photo image canvas choice
|
|
|
77
77
|
|
|
78
78
|
## 怎么挂
|
|
79
79
|
|
|
80
|
-
|
|
80
|
+
孩子端这位老师的牌上常驻一块「检查作业」方砖(家长端首页「每天都在」里能关),点了不带参数,老师先请孩子拍材料。要带范围,首页老师卡里写 `activity 检查作业`,下面填「范围:」和「重点:」。
|
package/package.json
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cotutor",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"description": "AI tutors that co-teach with parents at home: real-time voice, an interactive whiteboard, and learning memory in your own Obsidian vault. Self-hosted; built for China's elementary curriculum.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "SEE LICENSE IN LICENSE",
|
|
7
|
-
"repository":
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/TarsLab/cotutor.git"
|
|
10
|
+
},
|
|
8
11
|
"homepage": "https://github.com/TarsLab/cotutor#readme",
|
|
9
12
|
"bugs": "https://github.com/TarsLab/cotutor/issues",
|
|
10
13
|
"keywords": [
|
|
@@ -45,6 +48,7 @@
|
|
|
45
48
|
"dist",
|
|
46
49
|
"grades",
|
|
47
50
|
"themes",
|
|
51
|
+
"avatars",
|
|
48
52
|
"cards",
|
|
49
53
|
"skills",
|
|
50
54
|
"README.md",
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
## 分析用的命令(在 workspace 根跑;完整用法 cotutor --help)
|
|
4
4
|
|
|
5
5
|
```
|
|
6
|
-
cotutor doctor [--workspace <dir>] [--json] [--live] 逐项体检;--live
|
|
7
|
-
cotutor send <老师> [<消息>] [--from kid|system] [--runtime <名>] [--new] [--photo a.jpg,b.png] [--activity <名> [--param '名=值;名=值']] [--lane main,tts] [--quiet] 终端里发一条,现场按道打印每道工序的事件,说完打印结果(
|
|
6
|
+
cotutor doctor [--workspace <dir>] [--json] [--live] 逐项体检;--live 真连一次百炼实时模型、真合成一句配音(花一分钱)把 API 层的坑摆出来(真跑老师用 cotutor send);--json 里不过的项带 cmd(能直接跑)或 human(要人来)
|
|
7
|
+
cotutor send <老师> [<消息>] [--from kid|system] [--runtime <名>] [--new] [--photo a.jpg,b.png] [--activity <名> [--param '名=值;名=值']] [--lane main,tts] [--quiet] 终端里发一条,现场按道打印每道工序的事件,说完打印结果(孩子的话照实时写,同孩子端:上下文包带 live:、不补提问卡,只是没有嘴;--from system 不算;--new 开新话题;--photo 带作业照片,拷进 captures/,有照片时消息可以空;--activity 像孩子点了首页的 activity 按钮,新开话题,参数同按钮下面那几行;--quiet 只要结果)
|
|
8
8
|
cotutor pack <老师> [<消息>] [--from kid|system] [--at <ISO时间>] [--activity <名> [--param '名=值;名=值']] [--json] 干跑上下文包(--activity 看 activity 话题第一条老师拿到什么):不起模型,打印现在会发给老师的那份 + 每段来自哪个文件、那里一共几条、按政策带了几条(改了档案 / 日记 / 计划立刻看效果)
|
|
9
9
|
cotutor replay <老师> <job> [<日期>] [--runtime <名>] [--json] 回放一轮:同一问按现在的 vault 与提示词再跑一遍(落 evals/,不进孩子的对话、不配音),跑完并排打印上下文包 / 讲稿 / 卡 / 读了什么的 diff
|
|
10
10
|
cotutor compare <老师> [<evalJob>] [<日期>] [--json] 再看一次回放的对照(不给 evalJob 就列这天回放过哪些)
|
|
@@ -48,13 +48,13 @@
|
|
|
48
48
|
|
|
49
49
|
## 孩子看到什么
|
|
50
50
|
|
|
51
|
-
紫色卡:左边一个相机,右边大字写要拍什么。它在最后一节时,卡下沿写「等你拍…」,旁边「拍照」「相册」两颗按钮;点了进发照片屏(能裁、能圈、能配一句话)
|
|
51
|
+
紫色卡:左边一个相机,右边大字写要拍什么。它在最后一节时,卡下沿写「等你拍…」,旁边「拍照」「相册」两颗按钮;点了进发照片屏(能裁、能圈、能配一句话),发给你。拍来的照片放大在这张卡里,配的话写在照片下面,点照片看大图。
|
|
52
52
|
|
|
53
53
|
## 你会收回什么
|
|
54
54
|
|
|
55
55
|
卡上没有状态。孩子拍来的照片随下一条消息到你手里,和他自己拍的作业照片一样:上下文包里有 `photos:` 与 `photoFiles:`,照板书写法的「作业照片」读。他配的话就是这条消息的字;没配就是「(拍了 N 张)」。
|
|
56
56
|
|
|
57
|
-
孩子没拍、直接说话(「我找不到那幅图」)
|
|
57
|
+
孩子没拍、直接说话(「我找不到那幅图」),那句话也写在这张卡里。
|
|
58
58
|
|
|
59
59
|
## 状态的形状
|
|
60
60
|
|
|
@@ -79,6 +79,7 @@ description: 排 cotutor 孩子端的首页。孩子学完之后,家长在 works
|
|
|
79
79
|
- 看完怎么聊,在这位老师的 `agents/<老师>/activities/小课堂.md`;没有这份,小课堂按钮不出(首页检查报)。
|
|
80
80
|
- 小课堂的讲法写孩子在这一课常卡在哪,别写课里已经讲过的。
|
|
81
81
|
- 「activity」是老师的一种做法,写在 `agents/<老师>/activities/<名>.md`(如语文老师的「你说我画」)。`cotutor activity check <老师>` 列出这位老师有哪些、每个要家长填什么。
|
|
82
|
+
- 预习、检查作业、复习三块方砖一直在牌上(老师家里有那个文件就有,家长端「每天都在」能关),点了参数全用缺省、老师先请孩子拍材料。不用为它们摆按钮;要指定范围(「第 22 课 1–3 自然段」)才摆 `activity 预习 我要预习小蝌蚪找妈妈`,下面填 `范围:`。
|
|
82
83
|
- 看图说话、你说我画都是语文老师的 activity:`activity 看图说话`、`activity 你说我画`。孩子在新话题里拍看图说话,老师不走那套;要他照那套说,就摆按钮。
|
|
83
84
|
- 小课堂看完要接着照某个 activity 聊(如看图说话的课),在小课堂按钮下面挂一行 `activity: 看图说话`。
|
|
84
85
|
- activity 按钮写 `activity <名> [孩子看到的字]`,下面一行一个参数(`词: 播种、羞愧`),照那个文件「## 家长填的」填;同一个 activity 填不同的参数可以是两个按钮(你说我画、我来出题)。
|
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
- `讲法: …` 挂在上一个按钮下面,写给老师的:从哪开始、重点是什么、讲到哪收。可以写多行。孩子看不到。
|
|
26
26
|
- `留到: <日期>` 挂在上一个按钮下面:这个按钮留到那天(含那天),过了孩子就看不到。不写就一直留着。
|
|
27
27
|
- `新话题` 不用写,应用永远放第一个。
|
|
28
|
+
- 预习、检查作业、复习三块方砖不用写:老师家里有那个 activity 文件就常驻在牌上(家长端「每天都在」能关),点了参数全用缺省、老师先请孩子拍材料。要带范围、重点,才另写一个 `activity 预习` 按钮;两个都留着,方砖不占按钮的名额。
|
|
28
29
|
|
|
29
30
|
## 例子
|
|
30
31
|
|
|
@@ -137,7 +138,7 @@ activity 的名字写错、参数写错或少了要填的,解析得过,首页检
|
|
|
137
138
|
|
|
138
139
|
## 孩子看到什么
|
|
139
140
|
|
|
140
|
-
首页最上面,一位老师一张卡:头像、名字,下面一个学科色大气泡「新话题 ·
|
|
141
|
+
首页最上面,一位老师一张卡:头像、名字,下面一个学科色大气泡「新话题 · 想问我什么?」,再下面一行三块方砖(预习、检查作业、复习,图在上字在下,不写小字),然后是你写的(开场按钮与 activity 按钮是带 ▶ 的大胶囊,接着按钮带 ↻;小课堂是一张带预览图的海报,图上一个播放键,下面写课名与课长)。点开场或接着按钮,老师页打开、按钮上的字立刻发出去,老师接着就讲;点新话题是空白的老师页,等孩子开口。今天从同一个按钮聊过的,在老师页的空白板上接(新话题一个胶囊;activity、小课堂先问接着还是重新开始),不占按钮。今天的条数用完、或服务不通,整张卡变灰。讲法孩子永远看不到。
|
|
141
142
|
|
|
142
143
|
## 你会收回什么
|
|
143
144
|
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
- **第一个 `## ` 起是给家长的**(「## 为什么这么排」),孩子看不到。
|
|
8
8
|
- 围栏外的普通行首页不显示(检查会提醒),要给孩子看的写进卡里。
|
|
9
9
|
|
|
10
|
-
应用保证的:每位孩子端露出的老师都有一张老师卡(没写就补一张只有「新话题」的)
|
|
10
|
+
应用保证的:每位孩子端露出的老师都有一张老师卡(没写就补一张只有「新话题」的);「新话题」永远是第一个按钮;老师家里有预习、检查作业、复习这几个 activity 的,新话题下面常驻这几块方砖(不用写,家长端能关,不占按钮的名额);应用不加「接着刚才的」——今天从同一个入口聊过的,孩子进老师页后在空白板上接(新话题是一个胶囊,activity、小课堂先问接着那个还是重新开始);引用坏了(话题找不到)的按钮不出现。
|
|
11
11
|
|
|
12
12
|
老师卡的按钮最多 4 个,每个最多 16 个字。
|
|
13
13
|
|
|
@@ -28,6 +28,7 @@
|
|
|
28
28
|
- `讲法: …` 挂在上一个按钮下面,写给老师的:从哪开始、重点是什么、讲到哪收。可以写多行。孩子看不到。
|
|
29
29
|
- `留到: <日期>` 挂在上一个按钮下面:这个按钮留到那天(含那天),过了孩子就看不到。不写就一直留着。
|
|
30
30
|
- `新话题` 不用写,应用永远放第一个。
|
|
31
|
+
- 预习、检查作业、复习三块方砖不用写:老师家里有那个 activity 文件就常驻在牌上(家长端「每天都在」能关),点了参数全用缺省、老师先请孩子拍材料。要带范围、重点,才另写一个 `activity 预习` 按钮;两个都留着,方砖不占按钮的名额。
|
|
31
32
|
|
|
32
33
|
```tutor chinese-tutor
|
|
33
34
|
我要预习小蝌蚪找妈妈
|
|
@@ -10,7 +10,7 @@ frontmatter 只写应用支持的这几个键:`name`、`description`、`maxTurns
|
|
|
10
10
|
|---|---|---|---|
|
|
11
11
|
| `display` | 必需 | | 显示名:孩子端头像下的字,计划文件的 H2 标题 |
|
|
12
12
|
| `subject` | 可选 | | 学科:与课程表的学科列、观察的 subject、vault 入口文件的 subject 属性对齐即归到这位老师 |
|
|
13
|
-
| `avatar` | 可选 | | 头像:一个 emoji,或 workspace 根以内的图片相对路径(如 avatars/math-tutor.png;figshot pick --workspace 会写这个) |
|
|
13
|
+
| `avatar` | 可选 | | 头像:一个 emoji,或 workspace 根以内的图片相对路径(如 avatars/math-tutor.png;figshot pick --workspace 会写这个);不写 = 语文、数学、英语用出厂头像,其余显示学科首字 |
|
|
14
14
|
| `color` | 可选 | | 学科色 #rrggbb:头像的环、牌的边、新话题气泡(白字压在上面,要够深,doctor 会查)、听写页的按钮;不写 = 语文粉、数学蓝、英语绿,其余按先后自动分、不撞色 |
|
|
15
15
|
| `voice` | 可选 | | 卡的配音用的音色 id(百炼 Qwen-Audio-TTS,如 qwen-audio-3.0-tts-plus-longcanzhuyue;工作台音色页「卡的配音」听着挑;点读、单词卡、听写念词的声音);不配这些卡就没有声音。老师开口的嘴在 live.voices |
|
|
16
16
|
| `enabled` | 可选 | true | 开关:false 时两端都不见 |
|
|
@@ -18,6 +18,9 @@ frontmatter 只写应用支持的这几个键:`name`、`description`、`maxTurns
|
|
|
18
18
|
| `cards` | 可选 | | 这位老师的板书写法里讲哪几种卡(text / read / choice / image / tianzige / word / lecture / canvas / paint / photo / code);不写 = 全部,text 总是带着。只裁递给老师的写法,写了清单外的卡照常显示 |
|
|
19
19
|
| `runtime` | 可选 | | 这位老师用的运行时(runtimes 里的键;不配用 default)——预算、时限不同的老师配自己的 |
|
|
20
20
|
| `extras` | 可选 | | 老师卡上的常驻入口:dictation 听写(含拍照听写)、talk 口语课(要 talk.enabled);不写按学科给缺省:语文有听写,其余没有;[] = 都不要 |
|
|
21
|
+
| `tiles.preview` | 可选 | | |
|
|
22
|
+
| `tiles.check` | 可选 | | |
|
|
23
|
+
| `tiles.review` | 可选 | | |
|
|
21
24
|
|
|
22
25
|
`policy` 是下面这张表的子集,写了的覆盖 policyDefaults,没写的继承。
|
|
23
26
|
|
|
@@ -30,7 +33,7 @@ frontmatter 只写应用支持的这几个键:`name`、`description`、`maxTurns
|
|
|
30
33
|
| `contextPack.planLines` | 必需 | 10 | 上下文包带本周计划里这位老师的前几行 |
|
|
31
34
|
| `contextPack.entryChars` | 必需 | 4000 | 档案与这位老师的入口文件(vault 里 cotutor: subject 那篇)原文各最多带多少字;超出截断并在上下文包里注明 |
|
|
32
35
|
| `effort` | 必需 | low | 老师动笔前想多久:low = 想得少、开口快(缺省,孩子等 10–15 秒);medium = 多想一会儿(算题的老师);high = 最慢最细。填进运行时模板的 {effort};模板里没有 {effort} 的运行时不受影响 |
|
|
33
|
-
| `tools` | 必需 | off | 孩子说的话,老师带不带工具:off = 不带,只凭上下文包答,开口快(缺省);on = 带只读工具(查教材、读 vault,慢)。带照片的那条、记账,总是带只读工具(read_file / glob / grep_search)
|
|
36
|
+
| `tools` | 必需 | off | 孩子说的话,老师带不带工具:off = 不带,只凭上下文包答,开口快(缺省);on = 带只读工具(查教材、读 vault,慢)。带照片的那条、记账,总是带只读工具(read_file / glob / grep_search) |
|
|
34
37
|
| `board` | 必需 | auto | 板书:auto = 讲题讲概念时老师出卡(缺省);off = 只说话不出卡 |
|
|
35
38
|
| `stall.ms` | 必需 | 30000 | 老师进程多少毫秒没有任何输出就当断流(缺省 30000;工具在跑时不算;0 = 不看,交给 CLI 自己约 180 秒的重试) |
|
|
36
39
|
| `stall.retries` | 必需 | 2 | 一轮里断流后最多接着跑几次(缺省 2);用完还断,这轮按出错收尾 |
|
|
@@ -38,7 +41,7 @@ frontmatter 只写应用支持的这几个键:`name`、`description`、`maxTurns
|
|
|
38
41
|
## 相关命令(完整用法 cotutor --help)
|
|
39
42
|
|
|
40
43
|
```
|
|
41
|
-
cotutor doctor [--workspace <dir>] [--json] [--live] 逐项体检;--live
|
|
44
|
+
cotutor doctor [--workspace <dir>] [--json] [--live] 逐项体检;--live 真连一次百炼实时模型、真合成一句配音(花一分钱)把 API 层的坑摆出来(真跑老师用 cotutor send);--json 里不过的项带 cmd(能直接跑)或 human(要人来)
|
|
42
45
|
cotutor upgrade [--workspace <dir>] [--force <老师>]... 老师文件、activity 与 skill 换新版:没改过的直接换,改过的只报 diff(--force <老师> 或 --force <老师>/<名> 才覆盖,原文留 .bak)
|
|
43
46
|
cotutor upgrade --config [--dry-run] [--workspace <dir>] cotutor.json 补缺:新出厂老师 / 运行时 / 命令模板旗标(只加缺的,你改过的值不动)
|
|
44
47
|
cotutor add <老师名> --display <显示名> [--subject <学科>] [--avatar <emoji|图片相对路径>] [--hidden] 加一位自家的老师:出模板文件、进 cotutor.json、建目录(名字以 -tutor 结尾的是老师,figshot 给它做头像)
|