diff --git a/flask_app/alembic/versions/0003_question_ai_hint.py b/flask_app/alembic/versions/0003_question_ai_hint.py new file mode 100644 index 0000000..41b2448 --- /dev/null +++ b/flask_app/alembic/versions/0003_question_ai_hint.py @@ -0,0 +1,35 @@ +"""Добавление ai_hint в questions. + +Revision ID: 0003_question_ai_hint +Revises: 0002_tests_hints_result_mode +Create Date: 2026-04-29 + +Колонка опциональная (TEXT NULL), как в ORM Question.ai_hint. +""" +from __future__ import annotations + +from typing import Sequence, Union + +from alembic import op + +revision: str = "0003_question_ai_hint" +down_revision: Union[str, None] = "0002_tests_hints_result_mode" +branch_labels: Union[str, Sequence[str], None] = None +depends_on: Union[str, Sequence[str], None] = None + + +def upgrade() -> None: + op.execute( + """ + ALTER TABLE questions + ADD COLUMN IF NOT EXISTS ai_hint TEXT NULL; + """ + ) + + +def downgrade() -> None: + op.execute( + """ + ALTER TABLE questions DROP COLUMN IF EXISTS ai_hint; + """ + ) diff --git a/flask_app/app/services/editor_content.py b/flask_app/app/services/editor_content.py index e3d18c7..1b92184 100644 --- a/flask_app/app/services/editor_content.py +++ b/flask_app/app/services/editor_content.py @@ -51,6 +51,7 @@ def load_questions_for_version(session, test_version_id, *, include_correct: boo 'text': q.text, 'questionOrder': q.question_order, 'hasMultipleAnswers': bool(q.has_multiple_answers), + 'aiHint': (q.ai_hint or '').strip() or None, 'options': options, }) return out diff --git a/flask_app/app/services/test_draft.py b/flask_app/app/services/test_draft.py index ab90e13..1e57714 100644 --- a/flask_app/app/services/test_draft.py +++ b/flask_app/app/services/test_draft.py @@ -122,12 +122,17 @@ def _replace_version_content(session: Session, version: TestVersion, payload: di questions_payload = payload.get('questions') or [] for i, qp in enumerate(questions_payload): q_text = (qp.get('text') or '').strip() + hint_in = qp.get('aiHint') + if hint_in is not None: + hint_val = (str(hint_in).strip() or None) + else: + hint_val = old_hints.get(q_text) new_q = Question( test_version_id=version.id, text=q_text, question_order=qp.get('question_order') or (i + 1), has_multiple_answers=bool(qp.get('hasMultipleAnswers')), - ai_hint=old_hints.get(q_text), + ai_hint=hint_val, ) session.add(new_q) session.flush() diff --git a/flask_app/app/static/js/editor.js b/flask_app/app/static/js/editor.js index 9017d5a..80eccb5 100644 --- a/flask_app/app/static/js/editor.js +++ b/flask_app/app/static/js/editor.js @@ -109,6 +109,14 @@ syncOptionInputTypes(node); updateOptionsCounter(node); updateAiButtonLabel(node); + + const hintEl = $('.q-hint', node); + if (hintEl) { + hintEl.value = q.aiHint || ''; + const rh = () => autoResize(hintEl); + hintEl.addEventListener('input', () => { rh(); scheduleDirtyCheck(); }); + requestAnimationFrame(rh); + } return node; } @@ -207,6 +215,8 @@ const qTextEl = $('.q-text', node); qTextEl.value = ''; autoResize(qTextEl); + const qh = $('.q-hint', node); + if (qh) { qh.value = ''; autoResize(qh); } $$('.opt-text', node).forEach((t) => { t.value = ''; autoResize(t); }); $$('.opt-correct', node).forEach((c) => { c.checked = false; }); updateAiButtonLabel(node); @@ -406,16 +416,20 @@ // ─── collect ─────────────────────────────────────────────────────── function collectPayload() { - const questions = $$('#questions .q-item:not(.q-removed)').map((li, i) => ({ + const questions = $$('#questions .q-item:not(.q-removed)').map((li, i) => { + const hintVal = ($('.q-hint', li) && $('.q-hint', li).value.trim()) || ''; + return { text: $('.q-text', li).value.trim(), question_order: i + 1, hasMultipleAnswers: $('.q-multi', li).checked, + aiHint: hintVal || null, options: $$('.opt-item', li).map((op, j) => ({ text: $('.opt-text', op).value.trim(), isCorrect: $('.opt-correct', op).checked, option_order: j + 1, })), - })); + }; + }); const payload = { title: titleEl.value.trim() || null, description: descEl.value.trim() || null, diff --git a/flask_app/app/templates/tests/editor.html b/flask_app/app/templates/tests/editor.html index ea2d450..42f050c 100644 --- a/flask_app/app/templates/tests/editor.html +++ b/flask_app/app/templates/tests/editor.html @@ -346,6 +346,18 @@ + +
Необязательно. Показывается участнику во всплывающем окне при верном ответе.
+