← back to Designer Wallcoverings

DW-Agents/dw-agents/amazon-paapi-integration.ts

291 lines

/**
 * Amazon Product Advertising API Integration
 * Fetches REAL product data and prices from Amazon
 */

import { amazon } from 'amazon-paapi';
import * as fs from 'fs';
import * as dotenv from 'dotenv';

// Load environment variables
dotenv.config();

interface AmazonProduct {
  asin: string;
  title: string;
  price: number;
  currency: string;
  url: string;
  imageUrl?: string;
  rating?: number;
  reviewCount?: number;
}

interface AmazonSearchResult {
  query: string;
  products: AmazonProduct[];
  timestamp: Date;
}

// Amazon PA-API Configuration
const PAAPI_CONFIG = {
  accessKey: process.env.PAAPI_ACCESS_KEY || '',
  secretKey: process.env.PAAPI_SECRET_KEY || '',
  partnerTag: process.env.PAAPI_PARTNER_TAG || '',
  host: process.env.PAAPI_HOST || 'webservices.amazon.com',
  region: process.env.PAAPI_REGION || 'us-east-1'
};

/**
 * Check if PA-API credentials are configured
 */
export function isPaapiConfigured(): boolean {
  return !!(PAAPI_CONFIG.accessKey && PAAPI_CONFIG.secretKey && PAAPI_CONFIG.partnerTag);
}

/**
 * Search Amazon for products using PA-API
 */
export async function searchAmazonProducts(query: string, maxResults: number = 10): Promise<AmazonSearchResult> {
  console.log(`🔍 Searching Amazon PA-API for: "${query}"`);

  if (!isPaapiConfigured()) {
    console.error('❌ Amazon PA-API not configured!');
    console.log('\n📝 To configure:');
    console.log('   1. Sign up at: https://associates.amazon.com');
    console.log('   2. Get API credentials from Tools → Product Advertising API');
    console.log('   3. Copy .env.example to .env');
    console.log('   4. Add your credentials to .env\n');

    return {
      query,
      products: [],
      timestamp: new Date()
    };
  }

  try {
    const requestParameters = {
      Keywords: query,
      SearchIndex: 'All',
      ItemCount: Math.min(maxResults, 10), // PA-API max is 10 per request
      Resources: [
        'ItemInfo.Title',
        'Offers.Listings.Price',
        'Images.Primary.Large',
        'ItemInfo.ByLineInfo',
        'CustomerReviews.StarRating',
        'CustomerReviews.Count'
      ]
    };

    const response = await amazon.searchItems(requestParameters);

    const products: AmazonProduct[] = [];

    if (response.SearchResult && response.SearchResult.Items) {
      response.SearchResult.Items.forEach((item: any) => {
        try {
          const asin = item.ASIN || '';
          const title = item.ItemInfo?.Title?.DisplayValue || 'Unknown Product';

          let price = 0;
          let currency = 'USD';

          if (item.Offers?.Listings && item.Offers.Listings.length > 0) {
            const listing = item.Offers.Listings[0];
            if (listing.Price) {
              price = listing.Price.Amount || 0;
              currency = listing.Price.Currency || 'USD';
            }
          }

          const url = item.DetailPageURL || `https://www.amazon.com/dp/${asin}`;
          const imageUrl = item.Images?.Primary?.Large?.URL || undefined;

          let rating = undefined;
          let reviewCount = undefined;

          if (item.CustomerReviews) {
            rating = item.CustomerReviews.StarRating?.Value || undefined;
            reviewCount = item.CustomerReviews.Count || undefined;
          }

          products.push({
            asin,
            title,
            price: price / 100, // Convert cents to dollars
            currency,
            url,
            imageUrl,
            rating,
            reviewCount
          });

          console.log(`   ✅ ${title} - $${(price / 100).toFixed(2)}`);
        } catch (err) {
          console.error('   ⚠️  Error parsing item:', err);
        }
      });
    }

    console.log(`✅ Found ${products.length} products\n`);

    return {
      query,
      products,
      timestamp: new Date()
    };

  } catch (error: any) {
    console.error('❌ Amazon PA-API Error:', error.message || error);

    return {
      query,
      products: [],
      timestamp: new Date()
    };
  }
}

/**
 * Get product details by ASIN
 */
export async function getProductByAsin(asin: string): Promise<AmazonProduct | null> {
  console.log(`🔍 Fetching product details for ASIN: ${asin}`);

  if (!isPaapiConfigured()) {
    console.error('❌ Amazon PA-API not configured!');
    return null;
  }

  try {
    const requestParameters = {
      ItemIds: [asin],
      Resources: [
        'ItemInfo.Title',
        'Offers.Listings.Price',
        'Images.Primary.Large',
        'CustomerReviews.StarRating',
        'CustomerReviews.Count'
      ]
    };

    const response = await amazon.getItems(requestParameters);

    if (response.ItemsResult?.Items && response.ItemsResult.Items.length > 0) {
      const item = response.ItemsResult.Items[0];

      const title = item.ItemInfo?.Title?.DisplayValue || 'Unknown Product';
      let price = 0;
      let currency = 'USD';

      if (item.Offers?.Listings && item.Offers.Listings.length > 0) {
        const listing = item.Offers.Listings[0];
        if (listing.Price) {
          price = listing.Price.Amount || 0;
          currency = listing.Price.Currency || 'USD';
        }
      }

      const url = item.DetailPageURL || `https://www.amazon.com/dp/${asin}`;
      const imageUrl = item.Images?.Primary?.Large?.URL || undefined;

      let rating = undefined;
      let reviewCount = undefined;

      if (item.CustomerReviews) {
        rating = item.CustomerReviews.StarRating?.Value || undefined;
        reviewCount = item.CustomerReviews.Count || undefined;
      }

      const product: AmazonProduct = {
        asin,
        title,
        price: price / 100,
        currency,
        url,
        imageUrl,
        rating,
        reviewCount
      };

      console.log(`✅ ${title} - $${product.price.toFixed(2)}`);

      return product;
    }

    console.log('⚠️  Product not found');
    return null;

  } catch (error: any) {
    console.error('❌ Amazon PA-API Error:', error.message || error);
    return null;
  }
}

/**
 * Compare prices for office supplies
 */
export async function compareOfficeSupplyPrices(itemName: string): Promise<void> {
  console.log(`\n💰 Comparing Prices for: ${itemName}\n`);
  console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n');

  const results = await searchAmazonProducts(itemName, 5);

  if (results.products.length === 0) {
    console.log('⚠️  No products found');
    return;
  }

  // Sort by price (lowest first)
  results.products.sort((a, b) => a.price - b.price);

  console.log('📊 Price Comparison:\n');

  results.products.forEach((product, idx) => {
    const badge = idx === 0 ? '🏆 BEST PRICE' : '';
    console.log(`${idx + 1}. ${product.title}`);
    console.log(`   💵 Price: $${product.price.toFixed(2)} ${badge}`);
    if (product.rating) {
      console.log(`   ⭐ Rating: ${product.rating} (${product.reviewCount} reviews)`);
    }
    console.log(`   🔗 URL: ${product.url}`);
    console.log('');
  });

  console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n');
}

// Test function
if (require.main === module) {
  (async () => {
    console.log('🧪 Testing Amazon PA-API Integration\n');
    console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n');

    if (!isPaapiConfigured()) {
      console.log('⚠️  Amazon PA-API credentials not configured\n');
      console.log('📝 Setup Instructions:\n');
      console.log('1. Visit: https://associates.amazon.com');
      console.log('2. Sign up for Amazon Associates Program');
      console.log('3. Navigate to: Tools → Product Advertising API');
      console.log('4. Create API credentials (Access Key, Secret Key)');
      console.log('5. Copy .env.example to .env in this directory');
      console.log('6. Add your credentials to .env:\n');
      console.log('   PAAPI_ACCESS_KEY=your_access_key');
      console.log('   PAAPI_SECRET_KEY=your_secret_key');
      console.log('   PAAPI_PARTNER_TAG=your_associate_id\n');
      console.log('7. Run this script again: npx tsx amazon-paapi-integration.ts\n');

      process.exit(0);
    }

    // Test searches for common office supplies
    await compareOfficeSupplyPrices('printer paper');
    await compareOfficeSupplyPrices('black ink cartridge');
    await compareOfficeSupplyPrices('post-it notes');
  })();
}

export { AmazonProduct, AmazonSearchResult };