dsh-aha-tutor 1.1.0 → 1.3.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-aha-tutor",
3
- "version": "1.1.0",
3
+ "version": "1.3.0",
4
4
  "description": "开窍 Aha Tutor: a personal AI tutor for DeepSeek Harness that builds a course around you and teaches it on a narrated handwriting whiteboard",
5
5
  "type": "module",
6
6
  "main": "./lib/index.js",
@@ -16,6 +16,7 @@
16
16
  "files": [
17
17
  "icon.png",
18
18
  "lib/*.js",
19
+ "assets/fonts/*",
19
20
  "locale/*.json",
20
21
  "samples/*.aha-course.json",
21
22
  "cordis.patch.yml",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "format": "aha-tutor.coursepack",
3
3
  "version": 1,
4
- "exportedAt": "2026-10-18T14:31:18.235Z",
4
+ "exportedAt": "2026-10-19T05:41:04.608Z",
5
5
  "app": {
6
6
  "name": "dsh-aha-tutor",
7
7
  "version": "sample"
@@ -16,7 +16,7 @@
16
16
  "goal": "不需要高深数学,从掷骰子和人数表格出发,理解条件概率、基础比率和贝叶斯公式,最后亲手写一个会“学习”的垃圾短信过滤器。",
17
17
  "units": [
18
18
  {
19
- "id": "unt_mvdxbbh690s900",
19
+ "id": "unt_mvettalbbn2kda",
20
20
  "title": "条件概率的直觉",
21
21
  "summary": "新信息会把世界变小,概率要在小世界里重新计算。",
22
22
  "objectives": [
@@ -25,12 +25,12 @@
25
25
  ],
26
26
  "lectures": [
27
27
  {
28
- "id": "lec_mvdxbbh6smcou2",
28
+ "id": "lec_mvettalbqgcijj",
29
29
  "title": "条件概率",
30
30
  "summary": "",
31
31
  "lessons": [
32
32
  {
33
- "id": "les_mvdxbbh620t7ly",
33
+ "id": "les_mvettalb3489i1",
34
34
  "title": "条件概率:知道一点之后",
35
35
  "summary": "在信息划定的小世界里重新数一遍。",
36
36
  "objectives": [
@@ -39,11 +39,11 @@
39
39
  ],
40
40
  "concepts": [
41
41
  {
42
- "id": "cpt_mvdxbbh60774lz",
42
+ "id": "cpt_mvettalbr7booh",
43
43
  "name": "条件概率"
44
44
  },
45
45
  {
46
- "id": "cpt_mvdxbbh6onehpm",
46
+ "id": "cpt_mvettalbf883xz",
47
47
  "name": "P(A|B) 与 P(B|A)"
48
48
  }
49
49
  ],
@@ -51,7 +51,7 @@
51
51
  "kind": "lesson"
52
52
  },
53
53
  {
54
- "id": "les_mvdxbbh629kqxj",
54
+ "id": "les_mvettalb5cl7sw",
55
55
  "title": "独立与不独立",
56
56
  "summary": "什么时候一个信息完全不改变另一个事件的概率。",
57
57
  "objectives": [
@@ -60,7 +60,7 @@
60
60
  ],
61
61
  "concepts": [
62
62
  {
63
- "id": "cpt_mvdxbbh6eaqmze",
63
+ "id": "cpt_mvettalbvpbysf",
64
64
  "name": "独立事件"
65
65
  }
66
66
  ],
@@ -70,12 +70,12 @@
70
70
  ]
71
71
  },
72
72
  {
73
- "id": "lec_mvdxbbh6x0qf9i",
73
+ "id": "lec_mvettalbgfqiuc",
74
74
  "title": "全概率",
75
75
  "summary": "",
76
76
  "lessons": [
77
77
  {
78
- "id": "les_mvdxbbh6uj7vv8",
78
+ "id": "les_mvettalbfzwku4",
79
79
  "title": "把世界切成几块:全概率公式",
80
80
  "summary": "分情况讨论,再把各部分加起来。",
81
81
  "objectives": [
@@ -84,7 +84,7 @@
84
84
  ],
85
85
  "concepts": [
86
86
  {
87
- "id": "cpt_mvdxbbh6zlxjif",
87
+ "id": "cpt_mvettalb90l4hz",
88
88
  "name": "全概率公式"
89
89
  }
90
90
  ],
@@ -96,7 +96,7 @@
96
96
  ]
97
97
  },
98
98
  {
99
- "id": "unt_mvdxbbh6o9j389",
99
+ "id": "unt_mvettalbhn9nwv",
100
100
  "title": "贝叶斯公式",
101
101
  "summary": "从结果反推原因,用证据更新信念。",
102
102
  "objectives": [
@@ -105,12 +105,12 @@
105
105
  ],
106
106
  "lectures": [
107
107
  {
108
- "id": "lec_mvdxbbh6m1g5km",
108
+ "id": "lec_mvettalbrgha10",
109
109
  "title": "贝叶斯",
110
110
  "summary": "",
111
111
  "lessons": [
112
112
  {
113
- "id": "les_mvdxbbh6z276z9",
113
+ "id": "les_mvettalb0yqhx7",
114
114
  "title": "医学检测悖论:基础比率的力量",
115
115
  "summary": "准确率 99% 的检测,阳性也未必意味着得病。",
116
116
  "objectives": [
@@ -119,11 +119,11 @@
119
119
  ],
120
120
  "concepts": [
121
121
  {
122
- "id": "cpt_mvdxbbh6fx86ag",
122
+ "id": "cpt_mvettalbb84add",
123
123
  "name": "基础比率"
124
124
  },
125
125
  {
126
- "id": "cpt_mvdxbbh6diki3n",
126
+ "id": "cpt_mvettalbh8eot6",
127
127
  "name": "贝叶斯公式"
128
128
  }
129
129
  ],
@@ -131,7 +131,7 @@
131
131
  "kind": "lesson"
132
132
  },
133
133
  {
134
- "id": "les_mvdxbbh6e65iqm",
134
+ "id": "les_mvettalb6i1vvh",
135
135
  "title": "先验、似然与后验",
136
136
  "summary": "贝叶斯公式里每一项的含义。",
137
137
  "objectives": [
@@ -140,11 +140,11 @@
140
140
  ],
141
141
  "concepts": [
142
142
  {
143
- "id": "cpt_mvdxbbh6xw1l7r",
143
+ "id": "cpt_mvettalbx5h9qc",
144
144
  "name": "先验与后验"
145
145
  },
146
146
  {
147
- "id": "cpt_mvdxbbh6h4x0wt",
147
+ "id": "cpt_mvettalbfgnoeb",
148
148
  "name": "似然"
149
149
  }
150
150
  ],
@@ -154,12 +154,12 @@
154
154
  ]
155
155
  },
156
156
  {
157
- "id": "lec_mvdxbbh6c9yilz",
157
+ "id": "lec_mvettalb8j0rl9",
158
158
  "title": "用起来",
159
159
  "summary": "",
160
160
  "lessons": [
161
161
  {
162
- "id": "les_mvdxbbh6a9irby",
162
+ "id": "les_mvettalbpsslfv",
163
163
  "title": "一次次更新你的判断",
164
164
  "summary": "每一个新证据,都让昨天的后验变成今天的先验。",
165
165
  "objectives": [
@@ -168,7 +168,7 @@
168
168
  ],
169
169
  "concepts": [
170
170
  {
171
- "id": "cpt_mvdxbbh6vytbdc",
171
+ "id": "cpt_mvettalb03n28y",
172
172
  "name": "贝叶斯更新"
173
173
  }
174
174
  ],
@@ -182,7 +182,7 @@
182
182
  ],
183
183
  "projects": [
184
184
  {
185
- "id": "prj_mvdxbbh6cllv6y",
185
+ "id": "prj_mvettalb98jgu4",
186
186
  "title": "写一个会学习的垃圾短信过滤器",
187
187
  "kind": "code",
188
188
  "brief": "用朴素贝叶斯的思路,统计正常短信和垃圾短信里各个词出现的频率,对一条新短信计算它是垃圾短信的后验概率。完成后,试着输入几条你自己的短信,看看过滤器的判断是否合理。",
@@ -253,12 +253,12 @@
253
253
  "content": "import csv\nimport math\nfrom collections import Counter\n\nrows = list(csv.DictReader(open(\"messages.csv\", encoding=\"utf-8\")))\n\n# TODO 1:分别统计 spam 和 ham 中每个词出现的次数\nspam_words, ham_words = Counter(), Counter()\n\n# TODO 2:计算先验 P(spam) 和 P(ham)\np_spam = None\np_ham = None\n\ndef score(text):\n \"\"\"返回 log P(spam|text) - log P(ham|text)。大于 0 判为垃圾短信。\"\"\"\n # TODO 3:对每个词累加 log 似然,记得做拉普拉斯平滑(每个词的计数 +1)\n return 0.0\n\nfor text in [\"恭喜 中奖 点击 领取\", \"明天 一起 吃饭\"]:\n print(text, \"->\", \"垃圾\" if score(text) > 0 else \"正常\")\n"
254
254
  }
255
255
  ],
256
- "unitId": "unt_mvdxbbh6o9j389"
256
+ "unitId": "unt_mvettalbhn9nwv"
257
257
  }
258
258
  ]
259
259
  },
260
260
  "boards": {
261
- "les_mvdxbbh620t7ly": {
261
+ "les_mvettalb3489i1": {
262
262
  "title": "条件概率:知道一点之后",
263
263
  "steps": [
264
264
  {
@@ -313,7 +313,7 @@
313
313
  {
314
314
  "id": "o5",
315
315
  "t": "p",
316
- "text": "新的“世界”只剩下 ==\\{2, 4, 6\\}=="
316
+ "text": "新的“世界”只剩下 ==$\\{2, 4, 6\\}$=="
317
317
  }
318
318
  ]
319
319
  },
@@ -342,7 +342,7 @@
342
342
  "hints": [],
343
343
  "difficulty": 2,
344
344
  "conceptIds": [
345
- "cpt_mvdxbbh60774lz"
345
+ "cpt_mvettalbr7booh"
346
346
  ],
347
347
  "options": [
348
348
  {
@@ -455,7 +455,7 @@
455
455
  "hints": [],
456
456
  "difficulty": 2,
457
457
  "conceptIds": [
458
- "cpt_mvdxbbh60774lz"
458
+ "cpt_mvettalbr7booh"
459
459
  ],
460
460
  "answer": 0.25,
461
461
  "tolerance": 0.005,
@@ -516,7 +516,7 @@
516
516
  "hints": [],
517
517
  "difficulty": 2,
518
518
  "conceptIds": [
519
- "cpt_mvdxbbh6onehpm"
519
+ "cpt_mvettalbf883xz"
520
520
  ],
521
521
  "options": [
522
522
  {
@@ -540,9 +540,9 @@
540
540
  }
541
541
  }
542
542
  ],
543
- "lessonId": "les_mvdxbbh620t7ly"
543
+ "lessonId": "les_mvettalb3489i1"
544
544
  },
545
- "les_mvdxbbh6z276z9": {
545
+ "les_mvettalb0yqhx7": {
546
546
  "title": "医学检测悖论:基础比率的力量",
547
547
  "steps": [
548
548
  {
@@ -578,7 +578,7 @@
578
578
  "hints": [],
579
579
  "difficulty": 2,
580
580
  "conceptIds": [
581
- "cpt_mvdxbbh6fx86ag"
581
+ "cpt_mvettalbb84add"
582
582
  ],
583
583
  "options": [
584
584
  {
@@ -739,8 +739,8 @@
739
739
  "hints": [],
740
740
  "difficulty": 2,
741
741
  "conceptIds": [
742
- "cpt_mvdxbbh6diki3n",
743
- "cpt_mvdxbbh6fx86ag"
742
+ "cpt_mvettalbh8eot6",
743
+ "cpt_mvettalbb84add"
744
744
  ],
745
745
  "answer": 50,
746
746
  "tolerance": 1,
@@ -804,7 +804,7 @@
804
804
  "hints": [],
805
805
  "difficulty": 2,
806
806
  "conceptIds": [
807
- "cpt_mvdxbbh6diki3n"
807
+ "cpt_mvettalbh8eot6"
808
808
  ],
809
809
  "options": [
810
810
  {
@@ -828,12 +828,12 @@
828
828
  }
829
829
  }
830
830
  ],
831
- "lessonId": "les_mvdxbbh6z276z9"
831
+ "lessonId": "les_mvettalb0yqhx7"
832
832
  }
833
833
  },
834
834
  "practice": {
835
- "les_mvdxbbh620t7ly": {
836
- "lessonId": "les_mvdxbbh620t7ly",
835
+ "les_mvettalb3489i1": {
836
+ "lessonId": "les_mvettalb3489i1",
837
837
  "items": [
838
838
  {
839
839
  "id": "i1",
@@ -845,7 +845,7 @@
845
845
  ],
846
846
  "difficulty": 1,
847
847
  "conceptIds": [
848
- "cpt_mvdxbbh60774lz"
848
+ "cpt_mvettalbr7booh"
849
849
  ],
850
850
  "options": [
851
851
  {
@@ -877,7 +877,7 @@
877
877
  ],
878
878
  "difficulty": 1,
879
879
  "conceptIds": [
880
- "cpt_mvdxbbh60774lz"
880
+ "cpt_mvettalbr7booh"
881
881
  ],
882
882
  "answer": 0.3,
883
883
  "tolerance": 0.001,
@@ -893,7 +893,7 @@
893
893
  ],
894
894
  "difficulty": 2,
895
895
  "conceptIds": [
896
- "cpt_mvdxbbh6onehpm"
896
+ "cpt_mvettalbf883xz"
897
897
  ],
898
898
  "options": [
899
899
  {
@@ -923,7 +923,7 @@
923
923
  "hints": [],
924
924
  "difficulty": 1,
925
925
  "conceptIds": [
926
- "cpt_mvdxbbh60774lz"
926
+ "cpt_mvettalbr7booh"
927
927
  ],
928
928
  "answer": [
929
929
  "P(B)",
@@ -939,7 +939,7 @@
939
939
  "hints": [],
940
940
  "difficulty": 2,
941
941
  "conceptIds": [
942
- "cpt_mvdxbbh6onehpm"
942
+ "cpt_mvettalbf883xz"
943
943
  ],
944
944
  "answer": "例如:P(会游泳 | 是游泳运动员) 接近 100%,但 P(是游泳运动员 | 会游泳) 很小,因为会游泳的人里只有极少数是运动员。",
945
945
  "rubric": [
@@ -950,8 +950,8 @@
950
950
  }
951
951
  ]
952
952
  },
953
- "les_mvdxbbh6z276z9": {
954
- "lessonId": "les_mvdxbbh6z276z9",
953
+ "les_mvettalb0yqhx7": {
954
+ "lessonId": "les_mvettalb0yqhx7",
955
955
  "items": [
956
956
  {
957
957
  "id": "i1",
@@ -963,7 +963,7 @@
963
963
  ],
964
964
  "difficulty": 1,
965
965
  "conceptIds": [
966
- "cpt_mvdxbbh6fx86ag"
966
+ "cpt_mvettalbb84add"
967
967
  ],
968
968
  "answer": 999,
969
969
  "tolerance": 1,
@@ -979,7 +979,7 @@
979
979
  ],
980
980
  "difficulty": 2,
981
981
  "conceptIds": [
982
- "cpt_mvdxbbh6fx86ag"
982
+ "cpt_mvettalbb84add"
983
983
  ],
984
984
  "options": [
985
985
  {
@@ -1011,7 +1011,7 @@
1011
1011
  ],
1012
1012
  "difficulty": 2,
1013
1013
  "conceptIds": [
1014
- "cpt_mvdxbbh6diki3n"
1014
+ "cpt_mvettalbh8eot6"
1015
1015
  ],
1016
1016
  "answer": 0.2687,
1017
1017
  "tolerance": 0.01,
@@ -1025,7 +1025,7 @@
1025
1025
  "hints": [],
1026
1026
  "difficulty": 1,
1027
1027
  "conceptIds": [
1028
- "cpt_mvdxbbh6diki3n"
1028
+ "cpt_mvettalbh8eot6"
1029
1029
  ],
1030
1030
  "options": [
1031
1031
  {
@@ -1055,8 +1055,8 @@
1055
1055
  "hints": [],
1056
1056
  "difficulty": 3,
1057
1057
  "conceptIds": [
1058
- "cpt_mvdxbbh6diki3n",
1059
- "cpt_mvdxbbh6fx86ag"
1058
+ "cpt_mvettalbh8eot6",
1059
+ "cpt_mvettalbb84add"
1060
1060
  ],
1061
1061
  "answer": "一次阳性后,患病的后验概率从很低升到较高(如从 0.1% 到约 9%);复查时这个后验成为新的先验,若再次阳性,患病概率会大幅提高(约 91%),判断更可靠。",
1062
1062
  "rubric": [