Add admin vision lab and LLM vision verification

这个提交包含在:
cryptocommuniums-afk
2026-03-15 00:41:09 +08:00
父节点 20e183d2da
当前提交 ad83ce9c68
修改 18 个文件,包含 915 行新增16 行删除

查看文件

@@ -1,9 +1,10 @@
import { COOKIE_NAME, ONE_YEAR_MS } from "@shared/const";
import { getSessionCookieOptions } from "./_core/cookies";
import { systemRouter } from "./_core/systemRouter";
import { publicProcedure, protectedProcedure, router } from "./_core/trpc";
import { adminProcedure, publicProcedure, protectedProcedure, router } from "./_core/trpc";
import { z } from "zod";
import { sdk } from "./_core/sdk";
import { ENV } from "./_core/env";
import { storagePut } from "./storage";
import * as db from "./db";
import { nanoid } from "nanoid";
@@ -271,6 +272,111 @@ export const appRouter = router({
}),
}),
vision: router({
library: protectedProcedure.query(async () => {
await db.seedVisionReferenceImages();
return db.listVisionReferenceImages();
}),
seedLibrary: adminProcedure.mutation(async () => {
await db.seedVisionReferenceImages();
const images = await db.listVisionReferenceImages();
return { count: images.length };
}),
runs: protectedProcedure
.input(z.object({ limit: z.number().min(1).max(100).default(50) }).optional())
.query(async ({ ctx, input }) => {
const limit = input?.limit ?? 50;
return db.listVisionTestRuns(ctx.user.role === "admin" ? undefined : ctx.user.id, limit);
}),
runReference: protectedProcedure
.input(z.object({
referenceImageId: z.number(),
exerciseType: z.string().optional(),
}))
.mutation(async ({ ctx, input }) => {
const reference = await db.getVisionReferenceImageById(input.referenceImageId);
if (!reference || reference.isPublished !== 1) {
throw new Error("Reference image not found");
}
const task = await enqueueTask({
userId: ctx.user.id,
type: "pose_correction_multimodal",
title: `${reference.title} 视觉测试`,
message: "视觉标准图测试已加入后台队列",
payload: {
poseMetrics: {
referenceSource: "vision_reference_library",
expectedFocus: reference.expectedFocus,
sourcePageUrl: reference.sourcePageUrl,
},
exerciseType: input.exerciseType || reference.exerciseType,
detectedIssues: [],
imageUrls: [reference.imageUrl],
},
});
const runId = await db.createVisionTestRun({
taskId: task.taskId,
userId: ctx.user.id,
referenceImageId: reference.id,
title: `${reference.title} 视觉测试`,
exerciseType: input.exerciseType || reference.exerciseType,
imageUrl: reference.imageUrl,
status: "queued",
visionStatus: "pending",
configuredModel: ENV.llmVisionModel || null,
expectedFocus: reference.expectedFocus,
});
return { taskId: task.taskId, runId };
}),
runAll: protectedProcedure.mutation(async ({ ctx }) => {
const references = await db.listVisionReferenceImages();
const queued: Array<{ taskId: string; referenceImageId: number }> = [];
for (const reference of references) {
const task = await enqueueTask({
userId: ctx.user.id,
type: "pose_correction_multimodal",
title: `${reference.title} 视觉测试`,
message: "视觉标准图测试已加入后台队列",
payload: {
poseMetrics: {
referenceSource: "vision_reference_library",
expectedFocus: reference.expectedFocus,
sourcePageUrl: reference.sourcePageUrl,
},
exerciseType: reference.exerciseType,
detectedIssues: [],
imageUrls: [reference.imageUrl],
},
});
await db.createVisionTestRun({
taskId: task.taskId,
userId: ctx.user.id,
referenceImageId: reference.id,
title: `${reference.title} 视觉测试`,
exerciseType: reference.exerciseType,
imageUrl: reference.imageUrl,
status: "queued",
visionStatus: "pending",
configuredModel: ENV.llmVisionModel || null,
expectedFocus: reference.expectedFocus,
});
queued.push({ taskId: task.taskId, referenceImageId: reference.id });
}
return { count: queued.length, queued };
}),
}),
task: router({
list: protectedProcedure
.input(z.object({ limit: z.number().min(1).max(50).default(20) }).optional())