Procházet zdrojové kódy

fix: Qdrant point ID format - generate valid UUIDs instead of invalid string IDs #75

- Add generatePointId() helper function to create deterministic UUIDs from platform/store/item IDs
- Fix WooCommerce sync: replace invalid string IDs with UUID format
- Fix Shopify sync: replace invalid string IDs with UUID format
- Resolves Qdrant API error: 'value is not a valid point ID, valid values are either an unsigned integer or a UUID'
- Products/orders/customers will now sync successfully to Qdrant vector database
Claude před 5 měsíci
rodič
revize
e1298ce766

+ 39 - 0
supabase/functions/_shared/qdrant-client.ts

@@ -275,6 +275,45 @@ export async function getCollectionInfo(collectionName: string): Promise<any> {
   return response.result;
   return response.result;
 }
 }
 
 
+/**
+ * Generate a deterministic UUID from a string using a simple hash-based approach
+ * This creates valid UUIDs that Qdrant accepts, while being reproducible
+ */
+export function generatePointId(platform: string, storeId: string, itemId: string | number): string {
+  // Create a unique string identifier
+  const uniqueString = `${platform}-${storeId}-${itemId}`;
+
+  // Simple hash function (FNV-1a)
+  let hash = 2166136261;
+  for (let i = 0; i < uniqueString.length; i++) {
+    hash ^= uniqueString.charCodeAt(i);
+    hash = Math.imul(hash, 16777619);
+  }
+
+  // Convert to unsigned 32-bit and add more entropy from second pass
+  const hash1 = Math.abs(hash) >>> 0;
+
+  // Second hash for more bits
+  let hash2 = 2166136261;
+  for (let i = uniqueString.length - 1; i >= 0; i--) {
+    hash2 ^= uniqueString.charCodeAt(i);
+    hash2 = Math.imul(hash2, 16777619);
+  }
+  const hash2Val = Math.abs(hash2) >>> 0;
+
+  // Generate UUID v4 format: xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx
+  // Use hash values to create a deterministic but valid UUID
+  const hex = (hash1.toString(16).padStart(8, '0') + hash2Val.toString(16).padStart(8, '0')).padStart(32, '0');
+
+  return [
+    hex.substring(0, 8),
+    hex.substring(8, 12),
+    '4' + hex.substring(13, 16), // Version 4
+    ((parseInt(hex.substring(16, 17), 16) & 0x3) | 0x8).toString(16) + hex.substring(17, 20), // Variant
+    hex.substring(20, 32)
+  ].join('-');
+}
+
 /**
 /**
  * Generate standardized collection name for a store
  * Generate standardized collection name for a store
  */
  */

+ 4 - 3
supabase/functions/shopify-sync/index.ts

@@ -17,6 +17,7 @@ import {
   deletePointsByFilter,
   deletePointsByFilter,
   scrollPoints,
   scrollPoints,
   getCollectionName,
   getCollectionName,
+  generatePointId,
   initializeStoreCollections,
   initializeStoreCollections,
   generateEmbeddingBatch,
   generateEmbeddingBatch,
   createProductText,
   createProductText,
@@ -179,7 +180,7 @@ async function syncProductsToQdrant(
     const points: QdrantPoint[] = products.map((product, index) => {
     const points: QdrantPoint[] = products.map((product, index) => {
       const primaryVariant = product.variants?.[0]
       const primaryVariant = product.variants?.[0]
       return {
       return {
-        id: `shopify-${storeId}-${product.id}`,
+        id: generatePointId('shopify', storeId, product.id),
         vector: embeddings[index],
         vector: embeddings[index],
         payload: {
         payload: {
           store_id: storeId,
           store_id: storeId,
@@ -292,7 +293,7 @@ async function syncOrdersToQdrant(
 
 
     // Convert orders to Qdrant points with embeddings
     // Convert orders to Qdrant points with embeddings
     const points: QdrantPoint[] = orders.map((order, index) => ({
     const points: QdrantPoint[] = orders.map((order, index) => ({
-      id: `shopify-${storeId}-${order.id}`,
+      id: generatePointId('shopify', storeId, order.id),
       vector: embeddings[index],
       vector: embeddings[index],
       payload: {
       payload: {
         store_id: storeId,
         store_id: storeId,
@@ -406,7 +407,7 @@ async function syncCustomersToQdrant(
 
 
     // Convert customers to Qdrant points with embeddings
     // Convert customers to Qdrant points with embeddings
     const points: QdrantPoint[] = customers.map((customer, index) => ({
     const points: QdrantPoint[] = customers.map((customer, index) => ({
-      id: `shopify-${storeId}-${customer.id}`,
+      id: generatePointId('shopify', storeId, customer.id),
       vector: embeddings[index],
       vector: embeddings[index],
       payload: {
       payload: {
         store_id: storeId,
         store_id: storeId,

+ 4 - 3
supabase/functions/woocommerce-sync/index.ts

@@ -17,6 +17,7 @@ import {
   deletePointsByFilter,
   deletePointsByFilter,
   scrollPoints,
   scrollPoints,
   getCollectionName,
   getCollectionName,
+  generatePointId,
   initializeStoreCollections,
   initializeStoreCollections,
   generateEmbeddingBatch,
   generateEmbeddingBatch,
   createProductText,
   createProductText,
@@ -197,7 +198,7 @@ async function syncProductsToQdrant(
 
 
     // Convert products to Qdrant points with embeddings
     // Convert products to Qdrant points with embeddings
     const points: QdrantPoint[] = products.map((product, index) => ({
     const points: QdrantPoint[] = products.map((product, index) => ({
-      id: `woocommerce-${storeId}-${product.id}`,
+      id: generatePointId('woocommerce', storeId, product.id),
       vector: embeddings[index],
       vector: embeddings[index],
       payload: {
       payload: {
         store_id: storeId,
         store_id: storeId,
@@ -302,7 +303,7 @@ async function syncOrdersToQdrant(
 
 
     // Convert orders to Qdrant points with embeddings
     // Convert orders to Qdrant points with embeddings
     const points: QdrantPoint[] = orders.map((order, index) => ({
     const points: QdrantPoint[] = orders.map((order, index) => ({
-      id: `woocommerce-${storeId}-${order.id}`,
+      id: generatePointId('woocommerce', storeId, order.id),
       vector: embeddings[index],
       vector: embeddings[index],
       payload: {
       payload: {
         store_id: storeId,
         store_id: storeId,
@@ -411,7 +412,7 @@ async function syncCustomersToQdrant(
 
 
     // Convert customers to Qdrant points with embeddings
     // Convert customers to Qdrant points with embeddings
     const points: QdrantPoint[] = customers.map((customer, index) => ({
     const points: QdrantPoint[] = customers.map((customer, index) => ({
-      id: `woocommerce-${storeId}-${customer.id}`,
+      id: generatePointId('woocommerce', storeId, customer.id),
       vector: embeddings[index],
       vector: embeddings[index],
       payload: {
       payload: {
         store_id: storeId,
         store_id: storeId,