Fix label scanner: full field mapping, vision follow-up lookup, SDS/TDS extraction
- LookupByUrlAsync now maps all identity + spec fields from Claude response (manufacturer, SKU, colorName, description, sdsUrl, tdsUrl, unitCostPerLb, etc.) Previously only augmenting fields were mapped; Columbia QR path left 80% blank - Vision scan follow-up: after ScanLabelAsync reads label text, automatically run LookupAsync using the extracted manufacturer + color/SKU to fill SDS/TDS URLs, product page, image, description, and any specs not printed on the bag; label values (cure schedule, SKU) remain authoritative and are never overwritten - SDS/TDS URL extraction: added ExtractDocumentLinks() that scans anchor tags in raw HTML before tag-stripping, injects found URLs as [Structured Data] lines so Claude can read and echo them back in the JSON response; previously all hrefs were lost with the HTML stripping - Added SdsUrl/TdsUrl to InventoryAiLookupResult, Claude system prompt JSON schema, LookupAsync mapping, and ScanLabel response (catalog match ?? aiResult fallback) - SDS/TDS now also stored on auto-contributed catalog entries - jsQR inversionAttempts: 'dontInvert' → 'attemptBoth' for better QR detection under varying label contrast and lighting conditions Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -724,15 +724,49 @@ public class InventoryController : Controller
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(qrUrl))
|
||||
{
|
||||
// QR path: fetch the product page and let Claude extract specs from its content
|
||||
// QR path: fetch the product page; LookupByUrlAsync now maps all identity + spec fields
|
||||
aiResult = await _aiLookupService.LookupByUrlAsync(qrUrl, null);
|
||||
if (aiResult.Success && aiResult.SpecPageUrl == null)
|
||||
aiResult.SpecPageUrl = qrUrl;
|
||||
}
|
||||
else if (!string.IsNullOrWhiteSpace(imageBase64))
|
||||
{
|
||||
// Vision path: Claude reads the label photo directly
|
||||
// Vision path: Claude reads what's printed on the label (limited to visible text)
|
||||
aiResult = await _aiLookupService.ScanLabelAsync(imageBase64, mediaType ?? "image/jpeg");
|
||||
|
||||
// Follow-up web lookup so we get SDS/TDS URLs, product page, image, description,
|
||||
// and any specs not printed on the label. Label values are kept as-is (authoritative);
|
||||
// the full lookup only fills fields that are still null.
|
||||
if (aiResult.Success)
|
||||
{
|
||||
var mfr = aiResult.Manufacturer ?? aiResult.VendorName;
|
||||
if (!string.IsNullOrWhiteSpace(mfr) &&
|
||||
(!string.IsNullOrWhiteSpace(aiResult.ColorName) || !string.IsNullOrWhiteSpace(aiResult.ManufacturerPartNumber)))
|
||||
{
|
||||
var full = await _aiLookupService.LookupAsync(
|
||||
mfr, aiResult.ColorName, aiResult.ColorCode, aiResult.ManufacturerPartNumber);
|
||||
if (full.Success)
|
||||
{
|
||||
aiResult.Description ??= full.Description;
|
||||
aiResult.SdsUrl ??= full.SdsUrl;
|
||||
aiResult.TdsUrl ??= full.TdsUrl;
|
||||
aiResult.ImageUrl ??= full.ImageUrl;
|
||||
aiResult.SpecPageUrl ??= full.SpecPageUrl;
|
||||
aiResult.UnitCostPerLb ??= full.UnitCostPerLb;
|
||||
aiResult.VendorName ??= full.VendorName;
|
||||
aiResult.ColorFamilies ??= full.ColorFamilies;
|
||||
aiResult.Finish ??= full.Finish;
|
||||
aiResult.CureTemperatureF ??= full.CureTemperatureF;
|
||||
aiResult.CureTimeMinutes ??= full.CureTimeMinutes;
|
||||
aiResult.RequiresClearCoat ??= full.RequiresClearCoat;
|
||||
aiResult.CoverageSqFtPerLb ??= full.CoverageSqFtPerLb;
|
||||
aiResult.TransferEfficiency ??= full.TransferEfficiency;
|
||||
aiResult.ManufacturerPartNumber ??= full.ManufacturerPartNumber;
|
||||
aiResult.ColorName ??= full.ColorName;
|
||||
aiResult.ColorCode ??= full.ColorCode;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -783,6 +817,8 @@ public class InventoryController : Controller
|
||||
TransferEfficiency= aiResult.TransferEfficiency,
|
||||
ImageUrl = aiResult.ImageUrl,
|
||||
ProductUrl = aiResult.SpecPageUrl,
|
||||
SdsUrl = aiResult.SdsUrl,
|
||||
TdsUrl = aiResult.TdsUrl,
|
||||
IsUserContributed = true,
|
||||
CreatedAt = DateTime.UtcNow,
|
||||
};
|
||||
@@ -815,8 +851,8 @@ public class InventoryController : Controller
|
||||
unitPrice = catalogMatch?.UnitPrice ?? 0m,
|
||||
imageUrl = catalogMatch?.ImageUrl ?? aiResult.ImageUrl,
|
||||
productUrl = catalogMatch?.ProductUrl ?? aiResult.SpecPageUrl,
|
||||
sdsUrl = catalogMatch?.SdsUrl,
|
||||
tdsUrl = catalogMatch?.TdsUrl,
|
||||
sdsUrl = catalogMatch?.SdsUrl ?? aiResult.SdsUrl,
|
||||
tdsUrl = catalogMatch?.TdsUrl ?? aiResult.TdsUrl,
|
||||
vendorName = manufacturer,
|
||||
wasInCatalog = wasInCatalog,
|
||||
addedToCatalog = addedToCatalog,
|
||||
|
||||
Reference in New Issue
Block a user