Персональный образовательный ресурс для Константина на Deepseek API
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

162 lines
5.2 KiB

import { Router, Response } from "express";
import prisma from "../lib/prisma";
import { getDeepSeekClient, getPrompt } from "../lib/deepseek";
import type { AuthRequest } from "../middleware/auth";
const router = Router();
const DEFAULT_TEST_PROMPT = `Ты — составитель тестов. Сгенерируй тест из РОВНО 10 вопросов.
Требования к вопросам:
- Вопросы должны проверять ПОНИМАНИЕ темы, а не запоминание фактов
- Сложность: 3 лёгких, 4 средних, 3 сложных
- Каждый вопрос имеет 4 варианта ответа (a, b, c, d) и ровно один правильный
- Неправильные варианты должны быть правдоподобными (не абсурдными)
- Вопросы на русском языке
ВАЖНО: Верни ТОЛЬКО JSON-массив, без markdown-обёрток (\`\`\`json), без пояснений, ЧИСТЫЙ JSON:
[{"question":"текст вопроса","options":{"a":"вариант А","b":"вариант Б","c":"вариант В","d":"вариант Г"},"correct":"a"}]`;
/** Контекст пары: id назначенного ученика (общие тесты для наставника и ученика). */
function pairStudentScopeId(req: AuthRequest): number {
return req.studentId!;
}
const authorSelect = { username: true, displayName: true } as const;
router.get("/", async (req: AuthRequest, res: Response) => {
const scopeId = pairStudentScopeId(req);
const tests = await prisma.test.findMany({
where: { studentId: scopeId },
orderBy: { createdAt: "desc" },
include: {
author: { select: authorSelect },
results: {
where: { studentId: scopeId },
orderBy: { createdAt: "asc" },
},
},
});
res.json(tests);
});
router.get("/:id", async (req: AuthRequest, res: Response) => {
const id = parseInt(req.params.id as string, 10);
const scopeId = pairStudentScopeId(req);
const test = await prisma.test.findFirst({
where: { id, studentId: scopeId },
include: {
author: { select: authorSelect },
results: {
where: { studentId: scopeId },
orderBy: { createdAt: "asc" },
},
},
});
if (!test) {
res.status(404).json({ error: "Test not found" });
return;
}
res.json(test);
});
router.post("/generate", async (req: AuthRequest, res: Response) => {
const { topic, fromQuestions } = req.body;
const scopeId = pairStudentScopeId(req);
const questionBankStudentId = req.studentId!;
const client = await getDeepSeekClient();
const systemPrompt = await getPrompt("prompt_test", DEFAULT_TEST_PROMPT);
let userMessage: string;
if (fromQuestions) {
const questions = await prisma.question.findMany({
where: { studentId: questionBankStudentId },
orderBy: { createdAt: "desc" },
take: 20,
});
const questionTexts = questions.map((q: { text: string }) => q.text).join("\n");
userMessage = `Составь тест на основе этих вопросов, которые задавал пользователь ранее:\n${questionTexts}`;
} else {
if (!topic) {
res.status(400).json({ error: "Topic is required" });
return;
}
userMessage = `Тема: ${topic}`;
}
try {
const response = await client.chat.completions.create({
model: "deepseek-chat",
messages: [
{ role: "system", content: systemPrompt },
{ role: "user", content: userMessage },
],
});
const raw = response.choices[0]?.message?.content || "[]";
const jsonMatch = raw.match(/\[[\s\S]*\]/);
const questionsJson = jsonMatch ? jsonMatch[0] : "[]";
const test = await prisma.test.create({
data: {
topic: topic || "По прошлым вопросам",
questions: questionsJson,
studentId: scopeId,
authorId: req.user!.id,
},
include: {
author: { select: authorSelect },
results: true,
},
});
res.json(test);
} catch (err: any) {
res.status(500).json({ error: err.message });
}
});
router.post("/:id/submit", async (req: AuthRequest, res: Response) => {
const id = parseInt(req.params.id as string, 10);
const scopeId = pairStudentScopeId(req);
const { answers } = req.body as { answers: Record<string, string> };
const test = await prisma.test.findFirst({ where: { id, studentId: scopeId } });
if (!test) {
res.status(404).json({ error: "Test not found" });
return;
}
const questions = JSON.parse(test.questions);
let score = 0;
const total = questions.length;
for (const q of questions as { question: string; correct: string }[]) {
if (answers[q.question] === q.correct) {
score++;
}
}
if (req.user!.role === "TUTOR") {
res.json({ score, total, persisted: false as const });
return;
}
const result = await prisma.testResult.create({
data: {
testId: id,
studentId: req.user!.id,
answers: JSON.stringify(answers),
score,
total,
},
});
res.json({ ...result, persisted: true as const });
});
export default router;