From 3caf13b6f6c111b75c357ddb07e2cdabd8c145e3 Mon Sep 17 00:00:00 2001 From: Pyronewbic Date: Sat, 16 May 2026 00:41:30 +0530 Subject: [PATCH] fix: v3 grading for front-only uploads, resilient card detection MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - gradeDetailedLLM runs even without back image (was skipping to v2 fallback) - Card detection wrapped in try/catch — failures continue with original images - TOGETHER_API_KEY must be >20 chars (ignores placeholder values) --- lib/grading/grading.js | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/lib/grading/grading.js b/lib/grading/grading.js index 974f8f5..3f397a9 100644 --- a/lib/grading/grading.js +++ b/lib/grading/grading.js @@ -641,14 +641,21 @@ export async function gradeDetailedLLM(frontUrl, backUrl, config, extraImages = const apiKey = process.env.ANTHROPIC_API_KEY; let detectTokens = { input: 0, output: 0 }; - const togetherKey = process.env.TOGETHER_API_KEY; + const rawTogetherKey = process.env.TOGETHER_API_KEY; + const togetherKey = rawTogetherKey && rawTogetherKey.length > 20 ? rawTogetherKey : null; const detectOpts = togetherKey ? { provider: "together", togetherKey } : {}; const detectModel = togetherKey ? null : "claude-sonnet-4-6"; - const detectJobs = [detectAndCropCard(frontUrl, apiKey, detectModel, detectOpts)]; - if (hasBack) detectJobs.push(detectAndCropCard(backUrl, apiKey, detectModel, detectOpts)); - const [frontDetect, backDetect] = await Promise.all(detectJobs); + let frontDetect = { imageUrl: frontUrl, cropped: false }; + let backDetect = hasBack ? { imageUrl: backUrl, cropped: false } : null; + try { + const detectJobs = [detectAndCropCard(frontUrl, apiKey, detectModel, detectOpts)]; + if (hasBack) detectJobs.push(detectAndCropCard(backUrl, apiKey, detectModel, detectOpts)); + [frontDetect, backDetect] = await Promise.all(detectJobs); + } catch (e) { + console.warn(`[grade] card detection failed, using original images: ${e.message || e}`); + } const frontBlock = frontDetect.cropped ? imageBlockFromBase64(frontDetect.base64, frontDetect.mediaType) @@ -801,8 +808,8 @@ export async function gradeImage(imageUrl, config, extraImages = [], centeringHi if (config.aiGrading.mode === "llm") { const backImg = extraImages[0]?.imageUrl || extraImages[0] || null; const remainingExtras = extraImages.slice(1); - if (backImg && config.aiGrading.llm.provider === "claude") { - result = await gradeDetailedLLM(imageUrl, backImg, config, remainingExtras, centeringHint); + if (config.aiGrading.llm.provider === "claude") { + result = await gradeDetailedLLM(imageUrl, backImg || null, config, remainingExtras, centeringHint); } if (!result) { result = await gradeViaLLM(imageUrl, config, extraImages);