feat(trainer): P3 — текстовые задачи от LLM с серверной проверкой подстановкой
- practiceVerify.js: грузит SimExpr в Node (require), verifyRoot подстановкой корня - practiceGenService.js: LLM (инъектируемый ask) → parse → validateAndVerify (SimExpr + подстановка + санитизация) → авторетрай по фидбэку; дефолт ask = assistantController.callLLMFailover - пул practice_problems (мигр.083); POST /api/practice/generate (учитель/админ) + GET /api/practice/pool - инвариант: невалидная/неверная задача в БД НЕ пишется → ученику не попадёт - клиент: LS.practicePool/Generate, тема «Текстовые задачи» (из пула; учителю кнопка «Сгенерировать») - тесты practice-gen.test.js 13/13 (verify, ретраи, off→503, 403 ученику, пул); смоуки страница 26/26; план P3 → DONE Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,31 @@
|
||||
'use strict';
|
||||
/* Серверная проверка задач тренажёра через SimExpr — тот же безопасный
|
||||
* вычислитель, что на клиенте (⛔ без eval/new Function). Гарантирует, что любая
|
||||
* задача (от LLM или учителя) КОРРЕКТНА: подставляем заявленный корень в обе
|
||||
* части уравнения и сверяем с допуском. SimExpr — чистый (без DOM), грузится в
|
||||
* Node через require: его IIFE цепляется к globalThis.SimExpr. */
|
||||
require('../../../frontend/js/labs/_sim_expr.js'); // → globalThis.SimExpr
|
||||
const SimExpr = globalThis.SimExpr;
|
||||
|
||||
const EPS = 1e-7;
|
||||
|
||||
/* Компиляция выражения; null при синтаксической ошибке (мусор от модели). */
|
||||
function compileOk(expr) {
|
||||
if (typeof expr !== 'string') return null;
|
||||
const c = SimExpr.compile(expr);
|
||||
return (c && !c.error) ? c : null;
|
||||
}
|
||||
|
||||
/* Подстановочная проверка: lhs(var=value) ≈ rhs(var=value). */
|
||||
function verifyRoot(lhs, rhs, varName, value) {
|
||||
const cl = compileOk(lhs), cr = compileOk(rhs);
|
||||
if (!cl || !cr) return { ok: false, reason: 'parse' };
|
||||
if (typeof value !== 'number' || !isFinite(value)) return { ok: false, reason: 'bad-value' };
|
||||
const env = {}; env[varName || 'x'] = value;
|
||||
const L = cl.fn(env), R = cr.fn(env);
|
||||
const residual = Math.abs(L - R);
|
||||
const scale = Math.max(1, Math.abs(L), Math.abs(R));
|
||||
return { ok: residual <= EPS * scale, residual: residual, lhs: L, rhs: R };
|
||||
}
|
||||
|
||||
module.exports = { SimExpr, compileOk, verifyRoot };
|
||||
Reference in New Issue
Block a user