PluginProbe
ShopBuilder – WooCommerce Builder For Elementor / 3.2.5
ShopBuilder – WooCommerce Builder For Elementor v3.2.5
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
shopbuilder / app / AI / AIFns.php

AIFns.php in ShopBuilder – WooCommerce Builder For Elementor 3.2.5, at app/AI/AIFns.php

225 lines 6.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * AIFns Helpers class
4 *
5 * @package RadiusTheme\SB
6 */
7
8 namespace RadiusTheme\SB\AI;
9
10 // Do not allow directly accessing this file.
11 use Exception;
12 use RadiusTheme\SB\AI\AIServices\DeepSeekAdapter;
13 use RadiusTheme\SB\AI\AIServices\GeminiAdapter;
14 use RadiusTheme\SB\AI\AIServices\OpenAIAdapter;
15 use RadiusTheme\SB\Helpers\Fns;
16
17 if ( ! defined( 'ABSPATH' ) ) {
18 exit( 'This script cannot be accessed directly.' );
19 }
20
21 /**
22 * Fns class
23 */
24 class AIFns {
25 /**
26 * @var array
27 */
28 private static $cache = [];
29 /**
30 * AI Embeddings database table name.
31 *
32 * @var string
33 */
34 public static $ai_embeddings_table = 'rtsb_ai_embeddings';
35 /**
36 * Retrieve the activated AI client and its API key.
37 *
38 * @return array|false {
39 * @type string $client Active AI provider name.
40 * @type string $api_key Corresponding API key.
41 * }
42 */
43 public static function activated_ai_data() {
44 $ai_tools = self::get_options( 'ai_tools' );
45 if ( empty( $ai_tools ) ) {
46 return false;
47 }
48 $apiKey = '';
49 switch ( $ai_tools ) {
50 case 'OpenAI':
51 $apiKey = self::get_options( 'gpt_api_key' );
52 break;
53 case 'Gemini':
54 $apiKey = self::get_options( 'gemini_api_key' );
55 break;
56 case 'DeepSeek':
57 $apiKey = self::get_options( 'deepseek_api_key' );
58 break;
59 }
60 if ( empty( $apiKey ) ) {
61 return false;
62 }
63 return [
64 'client' => $ai_tools,
65 'api_key' => $apiKey,
66 ];
67 }
68 /**
69 * Get total published listings
70 */
71 public static function activated_semantic_search() {
72 $ai_data = self::activated_ai_data();
73 if ( ! $ai_data || ! in_array( $ai_data['client'], [ 'OpenAI', 'Gemini' ], true ) ) {
74 return false;
75 }
76 $semantic_search = self::get_options( 'enable_semantic_search' );
77 return 'on' === $semantic_search;
78 }
79
80 /**
81 * Get total published listings
82 */
83 public static function need_product_embedding() {
84 $listings = get_posts(
85 [
86 'post_type' => 'product',
87 'post_status' => 'publish',
88 'fields' => 'ids',
89 'meta_query' => [ // phpcs:ignore WordPress.DB.SlowDBQuery
90 [
91 'key' => '_has_embedding',
92 'compare' => 'NOT EXISTS',
93 ],
94 ],
95 ]
96 );
97 return count( $listings );
98 }
99 /**
100 * Returns the minimum cosine similarity threshold for semantic matching.
101 *
102 * Converts the user-selected percentage (1–100%) into a realistic cosine
103 * similarity range. Semantic search typically requires a threshold between
104 * 0.55–0.90 for meaningful accuracy.
105 *
106 * @return float Cosine similarity threshold (0.55–0.90).
107 */
108 public static function get_embedding_minimum_accuracy() {
109 $percentage = absint( self::get_options( 'minimum_matching_percentage' ) );
110 return ! empty( $percentage ) ? absint( $percentage ) / 100 : 0.4;
111 }
112
113 /**
114 * @param string $key Default Attribute.
115 * @param array|string $default Default.
116 * @return array|string
117 */
118 public static function get_options( $key = null, $default = '' ) {
119 $options = Fns::get_options( 'general', 'ai_implementation' );
120 if ( $key ) {
121 if ( isset( $options[ $key ] ) ) {
122 return $options[ $key ];
123 } else {
124 return $default;
125 }
126 }
127 return $options;
128 }
129
130 /**
131 * Initializes the AI service based on the configured AI tools.
132 *
133 * This method retrieves the AI tool settings from the configuration,
134 * dynamically instantiates the appropriate AI client class, and creates
135 * the corresponding AI service adapter. It handles validation and error
136 * reporting for missing or invalid configurations.
137 *
138 * @since 1.0.0
139 *
140 * @throws Exception If the client class cannot be instantiated or an error occurs during initialization.
141 *
142 * @return bool|DeepSeekAdapter|GeminiAdapter|OpenAIAdapter The initialized AI service adapter instance.
143 */
144 public static function initializeAIService() {
145 $ai_data = self::activated_ai_data();
146 if ( ! $ai_data ) {
147 return false;
148 }
149 $ai_tools = $ai_data['client'];
150 $clientClass = 'RadiusTheme\\SB\\AI\\AIServices\\AIClients\\' . $ai_tools . 'Client';
151 if ( ! class_exists( $clientClass ) ) {
152 return false;
153 }
154 try {
155 $client = new $clientClass();
156 return self::createAIService( $ai_tools, $client );
157 } catch ( Exception $e ) {
158 return false;
159 }
160 }
161
162 /**
163 * Creates an AI service adapter based on the specified AI type.
164 *
165 * This factory method instantiates and returns the appropriate AI service
166 * adapter (OpenAI, Gemini, or DeepSeek) based on the provided AI type string.
167 * Each adapter implements a common interface for interacting with different
168 * AI providers.
169 *
170 * @since 1.0.0
171 *
172 * @param string $aiType The type of AI service ('OpenAI', 'Gemini', or 'DeepSeek').
173 * @param object $client The AI client instance to be wrapped by the adapter.
174 *
175 * @throws Exception If the specified AI service type is not supported.
176 *
177 * @return OpenAIAdapter|GeminiAdapter|DeepSeekAdapter The created AI service adapter instance.
178 */
179 public static function createAIService( string $aiType, $client ) {
180 switch ( $aiType ) {
181 case 'OpenAI':
182 return new OpenAIAdapter( $client );
183 case 'Gemini':
184 return new GeminiAdapter( $client );
185 case 'DeepSeek':
186 return new DeepSeekAdapter( $client );
187 default:
188 throw new Exception( 'AI service not supported' );
189 }
190 }
191 /**
192 * Build an AI prompt based on content type and instruction language.
193 *
194 * @param string $content_type The type of content to generate (title, description, short_description).
195 * @param string $instruction The product information or user instruction.
196 *
197 * @return string The full AI prompt with language guidance.
198 */
199 public static function build_prompt( $content_type, $instruction ) {
200 // Sanitize instruction.
201 $instruction = trim( preg_replace( '/\s+/', ' ', $instruction ) );
202 // Truncate if needed (based on AI model token limits).
203 if ( strlen( $instruction ) > 2500 ) {
204 $instruction = substr( $instruction, 0, 2500 ) . '...';
205 }
206 $prompts = [
207 'title' => sprintf(
208 "Generate a compelling, SEO-friendly product title (50-70 chars) based on:\n\n%s\n\nCreate only the title.",
209 $instruction
210 ),
211 'description' => sprintf(
212 "Write a detailed product description (150-300 words) based on:\n\n%s\n\nInclude:\n• Key features\n• Benefits\n• Use cases\n• SEO-friendly content\n\nUse clear paragraphs.",
213 $instruction
214 ),
215 'short_description' => sprintf(
216 "Write a short description (2-3 sentences, max 160 chars) based on:\n\n%s\n\nHighlight key benefits only.",
217 $instruction
218 ),
219 ];
220 $base_prompt = $prompts[ $content_type ] ?? '';
221 $language_hint = "\n\nIMPORTANT: Write in the same language as the input above.";
222 return $base_prompt . $language_hint;
223 }
224 }
225