Fall back to TDS sheet for cure specs when main lookup returns none

After the main AI lookup and catalog search, if CureTemperatureF or
CureTimeMinutes is still null but a TDS URL was found, fetch that page
and ask Claude to extract just the cure schedule.

- IInventoryAiLookupService.FetchTdsCureSpecsAsync: new interface method
- InventoryAiLookupService.FetchTdsCureSpecsAsync: fetches the TDS URL via
  the existing FetchPageAsync pipeline (JSON-LD + doc-link extraction, HTML
  stripping). If the page is a PDF or unreachable, returns Success=false
  silently so no error surfaces in the UI. Otherwise sends a small targeted
  prompt that asks only for cureTemperatureF and cureTimeMinutes and uses
  MaxTokens=256 so the call is fast and cheap.
- InventoryController.ScanLabel: after catalog lookup, computes the resolved
  cure values (catalog preferred over AI result). If either is null and a
  TDS URL exists, calls FetchTdsCureSpecsAsync and merges any newly found
  values back into aiResult before building the JSON response.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-03 20:14:12 -04:00
parent 5e3b0b9ddf
commit 4182286a31
3 changed files with 126 additions and 0 deletions
@@ -834,6 +834,23 @@ public class InventoryController : Controller
}
}
// If cure specs are still missing but we have a TDS URL, fetch it and try to extract
// cure temperature and cure time. Most TDS pages are HTML; PDFs fail silently.
var resolvedCureTemp = catalogMatch?.CureTemperatureF ?? aiResult.CureTemperatureF;
var resolvedCureTime = catalogMatch?.CureTimeMinutes ?? aiResult.CureTimeMinutes;
var resolvedTdsUrl = catalogMatch?.TdsUrl ?? aiResult.TdsUrl;
if ((resolvedCureTemp == null || resolvedCureTime == null) && !string.IsNullOrEmpty(resolvedTdsUrl))
{
_logger.LogInformation("Cure specs missing after main lookup; trying TDS at {Url}", resolvedTdsUrl);
var tdsResult = await _aiLookupService.FetchTdsCureSpecsAsync(resolvedTdsUrl, colorName);
if (tdsResult.Success)
{
if (resolvedCureTemp == null) aiResult.CureTemperatureF = tdsResult.CureTemperatureF;
if (resolvedCureTime == null) aiResult.CureTimeMinutes = tdsResult.CureTimeMinutes;
}
}
// Check if this product already exists in the tenant's inventory.
// Match by ManufacturerPartNumber first (most precise); fall back to color name + manufacturer.
// Returns the first active match so the UI can prompt to add stock inline.