PluginProbe
BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot / 3.2.0
BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot v3.2.0
4.9.1 4.9.0 4.8.2 4.8.1 4.8.0 4.7.0 4.6.2 4.6.1 4.6.0 4.5.6 4.5.5 4.5.4 4.5.3 4.5.2 4.5.1 4.5.0 4.4.1 4.4.0 3.3.4 3.4.0 3.4.1 3.4.2 3.5.0 3.5.1 3.5.2 All 199 releases
betterdocs / includes / Core / WriteWithAI.php

WriteWithAI.php in BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot 3.2.0, at includes/Core/WriteWithAI.php

1,072 lines 46.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace WPDeveloper\BetterDocs\Core;
4
5 use WPDeveloper\BetterDocs\Utils\Base;
6 use WPDeveloper\BetterDocs\Core\Settings;
7 use WPDeveloper\BetterDocs\Core\PostType;
8
9 use WPDeveloper\BetterDocs\Utils\Helper;
10
11 class WriteWithAI extends Base {
12 public $settings;
13
14 public function __construct(Settings $settings) {
15 $this->settings = $settings;
16 // Get the post ID from the URL
17 $post_id = isset($_GET['post']) ? intval($_GET['post']) : 0;
18
19 if (!empty($_GET['post_type'])) {
20 $post_type = $_GET['post_type'];
21 } else if ($post_id > 0) {
22 $post_type = get_post_type($post_id);
23 } else {
24 $post_type = '';
25 }
26
27 if (!empty($this->isEnabledWriteWithAI()) && $post_type == 'docs') {
28 add_action('admin_footer', [$this, 'ai_autowrite_button']);
29 }
30 add_action('wp_ajax_generate_openai_content', [$this, 'generate_openai_content_callback']);
31 }
32
33 public function isEnabledWriteWithAI() {
34 $isEnableAutoWrite = $this->settings->get('enable_write_with_ai', true);
35 return $isEnableAutoWrite;
36 }
37
38 public function isValidAPIKey($apiKey){
39 if (empty($apiKey)) {
40 $api_response['valid'] = false;
41 $api_response['message'] = 'Please Insert your <a href="/admin.php?page=betterdocs-settings">OpenAI API Key</a> to use this Write with AI feature.';
42
43 return $api_response;
44 }
45
46 $ch = curl_init('https://api.openai.com/v1/engines');
47 curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
48 curl_setopt($ch, CURLOPT_HTTPHEADER, [
49 'Content-Type: application/json',
50 'Authorization: Bearer ' . $apiKey,
51 ]);
52
53 $api_response = [];
54
55 $response = curl_exec($ch);
56 $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
57
58 curl_close($ch);
59
60 if ($httpCode == 200) {
61 $api_response['valid'] = true;
62 $api_response['message'] = 'Valid API Key';
63 } else {
64 $responseData = json_decode($response, true);
65 // Access the message data (replace 'data' with the actual key used in the response)
66 $messageData = $responseData['error'] ? $responseData['error'] : '';
67 $api_response['valid'] = false;
68 $api_response['message'] = $messageData['message'] ? $messageData['message'] : 'Invalid API Key';
69 }
70
71 // print_r($response);
72
73 return $api_response;
74 }
75
76 public function get_api_key() {
77 $api_key = $this->settings->get('ai_autowrite_api_key', '');
78 return $api_key;
79 }
80
81
82 public function generate_openai_response($prompt, $keywords) {
83
84 $api_key = $this->settings->get('ai_autowrite_api_key', '');
85 $max_tokens = $this->settings->get('ai_autowrite_max_token', 1500);
86
87 $api_endpoint = 'https://api.openai.com/v1/engines/text-davinci-003/completions'; // Adjust the endpoint based on OpenAI API version
88
89 $response = wp_remote_post($api_endpoint, array(
90 'headers' => array(
91 'Content-Type' => 'application/json',
92 'Authorization' => 'Bearer ' . $api_key,
93 ),
94 'body' => json_encode(array(
95 'prompt' => esc_html($prompt),
96 'max_tokens' => $max_tokens, // Adjust as needed
97 )),
98 'timeout' => 50
99 ));
100
101
102 if (is_wp_error($response)) {
103 return 'Error: ' . $response->get_error_message();
104 } else {
105 $body = wp_remote_retrieve_body($response);
106
107 $data = json_decode($body, true);
108
109 if (!empty($data['error'])) {
110 return $data['error'];
111 }
112 return $data['choices'][0]['text'];
113 }
114 }
115
116
117 public function generate_openai_content_callback() {
118 // Verify the nonce
119 if (!isset($_POST['ai_nonce']) || !wp_verify_nonce($_POST['ai_nonce'], 'generate_openai_content_nonce')) {
120 wp_send_json_error('Invalid nonce');
121 wp_die();
122 }
123
124 $prompt = sanitize_text_field($_POST['prompt']);
125 // $num_of_sections = sanitize_text_field($_POST['numOfSections']);
126 // $num_of_paragraphs = sanitize_text_field($_POST['numOfParagraphs']);
127 $keywords = sanitize_text_field($_POST['keywords']);
128
129 $ai_instance = new WriteWithAI($this->settings);
130
131 $generated_content = $ai_instance->generate_openai_response($prompt, $keywords);
132
133 // Send the generated content as the AJAX response
134 wp_send_json_success($generated_content);
135 wp_die();
136 }
137
138 public function ai_autowrite_button() {
139
140 ?>
141 <script>
142 var docsTitle;
143
144 function responseMessage(message) {
145 return `<div class="warning-message">
146 <span class="dashicons dashicons-warning"></span>
147 <div class="footer-message">
148 ${message} <a href="#">Learn More</a>
149 </div>
150 </div>`;
151 }
152
153 function generateArticle(e) {
154
155
156 const title = document.getElementById('betterdocs-ai-title').value;
157 const keywords = document.getElementById('betterdocs-ai-keyword').value;
158 // const sectionOptions = document.getElementById('bd-autowrtite-content-section');
159 // const numOfSections = sectionOptions.options[sectionOptions.selectedIndex].value;
160
161 // const paragraphOptions = document.getElementById('bd-autowrtite-content-paragraph');
162 // const numOfParagraphs = paragraphOptions.options[paragraphOptions.selectedIndex].value;
163
164 const contentTextArea = document.getElementById('betterdocs-ai-content');
165 const docGenerateBtnTxt = document.querySelector('.generate-btn span');
166
167 // Add nonce value to the data being sent
168 const nonce = document.querySelector('input[name="ai_nonce"]').value;
169 const isOverwrite = document.getElementById('betterdocs-ai-checkbox').checked;
170 const generateDocLabel = "<?php echo esc_html__('Generate Doc', 'betterdocs'); ?>";
171 const reGenerateDocLabel = "<?php echo esc_html__('Regenerate Doc', 'betterdocs'); ?>";
172
173
174 // contentTextArea.value = `Write an article about ${title} in English. The article is organized by the following exact ${numOfSections} headings. Write exact ${numOfParagraphs} number of paragraphs per heading.${keywords} Use Markdown for formatting. Add an introduction and a conclusion. Style: creative. Tone: cheerful.`;
175
176
177 // Check if the title is not empty
178 if (title.trim() !== '' && keywords.trim() !== '') {
179 e.preventDefault();
180
181 if (!jQuery('#betterdocs-ai-error-message').parent().hasClass('hidden')) {
182 jQuery('#betterdocs-ai-error-message').parent().addClass('hidden');
183 }
184
185 docGenerateBtnTxt.innerHTML = "<?php echo esc_html__('Generating...', 'betterdocs'); ?>";
186
187 jQuery.post({
188 url: ajaxurl, // Make sure ajaxurl is defined in your script
189 type: 'POST',
190 data: {
191 action: 'generate_openai_content',
192 prompt: document.querySelector('#betterdocs-ai-content').value,
193 // numOfSections: numOfSections,
194 // numOfParagraphs: numOfParagraphs,
195 keywords: keywords,
196 ai_nonce: nonce, // Pass the nonce value
197 },
198 success: function(response) {
199 // Update the content in the textarea
200
201 if (response.success && (typeof response.data === 'string')) {
202 docGenerateBtnTxt.innerHTML = "<?php echo esc_html__('Generated', 'betterdocs'); ?>";
203 setTimeout(() => {
204 insertContentToEditor(title, response.data, isOverwrite, keywords);
205 docGenerateBtnTxt.innerHTML = reGenerateDocLabel;
206 // console.log(jQuery('.betterdocs-ai-autowrite-form-container').data('new-doc-page'));
207
208 // if(jQuery('.betterdocs-ai-autowrite-form-container')?.data('new-doc-page')) {
209 // docGenerateBtnTxt.innerHTML = reGenerateDocLabel;
210 // }
211 }, 2000);
212 } else {
213 // alert(response.data.message);
214 jQuery('#betterdocs-ai-error-message').parent().removeClass('hidden');
215 jQuery('#betterdocs-ai-error-message').html(responseMessage(response.data.message));
216 docGenerateBtnTxt.innerHTML = generateDocLabel;
217 }
218 },
219 error: function(error) {
220 console.error(error);
221 },
222 });
223
224 }
225 }
226
227 // Function to update the textarea
228 function updateTextarea() {
229
230 const title = document.getElementById('betterdocs-ai-title').value;
231 const keywords = document.getElementById('betterdocs-ai-keyword').value; //.split(', ').map(item => `'${item}'`).join(', ');
232 const sectionOptions = document.getElementById('bd-autowrtite-content-section');
233 let language = 'English'; //document.getElementById('betterdocs-ai-language').value;
234
235 if (language === '') {
236 language = 'English';
237 }
238
239 // const numOfSections = sectionOptions.options[sectionOptions.selectedIndex].value;
240
241 let keywordsText = ` and incorporate the keywords: ${keywords}`;
242 if (keywords == '') {
243 keywordsText = '';
244 }
245
246 // const paragraphOptions = document.getElementById('bd-autowrtite-content-paragraph');
247 // const numOfParagraphs = paragraphOptions.options[paragraphOptions.selectedIndex].value;
248 const contentTextArea = document.getElementById('betterdocs-ai-content');
249
250 if (!jQuery('#betterdocs-ai-error-message').parent().hasClass('hidden')) {
251 jQuery('#betterdocs-ai-error-message').parent().addClass('hidden');
252 }
253
254 // contentTextArea.value = `Make a knowledge base article with html heading tags about [${title}] in [${language}]. Here is some topic to describe the article: [${keywords}]. and wrap the content with p tag also add a span tag with a class named 'highlight' to all the heading and topic tags in the article.`;
255
256 contentTextArea.value = `Create a details knowledge base article in ${language} about [${title}] with html heading tags. Here is some topic to describe the article: [${keywords}]. And wrap the content with p tag also add a span tag with a class named 'highlight' to all the heading and topic tags in the article.`;
257
258 contentTextArea.value = `Generate a documentation using HTML heading tags for '${title}'. Include relevant details on ${keywords} in the documentation. Ensure all content is enclosed with <p> tags and apply a <span> tag with the class 'highlight' to headings and topic tags for emphasis.`;
259
260 // contentTextArea.value = `Create a knowledge base article with HTML heading tags on the topic of '${title}' in ${language}. Here are some topics to describe in the article: ${keywords}. Wrap the content with 'p' tags and also add a 'span' tag with a class named 'highlight' to all the heading and topic tags in the article.`;
261
262 }
263
264
265 function convertMarkdownToHTML(markdownContent) {
266 // Simple Markdown to HTML conversion (you may need to enhance this based on your needs)
267 const htmlContent = markdownContent
268 .replace(/^# (.+)$/gm, '<h1>$1</h1>')
269 .replace(/^## (.+)$/gm, '<h2>$1</h2>')
270 .replace(/^### (.+)$/gm, '<h3>$1</h3>')
271 .replace(/\*\*(.+?)\*\*/g, '<strong>$1</strong>')
272 .replace(/\*(.+?)\*/g, '<em>$1</em>');
273
274 return htmlContent;
275 }
276
277 function replaceHeadingTitle(content, title, overviewTitle) {
278 let regex = new RegExp(title, 'g');
279 let updateContent = content.replace(regex, overviewTitle);
280 return updateContent;
281 }
282
283 function removeFirstHeading(htmlString) {
284 var newDiv = document.createElement('div');
285 newDiv.innerHTML = htmlString;
286 var firstHeading = newDiv.querySelector('h1');
287 if (firstHeading) {
288 firstHeading.parentNode.removeChild(firstHeading);
289 }
290 return newDiv.innerHTML;
291 }
292
293
294 function wrapwithHeighlight(inputString, keywords) {
295 let modifiedString = inputString.replace(/<(h\d)(.*?)>(.*?)<\/\1>/g, '<$1$2><span class="highlight">$3</span></$1>');
296
297 const keywordArray = keywords.split(',').map(keyword => keyword.trim());
298
299 keywordArray.forEach(keyword => {
300 modifiedString = modifiedString.replace(new RegExp(`\\b(${keyword})\\b`, 'gi'), '<span class="highlight">$1</span>');
301 });
302
303 return modifiedString;
304 }
305
306 function insertContentToEditor(title, htmlContent, isOverwrite, keywords) {
307
308 const {
309 dispatch,
310 select
311 } = wp.data;
312
313 htmlContent = removeFirstHeading(htmlContent);
314 htmlContent = wrapwithHeighlight(htmlContent, keywords);
315 const isPostContent = `<?php echo isset($_GET['post']) ? get_the_content($_GET['post']) : ''; ?>`;
316
317 console.log(htmlContent);
318
319 const blocks = wp.blocks.rawHandler({
320 HTML: htmlContent
321 });
322
323 dispatch('core/editor').editPost({
324 title: title,
325 });
326
327 console.log(htmlContent);
328
329 const selectedBlockClientId = select('core/block-editor').getSelectedBlockClientId();
330
331 console.log(isOverwrite, blocks);
332
333 const allBlocks = select('core/block-editor').getBlocks();
334
335 console.log(allBlocks.length);
336
337 if (isOverwrite || isPostContent === '') {
338
339 allBlocks.forEach((block) => {
340 dispatch('core/block-editor').removeBlock(block.clientId);
341 });
342 dispatch('core/block-editor').insertBlocks(blocks);
343
344 } else if (selectedBlockClientId) {
345 const selectedIndex = select('core/block-editor').getBlockIndex(selectedBlockClientId);
346 dispatch('core/block-editor').insertBlocks(blocks, selectedIndex + 1);
347 } else {
348 dispatch('core/block-editor').insertBlocks(blocks);
349 }
350
351 closeWriteWithAIForm('afterInsertContent');
352 }
353
354 function closeWriteWithAIForm(after) {
355 jQuery('.betterdocs-ai-autowrite-form-container').addClass('hidden');
356 jQuery('#betterdocs-ai-autowrite-form-container-overlay').addClass('hidden');
357 jQuery('.betterdocs-ai-button').addClass('regenerate-btn');
358 }
359
360
361 document.addEventListener('DOMContentLoaded', function() {
362
363 // Subscribe to changes in the editor state
364 wp.data.subscribe(() => {
365 // Get the updated post title
366 docsTitle = wp.data.select('core/editor').getEditedPostAttribute('title');
367 let currentKeywords = jQuery('#betterdocs-ai-keyword').val();
368 if (!currentKeywords) {
369 currentKeywords = '{Documentation Keywords}';
370 }
371 const currentPrompt = `Generate a documentation using HTML heading tags for '${docsTitle}'. Include relevant details on ${currentKeywords} in the documentation. Ensure all content is enclosed with <p> tags and apply a <span> tag with the class 'highlight' to headings and topic tags for emphasis.`;
372 jQuery('#betterdocs-ai-title').val(docsTitle);
373 jQuery('#betterdocs-ai-content').val(currentPrompt);
374 });
375 });
376
377 // This example assumes that this code is executed when your script is loaded.
378 // You may want to place it within the appropriate context in your application.
379
380
381 function writeWithAIForm() {
382
383 let title = `<?php echo isset($_GET['post']) ? get_the_title($_GET['post']) : ''; ?>`;
384 if (docsTitle) {
385 title = docsTitle;
386 }
387
388 const promtTitle = `<?php echo isset($_GET['post']) ? get_the_title($_GET['post']) : '{Documentation Title}'; ?>`;
389 const titlePlaceholder = "<?php echo esc_attr('Enter a descriptive title for your documentation.'); ?>";
390 const keywords = "<?php echo esc_attr('{Documentation Keywords}'); ?>";
391 const keywordsPlaceholder = "<?php echo esc_attr('Add keywords to generate precise & relevant documentation (comma-separated).'); ?>";
392 const language = "<?php echo esc_attr('English'); ?>";
393 const titleLabel = "<?php echo esc_html__('Documentation Title:', 'betterdocs'); ?>";
394 const keywordLabel = "<?php echo esc_html__('Keywords:', 'betterdocs'); ?>";
395 const secLabel = "<?php echo esc_html__('# of Sections:', 'betterdocs'); ?>";
396 const paraLabel = "<?php echo esc_html__('# of Paragraph Per Section: ', 'betterdocs'); ?>";
397 const langLabel = "<?php echo esc_html__('Language:', 'betterdocs'); ?>";
398 const promtLabel = "<?php echo esc_html__('Prompt:', 'betterdocs'); ?>";
399 const promtBtnLabel = "<?php echo esc_html__('Generate Prompt', 'betterdocs'); ?>";
400 let promtArticleLabel = "<?php echo esc_html__('Generate Doc', 'betterdocs'); ?>";
401 const checkboxLabel = "<?php echo esc_html__('Overwrite your existing Doc:', 'betterdocs'); ?>";
402 const nonce = "<?php echo esc_attr(wp_create_nonce('generate_openai_content_nonce')); ?>";
403
404 <?php $is_valid = $this->isValidAPIKey($this->get_api_key());
405 $disable_field = 'disabled-input-field';
406 if ($is_valid['valid']) {
407 $disable_field = '';
408 }
409 ?>
410
411 let hiddenClass = 'hidden';
412 let newDocPageAtt = 'data-new-doc-page="true"';
413 const isPostContent = `<?php echo isset($_GET['post']) ? get_the_content($_GET['post']) : ''; ?>`;
414
415 if (isPostContent !== '') {
416 hiddenClass = '';
417 newDocPageAtt = '';
418 }
419
420
421 // const prompt = `Make a knowledge base article with html heading tags about [${title}] in [${language}]. Here is some topic to describe the article: [${keywords}]. and wrap the content with p tag also add a span tag with a class named 'highlight' to all the heading and topic tags in the article.`;
422
423 // const prompt = `Create a details knowledge base article in [${language}] about [${title}] with html heading tags. Here is some topic to describe the article: [${keywords}]. And wrap the content with p tag also add a span tag with a class named 'highlight' to all the heading and topic tags in the article.`;
424
425 const prompt = `Generate a documentation using HTML heading tags for '${promtTitle}'. Include relevant details on ${keywords} in the documentation. Ensure all content is enclosed with <p> tags and apply a <span> tag with the class 'highlight' to headings and topic tags for emphasis.`;
426
427 const aiIcon = `<svg xmlns="http://www.w3.org/2000/svg" width="21" height="20" viewBox="0 0 21 20" fill="none">
428 <g clip-path="url(#clip0_2460_1729)">
429 <path d="M10.3956 18.8608L6.10991 19.2322L6.48134 14.9465L15.3956 6.08936C15.5287 5.95329 15.6876 5.84518 15.863 5.77137C16.0384 5.69756 16.2268 5.65954 16.4171 5.65954C16.6074 5.65954 16.7957 5.69756 16.9711 5.77137C17.1466 5.84518 17.3054 5.95329 17.4385 6.08936L19.2528 7.91793C19.3865 8.05083 19.4926 8.20886 19.565 8.38293C19.6375 8.55701 19.6747 8.74368 19.6747 8.93221C19.6747 9.12075 19.6375 9.30742 19.565 9.48149C19.4926 9.65557 19.3865 9.8136 19.2528 9.9465L10.3956 18.8608ZM1.7042 5.67507C1.20277 5.58793 1.20277 4.86793 1.7042 4.78079C2.59203 4.62626 3.41374 4.21085 4.06456 3.58751C4.71538 2.96417 5.16583 2.16113 5.35848 1.28079L5.38848 1.14221C5.49705 0.647929 6.20277 0.643643 6.31705 1.13936L6.35277 1.29936C6.55248 2.17579 7.0067 2.97367 7.65837 3.59281C8.31005 4.21195 9.13013 4.62475 10.0156 4.77936C10.5199 4.86507 10.5199 5.58936 10.0156 5.67793C9.13005 5.83218 8.3098 6.24465 7.65787 6.86354C7.00594 7.48243 6.5514 8.28014 6.35134 9.1565L6.3142 9.31793C6.20134 9.81221 5.49563 9.80936 5.38705 9.31364L5.35848 9.17507C5.16564 8.29433 4.71476 7.49102 4.06339 6.86764C3.41202 6.24426 2.58969 5.82908 1.70134 5.67507H1.7042Z" stroke="white" stroke-width="1.42857" stroke-linecap="round" stroke-linejoin="round"/>
430 </g>
431 <defs>
432 <clipPath id="clip0_2460_1729">
433 <rect width="20" height="20" fill="white" transform="translate(0.5)"/>
434 </clipPath>
435 </defs>
436 </svg>`;
437
438
439
440 return `
441 <div class="betterdocs-ai-autowrite-form-container hidden" ${newDocPageAtt}>
442 <div class="betterdocs-ai-autowrite-form-content">
443 <div class="betterdocs-ai-autowrite-top-part">
444 <div class="autowrite-heading">
445 <span class="autowrite-icon">
446 <svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32" fill="none">
447 <g clip-path="url(#clip0_2453_20882)">
448 <path d="M15.8322 30.1765L8.97508 30.7708L9.56936 23.9136L23.8322 9.74219C24.0451 9.52448 24.2993 9.3515 24.58 9.23341C24.8606 9.11531 25.162 9.05447 25.4665 9.05447C25.771 9.05447 26.0724 9.11531 26.3531 9.23341C26.6337 9.3515 26.8879 9.52448 27.1008 9.74219L30.0037 12.6679C30.2176 12.8805 30.3874 13.1334 30.5033 13.4119C30.6192 13.6904 30.6788 13.9891 30.6788 14.2908C30.6788 14.5924 30.6192 14.8911 30.5033 15.1696C30.3874 15.4481 30.2176 15.701 30.0037 15.9136L15.8322 30.1765ZM1.92593 9.07933C1.12365 8.9399 1.12365 7.7879 1.92593 7.64848C3.34647 7.40124 4.6612 6.73658 5.70251 5.73923C6.74382 4.74188 7.46455 3.45703 7.77279 2.04848L7.82079 1.82676C7.99451 1.03591 9.12365 1.02905 9.30651 1.82219L9.36365 2.07819C9.68319 3.48048 10.4099 4.75709 11.4526 5.74772C12.4953 6.73834 13.8074 7.39881 15.2242 7.64619C16.0311 7.78333 16.0311 8.94219 15.2242 9.0839C13.8073 9.33071 12.4949 9.99066 11.4518 10.9809C10.4087 11.9711 9.68146 13.2474 9.36136 14.6496L9.30193 14.9079C9.12136 15.6988 7.99222 15.6942 7.81851 14.901L7.77279 14.6793C7.46424 13.2702 6.74284 11.9849 5.70064 10.9874C4.65845 9.99003 3.34273 9.32574 1.92136 9.07933H1.92593Z" stroke="#E31B54" stroke-width="2.28571" stroke-linecap="round" stroke-linejoin="round"/>
449 </g>
450 <defs>
451 <clipPath id="clip0_2453_20882">
452 <rect width="32" height="32" fill="white"/>
453 </clipPath>
454 </defs>
455 </svg>
456 </span>
457 <h1><?php echo esc_html__('Write Documentation with BetterDocs AI', 'betterdocs'); ?></h1>
458
459 </div>
460 <div class="autowrite-subheadding">
461 <p><?php echo esc_html__('Generate documentation effortlessly with BetterDocs AI. Simply input your doc title, keywords, prompt and let the system automatically generate comprehensive documentation tailored to your needs.', 'betterdocs'); ?></p>
462 </div>
463
464 <?php if (empty($is_valid['valid'])) : ?>
465 <div id="betterdocs-ai-message">
466 <div class="warning-message">
467 <span class="dashicons dashicons-warning"></span>
468 <div>
469 <?php echo wp_kses_post('Please Insert your <a target="_blank" href="' . esc_url(admin_url('admin.php?page=betterdocs-settings&tab=tab-ai-autowrite')) . '">OpenAI API Key</a> to use this Write with AI feature.', 'betterdocs'); ?>
470 </div>
471 </div>
472
473 </div>
474 <?php endif; ?>
475
476 </div>
477 <form id="betterdocs-ai-form" class="<?php echo esc_attr($disable_field); ?>">
478 <div class="form-inner-content">
479 <div class="form-group">
480 <label for="betterdocs-ai-title">${titleLabel}</label>
481 <input type="text" placeholder="${titlePlaceholder}" id="betterdocs-ai-title" name="betterdocs-ai-title" required value="${title}">
482 </div>
483
484 <div class="form-group">
485 <label for="betterdocs-ai-keyword">${keywordLabel}</label>
486 <input type="text" placeholder="${keywordsPlaceholder}" id="betterdocs-ai-keyword" name="betterdocs-ai-keyword" required>
487 </div>
488
489 <div class="form-group prompt-field">
490 <label for="betterdocs-ai-content">${promtLabel}</label>
491 <textarea id="betterdocs-ai-content" name="betterdocs-ai-content" rows="6" required>${prompt}</textarea>
492 <p class="input-description"><?php echo esc_html__('Ensure you include a clear and detailed prompt to receive the desired output. Follow the guidelines provided for the best results.', 'betterdocs'); ?></p>
493 </div>
494 <div class="betterdocs-ai-checkbox-field ${hiddenClass}">
495 <div class="form-group">
496 <div class="checkbox-field-label">
497 <label for="betterdocs-ai-checkbox">${checkboxLabel}</label>
498 <p class="input-description"><?php echo esc_html__('Overwrite the existing doc with the AI Generated Content. If Disabled, new AI Generated content will be added in the section you are currently editing.', 'betterdocs'); ?></p>
499 </div>
500
501 <div class="checkbox-input-field">
502 <input type="checkbox" id="betterdocs-ai-checkbox" name="betterdocs-ai-checkbox" data-overwrite="false">
503 <label for="betterdocs-ai-checkbox" class="toggle-label"></label>
504 </div>
505 </div>
506 </div>
507
508 <div class="form-group hidden">
509 <div id="betterdocs-ai-error-message"></div>
510 </div>
511 <input type="hidden" name="ai_nonce" value="${nonce}" />
512 </div>
513 <div class="generate-button-container">
514 <button type="submit" class="generate-btn" onclick="generateArticle(event)">
515 ${aiIcon} <span>${promtArticleLabel}</span>
516 </button>
517 </div>
518 </form>
519 </div>
520
521 <div class="bd-close-button" onclick="closeWriteWithAIForm('afterClosedClicked')">✕</div>
522 </div>
523
524 <div id="betterdocs-ai-autowrite-form-container-overlay" class="hidden"></div>
525 `;
526 }
527
528 jQuery(document).on('click', '.regenerate-btn', function() {
529 jQuery('.betterdocs-ai-autowrite-form-container').removeClass('hidden');
530 jQuery('#betterdocs-ai-autowrite-form-container-overlay').removeClass('hidden');
531 });
532
533 jQuery(document).ready(function($) {
534 // Check if we are in the Edit Post screen
535 if ($('.block-editor-page').length > 0) {
536 const bdAIButton = $(`<div class="betterdocs-ai-button-container">
537 <button class="betterdocs-ai-button">
538 <img src="<?php echo esc_url(BETTERDOCS_ABSURL . 'assets/admin/images/betterdocs-icon-white.png'); ?>" alt="<?php echo esc_attr__('betterdocs icon', 'embedpress'); ?>" />
539 <span><?php echo esc_html__('Write with AI', 'embedpress'); ?></span>
540 </button>
541 </div>`);
542 const closeBtn = $('bd-close-button');
543
544 const formHtml = writeWithAIForm();
545 $(formHtml).addClass('hidden');
546
547 $(document).on('click', '.betterdocs-ai-button', function() {
548 $('.betterdocs-ai-autowrite-form-container').removeClass('hidden');
549 $('#betterdocs-ai-autowrite-form-container-overlay').removeClass('hidden');
550 });
551
552 // $(document).on('click', '.betterdocs-ai-button', function() {
553 if ($('.betterdocs-ai-autowrite-form-container').length < 1) {
554 $('body').append(formHtml);
555
556 // Add event listeners to input elements
557 document.getElementById('betterdocs-ai-title').addEventListener('input', updateTextarea);
558 document.getElementById('betterdocs-ai-keyword').addEventListener('input', updateTextarea);
559 // document.getElementById('bd-autowrtite-content-section').addEventListener('change', updateTextarea);
560 // document.getElementById('bd-autowrtite-content-paragraph').addEventListener('change', updateTextarea);
561 // document.getElementById('betterdocs-ai-language').addEventListener('input', updateTextarea);
562 }
563 // });
564 const btn = document.createElement('button');
565 wp.data.subscribe(function() {
566 setTimeout(() => {
567 if ($('.edit-post-header__settings').length > 0) {
568 $('.edit-post-header__settings').prepend(bdAIButton);
569 }
570 }, 1);
571 });
572 }
573
574 $(document).on('click', '#betterdocs-ai-autowrite-form-container-overlay', function() {
575 closeWriteWithAIForm();
576 });
577 });
578 </script>
579
580 <style>
581 .hidden {
582 display: none !important;
583 }
584
585 .disabled-input-field input,
586 .disabled-input-field textarea,
587 .disabled-input-field button,
588 .disabled-input-field label {
589 pointer-events: none;
590 opacity: 0.6;
591 }
592
593 .disabled-input-field label {
594 opacity: 1;
595 }
596
597 .betterdocs-ai-button-container {
598 margin-left: 10px;
599 }
600
601 .autowrite-icon {
602 display: flex;
603 align-items: center;
604 width: 55px;
605 height: 55px;
606 background: #FFE4E8;
607 justify-content: center;
608 border-radius: 50px;
609 }
610
611 .autowrite-icon svg {
612 width: 28px;
613 height: 28px;
614 }
615
616 .autowrite-heading {
617 display: flex;
618 gap: 10px;
619 align-items: center;
620 }
621
622 .autowrite-heading h1 {
623 color: #1D2939;
624 font-family: 'IBM Plex Sans', sans-serif;
625 font-size: 24px;
626 font-style: normal;
627 font-weight: 500;
628 line-height: normal;
629 margin: 0;
630 }
631
632 .autowrite-heading p,
633 form#betterdocs-ai-form p {
634 margin: 0;
635 margin-bottom: 24px;
636 }
637
638 .autowrite-subheadding p {
639 font-family: 'IBM Plex Sans', sans-serif;
640 font-size: 14px;
641 }
642
643 .prompt-field .input-description {
644 margin: 0 !important;
645 }
646
647 .autowrite-heading p {
648 color: #475467;
649 font-family: 'IBM Plex Sans', sans-serif;
650 font-size: 16px;
651 font-style: normal;
652 font-weight: 400;
653 }
654
655 .betterdocs-ai-button {
656 background: #00B884;
657 border: 1px solid transparent;
658 color: #fff;
659 box-shadow: none;
660 font-size: 12px;
661 margin-right: 8px;
662 padding: 0px 15px;
663 cursor: pointer;
664 border-radius: 3px;
665 height: 38px;
666 display: flex;
667 align-items: center;
668 justify-content: space-between;
669 gap: 10px;
670 }
671
672 .betterdocs-ai-button img {
673 width: 20px;
674 height: 20px;
675 }
676
677 .betterdocs-ai-autowrite-form-container {
678 position: fixed;
679 top: 50%;
680 left: 50%;
681 transform: translate(-50%, -50%);
682 z-index: 100001;
683 width: 650px;
684 margin: 0 auto;
685 background-color: #fff;
686 border-radius: 5px;
687 font-family: 'IBM Plex Sans', sans-serif;
688 /* max-height: 600px; */
689 max-height: 100%;
690 max-width: 100%;
691 }
692
693 .betterdocs-ai-autowrite-form-content {
694 background-color: #fff;
695 padding: 20px 0px;
696 border-radius: 5px;
697 padding-bottom: 0;
698 overflow: auto;
699 /* max-height: 700px; */
700 height: 100%;
701
702 }
703
704 .betterdocs-ai-autowrite-top-part {
705 /* padding-bottom: 20px; */
706 border-bottom: 1px solid #ddd;
707 /* margin-bottom: 20px; */
708 padding: 0 40px;
709 }
710
711 #betterdocs-ai-form {
712 display: flex;
713 flex-direction: column;
714 /* height: 100%; */
715 overflow: hidden;
716 }
717
718 .form-inner-content {
719 overflow: auto;
720 height: 100%;
721 max-height: 435px;
722 /* max-height: 330px; */
723 padding: 0 40px;
724 }
725
726 .form-inner-content>.form-group {
727 margin-top: 20px;
728 }
729
730
731 #betterdocs-ai-autowrite-form-container-overlay {
732 position: fixed;
733 top: 0;
734 right: 0;
735 bottom: 0;
736 left: 0;
737 background-color: rgba(0, 0, 0, .7);
738 z-index: 100000;
739 }
740
741
742
743 #betterdocs-ai-form {
744 display: flex;
745 flex-direction: column;
746 }
747
748 #betterdocs-ai-form .form-group {
749 margin-bottom: 24px;
750 }
751
752 #betterdocs-ai-form .bd-aiform-flex {
753 display: flex;
754 justify-content: space-between;
755 }
756
757 #betterdocs-ai-form label {
758 font-weight: 600;
759 margin-bottom: 5px;
760 display: block;
761 font-size: 14px;
762 line-height: 20px;
763 }
764
765 select#bd-autowrtite-content-section,
766 #bd-autowrtite-content-paragraph,
767 #betterdocs-ai-language {
768 width: 150px !important;
769 height: 40px;
770 }
771
772 #betterdocs-ai-form input[type="text"],
773 #betterdocs-ai-form textarea {
774 width: 100%;
775 padding: 8px;
776 box-sizing: border-box;
777 border: 1px solid #D0D5DD;
778 border-radius: 4px;
779 color: #667085;
780 font-weight: 400;
781 }
782
783 /* Override autofill text color */
784 #betterdocs-ai-form input:-webkit-autofill {
785 -webkit-text-fill-color: #667085 !important;
786 }
787
788 #betterdocs-ai-form input::placeholder {
789 color: #acb2bf;
790 }
791
792 #betterdocs-ai-form textarea {
793 color: #667085;
794 }
795
796 #betterdocs-ai-form input:focus,
797 #betterdocs-ai-form textarea:focus {
798 box-shadow: none;
799 }
800
801 #betterdocs-ai-form textarea:focus {
802 color: inherit;
803 box-shadow: none;
804
805 }
806
807
808 .generate-button-container {
809 position: sticky;
810 bottom: 0px;
811 width: 100%;
812 margin-left: 0;
813 z-index: 999999 !important;
814 padding: 20px 0;
815 display: flex;
816 justify-content: end;
817 border-top: 1px solid #ddd;
818 background: white;
819 border-bottom-right-radius: 5px;
820 border-bottom-left-radius: 5px;
821 }
822
823 .generate-button-container button {
824 display: flex;
825 gap: 8px;
826 align-items: center;
827 justify-content: center;
828 opacity: 1 !important;
829 margin-right: 40px;
830 }
831
832 .input-description {
833 font-size: 14px;
834 color: #667085;
835 }
836
837 .betterdocs-ai-checkbox-field .form-group {
838 display: flex;
839 align-items: start;
840 /* gap: 200px; */
841 justify-content: space-between;
842 }
843
844 .betterdocs-ai-checkbox-field input {
845 width: 20px;
846 height: 20px;
847 }
848
849 /* Add this CSS to your existing stylesheet or create a new one */
850
851 .betterdocs-ai-checkbox-field {
852 position: relative;
853 font-size: 16px;
854 /* Adjust font size as needed */
855 }
856
857 .betterdocs-ai-checkbox-field input[type=checkbox]:checked::before {
858 padding: 2px;
859 }
860
861 .betterdocs-ai-checkbox-field input[type=checkbox] {
862 border: 1px solid #00b884;
863 }
864
865 .betterdocs-ai-checkbox-field input[type=checkbox]:checked::before {
866 content: '\2713';
867 color: #00b884;
868 }
869
870 /* Change the default checkbox color */
871 .betterdocs-ai-checkbox-field input[type="checkbox"]:hover {
872 -webkit-appearance: none;
873 /* WebKit/Blink Browsers */
874 -moz-appearance: none;
875 /* Firefox */
876 appearance: none;
877 border: 1px solid #00b884;
878 /* Set the height of the checkbox */
879 /* Optional: Round the corners */
880 outline: none;
881 /* Remove the default outline */
882 }
883
884 /* Style the checked state */
885 .betterdocs-ai-checkbox-field input[type="checkbox"]:checked {
886 /* Set the background color when checked */
887 border: 1px solid #00b884;
888 /* Set the border color when checked */
889 }
890
891 .checkbox-field-label {
892 width: calc(100% - 150px);
893 }
894
895 .checkbox-field-label p {
896 margin: 0 !important;
897 }
898
899 .checkbox-input-field {
900 width: 300px;
901 text-align: right;
902 }
903
904 .checkbox-input-field {
905 position: relative;
906 display: inline-block;
907 width: 60px;
908 height: 34px;
909 }
910
911 .checkbox-input-field input {
912 display: none;
913 }
914
915 .toggle-label {
916 position: absolute;
917 cursor: pointer;
918 top: 0;
919 left: 0;
920 right: 0;
921 bottom: 0;
922 background-color: #ccc;
923 border-radius: 34px;
924 transition: background-color 0.3s;
925 scale: .9;
926 width: 52px;
927 height: 26px;
928 }
929
930
931 .checkbox-input-field input:checked+.toggle-label {
932 background-color: #00b884;
933 }
934
935 .toggle-label:after {
936 content: "";
937 position: absolute;
938 height: 22px;
939 width: 22px;
940 left: 2px;
941 bottom: 2px;
942 background-color: white;
943 border-radius: 50%;
944 transition: transform 0.3s;
945 }
946
947 .checkbox-input-field input:checked+.toggle-label:after {
948 transform: translateX(26px);
949 }
950
951 .generate-btn,
952 .prompt-btn,
953 .keep-btn {
954 background-color: #00b884;
955 color: #fff;
956 border: none;
957 padding: 10px 15px;
958 text-align: center;
959 text-decoration: none;
960 display: inline-block;
961 font-size: 16px;
962 cursor: pointer;
963 border-radius: 4px;
964 }
965
966 .bd-close-button {
967 cursor: pointer;
968 font-size: 18px;
969 font-weight: bold;
970 float: right;
971 position: absolute;
972 right: 1px;
973 top: 1px;
974 padding: 10px;
975 background: #ffffff;
976 border-radius: 25px;
977 width: 20px;
978 height: 20px;
979 display: flex;
980 align-items: center;
981 justify-content: center;
982 color: #281617;
983 right: -60px;
984 }
985
986 div#betterdocs-ai-error-message,
987 #betterdocs-ai-message {
988 font-size: 14px;
989 font-family: 'IBM Plex Sans', sans-serif;
990 color: #667085;
991 margin-bottom: 20px;
992 }
993
994 div#betterdocs-ai-error-message a,
995 #betterdocs-ai-message a {
996 text-decoration: none;
997 font-weight: 600;
998 }
999
1000 div#betterdocs-ai-error-message a:focus,
1001 #betterdocs-ai-message a:focus {
1002 outline: none;
1003 box-shadow: none;
1004 color: #2271b1;
1005 }
1006
1007 #betterdocs-ai-message span {
1008 color: #d63638;
1009 }
1010
1011 .warning-message {
1012 display: flex;
1013 align-items: center;
1014 gap: 10px;
1015 background: #fbebed;
1016 padding: 12px;
1017 border-radius: 5px;
1018 font-size: 14px;
1019 line-height: 1.4em;
1020 border-left: 4px solid #d63638;
1021 }
1022
1023 .warning-message svg {
1024 width: 20px;
1025 height: 20px;
1026 }
1027
1028 .warning-message span {
1029 color: #d63638;
1030 }
1031
1032 .warning-message .footer-message {
1033 width: calc(100% - 20px);
1034 }
1035
1036 @media only screen and (max-width: 991px) {
1037 .betterdocs-ai-autowrite-form-container {
1038 left: 0;
1039 right: 0;
1040 transform: translate(0%, -50%);
1041 }
1042
1043 .betterdocs-ai-autowrite-form-content {
1044 overflow-x: auto;
1045 }
1046 }
1047
1048 @media only screen and (max-width: 740px) {
1049
1050 /* .bd-close-button {
1051 right: px;
1052 top: 1px;
1053 border-radius: 5px;
1054 width: 12px;
1055 height: 12px;
1056 color: #ffffff;
1057 background: #00b884;
1058 } */
1059 .bd-close-button {
1060 right: 0px;
1061 top: 0px;
1062 width: 12px;
1063 height: 12px;
1064 font-size: 14px;
1065 }
1066
1067 }
1068 </style>
1069 <?php
1070 }
1071 }
1072