PluginProbe
ShopBuilder – WooCommerce Builder For Elementor / 3.2.1
ShopBuilder – WooCommerce Builder For Elementor v3.2.1
3.4.2 3.4.1 3.4.0 2.0.1 2.0.2 2.0.3 2.1.0 2.1.1 2.1.10 2.1.11 2.1.12 2.1.13 2.1.14 2.1.15 2.1.2 2.1.3 2.1.4 2.1.5 2.1.6 2.1.7 2.1.8 2.1.9 2.2.0 2.2.1 2.2.2 All 63 releases
← All changes | app/AI/Embedding/DataEmbedding.php +11 -12 3.4.13.2.1 View file →
@@ -41,13 +41,8 @@
41 41 *
42 42 * @return bool True on success, false on failure.
43 43 */
44 44 public function generate_and_store( $product_id, $title, $content ) {
45 - $ai_data = AIFns::activated_ai_data();
46 - if ( empty( $ai_data['api_key'] ) ) {
47 - return false;
48 - }
49 -
50 45 $text = $title . ' ' . wp_strip_all_tags( $content );
51 46 $ai_service = AIFns::initializeAIService();
52 47 $embedding = $ai_service->generateEmbedding( $text );
53 48 if ( empty( $embedding ) || ! is_array( $embedding ) ) {
@@ -76,8 +71,9 @@
76 71 return [];
77 72 }
78 73 // Log query embedding.
79 74 $rows = AIDB::get_all();
75 +
80 76 if ( empty( $rows ) ) {
81 77 return [];
82 78 }
83 79 $results = $this->find_similar( $query_embedding, $rows, $limit );
@@ -97,8 +93,9 @@
97 93 * @return array List of matched items with product ID, title, and similarity score.
98 94 */
99 95 public function find_similar( array $embedding, array $rows, int $limit = 5 ): array {
100 96 $minimum_match = AIFns::get_embedding_minimum_accuracy();
97 + $query_norm = sqrt( array_sum( array_map( static fn( $x ) => $x * $x, $embedding ) ) );
101 98 $matches = [];
102 99 foreach ( $rows as $row ) {
103 100 if ( empty( $row['embedding'] ) ) {
104 101 continue;
@@ -107,9 +104,9 @@
107 104 if ( ! is_array( $vector ) ) {
108 105 continue;
109 106 }
110 107 // Avoid redundant norm computation if similarity calc includes it.
111 - $score = $this->calculate_similarity_score( $embedding, $vector );
108 + $score = $this->calculate_similarity_score( $embedding, $vector, $query_norm );
112 109 if ( $score >= $minimum_match ) {
113 110 $matches[] = [
114 111 'post_id' => isset( $row['product_id'] ) ? (int) $row['product_id'] : 0,
115 112 'post_title' => isset( $row['title'] ) ? sanitize_text_field( $row['title'] ) : '',
@@ -133,20 +130,22 @@
133 130 * query norm and computes the dot product and target norm in one pass.
134 131 *
135 132 * @param array $query_vec The query embedding vector.
136 133 * @param array $target_vec The stored embedding vector.
134 + * @param float $query_norm Precomputed L2 norm of the query vector.
137 135 *
138 136 * @return float Cosine similarity score (0.0–1.0).
139 137 */
140 - protected function calculate_similarity_score( array $query_vec, array $target_vec ): float {
138 + protected function calculate_similarity_score( array $query_vec, array $target_vec, float $query_norm ): float {
141 139 $dot = 0.0;
142 - $normA = 0.0;
143 140 $normB = 0.0;
144 - $count = min( count( $query_vec ), count( $target_vec ) );
145 - for ( $i = 0; $i < $count; $i++ ) {
141 + $len = min( count( $query_vec ), count( $target_vec ) );
142 + for ( $i = 0; $i < $len; $i++ ) {
146 143 $dot += $query_vec[ $i ] * $target_vec[ $i ];
147 - $normA += $query_vec[ $i ] ** 2;
148 144 $normB += $target_vec[ $i ] ** 2;
149 145 }
150 - return $dot / ( sqrt( $normA ) * sqrt( $normB ) );
146 + if ( $query_norm <= 0.0 || $normB <= 0.0 ) {
147 + return 0.0;
148 + }
149 + return $dot / ( $query_norm * sqrt( $normB ) );
151 150 }
152 151 }