feat(worker/ai): Gemini-lärar-tier för scan/detect/allergen + shadow-capture
- Utöka GeminiAamosClient med ANALYZE_MEAL_IMAGE, READ_NUTRITION_LABEL, READ_EXPIRY_DATE och READ_RECEIPT (vision-prompts mot kontraktsscheman). - Lägg till apps/worker/src/lib/shadow-capture.ts: S3/local fallback, imageTraining-gating, ingen PII, aldrig faila användarvägen. - Integrera capture i scan-processorn efter lyckad runTask med consentFlags. - Lägg till @aws-sdk/client-s3 i worker samt eval:capture-skript. - Uppdatera eval:scan till Wikimedia Special:FilePath + redirect-following. - Exkludera .terraform i brand-guard för att undvika false positives. - Uppdatera gemini-test för DEDUPLICATE_INVENTORY som unsupported.
This commit is contained in:
@@ -0,0 +1,52 @@
|
||||
/**
|
||||
* Best-effort verifiering av shadow-capture (ingen riktig AI, bara lagring).
|
||||
*
|
||||
* S3_MODE=mock pnpm --filter @app/worker eval:capture
|
||||
*/
|
||||
import { captureTrainingSample } from "../lib/shadow-capture.js";
|
||||
|
||||
async function main() {
|
||||
const result = await captureTrainingSample({
|
||||
taskType: "ANALYZE_FRIDGE_IMAGE",
|
||||
inputS3Keys: ["uploads/test/fridge.jpg"],
|
||||
output: {
|
||||
items: [
|
||||
{
|
||||
detectedName: "Testmjölk",
|
||||
canonicalIngredientId: null,
|
||||
brand: "Testa",
|
||||
estimatedQuantity: 1,
|
||||
unit: "LITER",
|
||||
bestBeforeDate: null,
|
||||
confidence: 0.97,
|
||||
requiresConfirmation: false,
|
||||
boundingBox: null,
|
||||
},
|
||||
],
|
||||
imageQualityIssues: [],
|
||||
},
|
||||
modelVersion: "gemini-2.5-flash",
|
||||
promptVersion: "gemini-fridge-v1",
|
||||
latencyMs: 1234,
|
||||
costUsd: 0.0001,
|
||||
inputTokens: 400,
|
||||
outputTokens: 120,
|
||||
consentFlags: {
|
||||
personalization: true,
|
||||
anonymizedImprovement: true,
|
||||
imageTraining: true,
|
||||
},
|
||||
readUrl: (key: string) => `http://localhost/v1/mock-s3/${encodeURIComponent(key)}?sig=dummy`,
|
||||
});
|
||||
|
||||
if (!result.ok) {
|
||||
console.error("[eval:capture] misslyckades:", result.error);
|
||||
process.exit(1);
|
||||
}
|
||||
console.log(`[eval:capture] träningspar sparat på nyckel: ${result.key}`);
|
||||
}
|
||||
|
||||
main().catch((err) => {
|
||||
console.error(err);
|
||||
process.exit(1);
|
||||
});
|
||||
@@ -40,7 +40,7 @@ interface ScanEvalCase {
|
||||
const CASES: ScanEvalCase[] = [
|
||||
{
|
||||
id: "arla-milk-fridge",
|
||||
imageUrls: ["https://upload.wikimedia.org/wikipedia/commons/6/6c/Arla_Ko_Mellanmj%C3%B6lk_1L.jpg"],
|
||||
imageUrls: ["https://commons.wikimedia.org/wiki/Special:FilePath/Arla_Ko_Mellanmj%C3%B6lk_1L.jpg?width=800"],
|
||||
locationType: "fridge",
|
||||
marketLocale: "sv-SE",
|
||||
checks: (items) => {
|
||||
@@ -56,7 +56,7 @@ const CASES: ScanEvalCase[] = [
|
||||
},
|
||||
{
|
||||
id: "swedish-butter-fridge",
|
||||
imageUrls: ["https://upload.wikimedia.org/wikipedia/commons/3/3e/Svenskt_Sm%C3%B6r_Normalsaltat_80-25_500g.jpg"],
|
||||
imageUrls: ["https://commons.wikimedia.org/wiki/Special:FilePath/Svenskt_Sm%C3%B6r_Normalsaltat_80-25_500g.jpg?width=800"],
|
||||
locationType: "fridge",
|
||||
marketLocale: "sv-SE",
|
||||
checks: (items) => {
|
||||
|
||||
Reference in New Issue
Block a user