Commit Graph

16 Commits

Author SHA1 Message Date
spouliot cb7bbc37bd Add three-layer feature gating for AI Catalog Price Check
Adds platform-level, plan-level (Enterprise only), and per-company
toggles for the AI Catalog Price Check feature. Includes:
- Company.AiCatalogPriceCheckEnabled per-company flag
- SubscriptionPlanConfig.AllowAiCatalogPriceCheck plan-level flag
- PlatformSetting 'AiCatalogPriceCheckEnabled' global kill switch
- IPlatformSettingsService.GetBoolAsync helper
- ISubscriptionService.CanUseAiCatalogPriceCheckAsync
- UI controls in Companies/Edit, PlatformSubscription/Edit+Index,
  and SubscriptionManagement/Manage
- Migration AddAiCatalogPriceCheckGating applied

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-26 08:29:51 -04:00
spouliot ff79c39e83 Switch to sequential batching to eliminate rate limit hits
1 concurrent + 20s pacing = ~3 batches/min × 2k tokens = 6k TPM,
safely under the 8k output TPM limit. Progress estimate updated to 22s/batch.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-25 22:27:10 -04:00
spouliot 2d25f6db2b Add proactive inter-batch pacing to avoid rate limit hits
Rather than relying on reactive 65s retries, each semaphore slot is held
for at least MinBatchIntervalSeconds (20s). With 2 concurrent slots that
limits throughput to ~3 batches/min × ~2k tokens = ~6k output TPM,
safely under the 8k/min limit.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-25 22:01:22 -04:00
spouliot 26b8244422 Reduce to 2 concurrent batches to avoid Haiku output TPM bursting
3 concurrent batches hit the rate limit simultaneously then retry in
unison, causing repeated 429s. 2 concurrent keeps output rate lower.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-25 21:54:32 -04:00
spouliot 7b902d90a2 Restore 3 concurrent batches with Haiku; recalibrate progress bar
Haiku has generous rate limits so parallelism is safe again. Retry
logic catches any 429s. Progress estimate updated to ~8s per wave.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-25 21:49:53 -04:00
spouliot f05e16a826 Switch AI price check to Haiku for cost and speed
Testing Haiku 4.5 for catalog price analysis — structured JSON output
with explicit rules is well within its capabilities. Revert to Sonnet
if result quality is insufficient.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-25 21:41:50 -04:00
spouliot 7407d1cd96 Fix rate limit errors in AI price check
Tier 1 Anthropic accounts are capped at 8,000 output tokens/minute on
Sonnet. 3 concurrent batches burst well past that, causing 429s.

- MaxConcurrentBatches: 3 → 1 (sequential prevents burst)
- Add retry: on rate_limit_error, wait 65s then retry up to 3 times
  so the per-minute window resets before the next attempt

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-25 20:54:30 -04:00
spouliot 740238a939 Drop description field from AI price check user prompt
Item name + category path give Claude sufficient context for surface area
estimation. Descriptions add input tokens without meaningfully improving
verdict quality.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-25 20:44:25 -04:00
spouliot 560a2c76b8 Add full category path to AI price check for coating-type context
- Skip $0-priced items (placeholders/category headers) in RunAiPriceCheck
- Build full category path (e.g. "Cerakote > Firearms") via BuildCategoryPath
  so Claude receives coating-type context — Cerakote pricing differs significantly
  from standard powder coat
- Update AI system prompt to instruct Claude to use the category path when
  determining process type, equipment, cure times, and market rates

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-25 20:35:41 -04:00
spouliot 19cc03ad1c Parallelize AI price check batches, increase batch size to 25
500-item catalog was making 50 sequential API calls, causing progressive rate-limit
throttling (explains "super slow towards the end") and ~$3 in credits.

- BatchSize: 10 → 25 (word limits are in place; 25 items × ~80 tokens ≈ 2000
  output tokens, well within MaxTokens=8192 — the original truncation cause)
- Run up to 3 batches concurrently via SemaphoreSlim(3) — independent API calls
  with no shared state, so no growing context issue
- For a 500-item catalog: 50 sequential calls → 20 calls in ~7 parallel waves,
  roughly 4× faster and 60% cheaper
- Dropped unused `costs` param from AnalyzeBatchAsync (system prompt has all costs)
- JS progress timing updated to reflect parallel waves

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-25 20:27:07 -04:00
spouliot 9370fcdd8f Reduce batch size to 10 and tighten AI price check prompt
Still seeing stubs despite MaxTokens=8192 — smaller batches and explicit
word limits in the prompt eliminate any remaining truncation risk.

- BatchSize: 15 → 10 (~1200 output tokens per batch vs. potential 3000+)
- Prompt: added 20-word cap on assumptions, 25-word cap on reasoning
- Prompt: strengthened "nothing before or after the '['" instruction
- Error log: now includes item IDs and first 300 chars of raw response
  so the next failure tells us exactly what Claude returned
- JS timing: updated batch divisor from 25 → 10 to match actual batch size

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-25 19:57:23 -04:00
spouliot 2c4c1a6846 Fix AI price check truncation and JSON parse errors
Root cause: MaxTokens=4096 was too low — 25 items at ~250 tokens each hit the
limit mid-array (logged error showed Path: $[17]).

- MaxTokens: 4096 → 8192
- BatchSize: 25 → 15 items (keeps each response well under the limit)
- StripJsonFences → ExtractJsonArray: now also handles prose before/after the
  JSON array, and recovers truncated responses by finding the last complete
  object and closing the array — so partial batches return whatever Claude
  finished rather than nothing
- GET action: added try-catch around ResultsJson deserialization so a bad DB
  row shows a friendly "re-run" warning instead of a raw error page

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-25 19:45:53 -04:00
spouliot 54f444d981 Add AI Catalog Price Check feature
Claude reviews every active catalog item against the shop's own operating costs
and returns a per-item verdict (below-cost / thin-margin / high / ok) with a
suggested price range, cost floor, and assumptions.

- New entity: CatalogPriceCheckReport (JSON blob, archived per company)
- New service: IAiCatalogPriceCheckService / AiCatalogPriceCheckService
  batches items 25 at a time to stay within model context limits
- Two new controller actions: GET AiPriceCheck (view report) + POST RunAiPriceCheck
- AiPriceCheck view: summary cards (counts by verdict), color-coded item cards
  with Edit Price link, assumptions detail, and loading spinner on submit
- AI Price Check button added to catalog Index header
- Migration AddCatalogPriceCheckReport applied

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-25 18:41:56 -04:00
spouliot 27ac793f62 Harden paid registration flow and add unit tests 2026-04-24 21:10:28 -04:00
spouliot 8d94013895 Add AI Quick Quote widget and inline customer reassignment
- New AI Quick Quote floating button: staff type a verbal description to
  get an instant price estimate for phone/walk-in customers; detected
  color names are fuzzy-matched against inventory for stock status;
  saves draft quote under a Walk-In / Phone customer with one click
- Inline customer change on Quote Details and Job Details: always-visible
  native select with inline confirmation banner (no TomSelect dependency);
  ChangeCustomer AJAX endpoints on QuotesController and JobsController
- Quote Edit page: customer dropdown is now editable (lock removed)
- Fix AutoMapper missing CatalogCategory -> UpdateCategoryDto mapping
  that caused a crash on the catalog category Edit page
- Help docs and AI knowledge base updated for all three features

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-24 17:02:03 -04:00
spouliot 63e12a9636 Initial commit 2026-04-23 21:38:24 -04:00