Przeglądaj źródła

fix: extract descriptions, tags, and attributes from ShopRenter productDescriptions array and filter URLs from Qdrant #81

Claude 5 miesięcy temu
rodzic
commit
8f58a24664
1 zmienionych plików z 96 dodań i 66 usunięć
  1. 96 66
      supabase/functions/shoprenter-sync/index.ts

+ 96 - 66
supabase/functions/shoprenter-sync/index.ts

@@ -120,19 +120,34 @@ async function syncProductsToQdrant(
     }
 
     // Generate text representations for all products
-    const productTexts = validProducts.map((product) =>
-      createProductText({
-        name: product.name,
-        description: product.description,
-        short_description: product.short_description,
+    // Extract descriptions, tags, and attributes from ShopRenter's nested structure
+    const productTexts = validProducts.map((product) => {
+      // Extract first language description from productDescriptions array
+      const productDesc = product.productDescriptions?.[0] || {}
+
+      // Extract tags from productTags array (ShopRenter structure: [{name: "tag1"}, ...])
+      const tags = (product.productTags || []).map((t: any) => t.name || t).filter(Boolean)
+
+      // Extract attributes from productAttributeExtend array
+      const attributes = (product.productAttributeExtend || []).map((attr: any) => {
+        if (attr.name && attr.value) {
+          return { name: attr.name, options: attr.value }
+        }
+        return null
+      }).filter(Boolean)
+
+      return createProductText({
+        name: productDesc.name || product.name,
+        description: productDesc.description || null,
+        short_description: productDesc.shortDescription || null,
         sku: product.sku,
         categories: product.categories || [],
-        tags: product.tags || [],
-        attributes: product.attributes || [],
+        tags: tags,
+        attributes: attributes,
         price: product.price,
-        meta_description: product.meta_description,
+        meta_description: productDesc.metaDescription || null,
       })
-    )
+    })
 
     // Generate embeddings in batch
     console.log(`[Qdrant] Generating embeddings for ${productTexts.length} products...`)
@@ -140,64 +155,79 @@ async function syncProductsToQdrant(
     console.log(`[Qdrant] Embeddings generated successfully`)
 
     // Convert products to Qdrant points with embeddings and comprehensive details
-    const points: QdrantPoint[] = validProducts.map((product, index) => ({
-      id: generatePointId('shoprenter', storeId, product.innerId),
-      vector: embeddings[index],
-      payload: {
-        // Basic identification
-        store_id: storeId,
-        product_id: product.innerId.toString(),
-        platform: 'shoprenter',
-        name: product.name,
-        sku: product.sku || null,
-
-        // Pricing
-        price: parseFloat(product.price) || 0,
-        currency: product.currency || 'HUF',
-        price_gross: product.price_gross ? parseFloat(product.price_gross) : null,
-
-        // Descriptions
-        description: product.description || null,
-        short_description: product.short_description || null,
-        meta_description: product.meta_description || null,
-
-        // Categorization
-        categories: product.categories?.map((cat: any) => ({
-          id: cat.id,
-          name: cat.name,
-          slug: cat.slug || null
-        })) || [],
-        tags: product.tags || [],
-
-        // Attributes
-        attributes: product.attributes || [],
-
-        // Images
-        images: product.images?.map((img: any) => ({
-          id: img.id,
-          src: img.src || img.url,
-          alt: img.alt || product.name,
-          position: img.position || 0
-        })) || [],
-
-        // Stock information
-        stock: product.stock || 0,
-        stock_status: product.stock > 0 ? 'instock' : 'outofstock',
-
-        // Product status
-        active: product.active !== false,
-        status: product.active !== false ? 'active' : 'inactive',
-
-        // Additional fields
-        manufacturer: product.manufacturer || null,
-        model: product.model || null,
-        weight: product.weight || null,
-        weight_unit: product.weight_unit || 'kg',
-
-        // Metadata
-        synced_at: new Date().toISOString(),
+    const points: QdrantPoint[] = validProducts.map((product, index) => {
+      // Extract first language description from productDescriptions array
+      const productDesc = product.productDescriptions?.[0] || {}
+
+      // Extract tags from productTags array
+      const tags = (product.productTags || []).map((t: any) => t.name || t).filter(Boolean)
+
+      // Extract attributes from productAttributeExtend array
+      const attributes = (product.productAttributeExtend || []).map((attr: any) => {
+        if (attr.name && attr.value) {
+          return { name: attr.name, value: attr.value }
+        }
+        return null
+      }).filter(Boolean)
+
+      // Extract categories from productCategoryRelations (filter out href/URL fields)
+      const categories = (product.productCategoryRelations || []).map((rel: any) => ({
+        id: rel.category?.id || null,
+      })).filter((cat: any) => cat.id)
+
+      // Extract manufacturer info (filter out href)
+      const manufacturer = product.manufacturer?.name || null
+
+      return {
+        id: generatePointId('shoprenter', storeId, product.innerId),
+        vector: embeddings[index],
+        payload: {
+          // Basic identification
+          store_id: storeId,
+          product_id: product.innerId.toString(),
+          platform: 'shoprenter',
+          name: productDesc.name || product.name || null,
+          sku: product.sku || null,
+
+          // Pricing
+          price: parseFloat(product.price) || 0,
+          currency: 'HUF',
+
+          // Descriptions (extracted from productDescriptions array)
+          description: productDesc.description || null,
+          short_description: productDesc.shortDescription || null,
+          meta_description: productDesc.metaDescription || null,
+
+          // Categorization
+          categories: categories,
+          tags: tags,
+
+          // Attributes
+          attributes: attributes,
+
+          // Images (filter out hrefs, keep only actual image data)
+          main_image: product.allImages?.mainImage || null,
+          image_alt: product.imageAlt || null,
+
+          // Stock information
+          stock: parseInt(product.stock1 || '0') || 0,
+          stock_status: parseInt(product.stock1 || '0') > 0 ? 'instock' : 'outofstock',
+
+          // Product status
+          active: product.status === '1',
+          status: product.status === '1' ? 'active' : 'inactive',
+
+          // Additional fields
+          manufacturer: manufacturer,
+          model: product.modelNumber || null,
+          weight: product.weight ? parseFloat(product.weight) : null,
+
+          // Metadata
+          synced_at: new Date().toISOString(),
+        }
       }
-    }))
+    })
+
 
     await upsertPoints(collectionName, points)
     synced = points.length