@xom11/whiteboard 0.24.1 → 0.25.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/README.md +85 -12
- package/dist/ai.d.mts +472 -0
- package/dist/ai.d.ts +472 -0
- package/dist/ai.js +2156 -0
- package/dist/ai.js.map +1 -0
- package/dist/ai.mjs +1495 -0
- package/dist/ai.mjs.map +1 -0
- package/dist/catalog.json +4 -4
- package/dist/chunk-73Q7ADVL.mjs +35 -0
- package/dist/chunk-73Q7ADVL.mjs.map +1 -0
- package/dist/{chunk-BKSXPNPQ.mjs → chunk-AYSFWUPK.mjs} +4 -3
- package/dist/chunk-AYSFWUPK.mjs.map +1 -0
- package/dist/chunk-B4NJJZFR.mjs +18 -0
- package/dist/chunk-B4NJJZFR.mjs.map +1 -0
- package/dist/{chunk-LVNCYP4J.mjs → chunk-CJBLJUWG.mjs} +5 -5
- package/dist/{chunk-LVNCYP4J.mjs.map → chunk-CJBLJUWG.mjs.map} +1 -1
- package/dist/{chunk-YIPI3WUL.mjs → chunk-ESVPQWHX.mjs} +5 -5
- package/dist/{chunk-YIPI3WUL.mjs.map → chunk-ESVPQWHX.mjs.map} +1 -1
- package/dist/{chunk-IBTRMWD6.mjs → chunk-I24QOHPU.mjs} +3 -3
- package/dist/{chunk-IBTRMWD6.mjs.map → chunk-I24QOHPU.mjs.map} +1 -1
- package/dist/{chunk-ZBJBQKJ2.mjs → chunk-IHUFOV7L.mjs} +4 -19
- package/dist/chunk-IHUFOV7L.mjs.map +1 -0
- package/dist/{chunk-AZIARTGX.mjs → chunk-M42TGYT6.mjs} +3 -3
- package/dist/{chunk-AZIARTGX.mjs.map → chunk-M42TGYT6.mjs.map} +1 -1
- package/dist/{chunk-WWMQ2VHZ.mjs → chunk-NDEZJKNY.mjs} +4 -4
- package/dist/{chunk-WWMQ2VHZ.mjs.map → chunk-NDEZJKNY.mjs.map} +1 -1
- package/dist/{chunk-CSCF3YFZ.mjs → chunk-ONBCUWVI.mjs} +6 -4
- package/dist/chunk-ONBCUWVI.mjs.map +1 -0
- package/dist/{chunk-6V4SH4JJ.mjs → chunk-REIJZDVZ.mjs} +6 -35
- package/dist/chunk-REIJZDVZ.mjs.map +1 -0
- package/dist/{chunk-4D5CSIJO.mjs → chunk-TB4CL25L.mjs} +10 -8
- package/dist/chunk-TB4CL25L.mjs.map +1 -0
- package/dist/chunk-VNCCIV6O.mjs +938 -0
- package/dist/chunk-VNCCIV6O.mjs.map +1 -0
- package/dist/{chunk-MFOGFFIL.mjs → chunk-VRHWDZ66.mjs} +6 -5
- package/dist/chunk-VRHWDZ66.mjs.map +1 -0
- package/dist/{chunk-CRAPWQKJ.mjs → chunk-YSJOVBCD.mjs} +4 -4
- package/dist/{chunk-CRAPWQKJ.mjs.map → chunk-YSJOVBCD.mjs.map} +1 -1
- package/dist/geometry-2d.d.mts +2 -1
- package/dist/geometry-2d.d.ts +2 -1
- package/dist/geometry-2d.js +1383 -23
- package/dist/geometry-2d.js.map +1 -1
- package/dist/geometry-2d.mjs +7 -5
- package/dist/geometry-3d.d.mts +2 -1
- package/dist/geometry-3d.d.ts +2 -1
- package/dist/geometry-3d.js +2 -2
- package/dist/geometry-3d.js.map +1 -1
- package/dist/geometry-3d.mjs +6 -4
- package/dist/graph-2d.d.mts +2 -1
- package/dist/graph-2d.d.ts +2 -1
- package/dist/graph-2d.js +2 -2
- package/dist/graph-2d.js.map +1 -1
- package/dist/graph-2d.mjs +9 -7
- package/dist/{host-TLIXN4CF.mjs → host-A64ITWVX.mjs} +8 -6
- package/dist/host-A64ITWVX.mjs.map +1 -0
- package/dist/{host-DOAYVL35.mjs → host-L7FMFZUW.mjs} +228 -30
- package/dist/host-L7FMFZUW.mjs.map +1 -0
- package/dist/{host-GKNQBBUE.mjs → host-QK53UYMD.mjs} +12 -10
- package/dist/host-QK53UYMD.mjs.map +1 -0
- package/dist/index.d.mts +4 -616
- package/dist/index.d.ts +4 -616
- package/dist/index.js +8889 -8529
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +21 -1012
- package/dist/index.mjs.map +1 -1
- package/dist/latex.d.mts +2 -1
- package/dist/latex.d.ts +2 -1
- package/dist/render-3WTY7NZB.mjs +9 -0
- package/dist/{render-SA4JTOW3.mjs.map → render-3WTY7NZB.mjs.map} +1 -1
- package/dist/serialize-SRJVKYUG.mjs +8 -0
- package/dist/{serialize-3NZS6A6Q.mjs.map → serialize-SRJVKYUG.mjs.map} +1 -1
- package/dist/{types-rA4slL08.d.ts → types-DWRyCa2m.d.mts} +139 -1
- package/dist/{types-rA4slL08.d.mts → types-DWRyCa2m.d.ts} +139 -1
- package/package.json +6 -1
- package/dist/chunk-4D5CSIJO.mjs.map +0 -1
- package/dist/chunk-6V4SH4JJ.mjs.map +0 -1
- package/dist/chunk-BKSXPNPQ.mjs.map +0 -1
- package/dist/chunk-CSCF3YFZ.mjs.map +0 -1
- package/dist/chunk-MFOGFFIL.mjs.map +0 -1
- package/dist/chunk-ZBJBQKJ2.mjs.map +0 -1
- package/dist/host-DOAYVL35.mjs.map +0 -1
- package/dist/host-GKNQBBUE.mjs.map +0 -1
- package/dist/host-TLIXN4CF.mjs.map +0 -1
- package/dist/render-SA4JTOW3.mjs +0 -8
- package/dist/serialize-3NZS6A6Q.mjs +0 -6
package/dist/index.mjs
CHANGED
|
@@ -1,34 +1,33 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import './index.css';
|
|
3
|
-
import { geometryStamp } from './chunk-
|
|
4
|
-
export { geometryStamp } from './chunk-
|
|
5
|
-
import { geometry3dStamp } from './chunk-
|
|
6
|
-
export { geometry3dStamp } from './chunk-
|
|
3
|
+
import { geometryStamp } from './chunk-YSJOVBCD.mjs';
|
|
4
|
+
export { geometryStamp } from './chunk-YSJOVBCD.mjs';
|
|
5
|
+
import { geometry3dStamp } from './chunk-NDEZJKNY.mjs';
|
|
6
|
+
export { geometry3dStamp } from './chunk-NDEZJKNY.mjs';
|
|
7
|
+
import './chunk-ONBCUWVI.mjs';
|
|
7
8
|
import { latexStamp } from './chunk-SGFJLHHG.mjs';
|
|
8
9
|
export { latexStamp } from './chunk-SGFJLHHG.mjs';
|
|
9
|
-
import { graph2dStamp } from './chunk-
|
|
10
|
-
export { graph2dStamp } from './chunk-
|
|
11
|
-
import './chunk-
|
|
10
|
+
import { graph2dStamp } from './chunk-ESVPQWHX.mjs';
|
|
11
|
+
export { graph2dStamp } from './chunk-ESVPQWHX.mjs';
|
|
12
|
+
import './chunk-CJBLJUWG.mjs';
|
|
12
13
|
import './chunk-O4WIZFRQ.mjs';
|
|
13
|
-
import './chunk-
|
|
14
|
-
import './chunk-
|
|
15
|
-
import './chunk-
|
|
16
|
-
import './chunk-BKSXPNPQ.mjs';
|
|
17
|
-
import './chunk-X5R72SSJ.mjs';
|
|
18
|
-
import './chunk-CSCF3YFZ.mjs';
|
|
14
|
+
import './chunk-M42TGYT6.mjs';
|
|
15
|
+
import './chunk-I24QOHPU.mjs';
|
|
16
|
+
import './chunk-VRHWDZ66.mjs';
|
|
19
17
|
import './chunk-R5FL6S7L.mjs';
|
|
18
|
+
import './chunk-AYSFWUPK.mjs';
|
|
20
19
|
import './chunk-ICR4CVOE.mjs';
|
|
21
|
-
import
|
|
22
|
-
import './chunk-
|
|
20
|
+
import './chunk-REIJZDVZ.mjs';
|
|
21
|
+
import './chunk-IHUFOV7L.mjs';
|
|
22
|
+
import './chunk-73Q7ADVL.mjs';
|
|
23
|
+
import './chunk-B4NJJZFR.mjs';
|
|
24
|
+
import './chunk-X5R72SSJ.mjs';
|
|
23
25
|
import './chunk-QGNU34T7.mjs';
|
|
24
26
|
import './chunk-5UTGXHLJ.mjs';
|
|
25
27
|
import { lazy, useRef, useCallback, useEffect, Suspense, useState, useMemo, useLayoutEffect } from 'react';
|
|
26
28
|
import { createPortal } from 'react-dom';
|
|
27
29
|
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
28
30
|
import '@excalidraw/excalidraw/index.css';
|
|
29
|
-
import { z } from 'zod';
|
|
30
|
-
import Anthropic from '@anthropic-ai/sdk';
|
|
31
|
-
import { zodToJsonSchema } from 'zod-to-json-schema';
|
|
32
31
|
|
|
33
32
|
// src/stamps/shared/catalog.ts
|
|
34
33
|
var STAMP_CATALOG = Object.freeze([
|
|
@@ -38,7 +37,7 @@ var STAMP_CATALOG = Object.freeze([
|
|
|
38
37
|
version: 1,
|
|
39
38
|
experimental: false,
|
|
40
39
|
runtimeDeps: ["jsxgraph"],
|
|
41
|
-
bundleSize: { js:
|
|
40
|
+
bundleSize: { js: 66.86, css: 0 }
|
|
42
41
|
},
|
|
43
42
|
{
|
|
44
43
|
id: "latex",
|
|
@@ -54,7 +53,7 @@ var STAMP_CATALOG = Object.freeze([
|
|
|
54
53
|
version: 2,
|
|
55
54
|
experimental: true,
|
|
56
55
|
runtimeDeps: ["jsxgraph"],
|
|
57
|
-
bundleSize: { js:
|
|
56
|
+
bundleSize: { js: 51.22, css: 0 }
|
|
58
57
|
},
|
|
59
58
|
{
|
|
60
59
|
id: "graph2d",
|
|
@@ -62,7 +61,7 @@ var STAMP_CATALOG = Object.freeze([
|
|
|
62
61
|
version: 2,
|
|
63
62
|
experimental: true,
|
|
64
63
|
runtimeDeps: ["jsxgraph"],
|
|
65
|
-
bundleSize: { js:
|
|
64
|
+
bundleSize: { js: 43.43, css: 0 }
|
|
66
65
|
}
|
|
67
66
|
]);
|
|
68
67
|
function findCatalogEntry(id) {
|
|
@@ -2155,997 +2154,7 @@ function Whiteboard({
|
|
|
2155
2154
|
)
|
|
2156
2155
|
] });
|
|
2157
2156
|
}
|
|
2158
|
-
var NameZ = z.string().regex(/^[A-Za-z][A-Za-z0-9_'₀-₉]{0,11}$/);
|
|
2159
|
-
var DslPoint = z.discriminatedUnion("kind", [
|
|
2160
|
-
z.object({
|
|
2161
|
-
name: NameZ,
|
|
2162
|
-
kind: z.literal("free"),
|
|
2163
|
-
x: z.number().finite(),
|
|
2164
|
-
y: z.number().finite()
|
|
2165
|
-
}),
|
|
2166
|
-
z.object({
|
|
2167
|
-
name: NameZ,
|
|
2168
|
-
kind: z.literal("midpoint"),
|
|
2169
|
-
p1: NameZ,
|
|
2170
|
-
p2: NameZ
|
|
2171
|
-
}),
|
|
2172
|
-
z.object({
|
|
2173
|
-
name: NameZ,
|
|
2174
|
-
kind: z.literal("onSegment"),
|
|
2175
|
-
segmentId: NameZ,
|
|
2176
|
-
t: z.number().min(0).max(1)
|
|
2177
|
-
}),
|
|
2178
|
-
z.object({
|
|
2179
|
-
name: NameZ,
|
|
2180
|
-
kind: z.literal("onLine"),
|
|
2181
|
-
lineId: NameZ,
|
|
2182
|
-
t: z.number().finite()
|
|
2183
|
-
}),
|
|
2184
|
-
z.object({
|
|
2185
|
-
name: NameZ,
|
|
2186
|
-
kind: z.literal("onCircle"),
|
|
2187
|
-
circleId: NameZ,
|
|
2188
|
-
theta: z.number().finite()
|
|
2189
|
-
}),
|
|
2190
|
-
z.object({
|
|
2191
|
-
name: NameZ,
|
|
2192
|
-
kind: z.literal("perpFoot"),
|
|
2193
|
-
from: NameZ,
|
|
2194
|
-
onLine: NameZ
|
|
2195
|
-
}),
|
|
2196
|
-
z.object({
|
|
2197
|
-
name: NameZ,
|
|
2198
|
-
kind: z.literal("circumcenter"),
|
|
2199
|
-
vertices: z.tuple([NameZ, NameZ, NameZ])
|
|
2200
|
-
}),
|
|
2201
|
-
z.object({
|
|
2202
|
-
name: NameZ,
|
|
2203
|
-
kind: z.literal("incenter"),
|
|
2204
|
-
vertices: z.tuple([NameZ, NameZ, NameZ])
|
|
2205
|
-
}),
|
|
2206
|
-
z.object({
|
|
2207
|
-
name: NameZ,
|
|
2208
|
-
kind: z.literal("centroid"),
|
|
2209
|
-
vertices: z.tuple([NameZ, NameZ, NameZ])
|
|
2210
|
-
}),
|
|
2211
|
-
z.object({
|
|
2212
|
-
name: NameZ,
|
|
2213
|
-
kind: z.literal("orthocenter"),
|
|
2214
|
-
vertices: z.tuple([NameZ, NameZ, NameZ])
|
|
2215
|
-
}),
|
|
2216
|
-
z.object({
|
|
2217
|
-
name: NameZ,
|
|
2218
|
-
kind: z.literal("intersection"),
|
|
2219
|
-
ref1: NameZ,
|
|
2220
|
-
ref2: NameZ,
|
|
2221
|
-
branch: z.union([z.literal(0), z.literal(1)]).optional()
|
|
2222
|
-
})
|
|
2223
|
-
]);
|
|
2224
|
-
var DslShape = z.discriminatedUnion("kind", [
|
|
2225
|
-
z.object({
|
|
2226
|
-
name: NameZ,
|
|
2227
|
-
kind: z.literal("segment"),
|
|
2228
|
-
p1: NameZ,
|
|
2229
|
-
p2: NameZ
|
|
2230
|
-
}),
|
|
2231
|
-
z.object({
|
|
2232
|
-
name: NameZ,
|
|
2233
|
-
kind: z.literal("line"),
|
|
2234
|
-
p1: NameZ,
|
|
2235
|
-
p2: NameZ
|
|
2236
|
-
}),
|
|
2237
|
-
z.object({
|
|
2238
|
-
name: NameZ,
|
|
2239
|
-
kind: z.literal("ray"),
|
|
2240
|
-
origin: NameZ,
|
|
2241
|
-
through: NameZ
|
|
2242
|
-
}),
|
|
2243
|
-
z.object({
|
|
2244
|
-
name: NameZ,
|
|
2245
|
-
kind: z.literal("polygon"),
|
|
2246
|
-
vertices: z.array(NameZ).min(3)
|
|
2247
|
-
}),
|
|
2248
|
-
// Line constructions
|
|
2249
|
-
z.object({
|
|
2250
|
-
name: NameZ,
|
|
2251
|
-
kind: z.literal("perpendicular"),
|
|
2252
|
-
throughPoint: NameZ,
|
|
2253
|
-
toLine: NameZ
|
|
2254
|
-
}),
|
|
2255
|
-
z.object({
|
|
2256
|
-
name: NameZ,
|
|
2257
|
-
kind: z.literal("parallel"),
|
|
2258
|
-
throughPoint: NameZ,
|
|
2259
|
-
toLine: NameZ
|
|
2260
|
-
}),
|
|
2261
|
-
z.object({
|
|
2262
|
-
name: NameZ,
|
|
2263
|
-
kind: z.literal("perpBisector"),
|
|
2264
|
-
p1: NameZ,
|
|
2265
|
-
p2: NameZ
|
|
2266
|
-
}),
|
|
2267
|
-
z.object({
|
|
2268
|
-
name: NameZ,
|
|
2269
|
-
kind: z.literal("angleBisector"),
|
|
2270
|
-
p1: NameZ,
|
|
2271
|
-
vertex: NameZ,
|
|
2272
|
-
p2: NameZ
|
|
2273
|
-
}),
|
|
2274
|
-
z.object({
|
|
2275
|
-
name: NameZ,
|
|
2276
|
-
kind: z.literal("tangent"),
|
|
2277
|
-
throughPoint: NameZ,
|
|
2278
|
-
toCircle: NameZ,
|
|
2279
|
-
branch: z.union([z.literal(0), z.literal(1), z.literal("on")]).optional()
|
|
2280
|
-
}),
|
|
2281
|
-
// Circle constructions
|
|
2282
|
-
z.object({
|
|
2283
|
-
name: NameZ,
|
|
2284
|
-
kind: z.literal("circleCP"),
|
|
2285
|
-
center: NameZ,
|
|
2286
|
-
surfacePoint: NameZ
|
|
2287
|
-
}),
|
|
2288
|
-
z.object({
|
|
2289
|
-
name: NameZ,
|
|
2290
|
-
kind: z.literal("circle3"),
|
|
2291
|
-
p1: NameZ,
|
|
2292
|
-
p2: NameZ,
|
|
2293
|
-
p3: NameZ
|
|
2294
|
-
})
|
|
2295
|
-
]);
|
|
2296
|
-
var DslInput = z.object({
|
|
2297
|
-
version: z.literal(1),
|
|
2298
|
-
points: z.array(DslPoint),
|
|
2299
|
-
shapes: z.array(DslShape).default([])
|
|
2300
|
-
});
|
|
2301
|
-
|
|
2302
|
-
// src/stamps/geometry-2d/dsl/transpile/errors.ts
|
|
2303
|
-
function mkError(code, message, opts) {
|
|
2304
|
-
return { code, message, path: opts?.path, hint: opts?.hint };
|
|
2305
|
-
}
|
|
2306
|
-
|
|
2307
|
-
// src/stamps/geometry-2d/dsl/transpile/symbols.ts
|
|
2308
|
-
function buildSymbols(dsl) {
|
|
2309
|
-
const symbols = /* @__PURE__ */ new Map();
|
|
2310
|
-
const errors = [];
|
|
2311
|
-
let counter = 0;
|
|
2312
|
-
for (const p of dsl.points) {
|
|
2313
|
-
if (symbols.has(p.name)) {
|
|
2314
|
-
errors.push(mkError("DUPLICATE_NAME", `T\xEAn tr\xF9ng: "${p.name}"`, { path: [p.name] }));
|
|
2315
|
-
continue;
|
|
2316
|
-
}
|
|
2317
|
-
symbols.set(p.name, { name: p.name, role: "point", entity: p, index: counter++ });
|
|
2318
|
-
}
|
|
2319
|
-
for (const s of dsl.shapes) {
|
|
2320
|
-
if (symbols.has(s.name)) {
|
|
2321
|
-
errors.push(mkError("DUPLICATE_NAME", `T\xEAn tr\xF9ng: "${s.name}"`, { path: [s.name] }));
|
|
2322
|
-
continue;
|
|
2323
|
-
}
|
|
2324
|
-
symbols.set(s.name, { name: s.name, role: "shape", entity: s, index: counter++ });
|
|
2325
|
-
}
|
|
2326
|
-
return { symbols, errors };
|
|
2327
|
-
}
|
|
2328
|
-
|
|
2329
|
-
// src/stamps/geometry-2d/dsl/transpile/refs.ts
|
|
2330
|
-
function isPointLike(sym) {
|
|
2331
|
-
return !!sym && sym.role === "point";
|
|
2332
|
-
}
|
|
2333
|
-
var LINE_LIKE_SHAPE_KINDS = /* @__PURE__ */ new Set([
|
|
2334
|
-
"line",
|
|
2335
|
-
"segment",
|
|
2336
|
-
"ray",
|
|
2337
|
-
"perpendicular",
|
|
2338
|
-
"parallel",
|
|
2339
|
-
"perpBisector",
|
|
2340
|
-
"angleBisector",
|
|
2341
|
-
"tangent"
|
|
2342
|
-
]);
|
|
2343
|
-
var CIRCLE_KINDS = /* @__PURE__ */ new Set(["circleCP", "circle3"]);
|
|
2344
|
-
function isLineLike(sym) {
|
|
2345
|
-
if (!sym || sym.role !== "shape") return false;
|
|
2346
|
-
return LINE_LIKE_SHAPE_KINDS.has(sym.entity.kind);
|
|
2347
|
-
}
|
|
2348
|
-
function isCircleLike(sym) {
|
|
2349
|
-
if (!sym || sym.role !== "shape") return false;
|
|
2350
|
-
return CIRCLE_KINDS.has(sym.entity.kind);
|
|
2351
|
-
}
|
|
2352
|
-
function isSegmentExact(sym) {
|
|
2353
|
-
return !!sym && sym.role === "shape" && sym.entity.kind === "segment";
|
|
2354
|
-
}
|
|
2355
|
-
function validateRefs(dsl, symbols) {
|
|
2356
|
-
const errors = [];
|
|
2357
|
-
const check = (owner, field, refName, predicate, expected) => {
|
|
2358
|
-
const sym = symbols.get(refName);
|
|
2359
|
-
if (!sym) {
|
|
2360
|
-
errors.push(mkError(
|
|
2361
|
-
"UNKNOWN_REF",
|
|
2362
|
-
`${owner}.${field} tham chi\u1EBFu "${refName}" kh\xF4ng t\u1ED3n t\u1EA1i`,
|
|
2363
|
-
{ path: [owner, field] }
|
|
2364
|
-
));
|
|
2365
|
-
return;
|
|
2366
|
-
}
|
|
2367
|
-
if (!predicate(sym)) {
|
|
2368
|
-
errors.push(mkError(
|
|
2369
|
-
"KIND_MISMATCH",
|
|
2370
|
-
`${owner}.${field}="${refName}" sai ki\u1EC3u (c\u1EA7n ${expected}, g\u1EB7p ${sym.role === "point" ? "point" : sym.entity.kind})`,
|
|
2371
|
-
{ path: [owner, field] }
|
|
2372
|
-
));
|
|
2373
|
-
}
|
|
2374
|
-
};
|
|
2375
|
-
for (const p of dsl.points) {
|
|
2376
|
-
switch (p.kind) {
|
|
2377
|
-
case "free":
|
|
2378
|
-
break;
|
|
2379
|
-
case "midpoint":
|
|
2380
|
-
check(p.name, "p1", p.p1, isPointLike, "point");
|
|
2381
|
-
check(p.name, "p2", p.p2, isPointLike, "point");
|
|
2382
|
-
break;
|
|
2383
|
-
case "onSegment":
|
|
2384
|
-
check(p.name, "segmentId", p.segmentId, isSegmentExact, "segment");
|
|
2385
|
-
break;
|
|
2386
|
-
case "onLine":
|
|
2387
|
-
check(p.name, "lineId", p.lineId, isLineLike, "line-like");
|
|
2388
|
-
break;
|
|
2389
|
-
case "onCircle":
|
|
2390
|
-
check(p.name, "circleId", p.circleId, isCircleLike, "circle");
|
|
2391
|
-
break;
|
|
2392
|
-
case "perpFoot":
|
|
2393
|
-
check(p.name, "from", p.from, isPointLike, "point");
|
|
2394
|
-
check(p.name, "onLine", p.onLine, isLineLike, "line-like");
|
|
2395
|
-
break;
|
|
2396
|
-
case "circumcenter":
|
|
2397
|
-
case "incenter":
|
|
2398
|
-
case "centroid":
|
|
2399
|
-
case "orthocenter":
|
|
2400
|
-
for (let i = 0; i < 3; i++) {
|
|
2401
|
-
check(p.name, `vertices[${i}]`, p.vertices[i], isPointLike, "point");
|
|
2402
|
-
}
|
|
2403
|
-
break;
|
|
2404
|
-
case "intersection": {
|
|
2405
|
-
const refPredicate = (s) => isLineLike(s) || isCircleLike(s);
|
|
2406
|
-
check(p.name, "ref1", p.ref1, refPredicate, "line-like ho\u1EB7c circle");
|
|
2407
|
-
check(p.name, "ref2", p.ref2, refPredicate, "line-like ho\u1EB7c circle");
|
|
2408
|
-
break;
|
|
2409
|
-
}
|
|
2410
|
-
}
|
|
2411
|
-
}
|
|
2412
|
-
for (const s of dsl.shapes) {
|
|
2413
|
-
switch (s.kind) {
|
|
2414
|
-
case "segment":
|
|
2415
|
-
case "line":
|
|
2416
|
-
check(s.name, "p1", s.p1, isPointLike, "point");
|
|
2417
|
-
check(s.name, "p2", s.p2, isPointLike, "point");
|
|
2418
|
-
break;
|
|
2419
|
-
case "ray":
|
|
2420
|
-
check(s.name, "origin", s.origin, isPointLike, "point");
|
|
2421
|
-
check(s.name, "through", s.through, isPointLike, "point");
|
|
2422
|
-
break;
|
|
2423
|
-
case "polygon":
|
|
2424
|
-
s.vertices.forEach((v, i) => check(s.name, `vertices[${i}]`, v, isPointLike, "point"));
|
|
2425
|
-
break;
|
|
2426
|
-
case "perpendicular":
|
|
2427
|
-
case "parallel":
|
|
2428
|
-
check(s.name, "throughPoint", s.throughPoint, isPointLike, "point");
|
|
2429
|
-
check(s.name, "toLine", s.toLine, isLineLike, "line-like");
|
|
2430
|
-
break;
|
|
2431
|
-
case "perpBisector":
|
|
2432
|
-
check(s.name, "p1", s.p1, isPointLike, "point");
|
|
2433
|
-
check(s.name, "p2", s.p2, isPointLike, "point");
|
|
2434
|
-
break;
|
|
2435
|
-
case "angleBisector":
|
|
2436
|
-
check(s.name, "p1", s.p1, isPointLike, "point");
|
|
2437
|
-
check(s.name, "vertex", s.vertex, isPointLike, "point");
|
|
2438
|
-
check(s.name, "p2", s.p2, isPointLike, "point");
|
|
2439
|
-
break;
|
|
2440
|
-
case "tangent":
|
|
2441
|
-
check(s.name, "throughPoint", s.throughPoint, isPointLike, "point");
|
|
2442
|
-
check(s.name, "toCircle", s.toCircle, isCircleLike, "circle");
|
|
2443
|
-
break;
|
|
2444
|
-
case "circleCP":
|
|
2445
|
-
check(s.name, "center", s.center, isPointLike, "point");
|
|
2446
|
-
check(s.name, "surfacePoint", s.surfacePoint, isPointLike, "point");
|
|
2447
|
-
break;
|
|
2448
|
-
case "circle3":
|
|
2449
|
-
check(s.name, "p1", s.p1, isPointLike, "point");
|
|
2450
|
-
check(s.name, "p2", s.p2, isPointLike, "point");
|
|
2451
|
-
check(s.name, "p3", s.p3, isPointLike, "point");
|
|
2452
|
-
break;
|
|
2453
|
-
}
|
|
2454
|
-
}
|
|
2455
|
-
return { errors };
|
|
2456
|
-
}
|
|
2457
|
-
function collectRefs(entity) {
|
|
2458
|
-
if ("kind" in entity) {
|
|
2459
|
-
switch (entity.kind) {
|
|
2460
|
-
case "free":
|
|
2461
|
-
return [];
|
|
2462
|
-
case "midpoint":
|
|
2463
|
-
return [entity.p1, entity.p2];
|
|
2464
|
-
case "onSegment":
|
|
2465
|
-
return [entity.segmentId];
|
|
2466
|
-
case "onLine":
|
|
2467
|
-
return [entity.lineId];
|
|
2468
|
-
case "onCircle":
|
|
2469
|
-
return [entity.circleId];
|
|
2470
|
-
case "perpFoot":
|
|
2471
|
-
return [entity.from, entity.onLine];
|
|
2472
|
-
case "circumcenter":
|
|
2473
|
-
case "incenter":
|
|
2474
|
-
case "centroid":
|
|
2475
|
-
case "orthocenter":
|
|
2476
|
-
return [...entity.vertices];
|
|
2477
|
-
case "intersection":
|
|
2478
|
-
return [entity.ref1, entity.ref2];
|
|
2479
|
-
case "segment":
|
|
2480
|
-
case "line":
|
|
2481
|
-
return [entity.p1, entity.p2];
|
|
2482
|
-
case "ray":
|
|
2483
|
-
return [entity.origin, entity.through];
|
|
2484
|
-
case "polygon":
|
|
2485
|
-
return [...entity.vertices];
|
|
2486
|
-
case "perpendicular":
|
|
2487
|
-
case "parallel":
|
|
2488
|
-
return [entity.throughPoint, entity.toLine];
|
|
2489
|
-
case "perpBisector":
|
|
2490
|
-
return [entity.p1, entity.p2];
|
|
2491
|
-
case "angleBisector":
|
|
2492
|
-
return [entity.p1, entity.vertex, entity.p2];
|
|
2493
|
-
case "tangent":
|
|
2494
|
-
return [entity.throughPoint, entity.toCircle];
|
|
2495
|
-
case "circleCP":
|
|
2496
|
-
return [entity.center, entity.surfacePoint];
|
|
2497
|
-
case "circle3":
|
|
2498
|
-
return [entity.p1, entity.p2, entity.p3];
|
|
2499
|
-
}
|
|
2500
|
-
}
|
|
2501
|
-
return [];
|
|
2502
|
-
}
|
|
2503
|
-
|
|
2504
|
-
// src/stamps/geometry-2d/dsl/transpile/cycles.ts
|
|
2505
|
-
function detectCycles(symbols) {
|
|
2506
|
-
const color = /* @__PURE__ */ new Map();
|
|
2507
|
-
const parent = /* @__PURE__ */ new Map();
|
|
2508
|
-
const errors = [];
|
|
2509
|
-
const reportedCycles = /* @__PURE__ */ new Set();
|
|
2510
|
-
for (const name of symbols.keys()) color.set(name, "white");
|
|
2511
|
-
function reportCycle(start, hit) {
|
|
2512
|
-
const chain = [start];
|
|
2513
|
-
let cur = parent.get(start);
|
|
2514
|
-
while (cur && cur !== hit && chain.length < symbols.size + 2) {
|
|
2515
|
-
chain.push(cur);
|
|
2516
|
-
cur = parent.get(cur);
|
|
2517
|
-
}
|
|
2518
|
-
chain.push(hit);
|
|
2519
|
-
const minIdx = chain.indexOf(chain.reduce((a, b) => a < b ? a : b));
|
|
2520
|
-
const rotated = [...chain.slice(minIdx), ...chain.slice(0, minIdx)];
|
|
2521
|
-
const key = rotated.join("\u2192");
|
|
2522
|
-
if (reportedCycles.has(key)) return;
|
|
2523
|
-
reportedCycles.add(key);
|
|
2524
|
-
errors.push(mkError(
|
|
2525
|
-
"CYCLE",
|
|
2526
|
-
`Ph\u1EE5 thu\u1ED9c v\xF2ng: ${chain.reverse().join(" \u2192 ")}`,
|
|
2527
|
-
{ path: [...chain], hint: "Ki\u1EC3m tra l\u1EA1i quan h\u1EC7 midpoint/perpFoot/intersection." }
|
|
2528
|
-
));
|
|
2529
|
-
}
|
|
2530
|
-
function dfs(name) {
|
|
2531
|
-
color.set(name, "gray");
|
|
2532
|
-
const sym = symbols.get(name);
|
|
2533
|
-
if (sym) {
|
|
2534
|
-
for (const ref of collectRefs(sym.entity)) {
|
|
2535
|
-
if (!symbols.has(ref)) continue;
|
|
2536
|
-
const c = color.get(ref);
|
|
2537
|
-
if (c === "gray") {
|
|
2538
|
-
reportCycle(name, ref);
|
|
2539
|
-
continue;
|
|
2540
|
-
}
|
|
2541
|
-
if (c === "white") {
|
|
2542
|
-
parent.set(ref, name);
|
|
2543
|
-
dfs(ref);
|
|
2544
|
-
}
|
|
2545
|
-
}
|
|
2546
|
-
}
|
|
2547
|
-
color.set(name, "black");
|
|
2548
|
-
}
|
|
2549
|
-
for (const name of symbols.keys()) {
|
|
2550
|
-
if (color.get(name) === "white") {
|
|
2551
|
-
parent.set(name, null);
|
|
2552
|
-
dfs(name);
|
|
2553
|
-
}
|
|
2554
|
-
}
|
|
2555
|
-
return { errors };
|
|
2556
|
-
}
|
|
2557
|
-
|
|
2558
|
-
// src/stamps/geometry-2d/dsl/transpile/ids.ts
|
|
2559
|
-
function prefixFor(sym) {
|
|
2560
|
-
if (sym.role === "point") {
|
|
2561
|
-
const p = sym.entity;
|
|
2562
|
-
return p.kind === "intersection" ? "i" : "p";
|
|
2563
|
-
}
|
|
2564
|
-
const s = sym.entity;
|
|
2565
|
-
switch (s.kind) {
|
|
2566
|
-
case "segment":
|
|
2567
|
-
return "s";
|
|
2568
|
-
case "ray":
|
|
2569
|
-
return "r";
|
|
2570
|
-
case "polygon":
|
|
2571
|
-
return "poly";
|
|
2572
|
-
case "circleCP":
|
|
2573
|
-
case "circle3":
|
|
2574
|
-
return "c";
|
|
2575
|
-
// line + 5 line-constructions all share 'l'
|
|
2576
|
-
case "line":
|
|
2577
|
-
case "perpendicular":
|
|
2578
|
-
case "parallel":
|
|
2579
|
-
case "perpBisector":
|
|
2580
|
-
case "angleBisector":
|
|
2581
|
-
case "tangent":
|
|
2582
|
-
return "l";
|
|
2583
|
-
}
|
|
2584
|
-
}
|
|
2585
|
-
function assignIds(symbols) {
|
|
2586
|
-
const counters = { p: 0, i: 0, s: 0, l: 0, r: 0, poly: 0, c: 0 };
|
|
2587
|
-
const ids = /* @__PURE__ */ new Map();
|
|
2588
|
-
for (const [name, sym] of symbols.entries()) {
|
|
2589
|
-
const prefix = prefixFor(sym);
|
|
2590
|
-
counters[prefix] += 1;
|
|
2591
|
-
ids.set(name, `${prefix}${counters[prefix]}`);
|
|
2592
|
-
}
|
|
2593
|
-
return ids;
|
|
2594
|
-
}
|
|
2595
|
-
|
|
2596
|
-
// src/stamps/geometry-2d/dsl/transpile/emitPoint.ts
|
|
2597
|
-
function resolveId(ids, name) {
|
|
2598
|
-
const id = ids.get(name);
|
|
2599
|
-
if (!id) throw new Error(`emitPoint: id not assigned for "${name}"`);
|
|
2600
|
-
return id;
|
|
2601
|
-
}
|
|
2602
|
-
function emitPoint(p, ids, kindHints) {
|
|
2603
|
-
const baseId = resolveId(ids, p.name);
|
|
2604
|
-
const baseFields = {
|
|
2605
|
-
label: p.name,
|
|
2606
|
-
visible: true,
|
|
2607
|
-
locked: false,
|
|
2608
|
-
layer: "default",
|
|
2609
|
-
schemaVersion: 1
|
|
2610
|
-
};
|
|
2611
|
-
if (p.kind === "intersection") {
|
|
2612
|
-
const r1Hint = kindHints.get(p.ref1);
|
|
2613
|
-
const r2Hint = kindHints.get(p.ref2);
|
|
2614
|
-
const r1IsCircle = r1Hint === "circle";
|
|
2615
|
-
const r2IsCircle = r2Hint === "circle";
|
|
2616
|
-
let intersectKind;
|
|
2617
|
-
if (r1IsCircle && r2IsCircle) intersectKind = "circleCircle";
|
|
2618
|
-
else if (r1IsCircle || r2IsCircle) intersectKind = "lineCircle";
|
|
2619
|
-
else intersectKind = "lineLine";
|
|
2620
|
-
const attrs = {
|
|
2621
|
-
kind: intersectKind,
|
|
2622
|
-
ref1: resolveId(ids, p.ref1),
|
|
2623
|
-
ref2: resolveId(ids, p.ref2)
|
|
2624
|
-
};
|
|
2625
|
-
if (intersectKind !== "lineLine") {
|
|
2626
|
-
attrs.branch = p.branch ?? 0;
|
|
2627
|
-
}
|
|
2628
|
-
return {
|
|
2629
|
-
id: baseId,
|
|
2630
|
-
kind: "intersection",
|
|
2631
|
-
...baseFields,
|
|
2632
|
-
attrs
|
|
2633
|
-
};
|
|
2634
|
-
}
|
|
2635
|
-
let constraint;
|
|
2636
|
-
switch (p.kind) {
|
|
2637
|
-
case "free":
|
|
2638
|
-
constraint = { kind: "free", x: p.x, y: p.y };
|
|
2639
|
-
break;
|
|
2640
|
-
case "midpoint":
|
|
2641
|
-
constraint = { kind: "midpoint", p1: resolveId(ids, p.p1), p2: resolveId(ids, p.p2) };
|
|
2642
|
-
break;
|
|
2643
|
-
case "onSegment":
|
|
2644
|
-
constraint = { kind: "onSegment", segmentId: resolveId(ids, p.segmentId), t: p.t };
|
|
2645
|
-
break;
|
|
2646
|
-
case "onLine":
|
|
2647
|
-
constraint = { kind: "onLine", lineId: resolveId(ids, p.lineId), t: p.t };
|
|
2648
|
-
break;
|
|
2649
|
-
case "onCircle":
|
|
2650
|
-
constraint = { kind: "onCircle", circleId: resolveId(ids, p.circleId), theta: p.theta };
|
|
2651
|
-
break;
|
|
2652
|
-
case "perpFoot":
|
|
2653
|
-
constraint = { kind: "perpFoot", from: resolveId(ids, p.from), onLine: resolveId(ids, p.onLine) };
|
|
2654
|
-
break;
|
|
2655
|
-
case "circumcenter":
|
|
2656
|
-
case "incenter":
|
|
2657
|
-
case "centroid":
|
|
2658
|
-
case "orthocenter":
|
|
2659
|
-
constraint = {
|
|
2660
|
-
kind: p.kind,
|
|
2661
|
-
vertices: [resolveId(ids, p.vertices[0]), resolveId(ids, p.vertices[1]), resolveId(ids, p.vertices[2])]
|
|
2662
|
-
};
|
|
2663
|
-
break;
|
|
2664
|
-
}
|
|
2665
|
-
return {
|
|
2666
|
-
id: baseId,
|
|
2667
|
-
kind: "point",
|
|
2668
|
-
...baseFields,
|
|
2669
|
-
attrs: { constraint }
|
|
2670
|
-
};
|
|
2671
|
-
}
|
|
2672
|
-
|
|
2673
|
-
// src/stamps/geometry-2d/dsl/transpile/emitShape.ts
|
|
2674
|
-
function r(ids, name) {
|
|
2675
|
-
const id = ids.get(name);
|
|
2676
|
-
if (!id) throw new Error(`emitShape: id not assigned for "${name}"`);
|
|
2677
|
-
return id;
|
|
2678
|
-
}
|
|
2679
|
-
function emitShape(s, ids) {
|
|
2680
|
-
const id = r(ids, s.name);
|
|
2681
|
-
const base = {
|
|
2682
|
-
label: s.name,
|
|
2683
|
-
visible: true,
|
|
2684
|
-
locked: false,
|
|
2685
|
-
layer: "default",
|
|
2686
|
-
schemaVersion: 1
|
|
2687
|
-
};
|
|
2688
|
-
switch (s.kind) {
|
|
2689
|
-
case "segment":
|
|
2690
|
-
return { id, kind: "segment", ...base, attrs: { p1: r(ids, s.p1), p2: r(ids, s.p2) } };
|
|
2691
|
-
case "line":
|
|
2692
|
-
return { id, kind: "line", ...base, attrs: { p1: r(ids, s.p1), p2: r(ids, s.p2) } };
|
|
2693
|
-
case "ray":
|
|
2694
|
-
return { id, kind: "ray", ...base, attrs: { origin: r(ids, s.origin), through: r(ids, s.through) } };
|
|
2695
|
-
case "polygon":
|
|
2696
|
-
return { id, kind: "polygon", ...base, attrs: { vertices: s.vertices.map((v) => r(ids, v)) } };
|
|
2697
|
-
case "perpendicular":
|
|
2698
|
-
case "parallel":
|
|
2699
|
-
return {
|
|
2700
|
-
id,
|
|
2701
|
-
kind: "line",
|
|
2702
|
-
...base,
|
|
2703
|
-
attrs: { construction: { kind: s.kind, throughPoint: r(ids, s.throughPoint), toLine: r(ids, s.toLine) } }
|
|
2704
|
-
};
|
|
2705
|
-
case "perpBisector":
|
|
2706
|
-
return {
|
|
2707
|
-
id,
|
|
2708
|
-
kind: "line",
|
|
2709
|
-
...base,
|
|
2710
|
-
attrs: { construction: { kind: "perpBisector", p1: r(ids, s.p1), p2: r(ids, s.p2) } }
|
|
2711
|
-
};
|
|
2712
|
-
case "angleBisector":
|
|
2713
|
-
return {
|
|
2714
|
-
id,
|
|
2715
|
-
kind: "line",
|
|
2716
|
-
...base,
|
|
2717
|
-
attrs: { construction: { kind: "angleBisector", p1: r(ids, s.p1), vertex: r(ids, s.vertex), p2: r(ids, s.p2) } }
|
|
2718
|
-
};
|
|
2719
|
-
case "tangent": {
|
|
2720
|
-
const construction = {
|
|
2721
|
-
kind: "tangent",
|
|
2722
|
-
throughPoint: r(ids, s.throughPoint),
|
|
2723
|
-
toCircle: r(ids, s.toCircle)
|
|
2724
|
-
};
|
|
2725
|
-
if (s.branch !== void 0) construction.branch = s.branch;
|
|
2726
|
-
return { id, kind: "line", ...base, attrs: { construction } };
|
|
2727
|
-
}
|
|
2728
|
-
case "circleCP":
|
|
2729
|
-
return {
|
|
2730
|
-
id,
|
|
2731
|
-
kind: "circle",
|
|
2732
|
-
...base,
|
|
2733
|
-
attrs: { center: r(ids, s.center), surfacePoint: r(ids, s.surfacePoint) }
|
|
2734
|
-
};
|
|
2735
|
-
case "circle3":
|
|
2736
|
-
return {
|
|
2737
|
-
id,
|
|
2738
|
-
kind: "circle",
|
|
2739
|
-
...base,
|
|
2740
|
-
attrs: { construction: { kind: "circumscribed", p1: r(ids, s.p1), p2: r(ids, s.p2), p3: r(ids, s.p3) } }
|
|
2741
|
-
};
|
|
2742
|
-
}
|
|
2743
|
-
}
|
|
2744
|
-
|
|
2745
|
-
// src/stamps/geometry-2d/dsl/transpile.ts
|
|
2746
|
-
function hintOf(entity) {
|
|
2747
|
-
if ("kind" in entity) {
|
|
2748
|
-
switch (entity.kind) {
|
|
2749
|
-
case "free":
|
|
2750
|
-
case "midpoint":
|
|
2751
|
-
case "onSegment":
|
|
2752
|
-
case "onLine":
|
|
2753
|
-
case "onCircle":
|
|
2754
|
-
case "perpFoot":
|
|
2755
|
-
case "circumcenter":
|
|
2756
|
-
case "incenter":
|
|
2757
|
-
case "centroid":
|
|
2758
|
-
case "orthocenter":
|
|
2759
|
-
case "intersection":
|
|
2760
|
-
return "point";
|
|
2761
|
-
case "segment":
|
|
2762
|
-
return "segment";
|
|
2763
|
-
case "line":
|
|
2764
|
-
return "line";
|
|
2765
|
-
case "ray":
|
|
2766
|
-
return "ray";
|
|
2767
|
-
case "polygon":
|
|
2768
|
-
return "point";
|
|
2769
|
-
// not used as ref target in MVP
|
|
2770
|
-
case "perpendicular":
|
|
2771
|
-
case "parallel":
|
|
2772
|
-
case "perpBisector":
|
|
2773
|
-
case "angleBisector":
|
|
2774
|
-
case "tangent":
|
|
2775
|
-
return "lineConstruction";
|
|
2776
|
-
case "circleCP":
|
|
2777
|
-
case "circle3":
|
|
2778
|
-
return "circle";
|
|
2779
|
-
}
|
|
2780
|
-
}
|
|
2781
|
-
return "point";
|
|
2782
|
-
}
|
|
2783
|
-
function transpile(dslRaw) {
|
|
2784
|
-
const parsed = DslInput.safeParse(dslRaw);
|
|
2785
|
-
if (!parsed.success) {
|
|
2786
|
-
const errors = parsed.error.issues.map(
|
|
2787
|
-
(iss) => mkError("SCHEMA", iss.message, { path: iss.path.map(String) })
|
|
2788
|
-
);
|
|
2789
|
-
return { ok: false, errors };
|
|
2790
|
-
}
|
|
2791
|
-
const dsl = parsed.data;
|
|
2792
|
-
const { symbols, errors: dupErrors } = buildSymbols(dsl);
|
|
2793
|
-
const { errors: refErrors } = validateRefs(dsl, symbols);
|
|
2794
|
-
const { errors: cycleErrors } = detectCycles(symbols);
|
|
2795
|
-
const allErrors = [...dupErrors, ...refErrors, ...cycleErrors];
|
|
2796
|
-
if (allErrors.length > 0) return { ok: false, errors: allErrors };
|
|
2797
|
-
const ids = assignIds(symbols);
|
|
2798
|
-
const kindHints = /* @__PURE__ */ new Map();
|
|
2799
|
-
for (const [name, sym] of symbols.entries()) {
|
|
2800
|
-
kindHints.set(name, hintOf(sym.entity));
|
|
2801
|
-
}
|
|
2802
|
-
const objects = {};
|
|
2803
|
-
const order = [];
|
|
2804
|
-
for (const p of dsl.points) {
|
|
2805
|
-
const obj = emitPoint(p, ids, kindHints);
|
|
2806
|
-
objects[obj.id] = obj;
|
|
2807
|
-
order.push(obj.id);
|
|
2808
|
-
}
|
|
2809
|
-
for (const s of dsl.shapes) {
|
|
2810
|
-
const obj = emitShape(s, ids);
|
|
2811
|
-
objects[obj.id] = obj;
|
|
2812
|
-
order.push(obj.id);
|
|
2813
|
-
}
|
|
2814
|
-
const empty = createEmptyState("2d");
|
|
2815
|
-
const state = {
|
|
2816
|
-
objects,
|
|
2817
|
-
order,
|
|
2818
|
-
counter: order.length,
|
|
2819
|
-
meta: empty.meta
|
|
2820
|
-
};
|
|
2821
|
-
return { ok: true, state };
|
|
2822
|
-
}
|
|
2823
|
-
async function callProvider(args) {
|
|
2824
|
-
const client = new Anthropic({ apiKey: args.apiKey });
|
|
2825
|
-
const resp = await client.messages.create(
|
|
2826
|
-
{
|
|
2827
|
-
model: args.model,
|
|
2828
|
-
max_tokens: args.maxTokens,
|
|
2829
|
-
system: args.system,
|
|
2830
|
-
tools: args.tools,
|
|
2831
|
-
tool_choice: args.toolChoice,
|
|
2832
|
-
messages: args.messages
|
|
2833
|
-
},
|
|
2834
|
-
args.signal ? { signal: args.signal } : void 0
|
|
2835
|
-
);
|
|
2836
|
-
return resp;
|
|
2837
|
-
}
|
|
2838
|
-
|
|
2839
|
-
// src/stamps/geometry-2d/dsl/fixtures/triangle-equilateral.ts
|
|
2840
|
-
var fixture = {
|
|
2841
|
-
problem: "Cho tam gi\xE1c \u0111\u1EC1u ABC c\u1EA1nh 4.",
|
|
2842
|
-
dsl: {
|
|
2843
|
-
version: 1,
|
|
2844
|
-
points: [
|
|
2845
|
-
{ name: "A", kind: "free", x: 0, y: 0 },
|
|
2846
|
-
{ name: "B", kind: "free", x: 4, y: 0 },
|
|
2847
|
-
{ name: "C", kind: "free", x: 2, y: 3.464 }
|
|
2848
|
-
],
|
|
2849
|
-
shapes: [
|
|
2850
|
-
{ name: "ABC", kind: "polygon", vertices: ["A", "B", "C"] }
|
|
2851
|
-
]
|
|
2852
|
-
}
|
|
2853
|
-
};
|
|
2854
|
-
|
|
2855
|
-
// src/stamps/geometry-2d/dsl/fixtures/triangle-median.ts
|
|
2856
|
-
var fixture2 = {
|
|
2857
|
-
problem: "Tam gi\xE1c ABC, M l\xE0 trung \u0111i\u1EC3m BC. V\u1EBD AM.",
|
|
2858
|
-
dsl: {
|
|
2859
|
-
version: 1,
|
|
2860
|
-
points: [
|
|
2861
|
-
{ name: "A", kind: "free", x: 0, y: 3 },
|
|
2862
|
-
{ name: "B", kind: "free", x: -2, y: 0 },
|
|
2863
|
-
{ name: "C", kind: "free", x: 3, y: 0 },
|
|
2864
|
-
{ name: "M", kind: "midpoint", p1: "B", p2: "C" }
|
|
2865
|
-
],
|
|
2866
|
-
shapes: [
|
|
2867
|
-
{ name: "ABC", kind: "polygon", vertices: ["A", "B", "C"] },
|
|
2868
|
-
{ name: "AM", kind: "segment", p1: "A", p2: "M" }
|
|
2869
|
-
]
|
|
2870
|
-
}
|
|
2871
|
-
};
|
|
2872
|
-
|
|
2873
|
-
// src/stamps/geometry-2d/dsl/fixtures/triangle-altitude.ts
|
|
2874
|
-
var fixture3 = {
|
|
2875
|
-
problem: "Tam gi\xE1c ABC, AH l\xE0 \u0111\u01B0\u1EDDng cao xu\u1ED1ng BC.",
|
|
2876
|
-
dsl: {
|
|
2877
|
-
version: 1,
|
|
2878
|
-
points: [
|
|
2879
|
-
{ name: "A", kind: "free", x: 1, y: 3 },
|
|
2880
|
-
{ name: "B", kind: "free", x: -2, y: 0 },
|
|
2881
|
-
{ name: "C", kind: "free", x: 3, y: 0 },
|
|
2882
|
-
{ name: "H", kind: "perpFoot", from: "A", onLine: "BC" }
|
|
2883
|
-
],
|
|
2884
|
-
shapes: [
|
|
2885
|
-
{ name: "ABC", kind: "polygon", vertices: ["A", "B", "C"] },
|
|
2886
|
-
{ name: "BC", kind: "segment", p1: "B", p2: "C" },
|
|
2887
|
-
{ name: "AH", kind: "segment", p1: "A", p2: "H" }
|
|
2888
|
-
]
|
|
2889
|
-
}
|
|
2890
|
-
};
|
|
2891
|
-
|
|
2892
|
-
// src/stamps/geometry-2d/dsl/fixtures/triangle-centroid.ts
|
|
2893
|
-
var fixture4 = {
|
|
2894
|
-
problem: "Tam gi\xE1c ABC, G l\xE0 tr\u1ECDng t\xE2m.",
|
|
2895
|
-
dsl: {
|
|
2896
|
-
version: 1,
|
|
2897
|
-
points: [
|
|
2898
|
-
{ name: "A", kind: "free", x: 0, y: 3 },
|
|
2899
|
-
{ name: "B", kind: "free", x: -2, y: 0 },
|
|
2900
|
-
{ name: "C", kind: "free", x: 3, y: 0 },
|
|
2901
|
-
{ name: "G", kind: "centroid", vertices: ["A", "B", "C"] }
|
|
2902
|
-
],
|
|
2903
|
-
shapes: [
|
|
2904
|
-
{ name: "ABC", kind: "polygon", vertices: ["A", "B", "C"] }
|
|
2905
|
-
]
|
|
2906
|
-
}
|
|
2907
|
-
};
|
|
2908
|
-
|
|
2909
|
-
// src/stamps/geometry-2d/dsl/fixtures/triangle-orthocenter.ts
|
|
2910
|
-
var fixture5 = {
|
|
2911
|
-
problem: "Tam gi\xE1c ABC, H l\xE0 tr\u1EF1c t\xE2m.",
|
|
2912
|
-
dsl: {
|
|
2913
|
-
version: 1,
|
|
2914
|
-
points: [
|
|
2915
|
-
{ name: "A", kind: "free", x: 0, y: 3 },
|
|
2916
|
-
{ name: "B", kind: "free", x: -2, y: 0 },
|
|
2917
|
-
{ name: "C", kind: "free", x: 3, y: 0 },
|
|
2918
|
-
{ name: "H", kind: "orthocenter", vertices: ["A", "B", "C"] }
|
|
2919
|
-
],
|
|
2920
|
-
shapes: [
|
|
2921
|
-
{ name: "ABC", kind: "polygon", vertices: ["A", "B", "C"] }
|
|
2922
|
-
]
|
|
2923
|
-
}
|
|
2924
|
-
};
|
|
2925
|
-
|
|
2926
|
-
// src/stamps/geometry-2d/dsl/fixtures/triangle-circumcircle.ts
|
|
2927
|
-
var fixture6 = {
|
|
2928
|
-
problem: "Tam gi\xE1c ABC n\u1ED9i ti\u1EBFp \u0111\u01B0\u1EDDng tr\xF2n t\xE2m O.",
|
|
2929
|
-
dsl: {
|
|
2930
|
-
version: 1,
|
|
2931
|
-
points: [
|
|
2932
|
-
{ name: "A", kind: "free", x: 0, y: 3 },
|
|
2933
|
-
{ name: "B", kind: "free", x: -2, y: 0 },
|
|
2934
|
-
{ name: "C", kind: "free", x: 3, y: 0 },
|
|
2935
|
-
{ name: "O", kind: "circumcenter", vertices: ["A", "B", "C"] }
|
|
2936
|
-
],
|
|
2937
|
-
shapes: [
|
|
2938
|
-
{ name: "ABC", kind: "polygon", vertices: ["A", "B", "C"] },
|
|
2939
|
-
{ name: "k", kind: "circle3", p1: "A", p2: "B", p3: "C" }
|
|
2940
|
-
]
|
|
2941
|
-
}
|
|
2942
|
-
};
|
|
2943
|
-
|
|
2944
|
-
// src/stamps/geometry-2d/dsl/fixtures/triangle-incircle.ts
|
|
2945
|
-
var fixture7 = {
|
|
2946
|
-
problem: "Tam gi\xE1c ABC, I l\xE0 t\xE2m n\u1ED9i ti\u1EBFp, \u0111\u01B0\u1EDDng tr\xF2n (I) ti\u1EBFp x\xFAc BC t\u1EA1i D.",
|
|
2947
|
-
dsl: {
|
|
2948
|
-
version: 1,
|
|
2949
|
-
points: [
|
|
2950
|
-
{ name: "A", kind: "free", x: 0, y: 3 },
|
|
2951
|
-
{ name: "B", kind: "free", x: -2, y: 0 },
|
|
2952
|
-
{ name: "C", kind: "free", x: 3, y: 0 },
|
|
2953
|
-
{ name: "I", kind: "incenter", vertices: ["A", "B", "C"] },
|
|
2954
|
-
{ name: "D", kind: "perpFoot", from: "I", onLine: "BC" }
|
|
2955
|
-
],
|
|
2956
|
-
shapes: [
|
|
2957
|
-
{ name: "ABC", kind: "polygon", vertices: ["A", "B", "C"] },
|
|
2958
|
-
{ name: "BC", kind: "segment", p1: "B", p2: "C" },
|
|
2959
|
-
{ name: "incircle", kind: "circleCP", center: "I", surfacePoint: "D" }
|
|
2960
|
-
]
|
|
2961
|
-
}
|
|
2962
|
-
};
|
|
2963
|
-
|
|
2964
|
-
// src/stamps/geometry-2d/dsl/fixtures/parallelogram.ts
|
|
2965
|
-
var fixture8 = {
|
|
2966
|
-
problem: "H\xECnh b\xECnh h\xE0nh ABCD, hai \u0111\u01B0\u1EDDng ch\xE9o AC, BD c\u1EAFt nhau t\u1EA1i O.",
|
|
2967
|
-
dsl: {
|
|
2968
|
-
version: 1,
|
|
2969
|
-
points: [
|
|
2970
|
-
{ name: "A", kind: "free", x: 0, y: 0 },
|
|
2971
|
-
{ name: "B", kind: "free", x: 4, y: 0 },
|
|
2972
|
-
{ name: "C", kind: "free", x: 5, y: 2 },
|
|
2973
|
-
{ name: "D", kind: "free", x: 1, y: 2 },
|
|
2974
|
-
{ name: "O", kind: "intersection", ref1: "AC", ref2: "BD" }
|
|
2975
|
-
],
|
|
2976
|
-
shapes: [
|
|
2977
|
-
{ name: "ABCD", kind: "polygon", vertices: ["A", "B", "C", "D"] },
|
|
2978
|
-
{ name: "AC", kind: "segment", p1: "A", p2: "C" },
|
|
2979
|
-
{ name: "BD", kind: "segment", p1: "B", p2: "D" }
|
|
2980
|
-
]
|
|
2981
|
-
}
|
|
2982
|
-
};
|
|
2983
|
-
|
|
2984
|
-
// src/stamps/geometry-2d/dsl/fixtures/two-circles-intersect.ts
|
|
2985
|
-
var fixture9 = {
|
|
2986
|
-
problem: "Hai \u0111\u01B0\u1EDDng tr\xF2n (O\u2081), (O\u2082) c\u1EAFt nhau t\u1EA1i P, Q.",
|
|
2987
|
-
dsl: {
|
|
2988
|
-
version: 1,
|
|
2989
|
-
points: [
|
|
2990
|
-
{ name: "O1", kind: "free", x: 0, y: 0 },
|
|
2991
|
-
{ name: "A1", kind: "free", x: 2, y: 0 },
|
|
2992
|
-
{ name: "O2", kind: "free", x: 3, y: 0 },
|
|
2993
|
-
{ name: "A2", kind: "free", x: 5, y: 0 },
|
|
2994
|
-
{ name: "P", kind: "intersection", ref1: "k1", ref2: "k2", branch: 0 },
|
|
2995
|
-
{ name: "Q", kind: "intersection", ref1: "k1", ref2: "k2", branch: 1 }
|
|
2996
|
-
],
|
|
2997
|
-
shapes: [
|
|
2998
|
-
{ name: "k1", kind: "circleCP", center: "O1", surfacePoint: "A1" },
|
|
2999
|
-
{ name: "k2", kind: "circleCP", center: "O2", surfacePoint: "A2" }
|
|
3000
|
-
]
|
|
3001
|
-
}
|
|
3002
|
-
};
|
|
3003
|
-
|
|
3004
|
-
// src/stamps/geometry-2d/ai/prompt.ts
|
|
3005
|
-
var FIXTURES = [fixture, fixture2, fixture3, fixture4, fixture5, fixture6, fixture7, fixture8, fixture9];
|
|
3006
|
-
function buildSystemPrompt() {
|
|
3007
|
-
const examples = FIXTURES.map(
|
|
3008
|
-
(f, i) => `### V\xED d\u1EE5 ${i + 1}
|
|
3009
|
-
**\u0110\u1EC1:** ${f.problem}
|
|
3010
|
-
**DSL:**
|
|
3011
|
-
\`\`\`json
|
|
3012
|
-
${JSON.stringify(f.dsl, null, 2)}
|
|
3013
|
-
\`\`\``
|
|
3014
|
-
).join("\n\n");
|
|
3015
|
-
return `B\u1EA1n l\xE0 tr\u1EE3 l\xFD v\u1EBD h\xECnh h\u1ECDc 2D cho h\u1ECDc sinh THCS v\xE0 l\u1EDBp 10 Vi\u1EC7t Nam.
|
|
3016
|
-
|
|
3017
|
-
## Nhi\u1EC7m v\u1EE5
|
|
3018
|
-
\u0110\u1ECDc \u0111\u1EC1 b\xE0i ti\u1EBFng Vi\u1EC7t \u2192 emit DSL JSON m\xF4 t\u1EA3 h\xECnh. H\u1EC7 th\u1ED1ng s\u1EBD render h\xECnh t\u1EEB DSL.
|
|
3019
|
-
|
|
3020
|
-
## Quy t\u1EAFc
|
|
3021
|
-
1. D\xF9ng tool \`build_figure\` khi v\u1EBD \u0111\u01B0\u1EE3c. D\xF9ng tool \`refuse\` khi kh\xF4ng v\u1EBD \u0111\u01B0\u1EE3c ho\u1EB7c \u0111\u1EC1 ngo\xE0i ph\u1EA1m vi (3D, l\u01B0\u1EE3ng gi\xE1c, ph\xE9p bi\u1EBFn h\xECnh l\u1EDBp 11+, \u0111\u1EA1i s\u1ED1).
|
|
3022
|
-
2. \u01AFu ti\xEAn derived points (midpoint, perpFoot, circumcenter, ...) thay v\xEC t\u1EF1 compute to\u1EA1 \u0111\u1ED9.
|
|
3023
|
-
3. Anchor (free) ch\u1EC9 d\xF9ng cho \u0111i\u1EC3m g\u1ED1c (th\u01B0\u1EDDng A, B, C c\u1EE7a tam gi\xE1c). \u0110\u1EB7t coord h\u1EE3p l\xFD quanh g\u1ED1c (-5..5).
|
|
3024
|
-
4. M\u1ECDi \u0111i\u1EC3m + h\xECnh ph\u1EA3i c\xF3 \`name\` (label "A", "M", "O\u2081", ...). Tham chi\u1EBFu b\u1EB1ng name, kh\xF4ng ph\u1EA3i id.
|
|
3025
|
-
5. Tam gi\xE1c: emit c\u1EA3 \`polygon\` (v\u1EBD vi\u1EC1n) + segment/\u0111\u01B0\u1EDDng ph\u1EE5 ri\xEAng n\u1EBFu \u0111\u1EC1 y\xEAu c\u1EA7u (\u0111\u01B0\u1EDDng cao, trung tuy\u1EBFn).
|
|
3026
|
-
6. \u0110\u01B0\u1EDDng tr\xF2n (O; R) cho tr\u01B0\u1EDBc b\xE1n k\xEDnh s\u1ED1: emit anchor helper tr\xEAn \u0111\u01B0\u1EDDng tr\xF2n r\u1ED3i d\xF9ng \`circleCP\` (DSL kh\xF4ng h\u1ED7 tr\u1EE3 radius numeric tr\u1EF1c ti\u1EBFp).
|
|
3027
|
-
7. N\u1EBFu \u0111\u1EC1 m\u01A1 h\u1ED3: ch\u1ECDn case ph\u1ED5 bi\u1EBFn nh\u1EA5t, kh\xF4ng h\u1ECFi l\u1EA1i.
|
|
3028
|
-
|
|
3029
|
-
## Primitives s\u1EB5n c\xF3
|
|
3030
|
-
**Points:** free, midpoint, onSegment, onLine, onCircle, perpFoot, circumcenter, incenter, centroid, orthocenter, intersection
|
|
3031
|
-
**Shapes:** segment, line, ray, polygon, perpendicular, parallel, perpBisector, angleBisector, tangent, circleCP, circle3
|
|
3032
|
-
|
|
3033
|
-
## 9 v\xED d\u1EE5
|
|
3034
|
-
${examples}
|
|
3035
|
-
|
|
3036
|
-
## Khi kh\xF4ng v\u1EBD \u0111\u01B0\u1EE3c
|
|
3037
|
-
G\u1ECDi \`refuse\` v\u1EDBi \`reason\` ti\u1EBFng Vi\u1EC7t gi\u1EA3i th\xEDch c\u1EE5 th\u1EC3 (vd: "\u0110\u1EC1 thu\u1ED9c l\u1EDBp 11, ngo\xE0i ph\u1EA1m vi MVP" ho\u1EB7c "\u0110\u1EC1 kh\xF4ng r\xF5 v\u1ECB tr\xED \u0111i\u1EC3m M").`;
|
|
3038
|
-
}
|
|
3039
|
-
var BUILD_FIGURE_TOOL = {
|
|
3040
|
-
name: "build_figure",
|
|
3041
|
-
description: "V\u1EBD h\xECnh h\u1ECDc 2D theo \u0111\u1EC1 b\xE0i. Emit DSL JSON m\xF4 t\u1EA3 c\xE1c \u0111i\u1EC3m v\xE0 h\xECnh.",
|
|
3042
|
-
input_schema: zodToJsonSchema(DslInput, {
|
|
3043
|
-
target: "jsonSchema7",
|
|
3044
|
-
$refStrategy: "none"
|
|
3045
|
-
})
|
|
3046
|
-
};
|
|
3047
|
-
var RefuseInputZ = z.object({
|
|
3048
|
-
reason: z.string().min(1).describe("L\xFD do kh\xF4ng v\u1EBD \u0111\u01B0\u1EE3c (ti\u1EBFng Vi\u1EC7t)")
|
|
3049
|
-
});
|
|
3050
|
-
var REFUSE_TOOL = {
|
|
3051
|
-
name: "refuse",
|
|
3052
|
-
description: "T\u1EEB ch\u1ED1i khi kh\xF4ng v\u1EBD \u0111\u01B0\u1EE3c ho\u1EB7c \u0111\u1EC1 ngo\xE0i ph\u1EA1m vi (3D, l\u01B0\u1EE3ng gi\xE1c, l\u1EDBp 11+).",
|
|
3053
|
-
input_schema: zodToJsonSchema(RefuseInputZ, { target: "jsonSchema7" })
|
|
3054
|
-
};
|
|
3055
|
-
var TOOLS = [BUILD_FIGURE_TOOL, REFUSE_TOOL];
|
|
3056
|
-
|
|
3057
|
-
// src/stamps/geometry-2d/ai/buildFigure.ts
|
|
3058
|
-
var DEFAULT_MODEL = "claude-opus-4-7";
|
|
3059
|
-
var DEFAULT_MAX_TOKENS = 8192;
|
|
3060
|
-
function toUsage(u) {
|
|
3061
|
-
return {
|
|
3062
|
-
inputTokens: u.input_tokens,
|
|
3063
|
-
outputTokens: u.output_tokens,
|
|
3064
|
-
cacheReadTokens: u.cache_read_input_tokens ?? 0,
|
|
3065
|
-
cacheCreationTokens: u.cache_creation_input_tokens ?? 0
|
|
3066
|
-
};
|
|
3067
|
-
}
|
|
3068
|
-
async function generateFigure(problem, opts) {
|
|
3069
|
-
if (!opts.apiKey) {
|
|
3070
|
-
return { ok: false, reason: "api_error", message: "apiKey b\u1EAFt bu\u1ED9c" };
|
|
3071
|
-
}
|
|
3072
|
-
if (!problem || !problem.trim()) {
|
|
3073
|
-
return { ok: false, reason: "api_error", message: "\u0110\u1EC1 b\xE0i r\u1ED7ng" };
|
|
3074
|
-
}
|
|
3075
|
-
const systemText = buildSystemPrompt();
|
|
3076
|
-
const enableCaching = opts.enableCaching !== false;
|
|
3077
|
-
const systemBlock = enableCaching ? { type: "text", text: systemText, cache_control: { type: "ephemeral" } } : { type: "text", text: systemText };
|
|
3078
|
-
let response;
|
|
3079
|
-
try {
|
|
3080
|
-
response = await callProvider({
|
|
3081
|
-
apiKey: opts.apiKey,
|
|
3082
|
-
model: opts.model ?? DEFAULT_MODEL,
|
|
3083
|
-
maxTokens: opts.maxTokens ?? DEFAULT_MAX_TOKENS,
|
|
3084
|
-
system: [systemBlock],
|
|
3085
|
-
tools: TOOLS,
|
|
3086
|
-
toolChoice: { type: "any" },
|
|
3087
|
-
messages: [{ role: "user", content: problem }],
|
|
3088
|
-
signal: opts.signal
|
|
3089
|
-
});
|
|
3090
|
-
} catch (e) {
|
|
3091
|
-
const err = e;
|
|
3092
|
-
return {
|
|
3093
|
-
ok: false,
|
|
3094
|
-
reason: "api_error",
|
|
3095
|
-
message: err.message ?? "L\u1ED7i g\u1ECDi Claude API",
|
|
3096
|
-
...err.status !== void 0 ? { status: err.status } : {}
|
|
3097
|
-
};
|
|
3098
|
-
}
|
|
3099
|
-
const usage = toUsage(response.usage);
|
|
3100
|
-
const toolUse = response.content.find((c) => c.type === "tool_use");
|
|
3101
|
-
if (!toolUse || toolUse.type !== "tool_use") {
|
|
3102
|
-
const text = response.content.find((c) => c.type === "text");
|
|
3103
|
-
const textStr = text?.type === "text" ? text.text : "(empty)";
|
|
3104
|
-
return {
|
|
3105
|
-
ok: false,
|
|
3106
|
-
reason: "parse_error",
|
|
3107
|
-
message: "AI kh\xF4ng g\u1ECDi tool n\xE0o. Response: " + textStr,
|
|
3108
|
-
raw: response.content,
|
|
3109
|
-
usage
|
|
3110
|
-
};
|
|
3111
|
-
}
|
|
3112
|
-
if (toolUse.name === "refuse") {
|
|
3113
|
-
const input = toolUse.input;
|
|
3114
|
-
return {
|
|
3115
|
-
ok: false,
|
|
3116
|
-
reason: "refused",
|
|
3117
|
-
message: input.reason ?? "AI t\u1EEB ch\u1ED1i kh\xF4ng n\xEAu l\xFD do",
|
|
3118
|
-
usage
|
|
3119
|
-
};
|
|
3120
|
-
}
|
|
3121
|
-
if (toolUse.name !== "build_figure") {
|
|
3122
|
-
return {
|
|
3123
|
-
ok: false,
|
|
3124
|
-
reason: "parse_error",
|
|
3125
|
-
message: `Tool kh\xF4ng x\xE1c \u0111\u1ECBnh: "${toolUse.name}"`,
|
|
3126
|
-
raw: toolUse,
|
|
3127
|
-
usage
|
|
3128
|
-
};
|
|
3129
|
-
}
|
|
3130
|
-
const tResult = transpile(toolUse.input);
|
|
3131
|
-
if (!tResult.ok) {
|
|
3132
|
-
return {
|
|
3133
|
-
ok: false,
|
|
3134
|
-
reason: "transpile_error",
|
|
3135
|
-
message: "DSL t\u1EEB AI kh\xF4ng h\u1EE3p l\u1EC7",
|
|
3136
|
-
errors: tResult.errors,
|
|
3137
|
-
dsl: toolUse.input,
|
|
3138
|
-
usage
|
|
3139
|
-
};
|
|
3140
|
-
}
|
|
3141
|
-
return {
|
|
3142
|
-
ok: true,
|
|
3143
|
-
state: tResult.state,
|
|
3144
|
-
dsl: toolUse.input,
|
|
3145
|
-
usage
|
|
3146
|
-
};
|
|
3147
|
-
}
|
|
3148
2157
|
|
|
3149
|
-
export { ALL_STAMPS, DEFAULT_STAMPS, EXPERIMENTAL_STAMPS, STABLE_STAMPS, STAMP_CATALOG, Whiteboard, closePdfDocument, configurePdfWorker, findCatalogEntry, findStampForCustomData,
|
|
2158
|
+
export { ALL_STAMPS, DEFAULT_STAMPS, EXPERIMENTAL_STAMPS, STABLE_STAMPS, STAMP_CATALOG, Whiteboard, closePdfDocument, configurePdfWorker, findCatalogEntry, findStampForCustomData, insertPdfPages, insertRasterizedPagesIntoScene, isStampElement, loadPdfDocument, parsePageRange, pickSyncableAppState, rasterizePdf, restoreMissingStampFiles };
|
|
3150
2159
|
//# sourceMappingURL=index.mjs.map
|
|
3151
2160
|
//# sourceMappingURL=index.mjs.map
|