wmounger commited on
Commit
70a185d
·
verified ·
1 Parent(s): d0423c2

Upload 6 files

Browse files
README.md ADDED
@@ -0,0 +1,66 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Phi Shampoo Analyzer WordPress Plugin
2
+
3
+ A WordPress plugin that analyzes shampoo ingredients using Microsoft's Phi-3.5 models via the Hugging Face Inference API. The plugin evaluates ingredient safety based on user-provided information about allergies and skin types.
4
+
5
+ ## Features
6
+
7
+ - Analyze shampoo ingredients using Microsoft Phi-3.5-mini-instruct model
8
+ - Extract ingredients from images using Microsoft Phi-3.5-vision-instruct model
9
+ - Input allergies and skin type for personalized recommendations
10
+ - Simple, user-friendly interface
11
+ - Test mode for trying the plugin without API calls
12
+
13
+ ## Installation
14
+
15
+ 1. Upload the `phi-shampoo-plugin` folder to your WordPress plugins directory (`/wp-content/plugins/`)
16
+ 2. Activate the plugin through the 'Plugins' menu in WordPress
17
+ 3. The plugin will automatically create a "Phi Shampoo Analyzer" page with the analyzer form
18
+
19
+ ## Configuration
20
+
21
+ 1. Go to "Phi Shampoo" in your WordPress admin menu
22
+ 2. Enter your Hugging Face API token (get one at [huggingface.co/settings/tokens](https://huggingface.co/settings/tokens))
23
+ 3. Make sure your Hugging Face account has the Inference API enabled
24
+ 4. Save your settings
25
+
26
+ > **Important**: Your API token requires at least "Read" access to use the Inference API. Never share your API token publicly.
27
+
28
+ ## Usage
29
+
30
+ 1. Go to the "Phi Shampoo Analyzer" page on your WordPress site
31
+ 2. Enter shampoo ingredients manually OR upload an image of the ingredient list
32
+ 3. (Optional) Enter any allergies you have
33
+ 4. (Optional) Select your skin type
34
+ 5. Click "Analyze" to get safety recommendations
35
+
36
+ ## Technical Details
37
+
38
+ - Uses Microsoft Phi-3.5-mini-instruct for text analysis
39
+ - Uses Microsoft Phi-3.5-vision-instruct for image processing
40
+ - Connects to Hugging Face Inference API
41
+ - jQuery for form handling and UI interactions
42
+ - Responsive design
43
+
44
+ ## Requirements
45
+
46
+ - WordPress 5.0 or higher
47
+ - PHP 7.2 or higher
48
+ - Active internet connection for API calls
49
+ - Hugging Face account with Inference API access
50
+
51
+ ## Troubleshooting
52
+
53
+ If you're experiencing issues with the API connection:
54
+
55
+ 1. Verify your API token is correctly entered in the plugin settings
56
+ 2. Ensure your Hugging Face account has the Inference API enabled
57
+ 3. Check that your token has at least "Read" permissions
58
+ 4. Use the diagnostic tool available in the plugin settings page
59
+
60
+ ## Screenshots
61
+
62
+ (Screenshots would be added here after plugin implementation)
63
+
64
+ ## License
65
+
66
+ GPL v2 or later
assets/.DS_Store ADDED
Binary file (6.15 kB). View file
 
assets/css/style.css ADDED
@@ -0,0 +1,110 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* Phi Shampoo Analyzer Styles */
2
+
3
+ .phi-shampoo-analyzer {
4
+ max-width: 800px;
5
+ margin: 0 auto;
6
+ padding: 20px;
7
+ background-color: #f9f9f9;
8
+ border-radius: 8px;
9
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
10
+ }
11
+
12
+ .phi-shampoo-analyzer h2 {
13
+ color: #333;
14
+ margin-bottom: 20px;
15
+ text-align: center;
16
+ font-size: 24px;
17
+ }
18
+
19
+ .phi-form-group {
20
+ margin-bottom: 20px;
21
+ }
22
+
23
+ .phi-form-group label {
24
+ display: block;
25
+ margin-bottom: 5px;
26
+ font-weight: bold;
27
+ color: #555;
28
+ }
29
+
30
+ .phi-form-group textarea,
31
+ .phi-form-group input[type="text"],
32
+ .phi-form-group select {
33
+ width: 100%;
34
+ padding: 10px;
35
+ border: 1px solid #ddd;
36
+ border-radius: 4px;
37
+ background-color: #fff;
38
+ font-family: inherit;
39
+ font-size: 14px;
40
+ }
41
+
42
+ .phi-form-group textarea {
43
+ min-height: 120px;
44
+ }
45
+
46
+ .phi-form-submit {
47
+ text-align: center;
48
+ margin-top: 20px;
49
+ }
50
+
51
+ .phi-submit-button {
52
+ background-color: #4a90e2;
53
+ color: white;
54
+ border: none;
55
+ padding: 12px 25px;
56
+ border-radius: 4px;
57
+ cursor: pointer;
58
+ font-size: 16px;
59
+ font-weight: bold;
60
+ transition: background-color 0.3s;
61
+ }
62
+
63
+ .phi-submit-button:hover {
64
+ background-color: #357bd8;
65
+ }
66
+
67
+ .phi-result {
68
+ margin-top: 30px;
69
+ padding: 20px;
70
+ background-color: #fff;
71
+ border-radius: 8px;
72
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
73
+ }
74
+
75
+ .phi-result h3 {
76
+ color: #333;
77
+ margin-bottom: 15px;
78
+ font-size: 20px;
79
+ border-bottom: 1px solid #eee;
80
+ padding-bottom: 10px;
81
+ }
82
+
83
+ .phi-analysis-content {
84
+ white-space: pre-line;
85
+ line-height: 1.6;
86
+ }
87
+
88
+ .phi-error {
89
+ color: #e74c3c;
90
+ font-weight: bold;
91
+ }
92
+
93
+ .phi-loading {
94
+ text-align: center;
95
+ margin: 20px 0;
96
+ padding: 15px;
97
+ background-color: #f5f5f5;
98
+ border-radius: 4px;
99
+ }
100
+
101
+ /* Responsive adjustments */
102
+ @media (max-width: 600px) {
103
+ .phi-shampoo-analyzer {
104
+ padding: 15px;
105
+ }
106
+
107
+ .phi-submit-button {
108
+ width: 100%;
109
+ }
110
+ }
assets/js/phi-shampoo.js ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * Phi Shampoo Analyzer JavaScript
3
+ */
4
+ (function($) {
5
+ 'use strict';
6
+
7
+ $(document).ready(function() {
8
+ // The form submit handler is already in the shortcode,
9
+ // but we can add additional functionality here
10
+
11
+ // Toggle between text input and image upload
12
+ $('#phi-image').on('change', function() {
13
+ if ($(this).val()) {
14
+ // If an image is selected, disable the ingredients textarea
15
+ $('#phi-ingredients').prop('disabled', true).css('opacity', '0.5');
16
+ } else {
17
+ // If no image is selected, enable the ingredients textarea
18
+ $('#phi-ingredients').prop('disabled', false).css('opacity', '1');
19
+ }
20
+ });
21
+
22
+ $('#phi-ingredients').on('input', function() {
23
+ if ($(this).val()) {
24
+ // If ingredients are entered, disable the image upload
25
+ $('#phi-image').prop('disabled', true).css('opacity', '0.5');
26
+ } else {
27
+ // If no ingredients are entered, enable the image upload
28
+ $('#phi-image').prop('disabled', false).css('opacity', '1');
29
+ }
30
+ });
31
+ });
32
+
33
+ })(jQuery);
diagnostic.php ADDED
@@ -0,0 +1,195 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Phi Shampoo Analyzer Diagnostic Tool
4
+ *
5
+ * This file can be accessed directly to test API connectivity and plugin functionality.
6
+ * URL: your-site.com/wp-content/plugins/phi-shampoo-plugin/diagnostic.php
7
+ */
8
+
9
+ // Test if WordPress is loaded
10
+ if (file_exists('../../../../wp-load.php')) {
11
+ require_once('../../../../wp-load.php');
12
+ } else {
13
+ die('Could not find WordPress. Make sure this file is in the plugin directory.');
14
+ }
15
+
16
+ // Security check - only admins can access
17
+ if (!current_user_can('manage_options')) {
18
+ die('You do not have permission to access this page.');
19
+ }
20
+
21
+ // Load plugin constants
22
+ if (!defined('PHI_SHAMPOO_TEXT_MODEL')) {
23
+ if (file_exists('./phi-shampoo-analyzer.php')) {
24
+ include_once('./phi-shampoo-analyzer.php');
25
+ } else {
26
+ die('Could not find the main plugin file.');
27
+ }
28
+ }
29
+
30
+ // Set up the page
31
+ ?>
32
+ <!DOCTYPE html>
33
+ <html>
34
+ <head>
35
+ <meta charset="utf-8">
36
+ <meta name="viewport" content="width=device-width, initial-scale=1">
37
+ <title>Phi Shampoo Analyzer Diagnostic</title>
38
+ <style>
39
+ body {
40
+ font-family: Arial, sans-serif;
41
+ line-height: 1.6;
42
+ margin: 20px;
43
+ max-width: 900px;
44
+ margin: 0 auto;
45
+ padding: 20px;
46
+ }
47
+ h1, h2 {
48
+ color: #333;
49
+ }
50
+ pre {
51
+ background-color: #f5f5f5;
52
+ padding: 10px;
53
+ border-radius: 4px;
54
+ overflow-x: auto;
55
+ }
56
+ .test-section {
57
+ margin-bottom: 30px;
58
+ padding: 15px;
59
+ border: 1px solid #ddd;
60
+ border-radius: 4px;
61
+ }
62
+ .success {
63
+ color: green;
64
+ font-weight: bold;
65
+ }
66
+ .error {
67
+ color: red;
68
+ font-weight: bold;
69
+ }
70
+ </style>
71
+ </head>
72
+ <body>
73
+ <h1>Phi Shampoo Analyzer Diagnostic Tool</h1>
74
+
75
+ <div class="test-section">
76
+ <h2>Plugin Information</h2>
77
+ <p><strong>Plugin Version:</strong> <?php echo defined('PHI_SHAMPOO_VERSION') ? PHI_SHAMPOO_VERSION : 'Not defined'; ?></p>
78
+ <p><strong>Text Model:</strong> <?php echo defined('PHI_SHAMPOO_TEXT_MODEL') ? PHI_SHAMPOO_TEXT_MODEL : 'Not defined'; ?></p>
79
+ <p><strong>Vision Model:</strong> <?php echo defined('PHI_SHAMPOO_VISION_MODEL') ? PHI_SHAMPOO_VISION_MODEL : 'Not defined'; ?></p>
80
+ <p><strong>Text API URL:</strong> <?php echo defined('PHI_SHAMPOO_HF_TEXT_API_URL') ? PHI_SHAMPOO_HF_TEXT_API_URL : 'Not defined'; ?></p>
81
+ <p><strong>Vision API URL:</strong> <?php echo defined('PHI_SHAMPOO_HF_VISION_API_URL') ? PHI_SHAMPOO_HF_VISION_API_URL : 'Not defined'; ?></p>
82
+ <p><strong>API Token:</strong> <?php
83
+ $api_token = function_exists('phi_shampoo_get_api_token') ? phi_shampoo_get_api_token() : '';
84
+ echo !empty($api_token) ? 'Configured' : '<span class="error">Not configured</span>';
85
+ ?></p>
86
+ </div>
87
+
88
+ <div class="test-section">
89
+ <h2>WordPress Environment</h2>
90
+ <p><strong>WordPress Version:</strong> <?php echo get_bloginfo('version'); ?></p>
91
+ <p><strong>PHP Version:</strong> <?php echo phpversion(); ?></p>
92
+ <p><strong>Analyzer Page:</strong>
93
+ <?php
94
+ $page_id = get_option('phi_shampoo_analyzer_page_id');
95
+ if ($page_id) {
96
+ echo 'Created (ID: ' . $page_id . ') - <a href="' . get_permalink($page_id) . '" target="_blank">View Page</a>';
97
+ } else {
98
+ echo '<span class="error">Not created</span>';
99
+ }
100
+ ?>
101
+ </p>
102
+ </div>
103
+
104
+ <div class="test-section">
105
+ <h2>API Connection Test</h2>
106
+
107
+ <h3>Text Model Test</h3>
108
+ <?php
109
+ // Test the text model API
110
+ if (!defined('PHI_SHAMPOO_HF_TEXT_API_URL') || !function_exists('phi_shampoo_get_api_token')) {
111
+ echo '<p class="error">API functions not defined.</p>';
112
+ } else {
113
+ $api_url = PHI_SHAMPOO_HF_TEXT_API_URL;
114
+ $api_token = phi_shampoo_get_api_token();
115
+
116
+ if (empty($api_token)) {
117
+ echo '<p class="error">API token not configured. Please go to the <a href="' . admin_url('admin.php?page=phi-shampoo-settings') . '">Settings Page</a> to configure your token.</p>';
118
+ } else {
119
+ $response = wp_remote_post($api_url, array(
120
+ 'headers' => array(
121
+ 'Authorization' => 'Bearer ' . $api_token,
122
+ 'Content-Type' => 'application/json'
123
+ ),
124
+ 'body' => json_encode(array(
125
+ 'inputs' => 'Test prompt: Analyze these ingredients: Water, Glycerin',
126
+ 'parameters' => array(
127
+ 'max_new_tokens' => 50,
128
+ 'temperature' => 0.7
129
+ )
130
+ )),
131
+ 'timeout' => 30
132
+ ));
133
+
134
+ if (is_wp_error($response)) {
135
+ echo '<p class="error">Error: ' . $response->get_error_message() . '</p>';
136
+ } else {
137
+ $status = wp_remote_retrieve_response_code($response);
138
+ $body = wp_remote_retrieve_body($response);
139
+
140
+ echo '<p><strong>Status Code:</strong> ' . $status . '</p>';
141
+
142
+ if ($status === 200) {
143
+ echo '<p class="success">Text API connection successful!</p>';
144
+ echo '<p><strong>Response Preview:</strong></p>';
145
+ echo '<pre>' . htmlspecialchars(substr($body, 0, 300)) . '...</pre>';
146
+ } else {
147
+ echo '<p class="error">API returned non-200 status code.</p>';
148
+ echo '<p><strong>Response:</strong></p>';
149
+ echo '<pre>' . htmlspecialchars($body) . '</pre>';
150
+ }
151
+ }
152
+ }
153
+ }
154
+ ?>
155
+
156
+ <h3>Vision Model Test</h3>
157
+ <p>Note: Vision model test requires an image upload. To test, please use the main plugin interface.</p>
158
+ </div>
159
+
160
+ <div class="test-section">
161
+ <h2>File Structure Check</h2>
162
+ <?php
163
+ $required_files = array(
164
+ 'phi-shampoo-analyzer.php' => 'Main plugin file',
165
+ 'assets/css/style.css' => 'CSS styles',
166
+ 'assets/js/phi-shampoo.js' => 'JavaScript functionality'
167
+ );
168
+
169
+ $all_files_exist = true;
170
+
171
+ foreach ($required_files as $file => $description) {
172
+ $file_path = dirname(__FILE__) . '/' . $file;
173
+ $exists = file_exists($file_path);
174
+
175
+ echo '<p>';
176
+ echo '<strong>' . $file . ':</strong> ';
177
+ if ($exists) {
178
+ echo '<span class="success">Found</span>';
179
+ } else {
180
+ echo '<span class="error">Missing</span>';
181
+ $all_files_exist = false;
182
+ }
183
+ echo ' - ' . $description;
184
+ echo '</p>';
185
+ }
186
+
187
+ if ($all_files_exist) {
188
+ echo '<p class="success">All required files are present.</p>';
189
+ } else {
190
+ echo '<p class="error">Some required files are missing.</p>';
191
+ }
192
+ ?>
193
+ </div>
194
+ </body>
195
+ </html>
phi-shampoo-analyzer.php ADDED
@@ -0,0 +1,658 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ Plugin Name: Phi Shampoo Analyzer
4
+ Plugin URI: https://example.com/
5
+ Description: Uses Microsoft Phi-3.5 models via Hugging Face Inference API for shampoo ingredient analysis.
6
+ Version: 1.0
7
+ Author: Monica Hsueh
8
+ License: GPL2
9
+ */
10
+
11
+ /*
12
+ Model Information:
13
+ --------------------------
14
+ Text Model: microsoft/Phi-3.5-mini-instruct
15
+ Vision Model: microsoft/Phi-3.5-vision-instruct
16
+ */
17
+
18
+ // Prevent direct access
19
+ if (!defined('ABSPATH')) {
20
+ exit;
21
+ }
22
+
23
+ // Define plugin constants
24
+ define('PHI_SHAMPOO_VERSION', '1.0');
25
+ define('PHI_SHAMPOO_PLUGIN_DIR', plugin_dir_path(__FILE__));
26
+ define('PHI_SHAMPOO_PLUGIN_URL', plugin_dir_url(__FILE__));
27
+ define('PHI_SHAMPOO_PLUGIN_BASENAME', plugin_basename(__FILE__));
28
+
29
+ // Define model constants
30
+ define('PHI_SHAMPOO_TEXT_MODEL', 'microsoft/Phi-3.5-mini-instruct');
31
+ define('PHI_SHAMPOO_VISION_MODEL', 'microsoft/Phi-3.5-vision-instruct');
32
+ define('PHI_SHAMPOO_HF_TEXT_API_URL', 'https://api-inference.huggingface.co/models/' . PHI_SHAMPOO_TEXT_MODEL);
33
+ define('PHI_SHAMPOO_HF_VISION_API_URL', 'https://api-inference.huggingface.co/models/' . PHI_SHAMPOO_VISION_MODEL);
34
+
35
+ /**
36
+ * Plugin activation hook
37
+ */
38
+ function phi_shampoo_activate() {
39
+ // Create default pages with shortcodes
40
+ phi_shampoo_create_pages();
41
+
42
+ // Set default settings
43
+ if (!get_option('phi_shampoo_test_mode')) {
44
+ update_option('phi_shampoo_test_mode', true); // Setting to true for initial testing
45
+ }
46
+
47
+ // Flush rewrite rules
48
+ flush_rewrite_rules();
49
+ }
50
+ register_activation_hook(__FILE__, 'phi_shampoo_activate');
51
+
52
+ /**
53
+ * Plugin deactivation hook
54
+ */
55
+ function phi_shampoo_deactivate() {
56
+ // Flush rewrite rules on deactivation
57
+ flush_rewrite_rules();
58
+ }
59
+ register_deactivation_hook(__FILE__, 'phi_shampoo_deactivate');
60
+
61
+ /**
62
+ * Create required pages with shortcodes
63
+ */
64
+ function phi_shampoo_create_pages() {
65
+ // Create analyzer page if it doesn't exist
66
+ $analyzer_page_id = wp_insert_post(array(
67
+ 'post_title' => 'Phi Shampoo Analyzer',
68
+ 'post_content' => '[phi_shampoo_analyzer]',
69
+ 'post_status' => 'publish',
70
+ 'post_type' => 'page',
71
+ 'comment_status' => 'closed'
72
+ ));
73
+
74
+ // Save page ID to settings
75
+ update_option('phi_shampoo_analyzer_page_id', $analyzer_page_id);
76
+ }
77
+
78
+ /**
79
+ * Enqueue scripts and styles
80
+ */
81
+ function phi_shampoo_enqueue_scripts() {
82
+ // Register and enqueue CSS
83
+ wp_register_style('phi-shampoo-style', PHI_SHAMPOO_PLUGIN_URL . 'assets/css/style.css', array(), PHI_SHAMPOO_VERSION);
84
+ wp_enqueue_style('phi-shampoo-style');
85
+
86
+ // Register and enqueue JavaScript
87
+ wp_register_script('phi-shampoo-script', PHI_SHAMPOO_PLUGIN_URL . 'assets/js/phi-shampoo.js', array('jquery'), PHI_SHAMPOO_VERSION, true);
88
+ wp_enqueue_script('phi-shampoo-script');
89
+
90
+ // Localize the script with the ajax URL
91
+ wp_localize_script('phi-shampoo-script', 'phiShampoo', array(
92
+ 'ajax_url' => admin_url('admin-ajax.php'),
93
+ 'nonce' => wp_create_nonce('phi_shampoo_nonce'),
94
+ 'analyzePage' => get_permalink(get_option('phi_shampoo_analyzer_page_id'))
95
+ ));
96
+ }
97
+ add_action('wp_enqueue_scripts', 'phi_shampoo_enqueue_scripts');
98
+
99
+ /**
100
+ * Write to debug log
101
+ */
102
+ function phi_shampoo_log($message) {
103
+ if (defined('WP_DEBUG') && WP_DEBUG) {
104
+ $log_file = WP_CONTENT_DIR . '/debug.log';
105
+ $timestamp = current_time('mysql');
106
+ if (is_array($message) || is_object($message)) {
107
+ error_log('[' . $timestamp . '] Phi Shampoo: ' . print_r($message, true) . "\n", 3, $log_file);
108
+ } else {
109
+ error_log('[' . $timestamp . '] Phi Shampoo: ' . $message . "\n", 3, $log_file);
110
+ }
111
+ }
112
+ }
113
+
114
+ /**
115
+ * Add settings link to plugins page
116
+ */
117
+ function phi_shampoo_add_settings_link($links) {
118
+ $settings_link = '<a href="' . admin_url('admin.php?page=phi-shampoo-settings') . '">' . __('Settings', 'phi-shampoo-analyzer') . '</a>';
119
+ array_unshift($links, $settings_link);
120
+ return $links;
121
+ }
122
+ add_filter('plugin_action_links_' . PHI_SHAMPOO_PLUGIN_BASENAME, 'phi_shampoo_add_settings_link');
123
+
124
+ /**
125
+ * Register shortcodes
126
+ */
127
+ function phi_shampoo_register_shortcodes() {
128
+ add_shortcode('phi_shampoo_analyzer', 'phi_shampoo_analyzer_shortcode');
129
+ }
130
+ add_action('init', 'phi_shampoo_register_shortcodes');
131
+
132
+ /**
133
+ * Shampoo analyzer shortcode
134
+ */
135
+ function phi_shampoo_analyzer_shortcode() {
136
+ ob_start();
137
+ ?>
138
+ <div class="phi-shampoo-analyzer">
139
+ <h2>Phi Shampoo Analyzer</h2>
140
+ <p>Enter shampoo ingredients below or upload an image of the ingredient list.</p>
141
+
142
+ <form id="phi-analyzer-form" method="post" enctype="multipart/form-data">
143
+ <?php wp_nonce_field('phi_shampoo_analyze', 'phi_shampoo_nonce'); ?>
144
+
145
+ <div class="phi-form-group">
146
+ <label for="phi-ingredients">Ingredients:</label>
147
+ <textarea id="phi-ingredients" name="ingredients" rows="5" placeholder="Enter ingredients separated by commas..."></textarea>
148
+ </div>
149
+
150
+ <div class="phi-form-group">
151
+ <label for="phi-image">Or upload image:</label>
152
+ <input type="file" id="phi-image" name="ingredient_image" accept="image/*">
153
+ </div>
154
+
155
+ <div class="phi-form-group">
156
+ <label for="phi-allergies">Known Allergies (optional):</label>
157
+ <input type="text" id="phi-allergies" name="allergies" placeholder="e.g., Parabens, Sulfates, Fragrances">
158
+ </div>
159
+
160
+ <div class="phi-form-group">
161
+ <label for="phi-skin-type">Skin Type (optional):</label>
162
+ <select id="phi-skin-type" name="skin_type">
163
+ <option value="">Select Skin Type</option>
164
+ <option value="Normal">Normal</option>
165
+ <option value="Dry">Dry</option>
166
+ <option value="Oily">Oily</option>
167
+ <option value="Combination">Combination</option>
168
+ <option value="Sensitive">Sensitive</option>
169
+ </select>
170
+ </div>
171
+
172
+ <div class="phi-form-submit">
173
+ <button type="submit" class="phi-submit-button">Analyze</button>
174
+ </div>
175
+ </form>
176
+
177
+ <div id="phi-result" class="phi-result" style="display: none;">
178
+ <h3>Analysis Result</h3>
179
+ <div id="phi-result-content"></div>
180
+ </div>
181
+
182
+ <div id="phi-loading" class="phi-loading" style="display: none;">
183
+ <p>Analyzing ingredients... Please wait.</p>
184
+ </div>
185
+ </div>
186
+
187
+ <script>
188
+ jQuery(document).ready(function($) {
189
+ $('#phi-analyzer-form').on('submit', function(e) {
190
+ e.preventDefault();
191
+
192
+ $('#phi-loading').show();
193
+ $('#phi-result').hide();
194
+
195
+ var formData = new FormData(this);
196
+ formData.append('action', 'phi_analyze_shampoo');
197
+
198
+ $.ajax({
199
+ url: phiShampoo.ajax_url,
200
+ type: 'POST',
201
+ data: formData,
202
+ contentType: false,
203
+ processData: false,
204
+ success: function(response) {
205
+ $('#phi-loading').hide();
206
+
207
+ if (response.success) {
208
+ $('#phi-result-content').html(response.data.result);
209
+ $('#phi-result').show();
210
+ } else {
211
+ $('#phi-result-content').html('<p class="phi-error">Error: ' + response.data.message + '</p>');
212
+ $('#phi-result').show();
213
+ }
214
+ },
215
+ error: function() {
216
+ $('#phi-loading').hide();
217
+ $('#phi-result-content').html('<p class="phi-error">Error: Could not connect to the server.</p>');
218
+ $('#phi-result').show();
219
+ }
220
+ });
221
+ });
222
+ });
223
+ </script>
224
+ <?php
225
+ return ob_get_clean();
226
+ }
227
+
228
+ /**
229
+ * AJAX handler for shampoo analysis
230
+ */
231
+ function phi_shampoo_ajax_analyze() {
232
+ // Check nonce
233
+ if (!isset($_POST['phi_shampoo_nonce']) || !wp_verify_nonce($_POST['phi_shampoo_nonce'], 'phi_shampoo_analyze')) {
234
+ wp_send_json_error(array('message' => 'Security check failed.'));
235
+ }
236
+
237
+ $ingredients = '';
238
+ $image_uploaded = false;
239
+
240
+ // Handle image upload
241
+ if (!empty($_FILES['ingredient_image']['tmp_name'])) {
242
+ $image_uploaded = true;
243
+ $tmp_name = $_FILES['ingredient_image']['tmp_name'];
244
+
245
+ // Process image to extract ingredients
246
+ $result = phi_shampoo_process_image($tmp_name);
247
+
248
+ if ($result['success']) {
249
+ $ingredients = $result['ingredients'];
250
+ } else {
251
+ wp_send_json_error(array('message' => 'Could not extract ingredients from image: ' . $result['error']));
252
+ }
253
+ } else if (!empty($_POST['ingredients'])) {
254
+ $ingredients = sanitize_textarea_field($_POST['ingredients']);
255
+ } else {
256
+ wp_send_json_error(array('message' => 'Please provide ingredients or upload an image.'));
257
+ }
258
+
259
+ // Gather additional data
260
+ $allergies = isset($_POST['allergies']) ? sanitize_text_field($_POST['allergies']) : '';
261
+ $skin_type = isset($_POST['skin_type']) ? sanitize_text_field($_POST['skin_type']) : '';
262
+
263
+ // Analyze ingredients
264
+ $analysis_data = array(
265
+ 'ingredients' => $ingredients,
266
+ 'allergies' => $allergies,
267
+ 'skin_type' => $skin_type
268
+ );
269
+
270
+ $analysis = phi_shampoo_analyze_ingredients($analysis_data);
271
+
272
+ if ($analysis['success']) {
273
+ $html_result = '<div class="phi-analysis">';
274
+
275
+ if ($image_uploaded) {
276
+ $html_result .= '<p><strong>Extracted Ingredients:</strong> ' . esc_html($ingredients) . '</p>';
277
+ }
278
+
279
+ $html_result .= '<div class="phi-analysis-content">' . nl2br(esc_html($analysis['result'])) . '</div>';
280
+ $html_result .= '</div>';
281
+
282
+ wp_send_json_success(array('result' => $html_result));
283
+ } else {
284
+ wp_send_json_error(array('message' => 'Analysis failed: ' . $analysis['error']));
285
+ }
286
+ }
287
+ add_action('wp_ajax_phi_analyze_shampoo', 'phi_shampoo_ajax_analyze');
288
+ add_action('wp_ajax_nopriv_phi_analyze_shampoo', 'phi_shampoo_ajax_analyze');
289
+
290
+ /**
291
+ * Process image to extract ingredients using Phi-3.5 Vision
292
+ */
293
+ function phi_shampoo_process_image($image_path) {
294
+ // Check if in test mode
295
+ $test_mode = get_option('phi_shampoo_test_mode', false);
296
+ if ($test_mode) {
297
+ phi_shampoo_log("Test mode active - returning test ingredients from image");
298
+ return array(
299
+ 'success' => true,
300
+ 'ingredients' => "Water, Sodium Laureth Sulfate, Cocamidopropyl Betaine, Sodium Chloride, Glycol Distearate, Dimethiconol, Fragrance, Carbomer, Guar Hydroxypropyltrimonium Chloride, Tetrasodium EDTA, Citric Acid, Sodium Benzoate, Methylchloroisothiazolinone, Methylisothiazolinone"
301
+ );
302
+ }
303
+
304
+ // Get API token
305
+ $api_token = phi_shampoo_get_api_token();
306
+
307
+ if (empty($api_token)) {
308
+ phi_shampoo_log("Error: Missing API token for Hugging Face");
309
+ return array(
310
+ 'success' => false,
311
+ 'error' => 'Missing API token. Please configure it in plugin settings.',
312
+ 'ingredients' => ''
313
+ );
314
+ }
315
+
316
+ // Check if file exists
317
+ if (!file_exists($image_path)) {
318
+ phi_shampoo_log("Error: Image file not found at path: " . $image_path);
319
+ return array(
320
+ 'success' => false,
321
+ 'error' => 'Image file not found.',
322
+ 'ingredients' => ''
323
+ );
324
+ }
325
+
326
+ // Read and encode image
327
+ $image_data = file_get_contents($image_path);
328
+ $base64_image = base64_encode($image_data);
329
+
330
+ // Make API request
331
+ $api_url = defined('PHI_SHAMPOO_HF_VISION_API_URL') ? PHI_SHAMPOO_HF_VISION_API_URL : '';
332
+
333
+ $response = wp_remote_post($api_url, array(
334
+ 'headers' => array(
335
+ 'Authorization' => 'Bearer ' . $api_token,
336
+ 'Content-Type' => 'application/json'
337
+ ),
338
+ 'body' => json_encode(array(
339
+ 'inputs' => array(
340
+ 'image' => $base64_image,
341
+ 'text' => "Extract all the ingredients from this shampoo product label. Format them as a comma-separated list."
342
+ )
343
+ )),
344
+ 'timeout' => 60
345
+ ));
346
+
347
+ // Handle response
348
+ if (is_wp_error($response)) {
349
+ phi_shampoo_log("API Error: " . $response->get_error_message());
350
+ return array(
351
+ 'success' => false,
352
+ 'error' => $response->get_error_message(),
353
+ 'ingredients' => ''
354
+ );
355
+ }
356
+
357
+ $body = wp_remote_retrieve_body($response);
358
+ $status_code = wp_remote_retrieve_response_code($response);
359
+
360
+ phi_shampoo_log("API Status: " . $status_code . ", Response: " . substr($body, 0, 200) . "...");
361
+
362
+ if ($status_code !== 200) {
363
+ $error_message = "API Error: Received status code " . $status_code;
364
+
365
+ $decoded = json_decode($body, true);
366
+ if ($decoded && isset($decoded['error'])) {
367
+ $error_message .= " - " . $decoded['error'];
368
+ }
369
+
370
+ return array(
371
+ 'success' => false,
372
+ 'error' => $error_message,
373
+ 'ingredients' => ''
374
+ );
375
+ }
376
+
377
+ $decoded = json_decode($body, true);
378
+
379
+ if (isset($decoded['generated_text'])) {
380
+ return array(
381
+ 'success' => true,
382
+ 'ingredients' => $decoded['generated_text']
383
+ );
384
+ } else {
385
+ return array(
386
+ 'success' => false,
387
+ 'error' => 'Unexpected response format',
388
+ 'ingredients' => ''
389
+ );
390
+ }
391
+ }
392
+
393
+ /**
394
+ * Analyze ingredients using Phi-3.5 Text model
395
+ */
396
+ function phi_shampoo_analyze_ingredients($data) {
397
+ // Check if in test mode
398
+ $test_mode = get_option('phi_shampoo_test_mode', false);
399
+ if ($test_mode) {
400
+ return phi_shampoo_generate_test_analysis($data);
401
+ }
402
+
403
+ // Get API token
404
+ $api_token = phi_shampoo_get_api_token();
405
+
406
+ if (empty($api_token)) {
407
+ return array(
408
+ 'success' => false,
409
+ 'error' => 'Missing API token. Please configure it in plugin settings.',
410
+ 'result' => 'Error: API token not configured.'
411
+ );
412
+ }
413
+
414
+ // Check if ingredients are provided
415
+ if (empty($data['ingredients'])) {
416
+ return array(
417
+ 'success' => false,
418
+ 'error' => 'No ingredients provided for analysis.',
419
+ 'result' => 'Error: No ingredients to analyze.'
420
+ );
421
+ }
422
+
423
+ // Build prompt for the model
424
+ $prompt = "You are a shampoo ingredient analyzer. Please analyze the following shampoo ingredients for safety and potential allergic reactions:\n\n";
425
+ $prompt .= "Ingredients:\n" . $data['ingredients'] . "\n\n";
426
+
427
+ // Add user information if available
428
+ if (!empty($data['allergies'])) {
429
+ $prompt .= "User has allergies to: " . $data['allergies'] . "\n\n";
430
+ }
431
+
432
+ if (!empty($data['skin_type'])) {
433
+ $prompt .= "User has " . $data['skin_type'] . " skin type.\n\n";
434
+ }
435
+
436
+ // Add analysis instructions
437
+ $prompt .= "Please provide a detailed analysis including:\n";
438
+ $prompt .= "1. Overall safety assessment (safe or not safe for this user)\n";
439
+ $prompt .= "2. Potentially harmful ingredients with explanations\n";
440
+ $prompt .= "3. Specific concerns based on the user's health profile\n";
441
+ $prompt .= "4. Alternative recommendations if needed\n";
442
+ $prompt .= "\nBegin your response with a clear 'SAFE TO USE' or 'NOT RECOMMENDED' statement.\n";
443
+
444
+ // Log the prompt
445
+ phi_shampoo_log("Analysis prompt: " . $prompt);
446
+
447
+ // Make API request
448
+ $api_url = defined('PHI_SHAMPOO_HF_TEXT_API_URL') ? PHI_SHAMPOO_HF_TEXT_API_URL : '';
449
+
450
+ $response = wp_remote_post($api_url, array(
451
+ 'headers' => array(
452
+ 'Authorization' => 'Bearer ' . $api_token,
453
+ 'Content-Type' => 'application/json'
454
+ ),
455
+ 'body' => json_encode(array(
456
+ 'inputs' => $prompt,
457
+ 'parameters' => array(
458
+ 'max_new_tokens' => 512,
459
+ 'temperature' => 0.7,
460
+ 'do_sample' => true
461
+ )
462
+ )),
463
+ 'timeout' => 60
464
+ ));
465
+
466
+ // Handle response
467
+ if (is_wp_error($response)) {
468
+ phi_shampoo_log("API Error: " . $response->get_error_message());
469
+ return array(
470
+ 'success' => false,
471
+ 'error' => $response->get_error_message(),
472
+ 'result' => 'Error: API request failed. ' . $response->get_error_message()
473
+ );
474
+ }
475
+
476
+ $body = wp_remote_retrieve_body($response);
477
+ $status_code = wp_remote_retrieve_response_code($response);
478
+
479
+ phi_shampoo_log("API Status: " . $status_code . ", Response: " . substr($body, 0, 200) . "...");
480
+
481
+ if ($status_code !== 200) {
482
+ $error_message = "API Error: Received status code " . $status_code;
483
+
484
+ $decoded = json_decode($body, true);
485
+ if ($decoded && isset($decoded['error'])) {
486
+ $error_message .= " - " . $decoded['error'];
487
+ }
488
+
489
+ return array(
490
+ 'success' => false,
491
+ 'error' => $error_message,
492
+ 'result' => 'Error: ' . $error_message
493
+ );
494
+ }
495
+
496
+ $decoded = json_decode($body, true);
497
+
498
+ if (isset($decoded['generated_text'])) {
499
+ return array(
500
+ 'success' => true,
501
+ 'result' => $decoded['generated_text']
502
+ );
503
+ } else {
504
+ return array(
505
+ 'success' => false,
506
+ 'error' => 'Unexpected response format',
507
+ 'result' => 'Error: Could not parse the AI response.'
508
+ );
509
+ }
510
+ }
511
+
512
+ /**
513
+ * Generate test analysis results (used when test mode is enabled)
514
+ */
515
+ function phi_shampoo_generate_test_analysis($data) {
516
+ $ingredients = $data['ingredients'];
517
+ $has_allergies = !empty($data['allergies']);
518
+
519
+ if (strpos(strtolower($ingredients), 'sulfate') !== false ||
520
+ strpos(strtolower($ingredients), 'methylisothiazolinone') !== false) {
521
+
522
+ $result = "NOT RECOMMENDED\n\n";
523
+ $result .= "Based on the ingredients analysis, this shampoo contains some potentially problematic ingredients for your specific health profile.\n\n";
524
+
525
+ if (strpos(strtolower($ingredients), 'sodium laureth sulfate') !== false ||
526
+ strpos(strtolower($ingredients), 'sodium lauryl sulfate') !== false) {
527
+ $result .= "• Sodium Laureth/Lauryl Sulfate: A strong detergent that can be irritating, especially for sensitive skin or those with certain allergies.\n";
528
+ }
529
+
530
+ if (strpos(strtolower($ingredients), 'methylisothiazolinone') !== false) {
531
+ $result .= "• Methylisothiazolinone: A preservative that is a known allergen and has been associated with skin sensitization.\n";
532
+ }
533
+
534
+ if ($has_allergies) {
535
+ $result .= "\nBased on your reported allergies, this product contains ingredients that may trigger a reaction. Consider alternative formulations labeled 'sulfate-free' and 'preservative-free'.\n";
536
+ }
537
+
538
+ $result .= "\nRecommendation: Look for shampoos with gentler cleansing agents like Cocamidopropyl Hydroxysultaine, Sodium Cocoyl Isethionate or Coco Glucoside.";
539
+ } else {
540
+ $result = "SAFE TO USE\n\n";
541
+ $result .= "Based on the ingredients analysis, this shampoo appears to be safe for general use. The formula contains:\n\n";
542
+ $result .= "• Mild cleansing agents that effectively clean without excessive drying\n";
543
+ $result .= "• Conditioning agents to help maintain hair moisture\n";
544
+
545
+ if (strpos(strtolower($ingredients), 'fragrance') !== false ||
546
+ strpos(strtolower($ingredients), 'parfum') !== false) {
547
+ $result .= "• Fragrances are present, which could potentially cause sensitivity in some individuals\n";
548
+ }
549
+
550
+ $result .= "\nNo major red flags were identified in this formulation that would likely trigger adverse reactions.";
551
+ }
552
+
553
+ return array(
554
+ 'success' => true,
555
+ 'result' => $result
556
+ );
557
+ }
558
+
559
+ /**
560
+ * Get the Hugging Face API token
561
+ * Returns the API token from WordPress options or an empty string if not set
562
+ */
563
+ function phi_shampoo_get_api_token() {
564
+ $token = get_option('phi_shampoo_hf_api_token', '');
565
+
566
+ // For extra security, you can decrypt the token here if you stored it encrypted
567
+ return $token;
568
+ }
569
+
570
+ /**
571
+ * Admin menu
572
+ */
573
+ function phi_shampoo_admin_menu() {
574
+ add_menu_page(
575
+ 'Phi Shampoo Analyzer',
576
+ 'Phi Shampoo',
577
+ 'manage_options',
578
+ 'phi-shampoo-settings',
579
+ 'phi_shampoo_settings_page',
580
+ 'dashicons-admin-generic'
581
+ );
582
+ }
583
+ add_action('admin_menu', 'phi_shampoo_admin_menu');
584
+
585
+ /**
586
+ * Admin settings page
587
+ */
588
+ function phi_shampoo_settings_page() {
589
+ // Save settings if submitted
590
+ if (isset($_POST['phi_shampoo_save_settings']) && isset($_POST['phi_shampoo_settings_nonce'])) {
591
+ if (wp_verify_nonce($_POST['phi_shampoo_settings_nonce'], 'phi_shampoo_settings')) {
592
+
593
+ // Sanitize and save the API token
594
+ if (isset($_POST['phi_shampoo_hf_api_token'])) {
595
+ $api_token = sanitize_text_field($_POST['phi_shampoo_hf_api_token']);
596
+ update_option('phi_shampoo_hf_api_token', $api_token);
597
+ }
598
+
599
+ // Save test mode setting
600
+ $test_mode = isset($_POST['phi_shampoo_test_mode']) ? true : false;
601
+ update_option('phi_shampoo_test_mode', $test_mode);
602
+
603
+ echo '<div class="notice notice-success is-dismissible"><p>Settings saved successfully!</p></div>';
604
+ } else {
605
+ echo '<div class="notice notice-error is-dismissible"><p>Security check failed. Settings not saved.</p></div>';
606
+ }
607
+ }
608
+
609
+ // Get current settings
610
+ $api_token = get_option('phi_shampoo_hf_api_token', '');
611
+ $test_mode = get_option('phi_shampoo_test_mode', true);
612
+
613
+ ?>
614
+ <div class="wrap">
615
+ <h1>Phi Shampoo Analyzer Settings</h1>
616
+
617
+ <form method="post" action="">
618
+ <?php wp_nonce_field('phi_shampoo_settings', 'phi_shampoo_settings_nonce'); ?>
619
+
620
+ <table class="form-table">
621
+ <tr>
622
+ <th scope="row">Hugging Face API Token</th>
623
+ <td>
624
+ <input type="password" name="phi_shampoo_hf_api_token" value="<?php echo esc_attr($api_token); ?>" class="regular-text" />
625
+ <p class="description">
626
+ Enter your Hugging Face API token.
627
+ <a href="https://huggingface.co/settings/tokens" target="_blank">Get a token here</a>.
628
+ </p>
629
+ </td>
630
+ </tr>
631
+ <tr>
632
+ <th scope="row">Test Mode</th>
633
+ <td>
634
+ <label>
635
+ <input type="checkbox" name="phi_shampoo_test_mode" <?php checked($test_mode, true); ?> />
636
+ Enable test mode (uses pre-defined responses instead of API calls)
637
+ </label>
638
+ </td>
639
+ </tr>
640
+ </table>
641
+
642
+ <div class="phi-shampoo-settings-info">
643
+ <h2>Important Information</h2>
644
+ <p>To use this plugin, make sure:</p>
645
+ <ul>
646
+ <li>You have a valid Hugging Face account</li>
647
+ <li>You have <a href="https://huggingface.co/settings/inference-providers" target="_blank">enabled the HF Inference API</a> in your Hugging Face account</li>
648
+ <li>Your API token has the necessary permissions (at least "Read" access)</li>
649
+ </ul>
650
+ </div>
651
+
652
+ <p class="submit">
653
+ <input type="submit" name="phi_shampoo_save_settings" class="button-primary" value="Save Settings" />
654
+ </p>
655
+ </form>
656
+ </div>
657
+ <?php
658
+ }