Plugin Directory

Changeset 3349746


Ignore:
Timestamp:
08/25/2025 01:54:52 PM (7 months ago)
Author:
ansera01
Message:

Release version 1.1.4

Location:
ansera-search
Files:
3 edited
127 copied

Legend:

Unmodified
Added
Removed
  • ansera-search/tags/1.1.4/ansera_search.php

    r3337395 r3349746  
    33 * Plugin Name: Ansera Search
    44 * Description: Ansera AI-powered search plugin provides answers based on your existing Wordpress content.
    5  * Version: 1.1.3
     5 * Version: 1.1.4
    66 * Author: Ansera.AI
    77 * Author URI:  https://www.ansera.ai/
     
    162162
    163163function ansera_search_send_page_data_to_ansera_on_publish($post_ID, $post = null) {
    164     //error_log("*************************** ansera_search_send_page_data_to_ansera_on_publish: " . $post_ID);
    165164    $sync_status = ansera_check_post_sync_status($post_ID);
    166165    if($sync_status) {
    167         //error_log("***************************if ansera_search_send_page_data_to_ansera_on_publish: " . $post_ID);
    168166        global $wpdb;
    169167        // Update the sync status to 'modified'
     
    184182        }
    185183    }
    186     else{
    187         //error_log("***************************else ansera_search_send_page_data_to_ansera_on_publish: " . $post_ID);
    188     }
    189184}
    190185
    191186function ansera_search_send_media_data_to_ansera_on_update($post_ID, $post = null) { 
    192     //error_log("*************************** ansera_search_send_media_data_to_ansera_on_update: " . $post_ID);
    193187    $sync_status = ansera_check_post_sync_status($post_ID);
    194188    if($sync_status) {
    195         //error_log("***************************if ansera_search_send_media_data_to_ansera_on_update: " . $post_ID);
    196189        ansera_update_media_sync_status($post_ID);//modified
    197190       
     
    200193            do_action('ansera_search_sync_batch_event');
    201194        }
    202     }
    203     else{
    204         //error_log("***************************else ansera_search_send_media_data_to_ansera_on_update: " . $post_ID);
    205195    }
    206196}
     
    496486                $removed_ids_array = $data['removed_ids_array'];
    497487
    498                 //error_log("*************************** removed_ids_array: " . print_r($removed_ids_array, true));
    499                 //error_log("*************************** newly_selected_ids_array: " . print_r($newly_selected_ids_array, true));
    500                 //error_log("*************************** modified_ids_array: " . print_r($modified_ids_array, true));
    501488                global $wpdb;
    502489
     
    524511            }
    525512           
    526             // Only trigger sync if not already in progress
    527             //error_log("*************************** before ansera_search_sync_batch_event");
    528513            if(!get_transient('ansera_search_syn_in_progress')){
    529514                wp_schedule_single_event(time() + 5, 'ansera_search_sync_batch_event');
    530515            }
    531             else{
    532                 //error_log("*************************** ansera_search_syn_in_progress is already set");
    533             }
    534             //error_log("*************************** after ansera_search_sync_batch_event");
    535516           
    536517            wp_send_json_success([ 
     
    563544    $video_title = esc_html($video_title);
    564545
    565     //error_log("video_link: " . $video_link);
    566     //error_log("video_title: " . $video_title);
    567 
    568 
    569546    global $wpdb;
    570547    $table_name = $wpdb->prefix . 'ansera_search_video_links';
    571548
    572     //error_log("video_link: " . $video_link);
    573     //error_log("video_title: " . $video_title);
    574 
    575    
    576             // Insert video link into database
    577         $result = $wpdb->insert(
    578             $table_name,
    579             array(
    580                 'video_url' => $video_link,
    581                 'video_title' => $video_title,
    582                 'sync_status' => 'new'
    583             ),
    584             array('%s', '%s', '%s')
    585         );
     549    $result = $wpdb->insert(
     550        $table_name,
     551        array(
     552            'video_url' => $video_link,
     553            'video_title' => $video_title,
     554            'sync_status' => 'new'
     555        ),
     556        array('%s', '%s', '%s')
     557    );
    586558
    587559    if ($result === false) {
     
    709681    // Check if video sync is already in progress
    710682    if (get_transient('ansera_video_sync_in_progress')) {
    711         //error_log("Video sync already in progress, skipping new sync request");
     683        // Video sync already in progress, skipping new sync request
    712684        return;
    713685    }
     
    728700    }
    729701   
    730     //error_log("Video sync batch scheduled for processing");
    731702}
    732703
     
    734705    global $wpdb;
    735706    $table_name = $wpdb->prefix . 'ansera_search_video_links';
    736    
    737707    try {
    738708        // Get up to 10 videos with 'new' or 'error' status, ordered by ID
     
    747717       
    748718        if (empty($new_videos)) {
    749             //error_log("No more videos with 'new' status found for sync");
     719            // No more videos with 'new' status found for sync;
    750720            // Clear the transient since we're done
    751721            delete_transient('ansera_video_sync_in_progress');
    752722            return;
    753723        }
    754        
    755         //error_log("Processing batch of " . count($new_videos) . " videos");
    756724       
    757725        $processed_count = 0;
     
    770738                );
    771739               
     740                //$media_type = (false == strpos($video['video_url'], 'youtube')) ? "document" : "video";
     741                $media_type = "document";
    772742                $page_id = 'vid_' . $video_id;
     743
    773744                $video_data = [
    774745                    'media_data' => '',
    775746                    'url' => $video['video_url'],
    776747                    'page_title' => $video['video_title'],
    777                     'page_id' => $page_id,
    778                     'page_type' => 'video'
     748                    'page_id' => $page_id
    779749                ];
    780750               
     
    783753                // Fire-and-forget approach - don't wait for response
    784754                // Use a very short timeout (2 seconds) just to ensure the request is sent
    785                 $response = wp_remote_request( esc_url(get_option("ansera_search_host_url") . '/api/media-content'), array(
     755                $response = wp_remote_request(esc_url(get_option("ansera_search_host_url") . '/api/media-content'), array(
    786756                    'method'  => 'POST',
    787757                    'headers' => $headers,
    788758                    'body'    => wp_json_encode( $video_data ),
    789                     'timeout' => 2, // Very short timeout - just to send the request
    790                     'blocking' => false, // Non-blocking request
     759                    'timeout' => 2,
     760                    'blocking' => false
    791761                ) );
    792                
    793762                // Since we're using fire-and-forget, we assume the request was sent successfully
    794763                // The backend will process the video asynchronously
     
    801770               
    802771            } catch (Exception $e) {
    803                 //error_log("Error processing video $video_id: " . $e->getMessage());
    804772                // Mark this video as error and continue with next video
    805773                $wpdb->update(
     
    814782        }
    815783       
    816         //error_log("Batch completed: $processed_count videos sent to backend for processing");
    817784       
    818785        // Check if there are more videos to process (including error videos for retry)
    819786        $remaining_count = $wpdb->get_var("SELECT COUNT(*) FROM $table_name WHERE sync_status IN ('new', 'error')");
    820         //error_log("*************************** inside ansera_search_sync_video_batch");
    821         //error_log("remaining_count: $remaining_count");
    822787        if ($remaining_count > 0) {
    823             //error_log("$remaining_count videos remaining, scheduling next batch");
    824788            // Schedule next batch with a 5-second delay
    825789            if (class_exists('ActionScheduler')) {
     
    833797            }
    834798        } else {
    835             //error_log("All videos sent for processing, clearing sync progress");
    836799            // Clear the transient since we're done sending videos
    837800            delete_transient('ansera_video_sync_in_progress');
     
    839802       
    840803    } catch (Exception $e) {
    841         //error_log("Critical error in video sync batch: " . $e->getMessage());
    842804        // Clear the transient to prevent sync from being stuck
    843805        delete_transient('ansera_video_sync_in_progress');
     
    11401102                                <div style="color: #000; background: none; font-family: inherit; line-height: 1.6; font-size: inherit;">
    11411103                                    <p style="margin-top:10px;">
    1142                                         Sync your external audios and videos with Ansera.
     1104                                        Sync your external documents, audios and videos with Ansera.
    11431105                                    </p>
    11441106                                        <ul>
     1107                                            <li> Documents Supported Formats: <b>(doc,docx,pdf,ppt,pptx,xls,xlsx) </b></li>
    11451108                                            <li> Audio Supported Formats: <b>(mp3,m4a,ogg,wav,wma) </b></li>
    11461109                                            <li> Video Supported Formats: <b>(mp4,m4v,webm,wmv,ogv) </b></li>
     
    25742537            $current_timeout = $base_timeout * pow(2, $attempt - 1); // Exponential backoff: 30s, 60s, 120s
    25752538           
    2576             //error_log("Ansera sync attempt $attempt for post $post_id with timeout {$current_timeout}s");
    2577            
    25782539            $response = wp_remote_post($url, array(
    25792540                'body'    => wp_json_encode($json),
     
    25822543            ));
    25832544
    2584             //error_log("************************start*************************");
    2585             //error_log("Request: " . $post_id);
    2586             //error_log("url: " . wp_json_encode($json));
    2587             //error_log("*************************************************");
    2588             ////error_log("Response: " . print_r($response['body'], true));
    2589             //error_log("************************end*************************");
    2590            
    25912545            if (is_wp_error($response)) {
    25922546                // Safely get error message with fallback
     
    26002554                // Check if it's a timeout error
    26012555                if (strpos($error_message, 'timeout') !== false || strpos($error_message, 'cURL error 28') !== false) {
    2602                     //error_log("Timeout on attempt $attempt for post $post_id: $error_message");
    2603                    
    26042556                    if ($attempt < $max_retries) {
    26052557                        // Wait before retry (exponential backoff)
    26062558                        $wait_time = min(30, pow(2, $attempt)); // Cap at 30 seconds
    2607                         //error_log("Waiting {$wait_time}s before retry for post $post_id");
    26082559                        sleep($wait_time);
    26092560                        continue;
     
    26292580                if ($status_code == 200) {
    26302581                    update_option(ANSERA_SEARCH_SYNC_COUNT, 1);
    2631                     //error_log("Successfully synced post $post_id on attempt $attempt");
    26322582                    return true;
    26332583                } else {
     
    26442594       
    26452595    } catch (Exception $e) {
    2646         //error_log("Exception in ansera_search_send_synchronous_request for post $post_id: " . $e->getMessage());
    26472596        ansera_search_mark_post_as_synced_with_status($post_id, 'error', "Exception: " . $e->getMessage());
    26482597        return false;
     
    26522601function ansera_search_send_post_to_rag($post)
    26532602{
    2654     //error_log("*************************** inside ansera_search_send_post_to_rag");
    26552603    if (empty($post->page_title)) {
    26562604        ansera_search_mark_post_as_synced_with_status($post->ID, 'error',"Post ID: " . $post->ID . " is missing data(title or web_data). Skipping...");
     
    26892637function ansera_search_send_media_file_to_rag($post)
    26902638{
    2691     //error_log("*************************** inside ansera_search_send_media_file_to_rag");
    26922639    try {
    26932640        $post_id = $post->ID;
     
    27502697        }
    27512698        catch(Exception $e){
    2752             //error_log("*************************** inside ansera_search_send_media_file_to_rag exception");
     2699           
    27532700        }
    27542701    return true;
     
    27572704function ansera_search_sync_data_with_rag()
    27582705{
    2759     //error_log("*************************** inside ansera_search_sync_data_with_rag");
    27602706    // Check if sync is already in progress to prevent overlap
    27612707    if (get_transient('ansera_search_syn_in_progress')) {
     
    27632709        $lock_time = get_transient('ansera_search_syn_in_progress_time');
    27642710        if ($lock_time && (time() - $lock_time) > 900) { // 15 minutes
    2765             //error_log("Ansera search sync lock is stale, clearing it");
    27662711            delete_transient('ansera_search_syn_in_progress');
    27672712            delete_transient('ansera_search_syn_in_progress_time');
    27682713        } else {
    2769             //error_log("Ansera search sync already in progress, skipping this execution");
     2714            // Ansera search sync already in progress, skipping this execution
    27702715            return;
    27712716        }
     
    27942739                            if($post->post_type == 'attachment')
    27952740                            {
    2796                                 //error_log("*************************** inside ansera_search_send_media_file_to_rag");
    27972741                                ansera_search_send_media_file_to_rag($post);
    27982742                            }
    27992743                            else
    28002744                            {
    2801                                 //error_log("*************************** inside ansera_search_send_post_to_rag");
    28022745                                ansera_search_send_post_to_rag($post);
    28032746                            }
     
    28232766                catch(Exception $e){
    28242767                    ansera_search_mark_post_as_synced_with_status($row->post_id, 'error', "Post-level error: " . $e->getMessage());
    2825                     //error_log("Ansera search sync error: " . $e->getMessage());
    28262768                    continue; // move to next post
    28272769                }
     
    28552797            delete_transient('ansera_search_syn_in_progress');
    28562798            delete_transient('ansera_search_syn_in_progress_time');
    2857             //error_log("Ansera search sync error: " . $e->getMessage());
    28582799        }
    28592800    } else {
     
    29252866    // Prepare video data for API
    29262867    $page_id = 'vid_' . $video_id;
     2868    // $media_type = (false == strpos($video->video_url, 'youtube')) ? "document" : "video";
     2869    $media_type = "document";
    29272870    $video_data = [
    29282871        'media_data' => '',
     
    30963039    delete_transient('ansera_search_syn_in_progress');
    30973040    delete_transient('ansera_search_syn_in_progress_time');
    3098     //error_log("Ansera search sync lock cleared manually");
    30993041}
    31003042
     
    31473089       
    31483090        if ($recent_failures && $recent_failures >= $max_failures) {
    3149             //error_log("Circuit breaker open for $url - too many recent failures");
    31503091            ansera_search_mark_post_as_synced_with_status($post_id, 'new', "Circuit breaker open - will retry later");
    31513092            return false;
     
    31583099        $max_timeout = 120; // Cap at 2 minutes
    31593100        $timeout = min($adaptive_timeout, $max_timeout);
    3160        
    3161         //error_log("Ansera sync for post $post_id with adaptive timeout {$timeout}s (content size: " . round($content_size/1024, 2) . "KB)");
    31623101       
    31633102        $response = wp_remote_post($url, array(
     
    31833122            // Handle different types of errors
    31843123            if (strpos($error_message, 'timeout') !== false || strpos($error_message, 'cURL error 28') !== false) {
    3185                 //error_log("Timeout error for post $post_id: $error_message");
    31863124                ansera_search_mark_post_as_synced_with_status($post_id, 'new', "Timeout - will retry with longer timeout");
    31873125            } elseif (strpos($error_message, 'connection') !== false || strpos($error_message, 'cURL error 7') !== false) {
    3188                 //error_log("Connection error for post $post_id: $error_message");
    31893126                ansera_search_mark_post_as_synced_with_status($post_id, 'new', "Connection error - will retry");
    31903127            } else {
    3191                 //error_log("Other error for post $post_id: $error_message");
    31923128                ansera_search_mark_post_as_synced_with_status($post_id, 'error', $error_message);
    31933129            }
     
    32033139            if ($status_code == 200) {
    32043140                update_option(ANSERA_SEARCH_SYNC_COUNT, 1);
    3205                 //error_log("Successfully synced post $post_id");
    32063141                return true;
    32073142            } else {
     
    32173152       
    32183153    } catch (Exception $e) {
    3219         //error_log("Exception in ansera_search_send_synchronous_request_advanced for post $post_id: " . $e->getMessage());
    32203154        ansera_search_mark_post_as_synced_with_status($post_id, 'error', "Exception: " . $e->getMessage());
    32213155        return false;
     
    33523286        $sync_data_posts = $data['result']['posts'] ?? [];
    33533287        $sync_data_pdfs = $data['result']['media']['pdfs'] ?? [];
    3354         $sync_data_videos = $data['result']['media']['videos'] ?? [];
     3288        $sync_data_videos = $data['result']['media']['documents'] ?? [];
    33553289
    33563290       
     
    34363370
    34373371    foreach ($media_data_array as $media_data) {
    3438         $media_id_string = explode('_', $media_data['video_id'])[1];
     3372        $post_id_arr = explode('_', $media_data['post_id']);
     3373        $media_id_string = isset($post_id_arr[1]) ? $post_id_arr[1] : '';
    34393374        $backend_status = sanitize_text_field($media_data['status'] ?? '');
    34403375        $last_synced = sanitize_text_field($media_data['last_synced'] ?? current_time('mysql'));
  • ansera-search/tags/1.1.4/js/ansera_search_admin_settings.js

    r3337395 r3349746  
    897897    url = url.trim();
    898898    // Accept all YouTube links (with or without protocol/www)
    899     const youtubeRegex = /^(https?:\/\/)?(www\.)?(youtube\.com|youtu\.be)\/.+/i;
     899    // const youtubeRegex = /^(https?:\/\/)?(www\.)?(youtube\.com|youtu\.be)\/.+/i;
     900    const pattern = new RegExp(
     901        '^(https?:\\/\\/)?' +                 // protocol
     902        '((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|' + // domain name
     903        '((\\d{1,3}\\.){3}\\d{1,3}))' +       // OR IP (v4) address
     904        '(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*' +   // port and path
     905        '(\\?[;&a-z\\d%_.~+=-]*)?' +          // query string
     906        '(\\#[-a-z\\d_]*)?$','i'              // fragment locator
     907    );
    900908    // Accept direct video/audio file links (any domain, must end with extension)
    901     const extRegex = /\.((mp3|m4a|ogg|wav|wma|mp4|m4v|webm|wmv|ogv)(\?.*)?)$/i;
    902     return youtubeRegex.test(url) || extRegex.test(url);
     909    const extRegex = /\.((mp3|m4a|ogg|wav|wma|mp4|m4v|webm|wmv|ogv|doc|docx|pdf|ppt|pptx|xls|xlsx|)(\?.*)?)$/i;
     910    return pattern.test(url) || extRegex.test(url);
    903911}
  • ansera-search/tags/1.1.4/readme.txt

    r3337395 r3349746  
    11=== Ansera Search ===
    22Contributors: Ansera01
    3 Tags: search, chatbot, openAI, AI search, chatgpt
     3Tags: ai search, chatbot, search, lead gen, relevance
    44Requires at least: 5.0
    55Tested up to: 6.8
    66Requires PHP: 7.2
    7 Stable tag: 1.1.3
     7Stable tag: 1.1.4
    88License: GPLv2 or later
    99License URI: https://www.gnu.org/licenses/gpl-2.0.html
     
    1212
    1313== Description ==
    14 Ansera Search replaces the default WordPress search with a powerful Generative AI (GenAI)-driven experience.
     14Ansera Search replaces the default WordPress search with an intuitive AI powered answer engine based on your site's existing content.
    1515
    16 Ansera is based off of your site's content so it will only provide responses based off of what you wish to train it on. Ansera solves the issue of visitors leaving in frustration when they can't find answers on your site. Ansera analytics let you see what your users are searching for to help you improve your content and conversion rates. Built on top of OpenAI, it understands your visitors' queries and delivers meaningful, summarized answers—far beyond keyword matches.
     16We all know that when website visitors can't find the answers they're looking for, they will leave in frustration never to return. Traditional website search just returns a list of links for visitors to sort through themselves while most chatbot solutions are annoying and require significant set up.
     17
     18Ansera solves for these issues and more by providing your website visitors with human readable natural language search responses based only on your site's content.
     19
     20Unlike traditional website search tools, Ansera can be up and running in as little as 5 minutes by even the least technical users. Once you install Ansera on your site, all you have to do is select the pages you want to train it to answer on. Additionally, you can link to externally stored content like youtube and vimeo videos or presentations.
     21
     22Ansera's analytics let you see what answers your users are actually seeking and how to improve your content and conversion to better serve them.
    1723
    1824**Features:**
    19 - Human-readable natural language search results 
    20 - AI responses are automatically trained off of your site's content
    21 - Replaces default search seamlessly 
    22 - Real-time sync with your content 
    23 - Customize and edit AI answers 
    24 - Floating search box or menu icon option 
    25 - Built using OpenAI’s advanced language models
    26 - Visitors can email results to themselves 
     25- Out of the box set up while also providing several visual customization options for more advanced users
     26- Human readable natural language search results
     27- Real-time sync that updates answers as site content is updated
     28- User analytics for all search queries
     29- Customizable guiding questions
     30- Visitors can email results to themselves
     31- Integrate a custom lead generation form into the Ansera widget
    2732
    28 Bring conversational AI search to your site in minutes—no code required.
     33Bring conversational AI search to your site in minutes - no coding required!
    2934
    3035== Installation ==
     
    3641== Frequently Asked Questions ==
    3742
    38 = How does the plugin work? = 
    39 The plugin syncs your site content with Ansera's GenAI backend. Users get contextual, summarized results powered by AI.
     43= What is Ansera? =
     44Ansera is an AI-powered tool that transforms WordPress websites into intelligent, conversational platforms. Leveraging the content already on your site, Ansera delivers contextual, summarized answers to visitors that make for a more intuitive and engaging user experience than traditional search or chatbots.
    4045
    41 = Can I customize the AI responses? = 
    42 Yes! We provide you with the option to edit any previously provided answers and ensure new users will receive an updated response.   
     46= Is Ansera a replacement for Search? =
     47Yes, Ansera is an enhanced replacement for search functionality on your wordpress site. Unlike traditional search, however, Ansera doesn’t just return a list of links for visitors to sort through.
     48It provides a natural language response interface for visitors to ask questions and get complete conversational responses
    4349
    44 = Where does the AI model run? = 
    45 Search queries are securely processed via the Ansera backend which is built on OpenAI.
     50= Can Ansera replace my chatbot? =
     51Ansera can be used in addition to or instead of a chatbot. You can configure Ansera to visually appear like a chatbot icon on the page as well as select up to 5 default questions to guide visitors.
     52
     53= What data does Ansera sync with automatically? =
     54Ansera syncs with any pages from your website that you select. You can select or unselect a page at any time; Ansera will update responses accordingly.
     55
     56= What other type of files can Ansera sync with? =
     57In addition to your website content, you can link to externally stored content such as YouTube/Vimeo videos, podcasts, pdfs, and presentations
     58
     59= Can I customize the look of Ansera? =
     60Yes! You can customize almost everything about Ansera from how the widget is displayed to the default questions customers can ask to how Ansera responds to questions that are out of scope.  Ansera’s color scheme will match your Wordpress site theme so you can use it out of the box if you would like.
     61
     62= Is my information being used to train an LLM? =
     63Your information remains local and will not be used to train an LLM or outside resource.
     64
     65= How do you prevent bot traffic? =
     66Ansera integrates with Google reCAPTCHA v3 for invisible spam protection that doesn't interfere with genuine visitor conversations.
     67
     68= What happens when Ansera can’t answer a question? =
     69A customizable message will be shown to the user stating that the question could not be answered. Additionally, you’ll be able to see which questions were not answered. This allows you to either guide your content strategy or train Ansera to train similar questions in the future.
     70
     71= Can I edit the answers Ansera generates? =
     72You can edit answers in the Ansera dashboard. Ansera will learn from the edited responses to answer similar future questions.
     73
     74= What metrics can I see in the Ansera dashboard? =
     75The Ansera dashboard lets you see information such as how many visitors and queries were generated during a certain time period. Additionally, you can see all queries and how users rated the answers they received.
    4676
    4777
     
    6393
    6494== Changelog ==
     95= 1.1.4 =
     96* Added support for external documents syncing (Google Drive or Direct File URLs)
     97* Introduced custom color theme and you can customize the widget UI.
     98* Updated FAQ
    6599
    66100= 1.1.0 =
  • ansera-search/trunk/ansera_search.php

    r3337395 r3349746  
    33 * Plugin Name: Ansera Search
    44 * Description: Ansera AI-powered search plugin provides answers based on your existing Wordpress content.
    5  * Version: 1.1.3
     5 * Version: 1.1.4
    66 * Author: Ansera.AI
    77 * Author URI:  https://www.ansera.ai/
     
    162162
    163163function ansera_search_send_page_data_to_ansera_on_publish($post_ID, $post = null) {
    164     //error_log("*************************** ansera_search_send_page_data_to_ansera_on_publish: " . $post_ID);
    165164    $sync_status = ansera_check_post_sync_status($post_ID);
    166165    if($sync_status) {
    167         //error_log("***************************if ansera_search_send_page_data_to_ansera_on_publish: " . $post_ID);
    168166        global $wpdb;
    169167        // Update the sync status to 'modified'
     
    184182        }
    185183    }
    186     else{
    187         //error_log("***************************else ansera_search_send_page_data_to_ansera_on_publish: " . $post_ID);
    188     }
    189184}
    190185
    191186function ansera_search_send_media_data_to_ansera_on_update($post_ID, $post = null) { 
    192     //error_log("*************************** ansera_search_send_media_data_to_ansera_on_update: " . $post_ID);
    193187    $sync_status = ansera_check_post_sync_status($post_ID);
    194188    if($sync_status) {
    195         //error_log("***************************if ansera_search_send_media_data_to_ansera_on_update: " . $post_ID);
    196189        ansera_update_media_sync_status($post_ID);//modified
    197190       
     
    200193            do_action('ansera_search_sync_batch_event');
    201194        }
    202     }
    203     else{
    204         //error_log("***************************else ansera_search_send_media_data_to_ansera_on_update: " . $post_ID);
    205195    }
    206196}
     
    496486                $removed_ids_array = $data['removed_ids_array'];
    497487
    498                 //error_log("*************************** removed_ids_array: " . print_r($removed_ids_array, true));
    499                 //error_log("*************************** newly_selected_ids_array: " . print_r($newly_selected_ids_array, true));
    500                 //error_log("*************************** modified_ids_array: " . print_r($modified_ids_array, true));
    501488                global $wpdb;
    502489
     
    524511            }
    525512           
    526             // Only trigger sync if not already in progress
    527             //error_log("*************************** before ansera_search_sync_batch_event");
    528513            if(!get_transient('ansera_search_syn_in_progress')){
    529514                wp_schedule_single_event(time() + 5, 'ansera_search_sync_batch_event');
    530515            }
    531             else{
    532                 //error_log("*************************** ansera_search_syn_in_progress is already set");
    533             }
    534             //error_log("*************************** after ansera_search_sync_batch_event");
    535516           
    536517            wp_send_json_success([ 
     
    563544    $video_title = esc_html($video_title);
    564545
    565     //error_log("video_link: " . $video_link);
    566     //error_log("video_title: " . $video_title);
    567 
    568 
    569546    global $wpdb;
    570547    $table_name = $wpdb->prefix . 'ansera_search_video_links';
    571548
    572     //error_log("video_link: " . $video_link);
    573     //error_log("video_title: " . $video_title);
    574 
    575    
    576             // Insert video link into database
    577         $result = $wpdb->insert(
    578             $table_name,
    579             array(
    580                 'video_url' => $video_link,
    581                 'video_title' => $video_title,
    582                 'sync_status' => 'new'
    583             ),
    584             array('%s', '%s', '%s')
    585         );
     549    $result = $wpdb->insert(
     550        $table_name,
     551        array(
     552            'video_url' => $video_link,
     553            'video_title' => $video_title,
     554            'sync_status' => 'new'
     555        ),
     556        array('%s', '%s', '%s')
     557    );
    586558
    587559    if ($result === false) {
     
    709681    // Check if video sync is already in progress
    710682    if (get_transient('ansera_video_sync_in_progress')) {
    711         //error_log("Video sync already in progress, skipping new sync request");
     683        // Video sync already in progress, skipping new sync request
    712684        return;
    713685    }
     
    728700    }
    729701   
    730     //error_log("Video sync batch scheduled for processing");
    731702}
    732703
     
    734705    global $wpdb;
    735706    $table_name = $wpdb->prefix . 'ansera_search_video_links';
    736    
    737707    try {
    738708        // Get up to 10 videos with 'new' or 'error' status, ordered by ID
     
    747717       
    748718        if (empty($new_videos)) {
    749             //error_log("No more videos with 'new' status found for sync");
     719            // No more videos with 'new' status found for sync;
    750720            // Clear the transient since we're done
    751721            delete_transient('ansera_video_sync_in_progress');
    752722            return;
    753723        }
    754        
    755         //error_log("Processing batch of " . count($new_videos) . " videos");
    756724       
    757725        $processed_count = 0;
     
    770738                );
    771739               
     740                //$media_type = (false == strpos($video['video_url'], 'youtube')) ? "document" : "video";
     741                $media_type = "document";
    772742                $page_id = 'vid_' . $video_id;
     743
    773744                $video_data = [
    774745                    'media_data' => '',
    775746                    'url' => $video['video_url'],
    776747                    'page_title' => $video['video_title'],
    777                     'page_id' => $page_id,
    778                     'page_type' => 'video'
     748                    'page_id' => $page_id
    779749                ];
    780750               
     
    783753                // Fire-and-forget approach - don't wait for response
    784754                // Use a very short timeout (2 seconds) just to ensure the request is sent
    785                 $response = wp_remote_request( esc_url(get_option("ansera_search_host_url") . '/api/media-content'), array(
     755                $response = wp_remote_request(esc_url(get_option("ansera_search_host_url") . '/api/media-content'), array(
    786756                    'method'  => 'POST',
    787757                    'headers' => $headers,
    788758                    'body'    => wp_json_encode( $video_data ),
    789                     'timeout' => 2, // Very short timeout - just to send the request
    790                     'blocking' => false, // Non-blocking request
     759                    'timeout' => 2,
     760                    'blocking' => false
    791761                ) );
    792                
    793762                // Since we're using fire-and-forget, we assume the request was sent successfully
    794763                // The backend will process the video asynchronously
     
    801770               
    802771            } catch (Exception $e) {
    803                 //error_log("Error processing video $video_id: " . $e->getMessage());
    804772                // Mark this video as error and continue with next video
    805773                $wpdb->update(
     
    814782        }
    815783       
    816         //error_log("Batch completed: $processed_count videos sent to backend for processing");
    817784       
    818785        // Check if there are more videos to process (including error videos for retry)
    819786        $remaining_count = $wpdb->get_var("SELECT COUNT(*) FROM $table_name WHERE sync_status IN ('new', 'error')");
    820         //error_log("*************************** inside ansera_search_sync_video_batch");
    821         //error_log("remaining_count: $remaining_count");
    822787        if ($remaining_count > 0) {
    823             //error_log("$remaining_count videos remaining, scheduling next batch");
    824788            // Schedule next batch with a 5-second delay
    825789            if (class_exists('ActionScheduler')) {
     
    833797            }
    834798        } else {
    835             //error_log("All videos sent for processing, clearing sync progress");
    836799            // Clear the transient since we're done sending videos
    837800            delete_transient('ansera_video_sync_in_progress');
     
    839802       
    840803    } catch (Exception $e) {
    841         //error_log("Critical error in video sync batch: " . $e->getMessage());
    842804        // Clear the transient to prevent sync from being stuck
    843805        delete_transient('ansera_video_sync_in_progress');
     
    11401102                                <div style="color: #000; background: none; font-family: inherit; line-height: 1.6; font-size: inherit;">
    11411103                                    <p style="margin-top:10px;">
    1142                                         Sync your external audios and videos with Ansera.
     1104                                        Sync your external documents, audios and videos with Ansera.
    11431105                                    </p>
    11441106                                        <ul>
     1107                                            <li> Documents Supported Formats: <b>(doc,docx,pdf,ppt,pptx,xls,xlsx) </b></li>
    11451108                                            <li> Audio Supported Formats: <b>(mp3,m4a,ogg,wav,wma) </b></li>
    11461109                                            <li> Video Supported Formats: <b>(mp4,m4v,webm,wmv,ogv) </b></li>
     
    25742537            $current_timeout = $base_timeout * pow(2, $attempt - 1); // Exponential backoff: 30s, 60s, 120s
    25752538           
    2576             //error_log("Ansera sync attempt $attempt for post $post_id with timeout {$current_timeout}s");
    2577            
    25782539            $response = wp_remote_post($url, array(
    25792540                'body'    => wp_json_encode($json),
     
    25822543            ));
    25832544
    2584             //error_log("************************start*************************");
    2585             //error_log("Request: " . $post_id);
    2586             //error_log("url: " . wp_json_encode($json));
    2587             //error_log("*************************************************");
    2588             ////error_log("Response: " . print_r($response['body'], true));
    2589             //error_log("************************end*************************");
    2590            
    25912545            if (is_wp_error($response)) {
    25922546                // Safely get error message with fallback
     
    26002554                // Check if it's a timeout error
    26012555                if (strpos($error_message, 'timeout') !== false || strpos($error_message, 'cURL error 28') !== false) {
    2602                     //error_log("Timeout on attempt $attempt for post $post_id: $error_message");
    2603                    
    26042556                    if ($attempt < $max_retries) {
    26052557                        // Wait before retry (exponential backoff)
    26062558                        $wait_time = min(30, pow(2, $attempt)); // Cap at 30 seconds
    2607                         //error_log("Waiting {$wait_time}s before retry for post $post_id");
    26082559                        sleep($wait_time);
    26092560                        continue;
     
    26292580                if ($status_code == 200) {
    26302581                    update_option(ANSERA_SEARCH_SYNC_COUNT, 1);
    2631                     //error_log("Successfully synced post $post_id on attempt $attempt");
    26322582                    return true;
    26332583                } else {
     
    26442594       
    26452595    } catch (Exception $e) {
    2646         //error_log("Exception in ansera_search_send_synchronous_request for post $post_id: " . $e->getMessage());
    26472596        ansera_search_mark_post_as_synced_with_status($post_id, 'error', "Exception: " . $e->getMessage());
    26482597        return false;
     
    26522601function ansera_search_send_post_to_rag($post)
    26532602{
    2654     //error_log("*************************** inside ansera_search_send_post_to_rag");
    26552603    if (empty($post->page_title)) {
    26562604        ansera_search_mark_post_as_synced_with_status($post->ID, 'error',"Post ID: " . $post->ID . " is missing data(title or web_data). Skipping...");
     
    26892637function ansera_search_send_media_file_to_rag($post)
    26902638{
    2691     //error_log("*************************** inside ansera_search_send_media_file_to_rag");
    26922639    try {
    26932640        $post_id = $post->ID;
     
    27502697        }
    27512698        catch(Exception $e){
    2752             //error_log("*************************** inside ansera_search_send_media_file_to_rag exception");
     2699           
    27532700        }
    27542701    return true;
     
    27572704function ansera_search_sync_data_with_rag()
    27582705{
    2759     //error_log("*************************** inside ansera_search_sync_data_with_rag");
    27602706    // Check if sync is already in progress to prevent overlap
    27612707    if (get_transient('ansera_search_syn_in_progress')) {
     
    27632709        $lock_time = get_transient('ansera_search_syn_in_progress_time');
    27642710        if ($lock_time && (time() - $lock_time) > 900) { // 15 minutes
    2765             //error_log("Ansera search sync lock is stale, clearing it");
    27662711            delete_transient('ansera_search_syn_in_progress');
    27672712            delete_transient('ansera_search_syn_in_progress_time');
    27682713        } else {
    2769             //error_log("Ansera search sync already in progress, skipping this execution");
     2714            // Ansera search sync already in progress, skipping this execution
    27702715            return;
    27712716        }
     
    27942739                            if($post->post_type == 'attachment')
    27952740                            {
    2796                                 //error_log("*************************** inside ansera_search_send_media_file_to_rag");
    27972741                                ansera_search_send_media_file_to_rag($post);
    27982742                            }
    27992743                            else
    28002744                            {
    2801                                 //error_log("*************************** inside ansera_search_send_post_to_rag");
    28022745                                ansera_search_send_post_to_rag($post);
    28032746                            }
     
    28232766                catch(Exception $e){
    28242767                    ansera_search_mark_post_as_synced_with_status($row->post_id, 'error', "Post-level error: " . $e->getMessage());
    2825                     //error_log("Ansera search sync error: " . $e->getMessage());
    28262768                    continue; // move to next post
    28272769                }
     
    28552797            delete_transient('ansera_search_syn_in_progress');
    28562798            delete_transient('ansera_search_syn_in_progress_time');
    2857             //error_log("Ansera search sync error: " . $e->getMessage());
    28582799        }
    28592800    } else {
     
    29252866    // Prepare video data for API
    29262867    $page_id = 'vid_' . $video_id;
     2868    // $media_type = (false == strpos($video->video_url, 'youtube')) ? "document" : "video";
     2869    $media_type = "document";
    29272870    $video_data = [
    29282871        'media_data' => '',
     
    30963039    delete_transient('ansera_search_syn_in_progress');
    30973040    delete_transient('ansera_search_syn_in_progress_time');
    3098     //error_log("Ansera search sync lock cleared manually");
    30993041}
    31003042
     
    31473089       
    31483090        if ($recent_failures && $recent_failures >= $max_failures) {
    3149             //error_log("Circuit breaker open for $url - too many recent failures");
    31503091            ansera_search_mark_post_as_synced_with_status($post_id, 'new', "Circuit breaker open - will retry later");
    31513092            return false;
     
    31583099        $max_timeout = 120; // Cap at 2 minutes
    31593100        $timeout = min($adaptive_timeout, $max_timeout);
    3160        
    3161         //error_log("Ansera sync for post $post_id with adaptive timeout {$timeout}s (content size: " . round($content_size/1024, 2) . "KB)");
    31623101       
    31633102        $response = wp_remote_post($url, array(
     
    31833122            // Handle different types of errors
    31843123            if (strpos($error_message, 'timeout') !== false || strpos($error_message, 'cURL error 28') !== false) {
    3185                 //error_log("Timeout error for post $post_id: $error_message");
    31863124                ansera_search_mark_post_as_synced_with_status($post_id, 'new', "Timeout - will retry with longer timeout");
    31873125            } elseif (strpos($error_message, 'connection') !== false || strpos($error_message, 'cURL error 7') !== false) {
    3188                 //error_log("Connection error for post $post_id: $error_message");
    31893126                ansera_search_mark_post_as_synced_with_status($post_id, 'new', "Connection error - will retry");
    31903127            } else {
    3191                 //error_log("Other error for post $post_id: $error_message");
    31923128                ansera_search_mark_post_as_synced_with_status($post_id, 'error', $error_message);
    31933129            }
     
    32033139            if ($status_code == 200) {
    32043140                update_option(ANSERA_SEARCH_SYNC_COUNT, 1);
    3205                 //error_log("Successfully synced post $post_id");
    32063141                return true;
    32073142            } else {
     
    32173152       
    32183153    } catch (Exception $e) {
    3219         //error_log("Exception in ansera_search_send_synchronous_request_advanced for post $post_id: " . $e->getMessage());
    32203154        ansera_search_mark_post_as_synced_with_status($post_id, 'error', "Exception: " . $e->getMessage());
    32213155        return false;
     
    33523286        $sync_data_posts = $data['result']['posts'] ?? [];
    33533287        $sync_data_pdfs = $data['result']['media']['pdfs'] ?? [];
    3354         $sync_data_videos = $data['result']['media']['videos'] ?? [];
     3288        $sync_data_videos = $data['result']['media']['documents'] ?? [];
    33553289
    33563290       
     
    34363370
    34373371    foreach ($media_data_array as $media_data) {
    3438         $media_id_string = explode('_', $media_data['video_id'])[1];
     3372        $post_id_arr = explode('_', $media_data['post_id']);
     3373        $media_id_string = isset($post_id_arr[1]) ? $post_id_arr[1] : '';
    34393374        $backend_status = sanitize_text_field($media_data['status'] ?? '');
    34403375        $last_synced = sanitize_text_field($media_data['last_synced'] ?? current_time('mysql'));
  • ansera-search/trunk/js/ansera_search_admin_settings.js

    r3337395 r3349746  
    897897    url = url.trim();
    898898    // Accept all YouTube links (with or without protocol/www)
    899     const youtubeRegex = /^(https?:\/\/)?(www\.)?(youtube\.com|youtu\.be)\/.+/i;
     899    // const youtubeRegex = /^(https?:\/\/)?(www\.)?(youtube\.com|youtu\.be)\/.+/i;
     900    const pattern = new RegExp(
     901        '^(https?:\\/\\/)?' +                 // protocol
     902        '((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|' + // domain name
     903        '((\\d{1,3}\\.){3}\\d{1,3}))' +       // OR IP (v4) address
     904        '(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*' +   // port and path
     905        '(\\?[;&a-z\\d%_.~+=-]*)?' +          // query string
     906        '(\\#[-a-z\\d_]*)?$','i'              // fragment locator
     907    );
    900908    // Accept direct video/audio file links (any domain, must end with extension)
    901     const extRegex = /\.((mp3|m4a|ogg|wav|wma|mp4|m4v|webm|wmv|ogv)(\?.*)?)$/i;
    902     return youtubeRegex.test(url) || extRegex.test(url);
     909    const extRegex = /\.((mp3|m4a|ogg|wav|wma|mp4|m4v|webm|wmv|ogv|doc|docx|pdf|ppt|pptx|xls|xlsx|)(\?.*)?)$/i;
     910    return pattern.test(url) || extRegex.test(url);
    903911}
  • ansera-search/trunk/readme.txt

    r3337395 r3349746  
    11=== Ansera Search ===
    22Contributors: Ansera01
    3 Tags: search, chatbot, openAI, AI search, chatgpt
     3Tags: ai search, chatbot, search, lead gen, relevance
    44Requires at least: 5.0
    55Tested up to: 6.8
    66Requires PHP: 7.2
    7 Stable tag: 1.1.3
     7Stable tag: 1.1.4
    88License: GPLv2 or later
    99License URI: https://www.gnu.org/licenses/gpl-2.0.html
     
    1212
    1313== Description ==
    14 Ansera Search replaces the default WordPress search with a powerful Generative AI (GenAI)-driven experience.
     14Ansera Search replaces the default WordPress search with an intuitive AI powered answer engine based on your site's existing content.
    1515
    16 Ansera is based off of your site's content so it will only provide responses based off of what you wish to train it on. Ansera solves the issue of visitors leaving in frustration when they can't find answers on your site. Ansera analytics let you see what your users are searching for to help you improve your content and conversion rates. Built on top of OpenAI, it understands your visitors' queries and delivers meaningful, summarized answers—far beyond keyword matches.
     16We all know that when website visitors can't find the answers they're looking for, they will leave in frustration never to return. Traditional website search just returns a list of links for visitors to sort through themselves while most chatbot solutions are annoying and require significant set up.
     17
     18Ansera solves for these issues and more by providing your website visitors with human readable natural language search responses based only on your site's content.
     19
     20Unlike traditional website search tools, Ansera can be up and running in as little as 5 minutes by even the least technical users. Once you install Ansera on your site, all you have to do is select the pages you want to train it to answer on. Additionally, you can link to externally stored content like youtube and vimeo videos or presentations.
     21
     22Ansera's analytics let you see what answers your users are actually seeking and how to improve your content and conversion to better serve them.
    1723
    1824**Features:**
    19 - Human-readable natural language search results 
    20 - AI responses are automatically trained off of your site's content
    21 - Replaces default search seamlessly 
    22 - Real-time sync with your content 
    23 - Customize and edit AI answers 
    24 - Floating search box or menu icon option 
    25 - Built using OpenAI’s advanced language models
    26 - Visitors can email results to themselves 
     25- Out of the box set up while also providing several visual customization options for more advanced users
     26- Human readable natural language search results
     27- Real-time sync that updates answers as site content is updated
     28- User analytics for all search queries
     29- Customizable guiding questions
     30- Visitors can email results to themselves
     31- Integrate a custom lead generation form into the Ansera widget
    2732
    28 Bring conversational AI search to your site in minutes—no code required.
     33Bring conversational AI search to your site in minutes - no coding required!
    2934
    3035== Installation ==
     
    3641== Frequently Asked Questions ==
    3742
    38 = How does the plugin work? = 
    39 The plugin syncs your site content with Ansera's GenAI backend. Users get contextual, summarized results powered by AI.
     43= What is Ansera? =
     44Ansera is an AI-powered tool that transforms WordPress websites into intelligent, conversational platforms. Leveraging the content already on your site, Ansera delivers contextual, summarized answers to visitors that make for a more intuitive and engaging user experience than traditional search or chatbots.
    4045
    41 = Can I customize the AI responses? = 
    42 Yes! We provide you with the option to edit any previously provided answers and ensure new users will receive an updated response.   
     46= Is Ansera a replacement for Search? =
     47Yes, Ansera is an enhanced replacement for search functionality on your wordpress site. Unlike traditional search, however, Ansera doesn’t just return a list of links for visitors to sort through.
     48It provides a natural language response interface for visitors to ask questions and get complete conversational responses
    4349
    44 = Where does the AI model run? = 
    45 Search queries are securely processed via the Ansera backend which is built on OpenAI.
     50= Can Ansera replace my chatbot? =
     51Ansera can be used in addition to or instead of a chatbot. You can configure Ansera to visually appear like a chatbot icon on the page as well as select up to 5 default questions to guide visitors.
     52
     53= What data does Ansera sync with automatically? =
     54Ansera syncs with any pages from your website that you select. You can select or unselect a page at any time; Ansera will update responses accordingly.
     55
     56= What other type of files can Ansera sync with? =
     57In addition to your website content, you can link to externally stored content such as YouTube/Vimeo videos, podcasts, pdfs, and presentations
     58
     59= Can I customize the look of Ansera? =
     60Yes! You can customize almost everything about Ansera from how the widget is displayed to the default questions customers can ask to how Ansera responds to questions that are out of scope.  Ansera’s color scheme will match your Wordpress site theme so you can use it out of the box if you would like.
     61
     62= Is my information being used to train an LLM? =
     63Your information remains local and will not be used to train an LLM or outside resource.
     64
     65= How do you prevent bot traffic? =
     66Ansera integrates with Google reCAPTCHA v3 for invisible spam protection that doesn't interfere with genuine visitor conversations.
     67
     68= What happens when Ansera can’t answer a question? =
     69A customizable message will be shown to the user stating that the question could not be answered. Additionally, you’ll be able to see which questions were not answered. This allows you to either guide your content strategy or train Ansera to train similar questions in the future.
     70
     71= Can I edit the answers Ansera generates? =
     72You can edit answers in the Ansera dashboard. Ansera will learn from the edited responses to answer similar future questions.
     73
     74= What metrics can I see in the Ansera dashboard? =
     75The Ansera dashboard lets you see information such as how many visitors and queries were generated during a certain time period. Additionally, you can see all queries and how users rated the answers they received.
    4676
    4777
     
    6393
    6494== Changelog ==
     95= 1.1.4 =
     96* Added support for external documents syncing (Google Drive or Direct File URLs)
     97* Introduced custom color theme and you can customize the widget UI.
     98* Updated FAQ
    6599
    66100= 1.1.0 =
Note: See TracChangeset for help on using the changeset viewer.