Send /nothink as a separate message before the actual prompt,
with a mock assistant response. This properly disables thinking
mode for Qwen3/DeepSeek models.
Removed the ineffective think:false API parameter.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Default 4K context was truncating the HTML before the model could see it.
Added num_ctx: 16384 to all 4 Ollama API calls to ensure the full
~25K character HTML content fits in context.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The /nothink prefix in prompt text doesn't work for Qwen3/DeepSeek.
The correct way is to pass "think": false in the API request body.
- Added think: false to all 4 Ollama API calls (extract, verify,
stock status, arbitrate)
- Removed ineffective /nothink prefixes from prompts
- Kept stripThinkingTags() as additional fallback protection
Ref: https://docs.ollama.com/capabilities/thinking
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
These models output <think>...</think> blocks before their actual JSON
response when in "thinking mode". This fix:
1. Adds /nothink prefix to all AI prompts (EXTRACTION_PROMPT,
VERIFICATION_PROMPT, STOCK_STATUS_PROMPT, ARBITRATION_PROMPT)
to request models disable thinking mode
2. Adds stripThinkingTags() helper function that removes <think>
blocks from responses as a fallback if models ignore /nothink
3. Applies stripping in all parse functions before JSON extraction
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When anchor price matches (user previously selected a specific variant),
we now call AI specifically to verify stock status for that price point.
- Add STOCK_STATUS_PROMPT focused on variant availability
- Add AIStockStatusResult interface
- Add verifyStockStatusWith{Anthropic,OpenAI,Ollama} functions
- Add tryAIStockStatusVerification export function
- Call stock verification when anchor price matches in scraper
The prompt instructs AI to only check stock for the specific variant at
the user's selected price, ignoring other variants that may be out of
stock. This fixes false "out of stock" reports on variant product pages.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add gotify_url, gotify_app_token, gotify_enabled columns to users table
- Add sendGotifyNotification function with priority levels
- Add testGotifyConnection function to verify server connectivity
- Add test-gotify endpoint for connection testing before save
- Add Gotify section in Settings with:
- Server URL input with Test Connection button
- App Token input (masked)
- Enable/disable toggle
- Send Test button (after configured)
- Include Gotify in notification dispatching
Gotify is a self-hosted push notification server popular in the
self-hosted community, complementing the existing ntfy support.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Update refresh endpoint to use scrapeProductWithVoting instead of scrapeProduct
- Pass skipAiVerification and skipAiExtraction flags from product settings
- Also use preferred extraction method and anchor price for consistency
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add ai_extraction_disabled column to products table
- Add toggle in Advanced Settings alongside AI verification disable
- Pass skipAiExtraction flag through scheduler to scraper
- Skip AI extraction fallback when flag is set for product
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add anthropic_model and openai_model columns to database
- Allow users to select their preferred AI model in settings
- Update defaults to current models (Claude Haiku 4.5, GPT-4.1 Nano)
- Include model options: Claude 4.5 series, GPT-4.1/5.1 series
- Pass user-selected model to all AI extraction/verification functions
- Log which model is being used for debugging
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Sonnet 4 is ~4-12x more expensive than Haiku 3.5.
Haiku 3.5 should still be capable enough for price extraction.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Users can now disable AI verification for individual products that
AI is having trouble with (e.g., Amazon products where AI keeps
picking the main buy box price instead of "other sellers").
Changes:
- Add ai_verification_disabled column to products table
- Add toggle in product detail page under "Advanced Settings"
- Pass skip flag to scrapeProductWithVoting
- Skip AI verification when flag is set
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Haiku was being too literal in price extraction, often "correcting"
valid alternative prices (like Amazon other sellers) to the main
buy box price.
Sonnet is more capable and should handle nuanced cases better.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When the scraper finds multiple valid prices (e.g., Amazon main price +
other sellers), skip AI verification entirely. AI was "correcting"
valid alternative prices to the main buy box price.
Now with multiple candidates, users see all options in the modal and
choose themselves - no AI interference.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Amazon products can have multiple prices:
- Main buy box price
- "Other Sellers" prices
- Subscribe & Save prices
- New & Used prices
The scraper now extracts ALL prices, not just the main one. This allows
anchor price matching to find the specific price the user selected.
Also fixed AI verification overriding user's anchor price selection.
When user deliberately chose a price (e.g., "other sellers" at $52.91),
don't let AI "correct" it to the main buy box price ($79.99).
Changes:
- Amazon scraper now collects all price variants
- extractSiteSpecificCandidates handles allPrices array
- Anchor matching now always returns (no fall-through to AI override)
- Increased anchor tolerance from 10% to 15% for small sales
- Added debug logging showing all candidate prices
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The previous logic checked preferred method first, which could select
a wrong price even when anchor price was available. Now:
1. PRIORITY 1: Anchor price - if user confirmed a price, find closest
match (within 10% tolerance) across ALL candidates
2. PRIORITY 2: Preferred method - only used if no anchor match found
3. PRIORITY 3: Consensus voting
Also added debug logging to trace anchor price saving and retrieval.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When a user confirms a price from the modal, we now store it as an
"anchor price". On subsequent refreshes, if multiple price candidates
are found (common with variant products like different sizes/colors),
we select the candidate closest to the anchor price.
This fixes the issue where variant products would randomly switch to
a different variant's price on refresh.
Changes:
- Add anchor_price column to products table
- Save anchor price when user confirms a price selection
- Use anchor price to select correct variant on refresh
- 20% tolerance - if no candidate is within 20% of anchor, fall back to consensus
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add prominent "You Choose the Price. Always." section at the top
- Explain the 4-method extraction system (JSON-LD, site-specific, CSS, AI)
- Detail the Price Selection Modal and its benefits
- Compare to competitors (Keepa, CamelCamelCamel, Honey)
- Add new "Multi-Strategy Price Extraction" feature section
- Add "Supported Retailers" table with browser rendering info
- Mention AI Arbitration as a new capability
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Fix TypeScript narrowing issue in Best Buy scraper
- Add browser rendering for JS-heavy sites (Best Buy, Target, Walmart, Costco)
- Improve Best Buy site-specific scraper with better selectors and logging
- Skip payment plan prices (/mo, per month, etc.)
- Enhance AI HTML preparation:
- Extract JSON-LD data before removing scripts
- Add price element extraction for better context
- Increase character limit from 15000 to 25000
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Always show price selection modal when adding a product so users can verify
- Use browser rendering for known JS-heavy sites (Best Buy, Target, Walmart, Costco)
- Update modal text to say "Confirm Price" for single candidates
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add multi-strategy voting: runs JSON-LD, site-specific, generic CSS,
and AI extraction methods in parallel
- Implement consensus voting to select the correct price when methods agree
- Add AI arbitration when extraction methods disagree
- Add PriceSelectionModal for users to select correct price when ambiguous
- Store preferred extraction method per product for faster re-checks
- Add database columns for preferred_extraction_method and needs_price_review
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add global filter in priceParser to reject monthly/payment plan prices
- Filters: "/mo", "per month", "payments starting", "4 payments", etc.
- Update Best Buy scraper to check each price element for payment terms
- Prevents scraping "$25/mo" instead of actual "$229.99" price
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Pure CSS/JS particle animation behind all content
- Multiple layers with different speeds for depth effect
- Theme-aware: white particles on dark mode, purple on light mode
- Low opacity for subtle, non-distracting ambiance
- Uses box-shadow technique for performance
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add notifications_cleared_at column to users table
- Clear button marks notifications as seen without deleting history
- Badge and dropdown only show notifications after last clear
- History page still shows all notifications
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
PostgreSQL DECIMAL fields are returned as strings by node-postgres.
Convert to numbers before calling toFixed() to prevent TypeError.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Relocate PriceGhost version, changelog, and GitHub links from bottom
of page to underneath the left navigation buttons
- Update sidebar CSS to use flexbox for proper layout
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add notification_history database table for logging all triggered notifications
- Create API endpoints for fetching recent and historical notifications
- Add NotificationBell component in navbar with badge showing recent count
- Dropdown shows 5 most recent notifications with links to products
- Create full NotificationHistory page with filtering by notification type
- Log notifications when sent: price drops, target prices, back-in-stock
- Track which channels (telegram, discord, pushover, ntfy) received each notification
- Update sendNotifications to return which channels succeeded
- Bump version to 1.0.3
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Remove overly generic pre-order phrases that caused false positives
("available in", "coming in", "arriving in" matched normal text)
- Add in-stock phrase priority check - "in stock", "add to cart",
"add to basket" now take precedence over pre-order detection
- Add Magento 2 stock status detection using stock classes and
add-to-cart buttons
- Bump version to 1.0.2
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- CI/CD now only rebuilds images when backend/ or frontend/ changes
- Uses dorny/paths-filter to detect which components changed
- README, docs, and asset changes no longer trigger builds
- Updated CHANGELOG with all recent changes
- Bumped version to 1.0.1
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Removed space between Price and Ghost (now one word)
- Ghost gradient starts at 85% opacity for smoother transition
- Price text remains fully prominent
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Combined icon + PriceGhost text in single SVG header
- Ghost text has gradient fade effect (solid to transparent)
- Subtle glow filter for ethereal look
- Replaces separate icon and h1 in README
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- If no price found in static HTML, automatically try headless browser
- Re-runs all extraction methods on browser-rendered HTML
- Fixes price extraction for Magento, React, Vue, and other JS-heavy sites
- AI extraction now also benefits from rendered HTML
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- AI verification now checks if product is purchasable RIGHT NOW
- AI returns stockStatus field for pre-order/coming soon detection
- Enhanced generic stock status detection with pre-order phrases:
- Coming soon, available soon, releases on, pre-order, etc.
- Notify me when available, join waitlist, etc.
- Pre-order buttons no longer count as Add to Cart
- Fixes issue where unreleased products showed as in stock
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Ghost text fades from solid to transparent (left to right)
- Soft ethereal glow effect via text-shadow
- Enhanced glow on hover
- Works in both light and dark modes
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Replace ghost emoji with SVG icon in navbar
- Replace ghost emoji with SVG icon on login/register page
- Consistent branding throughout the app
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Backend now creates all required tables if they do not exist
- Migrations run BEFORE server accepts connections (prevents race condition)
- Server exits if migrations fail instead of running with broken DB
- Fixes registration failure on fresh Docker installs without init.sql
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Create CHANGELOG.md documenting all features
- Add version.json for version tracking
- Display version in Settings page footer with links to Changelog and GitHub
- Tag release as v1.0.0
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add ai_status column to price_history table (verified/corrected/null)
- Track AI verification status through scraper and scheduler
- Display badges next to prices:
- ✓ AI (green): AI verified the price is correct
- ⚡ AI (orange): AI corrected an incorrect price
- Show badges on Dashboard product cards and ProductDetail page
- Add legend explaining badges in Settings when AI Verification is enabled
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The GET and PUT /api/settings/ai endpoints were missing
ai_verification_enabled in the request/response handling.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>