predict_with_openai( $data ); } else { return $this->predict_with_deepseek( $data ); } } /** * Generate prediction using OpenAI * * @param array $data Product data for prediction. * * @since 1.0.0 * @return array|\WP_Error */ private function predict_with_openai( $data ) { $settings = get_option( 'aistpr_api_settings', array() ); $api_key = isset( $settings['openai_api_key'] ) ? $settings['openai_api_key'] : ''; if ( empty( $api_key ) ) { return new \WP_Error( 'missing_api_key', __( 'OpenAI API key is not configured', 'ai-stock-predictor' ) ); } $prompt = $this->prepare_ai_prompt( $data ); $request_body = array( 'model' => 'gpt-3.5-turbo', 'messages' => array( array( 'role' => 'system', 'content' => 'You are a helpful assistant that predicts when products will go out of stock based on sales data and current inventory levels. Respond in JSON format only with "stockout_date" (YYYY-MM-DD) and "risk_level" (High/Medium/Low).', ), array( 'role' => 'user', 'content' => $prompt, ), ), 'temperature' => 0.3, 'max_tokens' => 150, ); $args = array( 'headers' => array( 'Content-Type' => 'application/json', 'Authorization' => 'Bearer ' . $api_key, ), 'body' => wp_json_encode( $request_body ), 'timeout' => 30, ); $response = wp_remote_post( 'https://api.openai.com/v1/chat/completions', $args ); return $this->process_ai_response( $response, 'openai' ); } /** * Generate prediction using DeepSeek * * @param array $data Product data for prediction. * * @since 1.0.0 * @return array|\WP_Error */ private function predict_with_deepseek( $data ) { $settings = get_option( 'aistpr_api_settings', array() ); $api_key = isset( $settings['deepseek_api_key'] ) ? $settings['deepseek_api_key'] : ''; if ( empty( $api_key ) ) { return new \WP_Error( 'missing_api_key', __( 'DeepSeek API key is not configured', 'ai-stock-predictor' ) ); } $prompt = $this->prepare_ai_prompt( $data ); $args = array( 'headers' => array( 'Content-Type' => 'application/json', 'Authorization' => 'Bearer ' . $api_key, ), 'body' => wp_json_encode( array( 'model' => 'deepseek-chat', 'messages' => array( array( 'role' => 'system', 'content' => 'You are a helpful assistant that predicts when products will go out of stock based on sales data and current inventory levels. Respond in JSON format only with "stockout_date" (YYYY-MM-DD) and "risk_level" (High/Medium/Low).', ), array( 'role' => 'user', 'content' => $prompt, ), ), 'temperature' => 0.3, 'max_tokens' => 150, ) ), 'timeout' => 30, ); $response = wp_remote_post( 'https://api.deepseek.com/v1/chat/completions', $args ); return $this->process_ai_response( $response, 'deepseek' ); } /** * Prepare AI prompt with product data * * @param array $data Product data. * * @since 1.0.0 * @return string */ private function prepare_ai_prompt( $data ) { $today = gmdate( 'Y-m-d' ); $prompt = "Today's date: {$today}\n\n"; $prompt .= "Product Data:\n"; $prompt .= "- Sales velocity (30 days): {$data['sales_velocity']['30']} units per day\n"; $prompt .= "- Sales velocity (60 days): {$data['sales_velocity']['60']} units per day\n"; $prompt .= "- Sales velocity (90 days): {$data['sales_velocity']['90']} units per day\n"; $prompt .= "- Current stock level: {$data['current_stock']} units\n"; if ( ! empty( $data['lead_time'] ) ) { $prompt .= "- Lead time for restocking: {$data['lead_time']} days\n"; } $prompt .= "\nBased on this data, predict: 1. When will this product go out of stock (provide date in YYYY-MM-DD format)? 2. What is the risk level of stockout (High/Medium/Low)? For risk assessment use these guidelines: - High: Will run out of stock within 14 days - Medium: Will run out of stock within 15-30 days - Low: Has stock for more than 30 days Return your answer in JSON format only: { \"stockout_date\": \"YYYY-MM-DD\", \"risk_level\": \"High/Medium/Low\" }"; return $prompt; } /** * Process AI API response * * @param array|\WP_Error $response API response. * @param string $provider API provider (openai or deepseek). * * @since 1.0.0 * @return array|\WP_Error */ private function process_ai_response( $response, $provider ) { if ( is_wp_error( $response ) ) { return $response; } $response_code = wp_remote_retrieve_response_code( $response ); if ( 200 !== $response_code ) { $body = wp_remote_retrieve_body( $response ); $error_message = ! empty( $body ) ? $body : "API error: HTTP {$response_code}"; return new \WP_Error( 'api_error', $error_message ); } $body = json_decode( wp_remote_retrieve_body( $response ), true ); $content = ''; if ( 'openai' === $provider ) { if ( isset( $body['choices'][0]['message']['content'] ) ) { $content = $body['choices'][0]['message']['content']; } } elseif ( isset( $body['choices'][0]['message']['content'] ) ) { $content = $body['choices'][0]['message']['content']; } if ( empty( $content ) ) { return new \WP_Error( 'invalid_response', __( 'Invalid response from AI service', 'ai-stock-predictor' ) ); } $json_matches = array(); preg_match( '/\{.*\}/s', $content, $json_matches ); if ( empty( $json_matches ) ) { return new \WP_Error( 'invalid_format', __( 'Could not extract JSON from AI response', 'ai-stock-predictor' ) ); } $prediction = json_decode( $json_matches[0], true ); if ( ! isset( $prediction['stockout_date'] ) || ! isset( $prediction['risk_level'] ) ) { return new \WP_Error( 'missing_data', __( 'Required prediction data is missing', 'ai-stock-predictor' ) ); } return array( 'stockout_date' => sanitize_text_field( $prediction['stockout_date'] ), 'risk_level' => sanitize_text_field( $prediction['risk_level'] ), ); } /** * Calculate a simple prediction fallback without AI * Used when AI fails or is not configured * * @param array $data Product data. * * @since 1.0.0 * @return array */ public function generate_fallback_prediction( $data ) { $daily_sales = $data['sales_velocity']['30']; if ( $daily_sales <= 0 ) { $daily_sales = $data['sales_velocity']['60']; } if ( $daily_sales <= 0 ) { $daily_sales = $data['sales_velocity']['90']; } if ( $daily_sales <= 0 ) { $daily_sales = 0.01; } $days_until_stockout = $data['current_stock'] / $daily_sales; $stockout_timestamp = strtotime( "+{$days_until_stockout} days" ); $stockout_date = gmdate( 'Y-m-d', $stockout_timestamp ); $risk_level = 'Low'; if ( $days_until_stockout <= 14 ) { $risk_level = 'High'; } elseif ( $days_until_stockout <= 30 ) { $risk_level = 'Medium'; } return array( 'stockout_date' => $stockout_date, 'risk_level' => $risk_level, ); } }