pelagora 0.2.0 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -4,6 +4,22 @@ All notable changes to **pelagora** will be documented in this file.
4
4
 
5
5
  This project follows [Keep a Changelog](https://keepachangelog.com/) and [Semantic Versioning](https://semver.org/).
6
6
 
7
+ ## [0.2.2] — 2026-03-26
8
+
9
+ ### Added
10
+ - Multi-stage UPC barcode resolution pipeline: UPCitemdb → Serper+AI → Direct AI → Reffo.ai fallback
11
+ - UPC normalization with multi-format digit variants (EAN-8, UPC-A, EAN-13)
12
+ - SKU-based product catalog cache with index for fast UPC lookups
13
+ - Rich barcode result card: product image, name, price with confidence badge, attributes, product URL
14
+ - Unidentified barcode flow: manual product name entry with retry
15
+ - Support for manual name override on barcode retry (`{ upc, name }` request body)
16
+
17
+ ### Changed
18
+ - Barcode route now resolves UPC → product name before enrichment (previously treated UPC digits as a product name)
19
+ - Cache lookup uses `sku` field instead of `name_normalized` for barcode results
20
+
21
+ ---
22
+
7
23
  ## [Unreleased]
8
24
 
9
25
  > **Note:** Versions 0.1.1–0.1.8 were published to npm but not documented here. Entries below cover all changes since 0.1.0.
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Multi-stage UPC/barcode resolution.
3
+ * Resolves a UPC code to a product name via a fallback chain:
4
+ * 1. UPCitemdb free trial API (no key required, 100/day)
5
+ * 2. Google search via Serper + AI extraction
6
+ * 3. Direct AI identification (least reliable)
7
+ */
8
+ import type { AiProvider } from './product-lookup';
9
+ export interface UpcResolveResult {
10
+ name: string;
11
+ brand: string | null;
12
+ description: string | null;
13
+ category: string | null;
14
+ imageUrl: string | null;
15
+ priceLow: number | null;
16
+ priceHigh: number | null;
17
+ }
18
+ /**
19
+ * Stage 1: Resolve UPC via UPCitemdb free trial API.
20
+ * Free tier: 100 lookups/day, 6/minute. No API key required.
21
+ */
22
+ export declare function resolveUpc(upc: string): Promise<UpcResolveResult | null>;
23
+ /**
24
+ * Stage 2: Search Google via Serper for a UPC and use AI to extract the product name.
25
+ */
26
+ export declare function resolveUpcViaSearch(upc: string, provider: AiProvider, aiApiKey: string, serperKey: string): Promise<UpcResolveResult | null>;
27
+ /**
28
+ * Stage 3: Ask AI directly to identify a product from its UPC/EAN barcode.
29
+ * Least reliable method — the AI may not have the UPC in its training data.
30
+ */
31
+ export declare function identifyUpcWithAI(upc: string, provider: AiProvider, apiKey: string): Promise<string | null>;
32
+ /**
33
+ * Stage 2 via Reffo.ai: Use Reffo.ai's barcode endpoint as the search+AI stage
34
+ * when the user has a Reffo API key but no direct AI provider or Serper key.
35
+ */
36
+ export declare function resolveUpcViaReffo(upc: string, reffoApiKey: string, reffoUrl: string): Promise<UpcResolveResult | null>;
37
+ //# sourceMappingURL=upc-lookup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"upc-lookup.d.ts","sourceRoot":"","sources":["../../src/ai/upc-lookup.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEnD,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAgBD;;;GAGG;AACH,wBAAsB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CA2C9E;AA4FD;;GAEG;AACH,wBAAsB,mBAAmB,CACvC,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,UAAU,EACpB,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAiFlC;AAED;;;GAGG;AACH,wBAAsB,iBAAiB,CACrC,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,UAAU,EACpB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAUxB;AAED;;;GAGG;AACH,wBAAsB,kBAAkB,CACtC,GAAG,EAAE,MAAM,EACX,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAgClC"}
@@ -0,0 +1,280 @@
1
+ "use strict";
2
+ /**
3
+ * Multi-stage UPC/barcode resolution.
4
+ * Resolves a UPC code to a product name via a fallback chain:
5
+ * 1. UPCitemdb free trial API (no key required, 100/day)
6
+ * 2. Google search via Serper + AI extraction
7
+ * 3. Direct AI identification (least reliable)
8
+ */
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.resolveUpc = resolveUpc;
11
+ exports.resolveUpcViaSearch = resolveUpcViaSearch;
12
+ exports.identifyUpcWithAI = identifyUpcWithAI;
13
+ exports.resolveUpcViaReffo = resolveUpcViaReffo;
14
+ /**
15
+ * Normalize a UPC/EAN barcode: strip leading zeros to get the core UPC-A (12 digits).
16
+ * Returns both the original and stripped versions for multi-format lookups.
17
+ */
18
+ function normalizeUpc(upc) {
19
+ const variants = new Set();
20
+ variants.add(upc);
21
+ const stripped = upc.replace(/^0+/, '');
22
+ if (stripped.length >= 8)
23
+ variants.add(stripped);
24
+ if (stripped.length <= 12)
25
+ variants.add(stripped.padStart(12, '0'));
26
+ if (stripped.length <= 13)
27
+ variants.add(stripped.padStart(13, '0'));
28
+ return [...variants];
29
+ }
30
+ /**
31
+ * Stage 1: Resolve UPC via UPCitemdb free trial API.
32
+ * Free tier: 100 lookups/day, 6/minute. No API key required.
33
+ */
34
+ async function resolveUpc(upc) {
35
+ const variants = normalizeUpc(upc);
36
+ for (const variant of variants) {
37
+ try {
38
+ const res = await fetch(`https://api.upcitemdb.com/prod/trial/lookup?upc=${encodeURIComponent(variant)}`, { signal: AbortSignal.timeout(5000) });
39
+ if (!res.ok)
40
+ continue;
41
+ const data = await res.json();
42
+ if (data.code !== 'OK' || !data.items?.length)
43
+ continue;
44
+ const item = data.items[0];
45
+ if (!item.title)
46
+ continue;
47
+ const catStr = typeof item.category === 'string' ? item.category : '';
48
+ const topCategory = catStr.split('>')[0]?.trim() || null;
49
+ const images = item.images;
50
+ return {
51
+ name: item.title,
52
+ brand: item.brand || null,
53
+ description: item.description || null,
54
+ category: topCategory,
55
+ imageUrl: images?.[0] || null,
56
+ priceLow: typeof item.lowest_recorded_price === 'number'
57
+ ? item.lowest_recorded_price
58
+ : null,
59
+ priceHigh: typeof item.highest_recorded_price === 'number'
60
+ ? item.highest_recorded_price
61
+ : null,
62
+ };
63
+ }
64
+ catch {
65
+ continue;
66
+ }
67
+ }
68
+ return null;
69
+ }
70
+ // --- AI helper functions for Serper + AI and direct AI stages ---
71
+ function extractAiText(provider, data) {
72
+ const d = data;
73
+ if (provider === 'anthropic') {
74
+ const content = d.content || [];
75
+ return content[0]?.type === 'text' ? content[0].text.trim() : '';
76
+ }
77
+ if (provider === 'google') {
78
+ const candidates = d.candidates;
79
+ return candidates?.[0]?.content?.parts?.[0]?.text?.trim() ?? '';
80
+ }
81
+ // openai / xai compatible
82
+ const choices = d.choices || [];
83
+ return choices[0]?.message?.content?.trim() ?? '';
84
+ }
85
+ function getAiEndpoint(provider) {
86
+ switch (provider) {
87
+ case 'anthropic':
88
+ return { url: 'https://api.anthropic.com/v1/messages', model: 'claude-haiku-4-5-20251001' };
89
+ case 'openai':
90
+ return { url: 'https://api.openai.com/v1/chat/completions', model: 'gpt-4o-mini' };
91
+ case 'google':
92
+ return { url: '', model: 'gemini-2.0-flash-lite' }; // URL constructed differently
93
+ case 'xai':
94
+ return { url: 'https://api.x.ai/v1/chat/completions', model: 'grok-3-mini-fast' };
95
+ }
96
+ }
97
+ async function callAiSimple(provider, apiKey, prompt, timeoutMs) {
98
+ const { url, model } = getAiEndpoint(provider);
99
+ let res;
100
+ if (provider === 'anthropic') {
101
+ res = await fetch(url, {
102
+ method: 'POST',
103
+ headers: {
104
+ 'Content-Type': 'application/json',
105
+ 'x-api-key': apiKey,
106
+ 'anthropic-version': '2023-06-01',
107
+ },
108
+ body: JSON.stringify({
109
+ model,
110
+ max_tokens: 256,
111
+ temperature: 0,
112
+ messages: [{ role: 'user', content: prompt }],
113
+ }),
114
+ signal: AbortSignal.timeout(timeoutMs),
115
+ });
116
+ }
117
+ else if (provider === 'google') {
118
+ const googleUrl = `https://generativelanguage.googleapis.com/v1beta/models/${model}:generateContent?key=${apiKey}`;
119
+ res = await fetch(googleUrl, {
120
+ method: 'POST',
121
+ headers: { 'Content-Type': 'application/json' },
122
+ body: JSON.stringify({
123
+ contents: [{ parts: [{ text: prompt }] }],
124
+ generationConfig: { temperature: 0, maxOutputTokens: 256 },
125
+ }),
126
+ signal: AbortSignal.timeout(timeoutMs),
127
+ });
128
+ }
129
+ else {
130
+ // openai / xai
131
+ res = await fetch(url, {
132
+ method: 'POST',
133
+ headers: {
134
+ 'Content-Type': 'application/json',
135
+ 'Authorization': `Bearer ${apiKey}`,
136
+ },
137
+ body: JSON.stringify({
138
+ model,
139
+ temperature: 0,
140
+ max_tokens: 256,
141
+ messages: [{ role: 'user', content: prompt }],
142
+ }),
143
+ signal: AbortSignal.timeout(timeoutMs),
144
+ });
145
+ }
146
+ if (!res.ok)
147
+ return '';
148
+ const data = await res.json();
149
+ return extractAiText(provider, data);
150
+ }
151
+ /**
152
+ * Stage 2: Search Google via Serper for a UPC and use AI to extract the product name.
153
+ */
154
+ async function resolveUpcViaSearch(upc, provider, aiApiKey, serperKey) {
155
+ try {
156
+ // Search Google for the UPC
157
+ const searchRes = await fetch('https://google.serper.dev/search', {
158
+ method: 'POST',
159
+ headers: {
160
+ 'X-API-KEY': serperKey,
161
+ 'Content-Type': 'application/json',
162
+ },
163
+ body: JSON.stringify({ q: `"${upc}" UPC product`, num: 10 }),
164
+ signal: AbortSignal.timeout(8000),
165
+ });
166
+ if (!searchRes.ok) {
167
+ console.error(`[upc-lookup] Serper search failed: ${searchRes.status}`);
168
+ return null;
169
+ }
170
+ const searchData = await searchRes.json();
171
+ const organic = searchData.organic;
172
+ const shopping = searchData.shopping;
173
+ const knowledgeGraph = searchData.knowledgeGraph;
174
+ // If knowledge graph has a direct answer, use it
175
+ if (knowledgeGraph?.title && !knowledgeGraph.title.match(/^\d+$/)) {
176
+ console.log(`[upc-lookup] Knowledge graph hit: "${knowledgeGraph.title}"`);
177
+ return {
178
+ name: knowledgeGraph.title,
179
+ brand: null,
180
+ description: knowledgeGraph.description || null,
181
+ category: null,
182
+ imageUrl: null,
183
+ priceLow: null,
184
+ priceHigh: null,
185
+ };
186
+ }
187
+ // Combine organic + shopping results for AI to parse
188
+ const allResults = [];
189
+ if (organic?.length) {
190
+ organic.slice(0, 5).forEach((r, i) => {
191
+ allResults.push(`${i + 1}. ${r.title}\n ${r.snippet}`);
192
+ });
193
+ }
194
+ if (shopping?.length) {
195
+ shopping.slice(0, 3).forEach((r) => {
196
+ allResults.push(`Shopping: ${r.title} (${r.source})`);
197
+ });
198
+ }
199
+ if (!allResults.length) {
200
+ console.log(`[upc-lookup] Serper returned no results for "${upc}"`);
201
+ return null;
202
+ }
203
+ const resultsSummary = allResults.join('\n');
204
+ // Ask AI to extract the product name from search results
205
+ const prompt = `I searched Google for UPC barcode "${upc}" and got these results:\n\n${resultsSummary}\n\nBased on these results, what is the product? Return ONLY a JSON object: {"name": "product name", "brand": "brand or null"}. If the results don't clearly identify a product, return {"name": null, "brand": null}. No other text.`;
206
+ const text = await callAiSimple(provider, aiApiKey, prompt, 10000);
207
+ if (!text)
208
+ return null;
209
+ const cleaned = text.replace(/```json\s*/g, '').replace(/```\s*/g, '').trim();
210
+ const parsed = JSON.parse(cleaned);
211
+ if (!parsed.name)
212
+ return null;
213
+ return {
214
+ name: parsed.name,
215
+ brand: parsed.brand || null,
216
+ description: null,
217
+ category: null,
218
+ imageUrl: null,
219
+ priceLow: null,
220
+ priceHigh: null,
221
+ };
222
+ }
223
+ catch (err) {
224
+ console.error('[upc-lookup] Serper search resolve error:', err);
225
+ return null;
226
+ }
227
+ }
228
+ /**
229
+ * Stage 3: Ask AI directly to identify a product from its UPC/EAN barcode.
230
+ * Least reliable method — the AI may not have the UPC in its training data.
231
+ */
232
+ async function identifyUpcWithAI(upc, provider, apiKey) {
233
+ try {
234
+ const prompt = `What product has the UPC/EAN barcode: ${upc}?\n\nReturn ONLY the product name as a short string (e.g. "Crest 3D White Toothpaste 4.1oz"). If you cannot confidently identify it, return exactly "UNKNOWN". Do not include any other text.`;
235
+ const text = await callAiSimple(provider, apiKey, prompt, 10000);
236
+ if (!text || text === 'UNKNOWN' || text.length > 200)
237
+ return null;
238
+ return text;
239
+ }
240
+ catch {
241
+ return null;
242
+ }
243
+ }
244
+ /**
245
+ * Stage 2 via Reffo.ai: Use Reffo.ai's barcode endpoint as the search+AI stage
246
+ * when the user has a Reffo API key but no direct AI provider or Serper key.
247
+ */
248
+ async function resolveUpcViaReffo(upc, reffoApiKey, reffoUrl) {
249
+ try {
250
+ const res = await fetch(`${reffoUrl}/api/scan/barcode`, {
251
+ method: 'POST',
252
+ headers: {
253
+ 'Content-Type': 'application/json',
254
+ 'Authorization': `Bearer ${reffoApiKey}`,
255
+ },
256
+ body: JSON.stringify({ upc }),
257
+ signal: AbortSignal.timeout(30000),
258
+ });
259
+ if (!res.ok)
260
+ return null;
261
+ const data = await res.json();
262
+ if (data.unidentified || !data.name)
263
+ return null;
264
+ const pe = (data.price_estimate || {});
265
+ return {
266
+ name: data.name,
267
+ brand: null,
268
+ description: data.description || null,
269
+ category: null,
270
+ imageUrl: data.image_url || null,
271
+ priceLow: typeof pe.low === 'number' ? pe.low : null,
272
+ priceHigh: typeof pe.high === 'number' ? pe.high : null,
273
+ };
274
+ }
275
+ catch (err) {
276
+ console.error('[upc-lookup] Reffo.ai resolve error:', err);
277
+ return null;
278
+ }
279
+ }
280
+ //# sourceMappingURL=upc-lookup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"upc-lookup.js","sourceRoot":"","sources":["../../src/ai/upc-lookup.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/api/index.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,SAAS,CAAC;AAe9B,wBAAgB,SAAS,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAyG9D"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/api/index.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,SAAS,CAAC;AAe9B,wBAAgB,SAAS,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CA2G9D"}
package/dist/api/index.js CHANGED
@@ -65,6 +65,8 @@ function createApp(localToken) {
65
65
  app.get('/favicon.ico', (_req, res) => { res.type('image/x-icon').sendFile(path_1.default.join(__dirname, '../../favicon.ico')); });
66
66
  app.get('/footer-brand.png', (_req, res) => { res.sendFile(path_1.default.join(__dirname, '../../footer-brand.png')); });
67
67
  app.get('/header-logo.png', (_req, res) => { res.sendFile(path_1.default.join(__dirname, '../../header-logo.png')); });
68
+ app.get('/pelagora-logo.png', (_req, res) => { res.sendFile(path_1.default.join(__dirname, '../../pelagora-logo.png')); });
69
+ app.get('/pelagora-logo-reverse.png', (_req, res) => { res.sendFile(path_1.default.join(__dirname, '../../pelagora-logo_reverse.png')); });
68
70
  app.get('/', (_req, res) => {
69
71
  res.type('html').send((0, ui_1.renderUI)(localToken));
70
72
  });
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/api/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/api/index.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"scans.d.ts","sourceRoot":"","sources":["../../src/api/scans.ts"],"names":[],"mappings":"AAsCA,QAAA,MAAM,MAAM,4CAAW,CAAC;AAmYxB,eAAe,MAAM,CAAC"}
1
+ {"version":3,"file":"scans.d.ts","sourceRoot":"","sources":["../../src/api/scans.ts"],"names":[],"mappings":"AAuCA,QAAA,MAAM,MAAM,4CAAW,CAAC;AAycxB,eAAe,MAAM,CAAC"}
package/dist/api/scans.js CHANGED
@@ -13,6 +13,7 @@ const reffo_client_1 = require("../sync/reffo-client");
13
13
  const schema_1 = require("../db/schema");
14
14
  const ref_schemas_1 = require("../ref-schemas");
15
15
  const product_lookup_1 = require("../ai/product-lookup");
16
+ const upc_lookup_1 = require("../ai/upc-lookup");
16
17
  const UPLOADS_DIR = path_1.default.join(process.cwd(), 'uploads');
17
18
  const SCAN_DIR = path_1.default.join(UPLOADS_DIR, 'scans');
18
19
  const scanStorage = multer_1.default.diskStorage({
@@ -286,27 +287,27 @@ router.post('/confirm', async (req, res) => {
286
287
  }
287
288
  res.json({ confirmed: created.length, refs: created });
288
289
  });
289
- // POST /scans/barcode — Barcode/UPC lookup (same logic as settings/product-lookup)
290
+ // POST /scans/barcode — Multi-stage UPC/barcode lookup
291
+ // Fallback chain: cache → UPCitemdb → Serper+AI → direct AI → Reffo.ai
290
292
  router.post('/barcode', async (req, res) => {
291
- const { upc } = req.body;
293
+ const { upc, name: manualName } = req.body;
292
294
  if (!upc || typeof upc !== 'string' || !upc.trim()) {
293
295
  return res.status(400).json({ error: 'upc is required' });
294
296
  }
295
- const name = upc.trim();
296
- const nameNormalized = name.toLowerCase();
297
- // Check local SQLite cache first
297
+ const trimmedUpc = upc.trim();
298
298
  const db = (0, schema_1.getDb)();
299
- const cached = db.prepare(`SELECT * FROM product_catalog
300
- WHERE name_normalized = ? AND category = '' AND subcategory = ''
301
- AND expires_at > datetime('now')`).get(nameNormalized);
299
+ // 1. Check cache by SKU (the UPC itself)
300
+ const cached = db.prepare(`SELECT * FROM product_catalog WHERE sku = ? AND expires_at > datetime('now')`).get(trimmedUpc);
302
301
  if (cached) {
303
302
  db.prepare(`UPDATE product_catalog SET lookup_count = lookup_count + 1 WHERE id = ?`).run(cached.id);
303
+ const attrs = JSON.parse(cached.attributes || '{}');
304
304
  return res.json({
305
+ name: attrs.product_name || cached.name_normalized,
305
306
  description: cached.description,
306
307
  sku: cached.sku,
307
308
  product_url: cached.product_url,
308
309
  image_url: cached.image_url,
309
- attributes: JSON.parse(cached.attributes || '{}'),
310
+ attributes: attrs,
310
311
  price_estimate: {
311
312
  low: cached.price_low, high: cached.price_high,
312
313
  typical: cached.price_typical, confidence: cached.price_confidence || 'low',
@@ -314,54 +315,115 @@ router.post('/barcode', async (req, res) => {
314
315
  cached: true,
315
316
  });
316
317
  }
318
+ // 2. Resolve UPC → product name via multi-stage fallback
319
+ let productName = null;
320
+ let productCategory;
317
321
  const provider = (process.env.AI_PROVIDER || 'reffo').toLowerCase();
318
- const attributeKeys = (0, ref_schemas_1.getAttributeKeys)(undefined, undefined);
322
+ const aiApiKey = process.env.AI_API_KEY;
323
+ const serperKey = process.env.SERPER_API_KEY;
324
+ const reffoApiKey = process.env.REFFO_API_KEY;
325
+ const reffoUrl = process.env.REFFO_API_URL || 'https://reffo.ai';
326
+ // Level 0: User provided the product name manually (retry of unidentified barcode)
327
+ if (manualName && typeof manualName === 'string' && manualName.trim()) {
328
+ productName = manualName.trim();
329
+ console.log(`[barcode] Manual name provided for "${trimmedUpc}" → "${productName}"`);
330
+ }
331
+ // Level 1: UPCitemdb free database (no API key needed)
332
+ if (!productName) {
333
+ const upcProduct = await (0, upc_lookup_1.resolveUpc)(trimmedUpc);
334
+ if (upcProduct?.name) {
335
+ productName = upcProduct.name;
336
+ productCategory = upcProduct.category || undefined;
337
+ console.log(`[barcode] UPCitemdb resolved "${trimmedUpc}" → "${productName}"`);
338
+ }
339
+ }
340
+ // Level 2: Google search via Serper + AI extraction
341
+ if (!productName && serperKey && provider !== 'reffo' && aiApiKey) {
342
+ const searchResult = await (0, upc_lookup_1.resolveUpcViaSearch)(trimmedUpc, provider, aiApiKey, serperKey);
343
+ if (searchResult?.name) {
344
+ productName = searchResult.name;
345
+ productCategory = searchResult.category || undefined;
346
+ console.log(`[barcode] Serper+AI resolved "${trimmedUpc}" → "${productName}"`);
347
+ }
348
+ }
349
+ // Level 3: Direct AI identification (least reliable)
350
+ if (!productName && provider !== 'reffo' && aiApiKey) {
351
+ productName = await (0, upc_lookup_1.identifyUpcWithAI)(trimmedUpc, provider, aiApiKey);
352
+ if (productName) {
353
+ console.log(`[barcode] Direct AI resolved "${trimmedUpc}" → "${productName}"`);
354
+ }
355
+ }
356
+ // Level 4: Reffo.ai fallback (has its own multi-stage pipeline)
357
+ if (!productName && reffoApiKey) {
358
+ const reffoResult = await (0, upc_lookup_1.resolveUpcViaReffo)(trimmedUpc, reffoApiKey, reffoUrl);
359
+ if (reffoResult?.name) {
360
+ productName = reffoResult.name;
361
+ productCategory = reffoResult.category || undefined;
362
+ console.log(`[barcode] Reffo.ai resolved "${trimmedUpc}" → "${productName}"`);
363
+ }
364
+ }
365
+ // All stages failed
366
+ if (!productName) {
367
+ console.log(`[barcode] Could not resolve UPC "${trimmedUpc}"`);
368
+ return res.json({
369
+ name: null,
370
+ description: null,
371
+ sku: trimmedUpc,
372
+ product_url: null,
373
+ image_url: null,
374
+ attributes: {},
375
+ price_estimate: { low: 0, high: 0, typical: 0, confidence: 'low' },
376
+ cached: false,
377
+ unidentified: true,
378
+ });
379
+ }
380
+ // 3. Enrich product data using the resolved name
319
381
  try {
382
+ const attributeKeys = (0, ref_schemas_1.getAttributeKeys)(productCategory, undefined);
320
383
  let result;
321
384
  if (provider === 'reffo') {
322
- const apiKey = process.env.REFFO_API_KEY;
323
- if (!apiKey) {
385
+ if (!reffoApiKey) {
324
386
  return res.status(400).json({
325
387
  error: 'No AI provider configured. Connect to Reffo.ai or set up a direct AI provider in Settings.',
326
388
  });
327
389
  }
328
- const reffoUrl = process.env.REFFO_API_URL || 'https://reffo.ai';
329
390
  const upstream = await fetch(`${reffoUrl}/api/product-lookup`, {
330
391
  method: 'POST',
331
- headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${apiKey}` },
332
- body: JSON.stringify({ name, category: '', subcategory: '' }),
392
+ headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${reffoApiKey}` },
393
+ body: JSON.stringify({ name: productName, category: productCategory || '', subcategory: '' }),
333
394
  });
334
395
  if (!upstream.ok) {
335
396
  const errData = await upstream.json().catch(() => ({}));
336
- return res.status(upstream.status).json({ error: errData.error || 'Product lookup failed' });
397
+ return res.status(upstream.status).json({ error: errData.error || 'Product enrichment failed' });
337
398
  }
338
399
  result = await upstream.json();
339
400
  }
340
401
  else {
341
- const aiApiKey = process.env.AI_API_KEY;
342
402
  if (!aiApiKey) {
343
403
  return res.status(400).json({ error: `AI provider "${provider}" selected but no API key configured.` });
344
404
  }
345
405
  result = await (0, product_lookup_1.callProductLookup)(provider, aiApiKey, {
346
- name, category: '', subcategory: '', attributeKeys,
406
+ name: productName, category: productCategory || '', subcategory: '', attributeKeys,
347
407
  });
348
408
  }
349
- // Cache result
350
- const id = require('uuid').v4();
409
+ // Override SKU with the actual UPC barcode
410
+ result.sku = trimmedUpc;
411
+ // 4. Cache with SKU for fast future lookups
412
+ const nameNormalized = productName.toLowerCase().trim();
351
413
  const pe = (result.price_estimate || {});
352
414
  db.prepare(`INSERT INTO product_catalog (id, name_normalized, category, subcategory, description, sku, product_url, image_url, attributes, price_low, price_high, price_typical, price_confidence, ai_model, expires_at)
353
- VALUES (?, ?, '', '', ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, datetime('now', '+30 days'))
415
+ VALUES (?, ?, ?, '', ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, datetime('now', '+30 days'))
354
416
  ON CONFLICT(name_normalized, category, subcategory) DO UPDATE SET
355
417
  description = excluded.description, sku = excluded.sku, product_url = excluded.product_url,
356
418
  image_url = excluded.image_url, attributes = excluded.attributes,
357
419
  price_low = excluded.price_low, price_high = excluded.price_high,
358
420
  price_typical = excluded.price_typical, price_confidence = excluded.price_confidence,
359
421
  ai_model = excluded.ai_model, lookup_count = product_catalog.lookup_count + 1,
360
- updated_at = datetime('now'), expires_at = datetime('now', '+30 days')`).run(id, nameNormalized, result.description ?? null, result.sku ?? null, result.product_url ?? null, result.image_url ?? null, JSON.stringify(result.attributes || {}), pe.low ?? null, pe.high ?? null, pe.typical ?? null, pe.confidence ?? 'low', provider);
361
- return res.json({ ...result, cached: false });
422
+ updated_at = datetime('now'), expires_at = datetime('now', '+30 days')`).run((0, uuid_1.v4)(), nameNormalized, productCategory || '', result.description ?? null, trimmedUpc, result.product_url ?? null, result.image_url ?? null, JSON.stringify({ ...(result.attributes || {}), product_name: productName }), pe.low ?? null, pe.high ?? null, pe.typical ?? null, pe.confidence ?? 'low', provider);
423
+ return res.json({ ...result, name: productName, cached: false, unidentified: false });
362
424
  }
363
425
  catch (err) {
364
- console.error('Barcode lookup error:', err);
426
+ console.error('Barcode enrichment error:', err);
365
427
  return res.status(502).json({ error: 'Product lookup failed. Check your AI provider configuration.' });
366
428
  }
367
429
  });