Add feedback system functionality
- Implement feedback management system in admin interface - Add feedback processing and AI-based features - Update user interface with new feedback components - Modify server-side API endpoints for feedback handling - Enhance worker.js for background feedback processing - Update deployment configuration for feedback components Co-authored-by: openhands <openhands@all-hands.dev>
This commit is contained in:
+53
-1
@@ -460,6 +460,32 @@ INSERT INTO settings (key, value) VALUES ('lesson_ai_prompt', 'Ты — реда
|
||||
ON CONFLICT (key) DO NOTHING;
|
||||
INSERT INTO settings (key, value) VALUES ('notify_lesson_ai_formatted', 'false')
|
||||
ON CONFLICT (key) DO NOTHING;
|
||||
INSERT INTO settings (key, value) VALUES ('feedback_ai_enabled','true') ON CONFLICT (key) DO NOTHING;
|
||||
INSERT INTO settings (key, value) VALUES ('feedback_ai_prompt','Ты — помощник по написанию коротких деловых отзывов тьютора детской IT-школы.
|
||||
|
||||
ЗАДАЧА: Сформируй короткий, ёмкий, деловой отзыв по итогам занятия. По стилю он должен быть близок к «короткому сообщению для обратной связи»: 1–3 предложения, без воды, конкретно по делу.
|
||||
|
||||
КОНТЕКСТ, КОТОРЫЙ ТЫ ПОЛУЧИШЬ:
|
||||
- Группа: ...
|
||||
- Дата занятия: ...
|
||||
- Резидент: ...
|
||||
- Тема занятия: ...
|
||||
- Позиция темы: ... (если есть)
|
||||
- Прошлый отзыв: ... (если есть)
|
||||
- Короткие сообщения (выбраны): список в формате "дата – тема – сообщение"
|
||||
|
||||
ПРАВИЛА:
|
||||
- Пиши только отзыв. Без заголовков, списков, markdown, подписей и пояснений.
|
||||
- Не упоминай группу, дату, время занятия в тексте отзыва.
|
||||
- Не начинай со слов «Сегодня», «Вчера», «На занятии», «В ходе занятия», если они избыточны.
|
||||
- Опирайся на факты из контекста: тема занятия, выбранные короткие сообщения и прошлый отзыв (если есть).
|
||||
- Сохраняй деловой, спокойный тон. Без оценок типа «отлично», «замечательно», избегай шаблонных «молодец».
|
||||
- Максимально кратко: 1–2 предложения. Если хватает одного — лучше одно.
|
||||
- Не оборачивай ответ в кавычки.
|
||||
- Не придумывай фактов, которых нет в контексте.
|
||||
|
||||
ФОРМАТ ОТВЕТА: только текст отзыва, без лишних элементов.') ON CONFLICT (key) DO NOTHING;
|
||||
INSERT INTO settings (key, value) VALUES ('notify_feedback_ai_ready','false') ON CONFLICT (key) DO NOTHING;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS short_messages (
|
||||
id SERIAL PRIMARY KEY,
|
||||
@@ -476,7 +502,33 @@ CREATE TABLE IF NOT EXISTS short_messages (
|
||||
updated_at TIMESTAMPTZ DEFAULT now()
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_short_messages_date ON short_messages(lesson_date DESC);
|
||||
CREATE INDEX IF NOT EXISTS idx_short_messages_deleted ON short_messages(deleted_at);
|
||||
CREATE INDEX IF NOT EXISTS idx_short_messages_date ON short_messages(lesson_date DESC);
|
||||
|
||||
INSERT INTO settings (key, value) VALUES ('short_messages_retention_days', '365') ON CONFLICT (key) DO NOTHING;
|
||||
|
||||
-- Обратная связь (отзывы тьютора)
|
||||
CREATE TABLE IF NOT EXISTS feedbacks (
|
||||
id SERIAL PRIMARY KEY,
|
||||
feedback_date DATE NOT NULL,
|
||||
group_id INT NOT NULL REFERENCES groups(id) ON DELETE CASCADE,
|
||||
resident VARCHAR(200) NOT NULL,
|
||||
topic VARCHAR(500),
|
||||
past_review TEXT,
|
||||
short_message_ids INT[] DEFAULT '{}'::int[],
|
||||
text TEXT NOT NULL DEFAULT '',
|
||||
ai_status VARCHAR(20) NOT NULL DEFAULT 'none',
|
||||
ai_checked_at TIMESTAMPTZ,
|
||||
ai_error TEXT,
|
||||
ai_profile VARCHAR(100),
|
||||
sent_at TIMESTAMPTZ,
|
||||
author_id INT REFERENCES users(id) ON DELETE SET NULL,
|
||||
branch_id INT REFERENCES branches(id) ON DELETE SET NULL,
|
||||
deleted_at TIMESTAMPTZ,
|
||||
purge_at TIMESTAMPTZ,
|
||||
created_at TIMESTAMPTZ DEFAULT now(),
|
||||
updated_at TIMESTAMPTZ DEFAULT now()
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_feedbacks_date ON feedbacks(feedback_date DESC);
|
||||
CREATE INDEX IF NOT EXISTS idx_feedbacks_deleted ON feedbacks(deleted_at);
|
||||
CREATE INDEX IF NOT EXISTS idx_feedbacks_pending ON feedbacks(ai_status, id);
|
||||
|
||||
+101
-20
@@ -456,31 +456,32 @@ INSERT INTO settings (key, value) VALUES ('lesson_ai_prompt', 'Ты — реда
|
||||
|
||||
ГЛАВНОЕ ПРАВИЛО:
|
||||
Отрабатывай ровно по этому исходному тексту. Ничего из примера выше в свой текст не переноси: тема, программа, персонажи и детали из примера не твои.') ON CONFLICT (key) DO NOTHING;
|
||||
|
||||
UPDATE settings
|
||||
SET value = 'Ты — редактор сообщений тьютора детской IT-школы.
|
||||
|
||||
Переработай исходный текст занятия так, чтобы он звучал естественно и грамотно, как будто его написал живой тьютор родителю, а не нейросеть.
|
||||
ЦЕЛЬ
|
||||
Привести текст отчёта о занятии к деловому стилю по строгому шаблону. Начало фразы должно соответствовать позиции темы (первое/промежуточное/последнее занятие модуля), исходя из формулировки «Позиция темы: ...».
|
||||
|
||||
ГЛАВНОЕ:
|
||||
- Не добавляй информацию, которой нет в исходном тексте. Сохрани все факты и смысл.
|
||||
- Исправь ошибки, повторы и неудачные формулировки. Убери канцелярит, шаблонные фразы и «ИИ-язык».
|
||||
- Не используй чрезмерную похвалу и не превращай обычное занятие в достижение мирового масштала.
|
||||
ПРАВИЛА ФОРМУЛИРОВКИ
|
||||
- Всегда начинай фразу строго в соответствии с «Позиция темы»:
|
||||
- если «первое занятие модуля (1 из N)» — начинай с «На занятии ребята начали...» (или близко по смыслу, без шаблонного «На данном занятии»)
|
||||
- если «промежуточное занятие модуля (K из N), K > 1 и K < N» — начинай с «На занятии ребята продолжили...»
|
||||
- если «последнее занятие модуля (N из N)» — начинай с «На занятии ребята завершили...» (при N==1 — это «последнее занятие модуля (1 из 1)», используй «завершили»)
|
||||
- Определи позицию ТОЛЬКО по строке «Позиция темы: ...». Не угадывай по номеру темы сам.
|
||||
- Если «Позиция темы» отсутствует или не содержит N/M — начни нейтрально, без жёсткого шаблона, но сохрани деловой стиль.
|
||||
- Перепиши текст в деловом стиле, сохрани смысл, факты и ключевые термины.
|
||||
- Убери разговорные слова, лишние повторы, воду.
|
||||
- Не добавляй факты, которых нет в исходном тексте.
|
||||
- Не используй оценочные слова («отлично», «хорошо», «замечательно»), не пиши «молодцы».
|
||||
|
||||
СТИЛЬ И СТРУКТУРА:
|
||||
- Один цельный абзац, 2–4 предложения, от третьего лица.
|
||||
- Первое предложение всегда начинай со слов «На занятии ребята …». Чем занимались в начале занятия — начало модуля, продолжение или завершение — определяй по правилу НАЧАЛО ФРАЗЫ.
|
||||
- Если в исходном тексте описана практическая часть, начни её со слов «В конце занятия …» или «Затем …». Нет практики в исходнике — не придумывай её.
|
||||
- Вместо «они» пиши «каждый». Обращение на «вы» не используй.
|
||||
- Коротко скажи, с чем познакомились или что изучали; затем — что конкретно делали; в конце — что сделал самостоятельно.
|
||||
- Сократи перечисления, объединяй их через «и», «а также», не повторяй одно и то же разными словами.
|
||||
- Убери разговорные и оценочные обороты: «было весело», «очень», «классно».
|
||||
ЗАПРЕТЫ
|
||||
- Не упоминай дату, время, группу, номер занятия и модуль.
|
||||
- Не начинай со слов «Сегодня», «Вчера».
|
||||
- Не используй шаблон «На данном занятии», «В рамках занятия».
|
||||
- Не пиши список (маркированный/нумерованный). Только сплошной текст.
|
||||
|
||||
НАЧАЛО ФРАЗЫ (определяется номером темы):
|
||||
Система присылает готовую подсказку строкой «Позиция темы: …». Если такой строки нет, смотри номер вида N/M в конце строки «Тема занятия: …», где N — номер занятия в модуле, M — сколько занятий в модуле всего. Пользуйся только одной из этих подсказок и всегда проверяй, что N не больше M.
|
||||
- «последнее занятие модуля» (N = M, например 2/2 или 7/7): занятие завершает модуль. Первое предложение обязательно начни с «завершили» или «закончили»: «На занятии ребята завершили изучение …», «На занятии ребята закончили знакомство с …».
|
||||
- «промежуточное занятие модуля» (1 < N < M, например 2/4, 3/5, 6/7): изучение продолжается. Первое предложение обязательно начни с «продолжили», «продолжали», «закрепили» или «углубили»: «На занятии ребята продолжили изучение …», «На занятии ребята закрепили …».
|
||||
- «первое занятие модуля» (N = 1 и N < M, например 1/4 или 1/7): модуль начинается. Первое предложение обязательно начни с «начали» или «приступили»: «На занятии ребята начали знакомство с …», «На занятии ребята начали изучение …».
|
||||
- Если подсказки нет или номер нечитаем — характер занятия не выбирай и не додумывай. Начни нейтрально, прямо с сути: «На занятии ребята разобрались …», «На занятии ребята отработали …», «На занятии ребята попробовали …».
|
||||
ГЛАВНОЕ ПРАВИЛО
|
||||
- Это требование сильнее всего остального: даже если начало исходного текста уже хорошо звучит, перепиши его по правилу выше. Слово «модуль», цифры номера и любые оценки в текст отчёта не переноси: номер темы — внутренний признак для выбора формулировки.
|
||||
|
||||
ФОРМАТ:
|
||||
@@ -501,7 +502,6 @@ SET value = 'Ты — редактор сообщений тьютора дет
|
||||
«На занятии ребята продолжили знакомство со Scratch Jr: научились выбирать фон, добавлять и изменять персонажей…».
|
||||
Тот же исходный текст, но «Позиция темы: последнее занятие модуля (3 из 3)»:
|
||||
«На занятии ребята завершили знакомство со Scratch Jr: научились выбирать фон, добавлять и изменять персонажей…».
|
||||
|
||||
ГЛАВНОЕ ПРАВИЛО:
|
||||
Отрабатывай ровно по этому исходному тексту. Ничего из примера выше в свой текст не переноси: тема, программа, персонажи и детали из примера не твои.'
|
||||
WHERE key = 'lesson_ai_prompt' AND value IN (
|
||||
@@ -589,3 +589,84 @@ ALTER TABLE short_messages ADD COLUMN IF NOT EXISTS used_at DATE;
|
||||
ALTER TABLE short_messages ADD COLUMN IF NOT EXISTS author_id INT REFERENCES users(id) ON DELETE SET NULL;
|
||||
|
||||
INSERT INTO settings (key, value) VALUES ('short_messages_retention_days', '365') ON CONFLICT (key) DO NOTHING;
|
||||
|
||||
-- Feedbacks
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = 'feedbacks') THEN
|
||||
CREATE TABLE feedbacks (
|
||||
id SERIAL PRIMARY KEY,
|
||||
feedback_date DATE NOT NULL,
|
||||
group_id INT NOT NULL REFERENCES groups(id) ON DELETE CASCADE,
|
||||
resident VARCHAR(200) NOT NULL,
|
||||
topic VARCHAR(500),
|
||||
past_review TEXT,
|
||||
short_message_ids INT[] DEFAULT '{}'::int[],
|
||||
text TEXT NOT NULL DEFAULT '',
|
||||
ai_status VARCHAR(20) NOT NULL DEFAULT 'none',
|
||||
ai_checked_at TIMESTAMPTZ,
|
||||
ai_error TEXT,
|
||||
ai_profile VARCHAR(100),
|
||||
author_id INT REFERENCES users(id) ON DELETE SET NULL,
|
||||
branch_id INT REFERENCES branches(id) ON DELETE SET NULL,
|
||||
deleted_at TIMESTAMPTZ,
|
||||
purge_at TIMESTAMPTZ,
|
||||
created_at TIMESTAMPTZ DEFAULT now(),
|
||||
updated_at TIMESTAMPTZ DEFAULT now()
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_feedbacks_date ON feedbacks(feedback_date DESC);
|
||||
CREATE INDEX IF NOT EXISTS idx_feedbacks_deleted ON feedbacks(deleted_at);
|
||||
CREATE INDEX IF NOT EXISTS idx_feedbacks_pending ON feedbacks(ai_status, id);
|
||||
END IF;
|
||||
END$$;
|
||||
|
||||
ALTER TABLE feedbacks ADD COLUMN IF NOT EXISTS feedback_date DATE;
|
||||
ALTER TABLE feedbacks ADD COLUMN IF NOT EXISTS group_id INT;
|
||||
ALTER TABLE feedbacks ADD COLUMN IF NOT EXISTS resident VARCHAR(200);
|
||||
ALTER TABLE feedbacks ADD COLUMN IF NOT EXISTS topic VARCHAR(500);
|
||||
ALTER TABLE feedbacks ADD COLUMN IF NOT EXISTS past_review TEXT;
|
||||
ALTER TABLE feedbacks ADD COLUMN IF NOT EXISTS short_message_ids INT[] DEFAULT '{}'::int[];
|
||||
ALTER TABLE feedbacks ADD COLUMN IF NOT EXISTS text TEXT NOT NULL DEFAULT '';
|
||||
ALTER TABLE feedbacks ADD COLUMN IF NOT EXISTS ai_status VARCHAR(20) NOT NULL DEFAULT 'none';
|
||||
ALTER TABLE feedbacks ADD COLUMN IF NOT EXISTS ai_checked_at TIMESTAMPTZ;
|
||||
ALTER TABLE feedbacks ADD COLUMN IF NOT EXISTS ai_error TEXT;
|
||||
ALTER TABLE feedbacks ADD COLUMN IF NOT EXISTS ai_profile VARCHAR(100);
|
||||
ALTER TABLE feedbacks ADD COLUMN IF NOT EXISTS sent_at TIMESTAMPTZ;
|
||||
ALTER TABLE feedbacks ADD COLUMN IF NOT EXISTS author_id INT REFERENCES users(id) ON DELETE SET NULL;
|
||||
ALTER TABLE feedbacks ADD COLUMN IF NOT EXISTS branch_id INT REFERENCES branches(id) ON DELETE SET NULL;
|
||||
ALTER TABLE feedbacks ADD COLUMN IF NOT EXISTS deleted_at TIMESTAMPTZ;
|
||||
ALTER TABLE feedbacks ADD COLUMN IF NOT EXISTS purge_at TIMESTAMPTZ;
|
||||
ALTER TABLE feedbacks ADD COLUMN IF NOT EXISTS created_at TIMESTAMPTZ DEFAULT now();
|
||||
ALTER TABLE feedbacks ADD COLUMN IF NOT EXISTS updated_at TIMESTAMPTZ DEFAULT now();
|
||||
|
||||
-- Индексы (если таблица существовала без них)
|
||||
CREATE INDEX IF NOT EXISTS idx_feedbacks_date ON feedbacks(feedback_date DESC);
|
||||
CREATE INDEX IF NOT EXISTS idx_feedbacks_deleted ON feedbacks(deleted_at);
|
||||
CREATE INDEX IF NOT EXISTS idx_feedbacks_pending ON feedbacks(ai_status, id);
|
||||
|
||||
INSERT INTO settings (key, value) VALUES ('feedback_ai_enabled','true') ON CONFLICT (key) DO NOTHING;
|
||||
INSERT INTO settings (key, value) VALUES ('feedback_ai_prompt','Ты — помощник по написанию коротких деловых отзывов тьютора детской IT-школы.
|
||||
|
||||
ЗАДАЧА: Сформируй короткий, ёмкий, деловой отзыв по итогам занятия. По стилю он должен быть близок к «короткому сообщению для обратной связи»: 1–3 предложения, без воды, конкретно по делу.
|
||||
|
||||
КОНТЕКСТ, КОТОРЫЙ ТЫ ПОЛУЧИШЬ:
|
||||
- Группа: ...
|
||||
- Дата занятия: ...
|
||||
- Резидент: ...
|
||||
- Тема занятия: ...
|
||||
- Позиция темы: ... (если есть)
|
||||
- Прошлый отзыв: ... (если есть)
|
||||
- Короткие сообщения (выбраны): список в формате "дата – тема – сообщение"
|
||||
|
||||
ПРАВИЛА:
|
||||
- Пиши только отзыв. Без заголовков, списков, markdown, подписей и пояснений.
|
||||
- Не упоминай группу, дату, время занятия в тексте отзыва.
|
||||
- Не начинай со слов «Сегодня», «Вчера», «На занятии», «В ходе занятия», если они избыточны.
|
||||
- Опирайся на факты из контекста: тема занятия, выбранные короткие сообщения и прошлый отзыв (если есть).
|
||||
- Сохраняй деловой, спокойный тон. Без оценок типа «отлично», «замечательно», избегай шаблонных «молодец».
|
||||
- Максимально кратко: 1–2 предложения. Если хватает одного — лучше одно.
|
||||
- Не оборачивай ответ в кавычки.
|
||||
- Не придумывай фактов, которых нет в контексте.
|
||||
|
||||
ФОРМАТ ОТВЕТА: только текст отзыва, без лишних элементов.') ON CONFLICT (key) DO NOTHING;
|
||||
INSERT INTO settings (key, value) VALUES ('notify_feedback_ai_ready','false') ON CONFLICT (key) DO NOTHING;
|
||||
|
||||
Reference in New Issue
Block a user