esc_html__('Message is empty.', 'aiy-sales-chat'))); } $api_key = get_option('wpaic_gemini_api_key'); if (empty($api_key)) { wp_send_json_error(array('message' => 'API Key is missing.')); } // 3. Construct Prompt with Backend Data (WooCommerce) $product_id = isset($_POST['product_id']) ? intval($_POST['product_id']) : 0; if ($product_id > 0 && function_exists('wc_get_product')) { $product = wc_get_product($product_id); if ($product) { // Get Attributes $attributes_str = ''; foreach ($product->get_attributes() as $attribute) { if ($attribute->is_taxonomy()) { // phpcs:ignore WordPress.DB.DirectDatabaseQuery $terms = wc_get_product_terms($product->get_id(), $attribute->get_name(), array('fields' => 'names')); $attributes_str .= $attribute->get_name() . ': ' . implode(', ', $terms) . "\n"; } else { $attributes_str .= $attribute->get_name() . ': ' . implode(', ', $attribute->get_options()) . "\n"; } } $context_title = $product->get_name(); $context_h1 = $product->get_name(); $context_price = $product->get_price_html(); // Formatted price $context_sizes = empty($context_sizes) ? $attributes_str : $context_sizes; // Prefer backend, fallback to scraped $context_status = $product->get_stock_status(); // instock / outofstock $context_desc = wp_strip_all_tags($product->get_short_description() . "\n" . $product->get_description()); } } $html_context = " Page Title: $context_title Product Name: $context_h1 Price: $context_price Stock Status: " . ($product ? $product->get_stock_status() : 'Unknown') . " Attributes/Sizes/Colors: $context_sizes Description: $context_desc"; // Default if empty // Default if empty $contact_info_default = "Or via email: contact@example.com"; $contact_info = get_option('wpaic_contact_info', $contact_info_default); $site_locale = get_locale(); $system_instruction = "You are an expert sales assistant. Context of the page where the customer is: $html_context Contact and company information: $contact_info Your task: - Answer the question: '$user_message'. - Be short, persuasive, and friendly. - Use the context data (price, benefits, sizes, colors) to sell the product. - Answer in the language corresponding to the locale: $site_locale. - IF YOU DO NOT know the answer or are unsure, politely offer the contact details above. - When providing contact details, use EXACTLY this format (bulleted list): * Contact: [Detail] * Or via email: email@address.com We look forward to your message!"; // 4. Call Google Gemini API $url = 'https://generativelanguage.googleapis.com/v1beta/models/gemini-flash-latest:generateContent?key=' . $api_key; $body = array( 'contents' => array( array( 'parts' => array( array('text' => $system_instruction) ) ) ) ); $response = wp_remote_post($url, array( 'headers' => array('Content-Type' => 'application/json'), 'body' => json_encode($body), 'timeout' => 15 )); if (is_wp_error($response)) { wp_send_json_error(array('message' => $response->get_error_message())); } $response_body = wp_remote_retrieve_body($response); $json = json_decode($response_body, true); if (isset($json['error'])) { wp_send_json_error(array('message' => 'AI Error: ' . $json['error']['message'])); } $reply = $json['candidates'][0]['content']['parts'][0]['text'] ?? "I didn't understand, can you repeat?"; $reply = str_replace("**", "", $reply); // Simple markdown cleanup // 5. Log Conversation global $wpdb; $table_name = $wpdb->prefix . 'wpaic_conversations'; // phpcs:ignore WordPress.DB.DirectDatabaseQuery $result = $wpdb->insert( $table_name, array( 'user_ip' => isset($_SERVER['REMOTE_ADDR']) ? sanitize_text_field(wp_unslash($_SERVER['REMOTE_ADDR'])) : '0.0.0.0', 'message' => $user_message, 'reply' => $reply, 'context' => json_encode($context), 'created_at' => current_time('mysql') ) ); if ($result === false) { // DB Error logging skipped for production } wp_send_json_success(array('reply' => $reply)); } } }