Bug fixes

This commit is contained in:
2026-07-05 17:52:43 +02:00
parent fb6108bd0c
commit c40531b6ae
12 changed files with 1196 additions and 946 deletions

View File

@@ -67,6 +67,7 @@ const {
isConfigured: isOpenAiConfigured,
} = require('./lib/openai');
const { applyCatalogGrounding, normalizeText } = require('./lib/scanGrounding');
const { decideReviewOutcome, reviewAgreesWithPrimary } = require('./lib/scanReview');
const { ensureStorageBucketWithRetry, uploadImage, isStorageConfigured } = require('./lib/storage');
const { isPurchaseEventType, notifyPurchase, notifyNewUser } = require('./lib/discord');
const {
@@ -85,6 +86,9 @@ const SCAN_REVIEW_COST = 0;
const SEMANTIC_SEARCH_COST = 2;
const HEALTH_CHECK_COST = 2;
const LOW_CONFIDENCE_REVIEW_THRESHOLD = 0.8;
// Below this the app should treat the identification as uncertain and nudge
// the user toward a clearer photo instead of presenting the name as settled.
const LOW_CONFIDENCE_RESULT_THRESHOLD = 0.6;
let catalogCache = null;
@@ -738,6 +742,7 @@ app.post('/v1/scan', async (request, response) => {
const scanPlan = accountSnapshot.plan === 'pro' ? 'pro' : 'free';
let result = pickCatalogFallback(catalogEntries, imageUri, false, { silent: true });
let usedOpenAi = false;
let rawPrimaryResult = null;
if (isOpenAiConfigured()) {
console.log(`Starting OpenAI identification for user ${userId} using model ${getScanModel(scanPlan)} (plan: ${scanPlan})`);
@@ -753,9 +758,9 @@ app.post('/v1/scan', async (request, response) => {
);
if (openAiPrimary?.result) {
console.log(`OpenAI primary identification successful for user ${userId}: ${openAiPrimary.result.name} (${openAiPrimary.result.confidence}) using ${openAiPrimary.modelUsed}`);
rawPrimaryResult = openAiPrimary.result;
const grounded = applyCatalogGrounding(openAiPrimary.result, catalogEntries, language);
result = grounded.result;
if (!grounded.grounded) result = { ...result, confidence: clamp(Math.max(result.confidence || 0.6, 0.72), 0.05, 0.99) };
usedOpenAi = true;
modelUsed = openAiPrimary.modelUsed || modelUsed;
modelPath.push('openai-primary');
@@ -806,12 +811,23 @@ app.post('/v1/scan', async (request, response) => {
);
if (openAiReview?.result) {
console.log(`OpenAI review identification successful for user ${userId}: ${openAiReview.result.name} (${openAiReview.result.confidence}) using ${openAiReview.modelUsed}`);
const agrees = reviewAgreesWithPrimary(rawPrimaryResult, openAiReview.result);
const grounded = applyCatalogGrounding(openAiReview.result, catalogEntries, language);
result = grounded.result;
if (!grounded.grounded) result = { ...result, confidence: clamp(Math.max(result.confidence || 0.6, 0.72), 0.05, 0.99) };
modelUsed = openAiReview.modelUsed || modelUsed;
modelPath.push('openai-review');
if (grounded.grounded) modelPath.push('catalog-grounded-review');
const decision = decideReviewOutcome({ primaryResult: result, reviewResult: grounded.result, agrees });
if (decision.accept) {
// modelUsed and the grounding marker describe the RESULT the user
// gets, so they only change when the review actually replaces it.
if (decision.replace) {
result = grounded.result;
modelUsed = openAiReview.modelUsed || modelUsed;
if (grounded.grounded) modelPath.push('catalog-grounded-review');
}
modelPath.push('openai-review');
modelPath.push(decision.reason);
} else {
console.log(`OpenAI review disagreed at lower confidence for user ${userId} (${grounded.result.name} ${grounded.result.confidence} vs ${result.name} ${result.confidence}) — keeping primary result.`);
modelPath.push(decision.reason);
}
} else {
console.warn(`OpenAI review identification returned null for user ${userId}.`, {
attemptedModels: openAiReview?.attemptedModels,
@@ -840,6 +856,7 @@ app.post('/v1/scan', async (request, response) => {
const payload = {
result,
lowConfidence: (result.confidence || 0) < LOW_CONFIDENCE_RESULT_THRESHOLD,
creditsCharged,
modelPath,
modelUsed,