PluginProbe
MxChat – AI Chatbot & Content Generation for WordPress / 3.2.10
MxChat – AI Chatbot & Content Generation for WordPress v3.2.10
3.2.21 3.2.20 3.2.19 3.2.18 3.2.17 3.2.16 3.2.15 3.2.14 3.2.12 3.2.13 3.2.11 3.2.10 3.2.9 3.2.8 3.2.7 3.2.6 3.2.5 3.2.4 3.2.3 3.2.2 3.2.1 2.0.3 2.0.4 2.0.5 2.0.6 All 152 releases
mxchat-basic / js / mxchat-test-streaming.js

mxchat-test-streaming.js in MxChat – AI Chatbot & Content Generation for WordPress 3.2.10, at js/mxchat-test-streaming.js

275 lines 12.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 jQuery(document).ready(function($) {
2 // Manual test button click
3 $('#mxchat-test-streaming-btn').on('click', function() {
4 const $button = $(this);
5 const $result = $('#mxchat-test-streaming-result');
6
7 $button.prop('disabled', true).text('Testing...');
8 $result.text('Testing streaming environment...');
9
10 // Test both backend capability AND frontend environment
11 testCompleteStreamingEnvironment()
12 .then(result => {
13 if (result.success) {
14 $result.css('color', 'green').html(result.message);
15 } else {
16 $result.css('color', 'red').html(result.message);
17 }
18 })
19 .catch(error => {
20 $result.css('color', 'red').html('❌ Test failed: ' + error.message);
21 })
22 .finally(() => {
23 $button.prop('disabled', false).html('<span class="dashicons dashicons-admin-tools" style="vertical-align: middle; margin-right: 5px;"></span>Test Streaming Compatibility');
24 });
25 });
26
27 // Intercept the streaming toggle BEFORE autosave fires
28 // We use a capturing event handler to run first
29 const streamingToggle = document.getElementById('enable_streaming_toggle');
30 if (streamingToggle) {
31 streamingToggle.addEventListener('change', function(e) {
32 if (this.checked) {
33 // Prevent the default autosave from firing immediately
34 e.stopImmediatePropagation();
35
36 const $toggle = $(this);
37 const $result = $('#mxchat-test-streaming-result');
38 const $button = $('#mxchat-test-streaming-btn');
39
40 // User is enabling streaming - run automatic compatibility test first
41 $button.prop('disabled', true);
42 $toggle.prop('disabled', true);
43 $result.css('color', '#666').html('🔄 Testing streaming compatibility before enabling...');
44
45 testCompleteStreamingEnvironment()
46 .then(result => {
47 if (result.success) {
48 // Test passed - now save the setting
49 saveStreamingSetting('on');
50 $result.css('color', 'green').html('�
51 Streaming enabled - compatibility verified!');
52 } else {
53 // Streaming failed - turn it back off (don't save 'on')
54 $toggle.prop('checked', false);
55 $result.css('color', 'red').html(result.message);
56 }
57 })
58 .catch(error => {
59 // Error during test - turn it back off
60 $toggle.prop('checked', false);
61 $result.css('color', 'red').html('❌ Streaming test failed: ' + error.message + '<br>Streaming has been disabled.');
62 })
63 .finally(() => {
64 $button.prop('disabled', false);
65 $toggle.prop('disabled', false);
66 });
67 }
68 // If turning OFF, let the normal autosave handle it
69 }, true); // 'true' for capturing phase - runs before jQuery handlers
70 }
71
72 // Helper function to save the streaming setting via AJAX
73 function saveStreamingSetting(value) {
74 $.ajax({
75 url: mxchatTestStreamingAjax.ajax_url,
76 type: 'POST',
77 data: {
78 action: 'mxchat_save_setting',
79 name: 'enable_streaming_toggle',
80 value: value,
81 _ajax_nonce: mxchatTestStreamingAjax.settings_nonce
82 }
83 });
84 }
85
86 function testCompleteStreamingEnvironment() {
87 return new Promise((resolve, reject) => {
88 let results = {
89 backendSupported: false,
90 frontendWorking: false,
91 chunks: 0,
92 timing: null,
93 issues: []
94 };
95
96 let startTime = Date.now();
97 let firstChunkTime = null;
98 let lastChunkTime = null;
99 let timeout;
100
101 // Set overall timeout
102 timeout = setTimeout(() => {
103 resolve({
104 success: false,
105 message: getFailureMessage(results)
106 });
107 }, 15000);
108
109 // Test the actual chat streaming endpoint (not the test endpoint)
110 const formData = new FormData();
111 formData.append('action', 'mxchat_stream_chat');
112 formData.append('message', 'Say "test 1", then "test 2", then "test 3" - each on a separate line.');
113 formData.append('session_id', 'streaming_test_' + Date.now());
114 formData.append('nonce', mxchatTestStreamingAjax.nonce);
115 formData.append('force_streaming_test', '1'); // Force streaming mode for testing
116
117 fetch(mxchatTestStreamingAjax.ajax_url, {
118 method: 'POST',
119 body: formData,
120 credentials: 'same-origin'
121 })
122 .then(response => {
123 const contentType = response.headers.get('content-type');
124 console.log('Content-Type:', contentType);
125
126 // Check if we got JSON (streaming failed)
127 if (contentType && contentType.includes('application/json')) {
128 response.json().then(data => {
129 clearTimeout(timeout);
130 results.backendSupported = true;
131 results.frontendWorking = false;
132 results.issues.push('Server fell back to JSON response');
133 resolve({
134 success: false,
135 message: getFailureMessage(results)
136 });
137 });
138 return;
139 }
140
141 // Check for proper SSE content type
142 if (!contentType || !contentType.includes('text/event-stream')) {
143 clearTimeout(timeout);
144 results.issues.push(`Wrong content-type: ${contentType || 'none'}`);
145 resolve({
146 success: false,
147 message: getFailureMessage(results)
148 });
149 return;
150 }
151
152 results.backendSupported = true;
153
154 // Process streaming response
155 const reader = response.body.getReader();
156 const decoder = new TextDecoder();
157 let buffer = '';
158
159 function processStream() {
160 reader.read().then(({ done, value }) => {
161 if (done) {
162 clearTimeout(timeout);
163 results.timing = {
164 total: Date.now() - startTime,
165 firstChunk: firstChunkTime ? firstChunkTime - startTime : null,
166 lastChunk: lastChunkTime ? lastChunkTime - startTime : null
167 };
168
169 if (results.chunks > 0) {
170 resolve({
171 success: true,
172 message: getSuccessMessage(results)
173 });
174 } else {
175 results.issues.push('No chunks received');
176 resolve({
177 success: false,
178 message: getFailureMessage(results)
179 });
180 }
181 return;
182 }
183
184 buffer += decoder.decode(value, { stream: true });
185 const lines = buffer.split('\n');
186 buffer = lines.pop() || '';
187
188 for (const line of lines) {
189 if (line.startsWith('data: ')) {
190 const data = line.substring(6);
191
192 if (data === '[DONE]') {
193 // Stream complete - will be handled in done section
194 continue;
195 }
196
197 try {
198 const json = JSON.parse(data);
199 if (json.content && json.content.trim().length > 0) {
200 results.chunks++;
201 results.frontendWorking = true;
202
203 if (!firstChunkTime) {
204 firstChunkTime = Date.now();
205 }
206 lastChunkTime = Date.now();
207
208 $result.text(`�
209 Streaming working... (${results.chunks} chunks received)`);
210 }
211 } catch (e) {
212 // Non-JSON data is fine for some SSE implementations
213 }
214 }
215 }
216
217 processStream();
218 }).catch(error => {
219 clearTimeout(timeout);
220 results.issues.push('Stream read error: ' + error.message);
221 resolve({
222 success: false,
223 message: getFailureMessage(results)
224 });
225 });
226 }
227
228 processStream();
229 })
230 .catch(error => {
231 clearTimeout(timeout);
232 results.issues.push('Fetch error: ' + error.message);
233 resolve({
234 success: false,
235 message: getFailureMessage(results)
236 });
237 });
238 });
239 }
240
241 function getSuccessMessage(results) {
242 return `�
243 <strong>Streaming is working!</strong><br>
244 📊 Received ${results.chunks} chunks in ${results.timing.total}ms<br>
245 ⚡ First chunk: ${results.timing.firstChunk}ms<br>
246 🎯 Your users will see real-time streaming responses.`;
247 }
248
249 function getFailureMessage(results) {
250 let message = '❌ <strong>Streaming is not working in your environment. Please disable and use regular response.</strong><br><br>';
251
252 if (results.backendSupported) {
253 message += '<strong>Likely causes:</strong><br>';
254 message += '• Caching plugin (WP Rocket, W3 Total Cache, etc.)<br>';
255 message += '• CDN buffering (Cloudflare, etc.)<br>';
256 message += '• Server-level buffering (nginx, Apache)<br>';
257 message += '• Hosting provider optimizations<br><br>';
258
259 message += '<strong>Solutions:</strong><br>';
260 message += '• Disable caching for chat endpoints<br>';
261 message += '• Add streaming exceptions in your CDN<br>';
262 message += '• Contact your hosting provider<br>';
263 } else {
264 message += '❌ Backend streaming not supported<br>';
265 if (results.issues.length > 0) {
266 message += '<br><strong>Issues detected:</strong><br>';
267 results.issues.forEach(issue => {
268 message += `${issue}<br>`;
269 });
270 }
271 }
272
273 return message;
274 }
275 });