Plugin Directory

Changeset 3260025


Ignore:
Timestamp:
03/22/2025 10:46:32 AM (10 months ago)
Author:
nachomd
Message:

Improved the quality of generated article content

Location:
easy-gpt-for-wp
Files:
66 added
10 edited

Legend:

Unmodified
Added
Removed
  • easy-gpt-for-wp/trunk/easy-gpt-for-wp.php

    r3257086 r3260025  
    44 * Plugin URI: https://easygptforwp.com/
    55 * Description: Integrates OpenAI GPT functionalities to automatically generate content and manage SEO in WordPress.
    6  * Version: 1.12
     6 * Version: 1.13
    77 * Author: Ignacio Gil Alvarez
    88 * Author URI: https://morris34.com/
     
    1616}
    1717
    18 define('EASY_GPT_PLUGIN_VERSION', '1.10');
     18define('EASY_GPT_PLUGIN_VERSION', '1.13');
    1919
    2020/**
     
    138138      video_position_bulk varchar(50) DEFAULT 'end', -- Nuevo campo
    139139      video_paragraph_bulk int(11) DEFAULT 3, -- Nuevo campo
     140      include_citations_bulk tinyint(1) DEFAULT 0,
     141      final_review_bulk tinyint(1) DEFAULT 0,
     142      minutes_between_articles int(11) DEFAULT 0,
    140143      PRIMARY KEY  (id)
    141144    ) $charset_collate;";
     
    183186        $alter_queries[] = "ADD COLUMN video_paragraph_bulk int(11) DEFAULT 3";
    184187    }
     188   
     189    if (!in_array('include_citations_bulk', $columns)) {
     190        $alter_queries[] = "ADD COLUMN include_citations_bulk tinyint(1) DEFAULT 0";
     191    }
     192    if (!in_array('final_review_bulk', $columns)) {
     193        $alter_queries[] = "ADD COLUMN final_review_bulk tinyint(1) DEFAULT 0";
     194    }
     195
     196    if (!in_array('minutes_between_articles', $columns)) {
     197        $alter_queries[] = "ADD COLUMN minutes_between_articles int(11) DEFAULT 0";
     198    }
    185199
    186200    if (!empty($alter_queries)) {
     
    222236}
    223237add_action('admin_init', 'easy_gpt_check_for_updates');
     238
     239add_action('admin_footer-plugins.php', 'easy_gpt_deactivate_feedback_modal');
     240
     241function easy_gpt_deactivate_feedback_modal() {
     242    ?>
     243    <style>
     244    #easy-gpt-feedback-modal {
     245        position: fixed;
     246        z-index: 9999;
     247        top: 0; left: 0; right: 0; bottom: 0;
     248        background: rgba(0,0,0,0.4);
     249        display: none;
     250        justify-content: center;
     251        align-items: center;
     252    }
     253
     254    #easy-gpt-feedback-modal.show {
     255        display: flex !important;
     256    }
     257
     258    #easy-gpt-feedback-box {
     259        background: #fff;
     260        padding: 24px;
     261        border-radius: 12px;
     262        width: 100%;
     263        max-width: 480px;
     264        box-shadow: 0 8px 24px rgba(0,0,0,0.2);
     265        font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
     266        position: relative;
     267        animation: fadeIn 0.2s ease-in-out;
     268        box-sizing: border-box;
     269    }
     270
     271    #easy-gpt-feedback-box h2 {
     272        margin-top: 0;
     273        font-size: 18px;
     274        margin-bottom: 16px;
     275    }
     276
     277    .easy-gpt-feedback-btn {
     278        display: block;
     279        width: 100%;
     280        margin: 6px 0;
     281        padding: 10px 14px;
     282        border: 1px solid #ccc;
     283        background: #f9f9f9;
     284        border-radius: 6px;
     285        cursor: pointer;
     286        text-align: left;
     287        transition: background 0.2s ease;
     288    }
     289
     290    .easy-gpt-feedback-btn:hover {
     291        background: #eef1f5;
     292    }
     293
     294    #easy-gpt-modal-close {
     295        position: absolute;
     296        top: 10px;
     297        right: 12px;
     298        font-size: 18px;
     299        cursor: pointer;
     300        color: #666;
     301    }
     302
     303    #easy-gpt-modal-close:hover {
     304        color: #000;
     305    }
     306
     307    @keyframes fadeIn {
     308        from { opacity: 0; transform: scale(0.95); }
     309        to { opacity: 1; transform: scale(1); }
     310    }
     311    </style>
     312
     313    <div id="easy-gpt-feedback-modal">
     314        <div id="easy-gpt-feedback-box">
     315            <div id="easy-gpt-modal-close" title="Close">✖️</div>
     316            <h2>Why are you deactivating Easy GPT for WP?</h2>
     317            <p style="font-size: 14px; color: #555; margin-top: -10px; margin-bottom: 16px;">
     318                We value your feedback and may improve based on it.
     319            </p>
     320            <button class="easy-gpt-feedback-btn" data-reason="It's just a temporary deactivation">1️⃣ Temporary deactivation</button>
     321            <button class="easy-gpt-feedback-btn" data-reason="I don't have the API">2️⃣ I don't have the API</button>
     322            <button class="easy-gpt-feedback-btn" data-reason="I don't like the results">3️⃣ I don't like the results</button>
     323            <button class="easy-gpt-feedback-btn" data-reason="I don't want to pay">4️⃣ I don't want to pay</button>
     324            <button class="easy-gpt-feedback-btn" data-reason="It's too expensive">5️⃣ It's too expensive</button>
     325            <button class="easy-gpt-feedback-btn" data-reason="The plugin is too complicated">6️⃣ Too complicated</button>
     326            <button class="easy-gpt-feedback-btn" data-reason="I'm switching to another AI tool">7️⃣ Switching to another AI tool</button>
     327            <button class="easy-gpt-feedback-btn" data-reason="Performance issues (slow, errors, etc.)">8️⃣ Performance issues</button>
     328            <button class="easy-gpt-feedback-btn" data-reason="Other">9️⃣ Other (please specify)</button>
     329        </div>
     330    </div>
     331
     332    <script>
     333    jQuery(document).ready(function($) {
     334        let easyGptDeactivateHref = '';
     335
     336        // Mostrar el modal al hacer clic en desactivar
     337        $(document).on('click', '#deactivate-easy-gpt-for-wp', function(e) {
     338            e.preventDefault();
     339            easyGptDeactivateHref = $(this).attr('href');
     340            $('#easy-gpt-feedback-modal').addClass('show');
     341        });
     342
     343        // Cerrar el modal al hacer clic en ✖️
     344        $(document).on('click', '#easy-gpt-modal-close', function() {
     345            $('#easy-gpt-feedback-modal').removeClass('show');
     346        });
     347
     348        // Enviar feedback
     349        $(document).on('click', '.easy-gpt-feedback-btn', function() {
     350            let reason = $(this).data('reason');
     351
     352            // Preguntar detalles para ciertas opciones
     353            if (reason === 'Other') {
     354                let details = prompt("Please provide more details:");
     355                if (details) {
     356                    reason += " - " + details;
     357                } else {
     358                    return;
     359                }
     360            }
     361
     362            if (reason.includes("Performance issues")) {
     363                let details = prompt("Could you describe the issue you experienced?");
     364                if (details) {
     365                    reason += " - Details: " + details;
     366                }
     367            }
     368
     369
     370            $.post(ajaxurl, {
     371                action: 'easy_gpt_send_uninstall_email',
     372                reason: reason
     373            }, function() {
     374                $('#easy-gpt-feedback-modal').removeClass('show');
     375                setTimeout(function() {
     376                    window.location.href = easyGptDeactivateHref;
     377                }, 50);
     378            });
     379        });
     380    });
     381    </script>
     382    <?php
     383}
     384
     385
     386
     387add_action('wp_ajax_easy_gpt_send_uninstall_email', 'easy_gpt_send_uninstall_email');
     388
     389function easy_gpt_send_uninstall_email() {
     390    if (!isset($_POST['reason'])) {
     391        wp_die();
     392    }
     393
     394    $reason = sanitize_text_field($_POST['reason']);
     395
     396    // Obtener datos del usuario actual
     397    $current_user = wp_get_current_user();
     398    $user_email   = $current_user->user_email;
     399    $user_name    = $current_user->display_name ?: $current_user->user_login;
     400
     401    // Información del sitio
     402    $site_url = get_site_url();
     403
     404    // Datos del correo
     405    $to       = '[email protected]';
     406    $subject  = "📌 Easy GPT – User feedback on plugin deactivation";
     407    $headers  = array('Reply-To: ' . $user_name . ' <' . $user_email . '>');
     408
     409    $message  = "A user is deactivating the Easy GPT for WP plugin.\n\n";
     410    $message .= "🔹 Reason: {$reason}\n";
     411    $message .= "👤 User: {$user_name} ({$user_email})\n";
     412    $message .= "🌐 Site: {$site_url}\n";
     413    $message .= "\n📩 This message was automatically generated.";
     414
     415    wp_mail($to, $subject, $message, $headers);
     416
     417    wp_die();
     418}
     419
     420
    224421?>
  • easy-gpt-for-wp/trunk/includes/bulk-article-processing.php

    r3255349 r3260025  
    698698    $entity_type = ($article_params['content_type'] === 'product') ? "product" : "article";
    699699   
    700     $full_prompt = "Generate an excerpt for a {$entity_type} titled '{$title}' with the following details:\n" .
     700   $full_prompt = "Generate an excerpt for a {$entity_type} titled '{$title}' with the following details:\n" .
    701701                   "Prompt: {$prompt}\n" .
    702702                   "Keywords: {$keywords}\n" .
     
    706706                   "Writing Style: {$writing_style}\n" .
    707707                   "Tone: {$writing_tone}\n" .
    708                    "Maximum Words for the excerpt: 60 words.";
     708                   "Maximum Words for the excerpt: 60 words. Do not include the title in the excerpt.";
    709709
    710710    $response = easy_gpt_call_openai_api_no_session($full_prompt, $model, $temperature, $api_key);
     
    846846    $writing_tone = $article_params['writing_tone'];
    847847    $api_key = get_option('easy_gpt_options')['easy_gpt_api_key'];
     848    $include_citations = isset($article_params['include_citations_bulk']) ? boolval($article_params['include_citations_bulk']) : false;
     849    $final_review = isset($article_params['final_review_bulk']) ? boolval($article_params['final_review_bulk']) : false;
    848850
    849851    $format_article = isset($article_params['format_article']) ? $article_params['format_article'] : false;
     
    851853    $includeLinks = isset($article_params['include_links']) ? $article_params['include_links'] : false;
    852854
    853     $links_instructions = $includeLinks ? " If necessary, you can insert links using <a> tags to justify data or claims, recommendations in the middle of the text, for example, according to a study made by <a> ... </a>, if possible use the name for the link, but do not say for more information." : "";
     855    $links_instructions = $includeLinks ? " You can insert links using <a> tags to justify data or claims, recommendations in the middle of the text, for example, according to a study made by <a> ... </a>, if possible use the name for the link, but do not say for more information." : "";
    854856
    855857    $bibliography_instructions = $includeBibliography
     
    879881
    880882    // Generar la introducción
    881     $intro_prompt = "Generate an introduction for a {$entity_type} titled '{$title}' with the following details, formatted with <p> tags for each paragraph {$format_instructions} (only return the introduction):\n" .
     883    $intro_prompt = "Generate an introduction for a {$entity_type} titled '{$title}' with the following details, formatted with <p> tags for each paragraph{$format_instructions}, do not include the title in the introducction, do not use # or * and <html> tag, (only return the introduction):\n" .
    882884                    "Prompt: {$prompt}\n" .
    883885                    "Keywords: {$keywords}\n" .
     
    924926    }
    925927
    926     $min_words_section = $min_words / max(count($h2_sections), 1);
    927     $max_words_section = $max_words / max(count($h2_sections), 1);
    928 
     928    $min_words_per_section = $min_words / max(count($h2_sections), 1);
     929    $max_words_per_section = $max_words / max(count($h2_sections), 1);
     930
     931    $citation_instructions = $include_citations
     932    ? " and blockquotes (`<i>`) (blockquotes only if necesary) with the autor name (like real) where relevant."
     933    : ".";
     934   
     935    $citation_instructions2 = $include_citations
     936    ? ", blockquotes (with the person of the quote), "
     937    : " "; 
     938     
     939   
     940   
    929941    foreach ($h2_sections as $index => $h2_section) {
     942        error_log("Generando...");
     943       
    930944        $h2_title = array_shift($h2_section);
     945        error_log($h2_title);
    931946        $h3_h4 = implode("\n", $h2_section);
    932947        if (empty($h3_h4)) {
     
    934949        }
    935950
    936 
    937     // Generar la sección
    938     $section_prompt = "Generate a detailed section for the {$entity_type} titled '{$title}'. Include the following details:\n" .
    939                       "Section Title: {$h2_title}\n" .
    940                       "Subheadings:\n{$h3_h4}\n" .
    941                       "Format the {$entity_type} using tags like <h2> for section title, <p> for paragraphs, <h3> <h4> for subheadings, <ul><li> for lists... {$format_instructions}. Do not write <html>.\n" .
    942                       "Prompt: {$prompt}\n" .
    943                       "Keywords: {$keywords}\n" .
    944                       "Specific Instructions: {$specific_instructions_content}\n" .
    945                       "Language: {$language}\n" .
    946                       "Style: {$writing_style}\n" .
    947                       "Tone: {$writing_tone}\n" .
    948                       "Note: This is a section of a larger {$entity_type}. Begin with an introduction (it is an introduction for the section, not a subheading), follow with detailed content under each subheading and do not include conclusions or summaries.\n" .
    949                       "Word Limit: This section should contain at least {$min_words_section} words and no more than {$max_words_section} words. Do not use the symbol #.\n" .
    950                       $links_instructions;
    951 
    952 
    953         $response = easy_gpt_call_openai_api_no_session($section_prompt, $model, $temperature, $api_key);
     951        //error_log("Contenido previo - ". $index . ": ". $previous_content);
     952        $previous_content = implode("\n", $responses); // Unir todo lo generado hasta el momento
     953       
     954
     955$section_prompt = "Continue writing the article about {$entity_type} titled '{$title}', ensuring a smooth transition from the previous sections. Avoid repeating general information already covered.
     956
     957Previously written sections:\n{$previous_content}\n
     958
     959Generate a detailed section with the following details:
     960
     961- Section Title: {$h2_title}
     962- Subheadings: {$h3_h4}
     963- Format: Use proper HTML tags, like <h2> for section titles, <h3>, <h4> for subheadings, <p> for paragraphs, and <ul><li> for lists, and <blockquote> for quotes. {$format_instructions}. 
     964  - Do not use # and <html> tag.
     965  - Important: In the section Apply bold <b> for key concepts, important phrases, and crucial data. 
     966  - Apply italics <i> to scientific terms, foreign words... 
     967  - Incorporate lists (`<ul><li>`){$citation_instructions}
     968  - Ensure these formatting elements appear naturally throughout the entire section, not just in the introduction or conclusion.
     969  - Before introducing any `<h3>` or `<h4>`, ensure there is a short introductory paragraph (2-3 sentences) explaining what will be covered in the subsection.
     970
     971---
     972
     973Refining Introductions and Transitions:
     974* Vary how the section starts: Instead of beginning with a direct statement about the topic, consider alternative openings: 
     975   - Ask a rhetorical question to engage the reader. 
     976   - Use an intriguing fact or statistic to draw attention. 
     977   - Introduce a brief anecdote or historical reference (if relevant). 
     978   - Make a comparison or contrast with another related concept. 
     979*Avoid starting multiple sections or paragraphs with the same noun or phrase. Instead, use synonyms, rephrase, or introduce the idea in a different way. 
     980*Make transitions natural and fluid, do not use always the same, variety
     981*Ensure logical connections between subtopics, so the article flows smoothly rather than feeling fragmented. 
     982
     983---
     984
     985The section must begin with a short, engaging introduction that:
     986   - Do not start by repeating the article’s main topic. 
     987   - Introduce the section in a natural and engaging way to maintain reader interest. 
     988   - Avoid generic phrasing—connect the section to the broader article context. 
     989   - You can use a rhetorical question.
     990
     991Detailed Section Development
     992- Expand each subheading into 2-4 paragraphs. 
     993- Use lists{$citation_instructions2}or tables when appropriate to improve readability. 
     994- Introduce new insights rather than restating previous content. 
     995- Add real-world examples, statistics, or historical context where relevant.
     996- {$links_instructions}
     997
     998---
     999
     1000### Enhancing Readability and Style
     1001- Avoid repetitive sentence structures (e.g., multiple paragraphs starting with the same noun or phrase). 
     1002- If a keyword (singular or plural) appeared in the first 20 words of the last 3 paragraphs, avoid it in the new paragraph.
     1003- Diversify sentence structures: Mix short and long sentences, use subordinate clauses, and include comparisons or rhetorical questions.
     1004- Ensure a smooth, engaging flow that keeps the reader interested. 
     1005- Use proper linking phrases for smooth transitions between subtopics.
     1006
     1007---
     1008
     1009Formatting Consistency
     1010Ensure proper distribution of formatting elements: 
     1011  - Bold (`<b>`) should emphasize key facts, not entire sentences. 
     1012  - Italics (`<i>`) should highlight technical terms and foreign words. 
     1013  - Lists and blockquotes should naturally complement the content, rather than being forced in. 
     1014  - Dont use ** or *, use <b> or <i> insteed
     1015
     1016---
     1017
     1018- Prompt: {$prompt} 
     1019- Keywords: {$keywords} 
     1020- Specific Instructions: {$specific_instructions_content} 
     1021- Language: {$language} 
     1022- Style: {$writing_style} 
     1023- Tone: {$writing_tone} 
     1024
     1025- Do not forget Apply bold <b> for key concepts, important phrases, and crucial data.
     1026- Word Limit: Between {$min_words_per_section} and {$max_words_per_section} words. 
     1027
     1028{$links_instructions}";
     1029
     1030
     1031        //error_log($section_prompt);
     1032
     1033        $response = easy_gpt_call_openai_api_no_session($section_prompt, $model, $temperature, $api_key, $post_id);
    9541034
    9551035        if (!$response) {
    956             return false;
     1036            wp_send_json_error(['message' => "Failed to generate section for '{$h2_title}'"]);
     1037            wp_die();
    9571038        }
    9581039
    9591040        $responses[] = $response['text'];
    960        
     1041
     1042        // Insertar video si la opción es 'random' y esta es la sección seleccionada
    9611043        if (!empty($video_url) && $include_video && $video_position === 'random' && $index === $insert_video_after_section) {
    9621044            $responses[] .= "$video_url";
    9631045        }
    964        
    965     }
    966    
     1046    }
     1047
     1048    // Generar la conclusión
    9671049
    9681050    if (!empty($video_url) && $include_video && $video_position === 'end') {
     
    9701052    }
    9711053
    972     // Generar conclusión
    973     $conclusion_prompt = "Generate a conclusion for a {$entity_type} titled '{$title}' with the following details, formatted with <p> tags for each paragraph {$format_instructions}, give it a <h2> heading:\n" .
    974                          "Prompt: {$prompt}\n" .
    975                          "Keywords: {$keywords}\n" .
    976                          "Language: {$language}\n" .
    977                          "Writing Style: {$writing_style}\n" .
    978                          "Tone: {$writing_tone}\n" .
    979                          "Maximum Words for the conclusion: 200 words.\n" .
    980                          $bibliography_instructions;
    981                      
    982     $conclusion_response = easy_gpt_call_openai_api_no_session($conclusion_prompt, $model, $temperature, $api_key);
     1054    $previous_content = implode("\n", $responses); // Unir todo el contenido generado antes de la conclusión
     1055
     1056    $conclusion_prompt = "Generate a strong conclusion for a {$entity_type} titled '{$title}'. The conclusion should summarize the main insights without repeating detailed information already covered. Ensure a natural and engaging closing statement.
     1057
     1058    Previously written content:\n{$previous_content}\n
     1059
     1060    Consider the key points from this outline: {$outline}. Format the conclusion with <p> tags for each paragraph{$format_instructions}. Provide a <h2> heading that naturally summarizes the key message of the conclusion, avoiding generic titles like 'Conclusion'.\n
     1061
     1062    Prompt: {$prompt}\n
     1063    Keywords: {$keywords}\n
     1064    Language: {$language}\n
     1065    Writing Style: {$writing_style}\n
     1066    Tone: {$writing_tone}\n
     1067    Maximum Words for the conclusion: 200 words.\n
     1068    {$bibliography_instructions}";
     1069
     1070
     1071    $conclusion_response = easy_gpt_call_openai_api_no_session($conclusion_prompt, $model, $temperature, $api_key, $post_id);
    9831072
    9841073    if (!$conclusion_response) {
    985         return false;
     1074        wp_send_json_error(['message' => "Failed to generate conclusion"]);
     1075        wp_die();
    9861076    }
    9871077
    9881078    $responses[] = $conclusion_response['text'];
    9891079
    990     // Manejar la opción 'after_paragraph'
    991     if (!empty($video_url) && $include_video && $video_position === 'after_paragraph') {
    992         $full_article = implode("", $responses);
    993         // Usar preg_split para mantener las etiquetas <p>
    994         $paragraphs = preg_split('/(<p\b[^>]*>.*?<\/p>)/i', $full_article, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
    995 
    996 
    997         error_log("Total paragraphs found: " . count($paragraphs));
    998         error_log("After paragraph number: " . $after_paragraph);
    999 
    1000         // Validar el número de párrafos
    1001         if ($after_paragraph > 0 && $after_paragraph <= count($paragraphs)) {
    1002             // Insertar el video después del párrafo especificado
    1003             // $after_paragraph es 1-based, ajustar a 0-based
    1004             $insert_index = $after_paragraph; // Como cada párrafo está en un índice separado
    1005             if (isset($paragraphs[$insert_index])) {
    1006                 array_splice($paragraphs, $insert_index, 0, "\n<p>{$video_url}</p>\n");
    1007                 error_log("Inserted video after paragraph {$after_paragraph}.");
    1008             } else {
    1009                 // Fallback en caso de que no exista el índice
    1010                 $paragraphs[] = "\n<p>{$video_url}</p>\n";
    1011                 error_log("Paragraph index {$insert_index} not found. Inserted video at the end.");
    1012             }
    1013         } else {
    1014             // Si el número de párrafos es mayor o igual, insertar al final antes de la conclusión
    1015             $paragraphs[] = "\n<p>{$video_url}</p>\n";
    1016             error_log("After paragraph number {$after_paragraph} exceeds paragraph count. Inserted video at the end.");
    1017         }
    1018 
    1019         $full_article = implode("", $paragraphs);
    1020     } else {
    1021         $full_article = implode("", $responses);
    1022     }
     1080
     1081    $full_article = implode("\n", $responses);
     1082
     1083        if ($final_review) {
     1084        // 📌 **Paso adicional: Revisar el artículo después de la conclusión pero antes del video**
     1085        $review_prompt = "Here is a complete article about {$entity_type} titled '{$title}'. Review and refine it to improve coherence, eliminate redundancies, and ensure a more natural flow.
     1086
     1087    Previously written content:\n{$full_article}\n
     1088
     1089    Instructions for Refinement:
     1090    - Each section (H2) must start with a short, engaging introduction (2-3 sentences) if missing.
     1091    - Ensure a logical transition between sections and subheadings (H3, H4).
     1092    - Avoid repetitive sentence structures: Do not start multiple paragraphs with the same noun or phrase.
     1093    - Reword initial sentences to introduce variety while keeping the meaning intact.
     1094    - Do not add new information—only refine and optimize existing content.
     1095    - Summarize the conclusion concisely without repeating details already covered.
     1096    - Use bold (`<b>`) for key concepts, important phrases, and crucial data. 
     1097    - Apply italics (`<i>`) to scientific terms, foreign words... 
     1098    - Use <a> for links
     1099    - If there are ** or * change per <b> or <i> tags
     1100
     1101    Formatting Instructions:
     1102    - Maintain proper structure using <h2> for section titles, <h3> and <h4> for subheadings, <p> for paragraphs, and <ul><li> for lists and  <i> for quotes, {$format_instructions}, do not write <html> tag.
     1103    - If a YouTube URL is present, leave it unchanged.
     1104
     1105    Only return the article
     1106
     1107    Article for Review:
     1108    {$full_article}";
     1109
     1110
     1111        $review_response = easy_gpt_call_openai_api($review_prompt, $model, $temperature, $api_key, $post_id);
     1112
     1113        if (!$review_response) {
     1114            wp_send_json_error(['message' => "Failed to review the article"]);
     1115            wp_die();
     1116        }
     1117
     1118        // Reemplazar el contenido con la versión revisada
     1119        $full_article = $review_response['text'];
     1120    }
     1121
     1122    // 📌 **Solo ahora, insertar el video si corresponde**
     1123    if (!empty($video_url) && $include_video && $video_position === 'after_paragraph') {
     1124        $paragraphs = preg_split('/(<p\b[^>]*>.*?<\/p>)/i', $full_article, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
     1125
     1126        error_log("Total paragraphs found: " . count($paragraphs));
     1127        error_log("After paragraph number: " . $after_paragraph);
     1128
     1129        // Validar el número de párrafos
     1130        if ($after_paragraph > 0 && $after_paragraph <= count($paragraphs)) {
     1131            // Insertar el video después del párrafo especificado
     1132            $insert_index = $after_paragraph;
     1133            if (isset($paragraphs[$insert_index])) {
     1134                array_splice($paragraphs, $insert_index, 0, "\n<p>{$video_url}</p>\n");
     1135                error_log("Inserted video after paragraph {$after_paragraph}.");
     1136            } else {
     1137                $paragraphs[] = "\n<p>{$video_url}</p>\n";
     1138                error_log("Paragraph index {$insert_index} not found. Inserted video at the end.");
     1139            }
     1140        } else {
     1141            $paragraphs[] = "\n<p>{$video_url}</p>\n";
     1142            error_log("After paragraph number {$after_paragraph} exceeds paragraph count. Inserted video at the end.");
     1143        }
     1144
     1145        $full_article = implode("", $paragraphs);
     1146    }
    10231147
    10241148    // Combinar todas las secciones del artículo en una sola variable
  • easy-gpt-for-wp/trunk/includes/bulk-generation.php

    r3253315 r3260025  
    103103$video_position_bulk = isset($options['easy_gpt_video_position']) ? $options['easy_gpt_video_position'] : 'end';
    104104$video_paragraph_bulk = isset($options['easy_gpt_video_paragraph']) ? $options['easy_gpt_video_paragraph'] : 3;
     105$include_citations_bulk = isset($options['easy_gpt_include_citations']) ? $options['easy_gpt_include_citations'] : '0';
     106$final_review_bulk = isset($options['easy_gpt_final_review']) ? $options['easy_gpt_final_review'] : '0';
    105107
    106108
     
    274276                                        <input type="number" id="articles_per_interval" name="articles_per_interval" min="1" value="1">
    275277                                    </div>
     278                                    <div class="easy-gpt-field" id="minutes_between_articles_container" style="display: none;">
     279                                        <label for="minutes_between_articles"><?php esc_html_e( 'Minutes Between Articles:', 'easy-gpt-for-wp' ); ?></label>
     280                                        <input type="number" id="minutes_between_articles" name="minutes_between_articles" min="1" value="30">
     281                                    </div>
    276282                                </div>
    277283                            </div>
     
    327333                    <small><?php esc_html_e( 'Format article with bold and italic text (e.g., bold, italic)', 'easy-gpt-for-wp' ); ?></small>
    328334                </p>
     335                <p class="easy-gpt-field easy-gpt-inline-bold">
     336                    <label for="easy_gpt_include_citations_bulk" class="black-label"><?php esc_html_e( 'Include Citations in Text:', 'easy-gpt-for-wp' ); ?></label>
     337                    <input type="checkbox" id="easy_gpt_include_citations_bulk" name="easy_gpt_include_citations_bulk" <?php checked( $include_citations_bulk, '1' ); ?> class="adjusted-checkbox">
     338                    <small><?php esc_html_e( 'Insert blockquotes with author names when appropriate.', 'easy-gpt-for-wp' ); ?></small>
     339                </p>
    329340                <p class="easy-gpt-field easy-gpt-inline-bold">
    330341                    <label for="easy_gpt_include_links" class="black-label"><?php esc_html_e( 'Automatically Insert Links:', 'easy-gpt-for-wp' ); ?></label>
     
    374385                    <input type="checkbox" id="easy_gpt_include_excerpt" name="easy_gpt_include_excerpt" <?php checked( $include_excerpt ); ?> class="adjusted-checkbox">
    375386                </p>
     387                <p class="easy-gpt-field easy-gpt-inline-bold">
     388                    <label for="easy_gpt_final_review_bulk" class="black-label"><?php esc_html_e( 'Final AI-Based Review:', 'easy-gpt-for-wp' ); ?></label>
     389                    <input type="checkbox" id="easy_gpt_final_review_bulk" name="easy_gpt_final_review_bulk" <?php checked( $final_review_bulk, '1' ); ?> class="adjusted-checkbox">
     390                    <small><?php esc_html_e( 'Run a final AI review to improve coherence and style.', 'easy-gpt-for-wp' ); ?></small>
     391                </p>
    376392                <h3><?php esc_html_e( 'Video Settings', 'easy-gpt-for-wp' ); ?></h3>
    377393               
     
    513529    $data['specific_instructions_excerpt'] = isset($_POST['specific_instructions_excerpt']) ? sanitize_textarea_field(wp_unslash($_POST['specific_instructions_excerpt'])) : '';
    514530    $data['use_same_specific_excerpt_instructions'] = isset($_POST['use_same_specific_excerpt_instructions']) ? intval($_POST['use_same_specific_excerpt_instructions']) : 0;
     531   
    515532   
    516533
     
    553570    $data['video_position_bulk'] = isset($_POST['easy_gpt_video_position_bulk']) ? sanitize_text_field(wp_unslash($_POST['easy_gpt_video_position_bulk'])) : 'end';
    554571    $data['video_paragraph_bulk'] = isset($_POST['easy_gpt_video_paragraph_bulk']) ? intval($_POST['easy_gpt_video_paragraph_bulk']) : 3;
     572
     573$data['include_citations_bulk'] = isset($_POST['easy_gpt_include_citations_bulk']) ? intval($_POST['easy_gpt_include_citations_bulk']) : 0;
     574$data['final_review_bulk'] = isset($_POST['easy_gpt_final_review_bulk']) ? intval($_POST['easy_gpt_final_review_bulk']) : 0;
     575    $data['minutes_between_articles'] = isset($_POST['minutes_between_articles']) ? intval($_POST['minutes_between_articles']) : 0;
     576
     577
     578
     579   
     580    error_log('Valores recibidos para insert (easy_gpt_handle_save_bulk_generation):');
     581foreach ($data as $key => $value) {
     582    error_log("$key => " . var_export($value, true));
     583}
    555584   
    556585    // Inserción en la base de datos
     
    607636        '%s', // video_position_bulk
    608637        '%d', // video_paragraph_bulk
     638        '%d', // include_citations_bulk
     639        '%d',
     640        '%d',
    609641    );
    610642
  • easy-gpt-for-wp/trunk/includes/easy-gpt-bulk-article-generator.php

    r3232882 r3260025  
    8282
    8383        // Calcular las fechas programadas
    84         $scheduled_dates = easy_gpt_calculate_scheduled_dates($start_date, $start_time, $frequency, $num_articles, $articles_per_interval);
     84        $minutes_between_articles = isset($other_params['minutes_between_articles']) ? intval($other_params['minutes_between_articles']) : 0;
     85
     86        $scheduled_dates = easy_gpt_calculate_scheduled_dates($start_date, $start_time, $frequency, $num_articles, $articles_per_interval, $minutes_between_articles);
    8587    }
    8688
     
    163165            'include_videos_bulk' => !empty($other_params['include_videos_bulk']),
    164166            'video_position_bulk' => sanitize_text_field($other_params['video_position_bulk']),
    165             'video_paragraph_bulk' => intval($other_params['video_paragraph_bulk'])
     167            'video_paragraph_bulk' => intval($other_params['video_paragraph_bulk']),
     168            'include_citations_bulk' => !empty($other_params['include_citations_bulk']),
     169            'final_review_bulk' => !empty($other_params['final_review_bulk'])
    166170        ];
    167171
     
    171175}
    172176
    173 function easy_gpt_calculate_scheduled_dates($start_date, $start_time, $frequency, $num_articles, $articles_per_interval) {
     177function easy_gpt_calculate_scheduled_dates($start_date, $start_time, $frequency, $num_articles, $articles_per_interval, $minutes_between) {
    174178    $dates = [];
    175179    $interval_spec = '';
     
    177181    switch ($frequency) {
    178182        case 'daily':
    179             $interval_spec = 'P1D'; // Periodo de 1 día
     183            $interval_spec = 'P1D';
    180184            break;
    181185        case 'weekly':
    182             $interval_spec = 'P1W'; // Periodo de 1 semana
     186            $interval_spec = 'P1W';
    183187            break;
    184188        case 'monthly':
    185             $interval_spec = 'P1M'; // Periodo de 1 mes
     189            $interval_spec = 'P1M';
    186190            break;
    187191        default:
    188             $interval_spec = 'P1D'; // Valor por defecto
     192            $interval_spec = 'P1D';
    189193            break;
    190194    }
    191195
    192196    try {
    193         $current_date = new DateTime($start_date . ' ' . $start_time);
     197        $base_datetime = new DateTime($start_date . ' ' . $start_time);
    194198    } catch (Exception $e) {
    195         $current_date = new DateTime();
     199        $base_datetime = new DateTime();
    196200    }
    197201
     
    199203
    200204    while ($articles_scheduled < $num_articles) {
     205        // Clonar el objeto para evitar modificar la base directamente
     206        $current_datetime = clone $base_datetime;
     207
    201208        for ($i = 0; $i < $articles_per_interval && $articles_scheduled < $num_articles; $i++) {
    202             $dates[] = $current_date->format('Y-m-d H:i:s');
     209            // Agregar minutos solo si es el segundo o posterior artículo del mismo intervalo
     210            if ($i > 0 && $minutes_between > 0) {
     211                $current_datetime->modify("+{$minutes_between} minutes");
     212            }
     213
     214            $dates[] = $current_datetime->format('Y-m-d H:i:s');
    203215            $articles_scheduled++;
    204216        }
    205         $current_date->add(new DateInterval($interval_spec));
     217
     218        // Pasar al siguiente intervalo (día/semana/mes)
     219        $base_datetime->add(new DateInterval($interval_spec));
    206220    }
    207221
    208222    return $dates;
    209223}
     224
    210225
    211226function easy_gpt_enqueue_article_generation_tasks($generation_id, $article_params) {
  • easy-gpt-for-wp/trunk/includes/metaboxes.php

    r3254795 r3260025  
    270270if ($include_links === '') {
    271271    $include_links = isset($options['easy_gpt_include_links']) ? $options['easy_gpt_include_links'] : '0';
     272}
     273   
     274$include_citations = get_post_meta($post->ID, '_easy_gpt_include_citations', true);
     275if ($include_citations === '') {
     276    $include_citations = isset($options['easy_gpt_include_citations']) ? $options['easy_gpt_include_citations'] : '0';
     277}
     278
     279$final_review = get_post_meta($post->ID, '_easy_gpt_final_review', true);
     280if ($final_review === '') {
     281    $final_review = isset($options['easy_gpt_final_review']) ? $options['easy_gpt_final_review'] : '0';
    272282}
    273283
     
    483493                <small><?php esc_html_e( 'Format article with bold and italic text (e.g., bold, italic)', 'easy-gpt-for-wp' ); ?></small>
    484494            </p>
     495            <p class="easy-gpt-field easy-gpt-inline-bold">
     496                <label for="easy_gpt_include_citations" class="black-label"><?php esc_html_e( 'Include Citations in Text:', 'easy-gpt-for-wp' ); ?></label>
     497                <input type="checkbox" id="easy_gpt_include_citations" name="easy_gpt_include_citations" <?php checked( $include_citations ); ?> class="adjusted-checkbox">
     498                <small><?php esc_html_e( 'Insert citations within the body of the article.', 'easy-gpt-for-wp' ); ?></small>
     499            </p>
    485500            <p class="easy-gpt-field easy-gpt-inline-bold">
    486501                <label for="easy_gpt_include_links" class="black-label"><?php esc_html_e( 'Automatically Insert Links:', 'easy-gpt-for-wp' ); ?></label>
     
    530545                <input type="checkbox" id="easy_gpt_include_excerpt" name="easy_gpt_include_excerpt" <?php checked( $include_excerpt ); ?> class="adjusted-checkbox">
    531546            </p>
     547            <p class="easy-gpt-field easy-gpt-inline-bold">
     548                <label for="easy_gpt_final_review" class="black-label"><?php esc_html_e( 'Final AI-Based Review:', 'easy-gpt-for-wp' ); ?></label>
     549                <input type="checkbox" id="easy_gpt_final_review" name="easy_gpt_final_review" <?php checked( $final_review ); ?> class="adjusted-checkbox">
     550                <small><?php esc_html_e( 'Request a final AI-based review for the article (it may correct minor errors in the text but slightly increases the API cost).', 'easy-gpt-for-wp' ); ?></small>
     551            </p>
     552           
    532553            <h3><?php esc_html_e( 'Video Settings', 'easy-gpt-for-wp' ); ?></h3>
    533554       
     
    676697    $new_video_position_per_post = isset($_POST['easy_gpt_video_position_per_post']) ? sanitize_text_field(wp_unslash($_POST['easy_gpt_video_position_per_post'])) : 'end';
    677698    $new_video_paragraph_per_post = isset($_POST['easy_gpt_video_paragraph_per_post']) ? intval($_POST['easy_gpt_video_paragraph_per_post']) : 3;
    678 
     699    $new_include_citations = isset($_POST['easy_gpt_include_citations']) ? '1' : '0';
     700    $new_final_review = isset($_POST['easy_gpt_final_review']) ? '1' : '0';
    679701
    680702    // Actualizar los campos meta en la base de datos.
     
    708730    update_post_meta($post_id, '_easy_gpt_video_position_per_post', $new_video_position_per_post);
    709731    update_post_meta($post_id, '_easy_gpt_video_paragraph_per_post', $new_video_paragraph_per_post);
     732    update_post_meta($post_id, '_easy_gpt_include_citations', $new_include_citations);
     733    update_post_meta($post_id, '_easy_gpt_final_review', $new_final_review);
     734
    710735}
    711736
     
    855880    $after_paragraph = isset($_POST['easy_gpt_video_paragraph_per_post']) ? max(1, intval($_POST['easy_gpt_video_paragraph_per_post'])) : 3;
    856881
     882$include_citations = isset($_POST['easy_gpt_include_citations']) ? '1' : '0';
     883$final_review = isset($_POST['easy_gpt_final_review']) ? '1' : '0';
     884
    857885
    858886    // Construir instrucciones adicionales
    859887    $links_instructions = $includeLinks
    860         ? " If necessary, you can insert links using <a> </a> tags to justify data or claims, recommendations in the middle of the text. For example, 'according to a study made by <a>...'</a>. If possible, use the name for the link, but do not say 'for more information'."
     888        ? " You can insert links using <a> </a> tags to justify data or claims, recommendations in the middle of the text. For example, 'according to a study made by <a>...'</a>. If possible, use the name for the link, but do not say 'for more information'."
    861889        : "";
    862890
     
    881909    $entity_type = $is_product ? "product" : "article";
    882910   
    883     $intro_prompt = "Generate an introduction for a {$entity_type} titled '{$title}' with the following details, formatted with <p> tags for each paragraph{$format_instructions} (only return the introduction):\n" .
     911    $intro_prompt = "Generate an introduction for a {$entity_type} titled '{$title}' with the following details, formatted with <p> tags for each paragraph{$format_instructions}, do not include the title in the introducction, do not use # or * and <html> tag, (only return the introduction):\n" .
    884912                    "Prompt: {$prompt}\n" .
    885913                    "Keywords: {$keywords}\n" .
     
    938966    $max_words_per_section = $num_sections > 0 ? $max_words / $num_sections : $max_words;
    939967
     968
     969   
     970    $citation_instructions = $include_citations
     971    ? " and blockquotes (`<i>`) (blockquotes only if necesary) with the autor name (like real) where relevant."
     972    : ".";
     973   
     974    $citation_instructions2 = $include_citations
     975    ? ", blockquotes (with the person of the quote), "
     976    : " "; 
     977     
     978   
     979   
    940980    foreach ($h2_sections as $index => $h2_section) {
    941981        error_log("Generando...");
     
    948988        }
    949989
    950         $section_prompt = "Generate a detailed section for the {$entity_type} titled '{$title}'. Include the following details:\n" .
    951                   "Section Title: {$h2_title}\n" .
    952                   "Subheadings:\n{$h3_h4}\n" .
    953                   "Format the {$entity_type} using tags, like <h2> for section title, <p> for paragraphs, <h3>, <h4> for subheadings, <ul><li> for lists... {$format_instructions}, do not write <html>.\n" .
    954                   "Prompt: {$prompt}\n" .
    955                   "Keywords: {$keywords}\n" .
    956                   "Specific Instructions: {$specific_instructions_content}\n" .
    957                   "Language: {$language}\n" .
    958                   "Style: {$writing_style}\n" .
    959                   "Tone: {$writing_tone}\n" .
    960                   "Note: This is a section of a larger {$entity_type}. Begin with an introduction (an introduction for the section, not a subheading), follow with detailed content under each subheading, and do not include conclusions or summaries.\n" .
    961                   "Word Limit: This section should contain at least {$min_words_per_section} words and no more than {$max_words_per_section} words. Do not use this symbol #.\n" .
    962                   $links_instructions;
     990        //error_log("Contenido previo - ". $index . ": ". $previous_content);
     991        $previous_content = implode("\n", $responses); // Unir todo lo generado hasta el momento
     992       
     993
     994$section_prompt = "Continue writing the article about {$entity_type} titled '{$title}', ensuring a smooth transition from the previous sections. Avoid repeating general information already covered.
     995
     996Previously written sections:\n{$previous_content}\n
     997
     998Generate a detailed section with the following details:
     999
     1000- Section Title: {$h2_title}
     1001- Subheadings: {$h3_h4}
     1002- Format: Use proper HTML tags, like <h2> for section titles, <h3>, <h4> for subheadings, <p> for paragraphs, and <ul><li> for lists, and <blockquote> for quotes. {$format_instructions}. 
     1003  - Do not use # and <html> tag.
     1004  - Important: In the section Apply bold <b> for key concepts, important phrases, and crucial data. 
     1005  - Apply italics <i> to scientific terms, foreign words... 
     1006  - Incorporate lists (`<ul><li>`){$citation_instructions}
     1007  - Ensure these formatting elements appear naturally throughout the entire section, not just in the introduction or conclusion.
     1008  - Before introducing any `<h3>` or `<h4>`, ensure there is a short introductory paragraph (2-3 sentences) explaining what will be covered in the subsection.
     1009
     1010---
     1011
     1012Refining Introductions and Transitions:
     1013* Vary how the section starts: Instead of beginning with a direct statement about the topic, consider alternative openings: 
     1014   - Ask a rhetorical question to engage the reader. 
     1015   - Use an intriguing fact or statistic to draw attention. 
     1016   - Introduce a brief anecdote or historical reference (if relevant). 
     1017   - Make a comparison or contrast with another related concept. 
     1018*Avoid starting multiple sections or paragraphs with the same noun or phrase. Instead, use synonyms, rephrase, or introduce the idea in a different way. 
     1019*Make transitions natural and fluid, do not use always the same, variety
     1020*Ensure logical connections between subtopics, so the article flows smoothly rather than feeling fragmented. 
     1021
     1022---
     1023
     1024The section must begin with a short, engaging introduction that:
     1025   - Do not start by repeating the article’s main topic. 
     1026   - Introduce the section in a natural and engaging way to maintain reader interest. 
     1027   - Avoid generic phrasing—connect the section to the broader article context. 
     1028   - You can use a rhetorical question.
     1029
     1030Detailed Section Development
     1031- Expand each subheading into 2-4 paragraphs. 
     1032- Use lists{$citation_instructions2}or tables when appropriate to improve readability. 
     1033- Introduce new insights rather than restating previous content. 
     1034- Add real-world examples, statistics, or historical context where relevant. 
     1035- {$links_instructions}
     1036
     1037---
     1038
     1039### Enhancing Readability and Style
     1040- Avoid repetitive sentence structures (e.g., multiple paragraphs starting with the same noun or phrase). 
     1041- If a keyword (singular or plural) appeared in the first 20 words of the last 3 paragraphs, avoid it in the new paragraph.
     1042- Diversify sentence structures: Mix short and long sentences, use subordinate clauses, and include comparisons or rhetorical questions.
     1043- Ensure a smooth, engaging flow that keeps the reader interested. 
     1044- Use proper linking phrases for smooth transitions between subtopics.
     1045
     1046---
     1047
     1048Formatting Consistency
     1049Ensure proper distribution of formatting elements: 
     1050  - Bold (`<b>`) should emphasize key facts, not entire sentences. 
     1051  - Italics (`<i>`) should highlight technical terms and foreign words. 
     1052  - Lists and blockquotes should naturally complement the content, rather than being forced in. 
     1053  - Dont use ** or *, use <b> or <i> insteed
     1054
     1055---
     1056
     1057- Prompt: {$prompt} 
     1058- Keywords: {$keywords} 
     1059- Specific Instructions: {$specific_instructions_content} 
     1060- Language: {$language} 
     1061- Style: {$writing_style} 
     1062- Tone: {$writing_tone} 
     1063
     1064- Do not forget Apply bold <b> for key concepts, important phrases, and crucial data.
     1065- Word Limit: Between {$min_words_per_section} and {$max_words_per_section} words. 
     1066
     1067{$links_instructions}";
     1068
     1069
     1070
     1071        //error_log($section_prompt);
    9631072
    9641073        $response = easy_gpt_call_openai_api($section_prompt, $model, $temperature, $api_key, $post_id);
     
    9831092    }
    9841093
    985     $conclusion_prompt = "Generate a conclusion for a {$entity_type} titled '{$title}' with the following details, formatted with <p> tags for each paragraph{$format_instructions}, give it a <h2> heading:\n" .
    986                      "Prompt: {$prompt}\n" .
    987                      "Keywords: {$keywords}\n" .
    988                      "Language: {$language}\n" .
    989                      "Writing Style: {$writing_style}\n" .
    990                      "Tone: {$writing_tone}\n" .
    991                      "Maximum Words for the conclusion: 200 words.\n" .
    992                      $bibliography_instructions;
     1094    $previous_content = implode("\n", $responses); // Unir todo el contenido generado antes de la conclusión
     1095
     1096    $conclusion_prompt = "Generate a strong conclusion for a {$entity_type} titled '{$title}'. The conclusion should summarize the main insights without repeating detailed information already covered. Ensure a natural and engaging closing statement.
     1097
     1098    Previously written content:\n{$previous_content}\n
     1099
     1100    Consider the key points from this outline: {$outline}. Format the conclusion with <p> tags for each paragraph{$format_instructions}. Provide a <h2> heading that naturally summarizes the key message of the conclusion, avoiding generic titles like 'Conclusion'.\n
     1101
     1102    Prompt: {$prompt}\n
     1103    Keywords: {$keywords}\n
     1104    Language: {$language}\n
     1105    Writing Style: {$writing_style}\n
     1106    Tone: {$writing_tone}\n
     1107    Maximum Words for the conclusion: 200 words.\n
     1108    {$bibliography_instructions}";
    9931109
    9941110
     
    10031119
    10041120
    1005     // Manejar la opción 'after_paragraph'
    1006     if (!empty($video_url) && $include_video && $video_position === 'after_paragraph') {
    1007         $full_article = implode("", $responses);
    1008         // Usar preg_split para mantener las etiquetas <p>
    1009         $paragraphs = preg_split('/(<p\b[^>]*>.*?<\/p>)/i', $full_article, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
    1010 
    1011 
    1012         error_log("Total paragraphs found: " . count($paragraphs));
    1013         error_log("After paragraph number: " . $after_paragraph);
    1014 
    1015         // Validar el número de párrafos
    1016         if ($after_paragraph > 0 && $after_paragraph <= count($paragraphs)) {
    1017             // Insertar el video después del párrafo especificado
    1018             // $after_paragraph es 1-based, ajustar a 0-based
    1019             $insert_index = $after_paragraph; // Como cada párrafo está en un índice separado
    1020             if (isset($paragraphs[$insert_index])) {
    1021                 array_splice($paragraphs, $insert_index, 0, "\n<p>{$video_url}</p>\n");
    1022                 error_log("Inserted video after paragraph {$after_paragraph}.");
    1023             } else {
    1024                 // Fallback en caso de que no exista el índice
    1025                 $paragraphs[] = "\n<p>{$video_url}</p>\n";
    1026                 error_log("Paragraph index {$insert_index} not found. Inserted video at the end.");
    1027             }
    1028         } else {
    1029             // Si el número de párrafos es mayor o igual, insertar al final antes de la conclusión
    1030             $paragraphs[] = "\n<p>{$video_url}</p>\n";
    1031             error_log("After paragraph number {$after_paragraph} exceeds paragraph count. Inserted video at the end.");
    1032         }
    1033 
    1034         $full_article = implode("", $paragraphs);
    1035     } else {
    1036         $full_article = implode("", $responses);
    1037     }
     1121    $full_article = implode("\n", $responses);
     1122
     1123    if ($final_review) {
     1124        // 📌 **Paso adicional: Revisar el artículo después de la conclusión pero antes del video**
     1125        $review_prompt = "Here is a complete article about {$entity_type} titled '{$title}'. Review and refine it to improve coherence, eliminate redundancies, and ensure a more natural flow.
     1126
     1127    Previously written content:\n{$full_article}\n
     1128
     1129    Instructions for Refinement:
     1130    - Each section (H2) must start with a short, engaging introduction (2-3 sentences) if missing.
     1131    - Ensure a logical transition between sections and subheadings (H3, H4).
     1132    - Avoid repetitive sentence structures: Do not start multiple paragraphs with the same noun or phrase.
     1133    - Reword initial sentences to introduce variety while keeping the meaning intact.
     1134    - Do not add new information—only refine and optimize existing content.
     1135    - Summarize the conclusion concisely without repeating details already covered.
     1136    - Use bold (`<b>`) for key concepts, important phrases, and crucial data. 
     1137    - Apply italics (`<i>`) to scientific terms, foreign words...
     1138    - Use <a> for links
     1139    - If there are ** or * change per <b> or <i> tags
     1140
     1141    Formatting Instructions:
     1142    - Maintain proper structure using <h2> for section titles, <h3> and <h4> for subheadings, <p> for paragraphs, and <ul><li> for lists and  <i> for quotes, {$format_instructions}, do not write <html> tag.
     1143    - If a YouTube URL is present, leave it unchanged.
     1144
     1145    Only return the article
     1146
     1147    Article for Review:
     1148    {$full_article}";
     1149
     1150
     1151        $review_response = easy_gpt_call_openai_api($review_prompt, $model, $temperature, $api_key, $post_id);
     1152
     1153        if (!$review_response) {
     1154            wp_send_json_error(['message' => "Failed to review the article"]);
     1155            wp_die();
     1156        }
     1157
     1158        // Reemplazar el contenido con la versión revisada
     1159        $full_article = $review_response['text'];
     1160    }
     1161
     1162    // 📌 **Solo ahora, insertar el video si corresponde**
     1163    if (!empty($video_url) && $include_video && $video_position === 'after_paragraph') {
     1164        $paragraphs = preg_split('/(<p\b[^>]*>.*?<\/p>)/i', $full_article, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
     1165
     1166        error_log("Total paragraphs found: " . count($paragraphs));
     1167        error_log("After paragraph number: " . $after_paragraph);
     1168
     1169        // Validar el número de párrafos
     1170        if ($after_paragraph > 0 && $after_paragraph <= count($paragraphs)) {
     1171            // Insertar el video después del párrafo especificado
     1172            $insert_index = $after_paragraph;
     1173            if (isset($paragraphs[$insert_index])) {
     1174                array_splice($paragraphs, $insert_index, 0, "\n<p>{$video_url}</p>\n");
     1175                error_log("Inserted video after paragraph {$after_paragraph}.");
     1176            } else {
     1177                $paragraphs[] = "\n<p>{$video_url}</p>\n";
     1178                error_log("Paragraph index {$insert_index} not found. Inserted video at the end.");
     1179            }
     1180        } else {
     1181            $paragraphs[] = "\n<p>{$video_url}</p>\n";
     1182            error_log("After paragraph number {$after_paragraph} exceeds paragraph count. Inserted video at the end.");
     1183        }
     1184
     1185        $full_article = implode("", $paragraphs);
     1186    }
    10381187
    10391188    wp_send_json_success([
     
    10801229                   "Writing Style: {$writing_style}\n" .
    10811230                   "Tone: {$writing_tone}\n" .
    1082                    "Maximum Words for the excerpt: 60 words.";
     1231                   "Maximum Words for the excerpt: 60 words. Do not include the title in the excerpt.";
    10831232   
    10841233
     
    17861935
    17871936    // Construir la URL con parámetros mejorados
    1788     $api_url = "https://www.googleapis.com/youtube/v3/search?part=snippet&q={$encoded_query}&type=video&maxResults=3&order=relevance&relevanceLanguage=" . strtolower($language) . "&key={$api_key}";
     1937$api_url = "https://www.googleapis.com/youtube/v3/search?part=snippet&q={$encoded_query}&type=video&maxResults=3&order=relevance&videoDuration=long&relevanceLanguage=" . strtolower($language) . "&key={$api_key}";
    17891938
    17901939    error_log("YouTube API Request: " . urldecode($api_url)); // Log para depuración
  • easy-gpt-for-wp/trunk/includes/settings-functions.php

    r3257086 r3260025  
    136136        'easy_gpt_article_settings_section'
    137137    );
     138   
     139    add_settings_field(
     140        'easy_gpt_include_citations',
     141        'Include Citations in Text',
     142        'easy_gpt_include_citations_render',
     143        'easy-gpt-settings',
     144        'easy_gpt_article_settings_section'
     145    );
    138146
    139147    add_settings_field(
     
    255263        'easy_gpt_article_settings_section'
    256264    );
     265
     266    add_settings_field(
     267        'easy_gpt_final_review',
     268        'Final Review (Optional)',
     269        'easy_gpt_final_review_render',
     270        'easy-gpt-settings',
     271        'easy_gpt_article_settings_section'
     272    );
    257273
    258274    add_settings_field(
     
    705721        'easy_gpt_include_excerpt',
    706722        'easy_gpt_set_featured_image',
     723        'easy_gpt_include_citations',
     724        'easy_gpt_final_review',
    707725    ];
    708726
     
    11901208    echo "<p><small>Set the maximum age (in days) of a comment that will be processed for auto reply (default: 7 days).</small></p>";
    11911209}
     1210
     1211function easy_gpt_include_citations_render() {
     1212    $options = get_option('easy_gpt_options');
     1213    $value = isset($options['easy_gpt_include_citations']) ? $options['easy_gpt_include_citations'] : '0';
     1214    echo "<input type='checkbox' name='easy_gpt_options[easy_gpt_include_citations]' value='1' " . checked($value, '1', false) . ">";
     1215    echo "<small>Check this box to include in-text citations throughout the article.</small>";
     1216}
     1217
     1218function easy_gpt_final_review_render() {
     1219    $options = get_option('easy_gpt_options');
     1220    $value = isset($options['easy_gpt_final_review']) ? $options['easy_gpt_final_review'] : '0';
     1221    echo "<input type='checkbox' name='easy_gpt_options[easy_gpt_final_review]' value='1' " . checked($value, '1', false) . ">";
     1222    echo '<small>' . esc_html__('Request a final AI-based review for the article (it may correct minor errors in the text but slightly increases the API cost).', 'easy-gpt-for-wp') . '</small>';
     1223
     1224}
  • easy-gpt-for-wp/trunk/js/bulk-generation.js

    r3253315 r3260025  
    180180            'easy_gpt_video_position_bulk': $('#easy_gpt_video_position_bulk').val(),
    181181            'easy_gpt_video_paragraph_bulk': $('#easy_gpt_video_paragraph_bulk').val(),
     182            'easy_gpt_include_citations_bulk': $('#easy_gpt_include_citations_bulk').is(':checked') ? 1 : 0,
     183            'easy_gpt_final_review_bulk': $('#easy_gpt_final_review_bulk').is(':checked') ? 1 : 0,
     184            'minutes_between_articles': $('#minutes_between_articles').val(),
    182185        };
    183186
     
    292295
    293296});
     297
     298jQuery(document).ready(function($) {
     299    $('#articles_per_interval').on('input change', function() {
     300        const value = parseInt($(this).val(), 10);
     301        if (value > 1) {
     302            $('#minutes_between_articles_container').slideDown();
     303        } else {
     304            $('#minutes_between_articles_container').slideUp();
     305        }
     306    }).trigger('change'); // Ejecutar una vez al cargar la página
     307});
  • easy-gpt-for-wp/trunk/js/easy-gpt-custom.js

    r3254795 r3260025  
    491491        easy_gpt_include_videos_per_post: include_videos_per_post,
    492492        easy_gpt_video_position_per_post: video_position_per_post,
    493         easy_gpt_video_paragraph_per_post: video_paragraph_per_post
     493        easy_gpt_video_paragraph_per_post: video_paragraph_per_post,
     494        easy_gpt_include_citations: $('#easy_gpt_include_citations').is(':checked') ? '1' : '0',
     495        easy_gpt_final_review: $('#easy_gpt_final_review').is(':checked') ? '1' : '0'
    494496    };
    495497
  • easy-gpt-for-wp/trunk/readme.txt

    r3257086 r3260025  
    55Tested up to: 6.7.2
    66Requires PHP: 7.3
    7 Stable tag: 1.12
     7Stable tag: 1.13
    88License: GPLv2 or later
    99License URI: https://www.gnu.org/licenses/gpl-2.0.html
     
    134134
    135135== Changelog ==
     136= 1.13 =
     137* Improved the quality of generated articles.
     138* Added support for automatic citation inclusion within articles.
     139* Introduced an optional final review step before publishing generated content.
     140* Enhanced batch generation with control over the time interval between same-day articles.
     141* Improved YouTube video selection for better content relevance.
     142
    136143= 1.12 =
    137144* Added AI-powered comment moderation.
Note: See TracChangeset for help on using the changeset viewer.