157 lines
5.1 KiB
TypeScript
157 lines
5.1 KiB
TypeScript
import path from "path";
|
|
import { getTask, setTask } from "./store";
|
|
import { validateStandardCode } from "./runner";
|
|
import { generateFallbackTestCases, runAIGeneratedCases, getOutputBase } from "./generator";
|
|
import { generateTestCases, isQwenAvailable } from "./qwen-service";
|
|
|
|
function formatErrorMessage(err: unknown): string {
|
|
const message = err instanceof Error ? err.message : String(err);
|
|
if ((err as Error & { code?: string }).code === "COMPILATION_ERROR") {
|
|
return `C++程序编译失败: ${message}`;
|
|
}
|
|
if ((err as Error & { code?: string }).code === "EXECUTION_ERROR") {
|
|
return `程序执行错误: ${message}`;
|
|
}
|
|
return message;
|
|
}
|
|
|
|
function updateTaskProgress(
|
|
taskId: string,
|
|
status: "pending" | "running" | "completed" | "failed",
|
|
progress: number,
|
|
message: string,
|
|
generatedCount?: number
|
|
): void {
|
|
const task = getTask(taskId);
|
|
if (!task) return;
|
|
task.status = status;
|
|
task.progress = Math.min(100, Math.max(0, progress));
|
|
task.updatedAt = new Date();
|
|
task.currentMessage = message;
|
|
if (generatedCount !== undefined) task.generatedCases = generatedCount;
|
|
setTask(taskId, task);
|
|
}
|
|
|
|
export async function processTask(taskId: string): Promise<void> {
|
|
const task = getTask(taskId);
|
|
if (!task) {
|
|
console.error(`任务不存在: ${taskId}`);
|
|
return;
|
|
}
|
|
|
|
try {
|
|
updateTaskProgress(taskId, "running", 10, "正在初始化生成环境...");
|
|
|
|
await validateStandardCode(task.standardCode);
|
|
updateTaskProgress(taskId, "running", 20, "标准程序验证通过,开始生成测试数据...");
|
|
|
|
let result: { testCases: { input: string; output: string }[]; outputDirName: string; zipFileName: string };
|
|
|
|
if (isQwenAvailable()) {
|
|
try {
|
|
updateTaskProgress(taskId, "running", 22, "正在调用阿里云大模型生成测试用例...", 0);
|
|
const aiCases = await generateTestCases({
|
|
title: task.title,
|
|
englishName: task.englishName,
|
|
description: task.description,
|
|
standardCode: task.standardCode,
|
|
testCaseCount: task.testCaseCount,
|
|
serviceLevel: task.serviceLevel,
|
|
});
|
|
if (aiCases.length > 0) {
|
|
updateTaskProgress(taskId, "running", 25, "AI 生成完成,正在用标程计算输出...", 0);
|
|
result = await runAIGeneratedCases(
|
|
{
|
|
englishName: task.englishName,
|
|
description: task.description,
|
|
standardCode: task.standardCode,
|
|
testCaseCount: task.testCaseCount,
|
|
},
|
|
aiCases,
|
|
(progress, message, generatedCount) => {
|
|
updateTaskProgress(
|
|
taskId,
|
|
"running",
|
|
25 + Math.floor(progress * 65),
|
|
message,
|
|
generatedCount
|
|
);
|
|
}
|
|
);
|
|
} else {
|
|
throw new Error("AI 未返回有效用例");
|
|
}
|
|
} catch (aiErr) {
|
|
console.warn("AI 生成失败,使用备用算法:", aiErr);
|
|
updateTaskProgress(taskId, "running", 20, "使用智能算法生成测试用例...", 0);
|
|
result = await generateFallbackTestCases(
|
|
{
|
|
englishName: task.englishName,
|
|
description: task.description,
|
|
standardCode: task.standardCode,
|
|
testCaseCount: task.testCaseCount,
|
|
},
|
|
(progress, message, generatedCount) => {
|
|
updateTaskProgress(
|
|
taskId,
|
|
"running",
|
|
20 + Math.floor(progress * 70),
|
|
message,
|
|
generatedCount
|
|
);
|
|
}
|
|
);
|
|
}
|
|
} else {
|
|
result = await generateFallbackTestCases(
|
|
{
|
|
englishName: task.englishName,
|
|
description: task.description,
|
|
standardCode: task.standardCode,
|
|
testCaseCount: task.testCaseCount,
|
|
},
|
|
(progress, message, generatedCount) => {
|
|
updateTaskProgress(
|
|
taskId,
|
|
"running",
|
|
20 + Math.floor(progress * 70),
|
|
message,
|
|
generatedCount
|
|
);
|
|
}
|
|
);
|
|
}
|
|
|
|
updateTaskProgress(taskId, "running", 95, "正在打包文件...", result.testCases.length);
|
|
|
|
const finalTask = getTask(taskId);
|
|
if (finalTask) {
|
|
finalTask.status = "completed";
|
|
finalTask.progress = 100;
|
|
finalTask.updatedAt = new Date();
|
|
finalTask.completedAt = new Date();
|
|
finalTask.generatedCases = result.testCases.length;
|
|
finalTask.zipFileName = result.zipFileName;
|
|
finalTask.outputDirName = result.outputDirName;
|
|
setTask(taskId, finalTask);
|
|
}
|
|
} catch (err) {
|
|
console.error(`任务失败: ${taskId}`, err);
|
|
const finalTask = getTask(taskId);
|
|
if (finalTask) {
|
|
finalTask.status = "failed";
|
|
finalTask.progress = 0;
|
|
finalTask.errorMessage = formatErrorMessage(err);
|
|
finalTask.updatedAt = new Date();
|
|
finalTask.failedAt = new Date();
|
|
setTask(taskId, finalTask);
|
|
}
|
|
}
|
|
}
|
|
|
|
export function getZipPathForTask(taskId: string): string | null {
|
|
const task = getTask(taskId);
|
|
if (!task?.zipFileName) return null;
|
|
return path.join(getOutputBase(), task.zipFileName);
|
|
}
|