{"id":10435,"date":"2025-06-28T15:36:39","date_gmt":"2025-06-28T14:36:39","guid":{"rendered":"https:\/\/stevepedwards.today\/DebianAdmin\/?p=10435"},"modified":"2025-12-20T11:25:10","modified_gmt":"2025-12-20T16:25:10","slug":"ai-powered-semantic-search-for-wordpress","status":"publish","type":"post","link":"https:\/\/stevepedwards.today\/DebianAdmin\/ai-powered-semantic-search-for-wordpress\/","title":{"rendered":"AI Semantic Search Project Summary &#8211; Local PC Version"},"content":{"rendered":"<div class=\"pvc_clear\"><\/div>\n<p id=\"pvc_stats_10435\" class=\"pvc_stats all  \" data-element-id=\"10435\" style=\"\"><i class=\"pvc-stats-icon medium\" aria-hidden=\"true\"><svg aria-hidden=\"true\" focusable=\"false\" data-prefix=\"far\" data-icon=\"chart-bar\" role=\"img\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" viewBox=\"0 0 512 512\" class=\"svg-inline--fa fa-chart-bar fa-w-16 fa-2x\"><path fill=\"currentColor\" d=\"M396.8 352h22.4c6.4 0 12.8-6.4 12.8-12.8V108.8c0-6.4-6.4-12.8-12.8-12.8h-22.4c-6.4 0-12.8 6.4-12.8 12.8v230.4c0 6.4 6.4 12.8 12.8 12.8zm-192 0h22.4c6.4 0 12.8-6.4 12.8-12.8V140.8c0-6.4-6.4-12.8-12.8-12.8h-22.4c-6.4 0-12.8 6.4-12.8 12.8v198.4c0 6.4 6.4 12.8 12.8 12.8zm96 0h22.4c6.4 0 12.8-6.4 12.8-12.8V204.8c0-6.4-6.4-12.8-12.8-12.8h-22.4c-6.4 0-12.8 6.4-12.8 12.8v134.4c0 6.4 6.4 12.8 12.8 12.8zM496 400H48V80c0-8.84-7.16-16-16-16H16C7.16 64 0 71.16 0 80v336c0 17.67 14.33 32 32 32h464c8.84 0 16-7.16 16-16v-16c0-8.84-7.16-16-16-16zm-387.2-48h22.4c6.4 0 12.8-6.4 12.8-12.8v-70.4c0-6.4-6.4-12.8-12.8-12.8h-22.4c-6.4 0-12.8 6.4-12.8 12.8v70.4c0 6.4 6.4 12.8 12.8 12.8z\" class=\"\"><\/path><\/svg><\/i> <img loading=\"lazy\" decoding=\"async\" width=\"16\" height=\"16\" alt=\"Loading\" src=\"https:\/\/stevepedwards.today\/DebianAdmin\/wp-content\/plugins\/page-views-count\/ajax-loader-2x.gif\" border=0 \/><\/p>\n<div class=\"pvc_clear\"><\/div>\n<p>STOP ALL:<br \/>\nsudo pkill -f \"python3 rag_api_server.py\"; sudo pkill -f \"ollama serve\"; sudo systemctl stop apache2; sudo systemctl stop mysql;<\/p>\n<p>CHECK STATUS:<br \/>\nsudo ps aux | grep -E 'apache2|mysqld|ollama|rag_api_server.py' | grep -v grep<br \/>\nstevee@hplaptop:~$ curl https:\/\/127.0.0.1:11434<br \/>\nOllama is runningstevee@hplaptop:~$<\/p>\n<p>Reason: This command uses ps aux to list all running processes on your system. It then filters that list for common process names associated with your services (Apache, MySQL, Ollama, and your Flask server script) and excludes the grep command itself. If a line appears in the output, that process is still running. If nothing is returned, the process is truly stopped. This is more definitive for crashed\/stuck processes than just checking port listening status.<\/p>\n<p>(venv_ollama_rag)stevee@hplaptop:\/var\/www\/stevee@hplaptop:~$ sudo systemctl is-active ollama<br \/>\n[sudo] password for stevee:<br \/>\nactive<br \/>\nstevee@hplaptop:~$ sudo systemctl is-active apache2<br \/>\nactive<br \/>\nstevee@hplaptop:~$ sudo systemctl is-active mysql.service<br \/>\nactive<\/p>\n<p>START ALL:<\/p>\n<p><span style=\"color: #00ff00;\">cd \/var\/www\/my-llm-project\/ ; source llm_venv\/bin\/activate ;<\/span><br \/>\n<span style=\"color: #00ff00;\">sudo service apache2 start &amp;&gt;\/dev\/null &amp;&amp; echo \"Apache2: $(sudo systemctl is-active apache2 &amp;&amp; echo 'active' || echo 'failed')\";<\/span><br \/>\n<span style=\"color: #00ff00;\">sudo service mysql start &amp;&gt;\/dev\/null &amp;&amp; echo \"MYSQL: $(sudo systemctl is-active mysql &amp;&amp; echo 'active' || echo 'failed')\";<\/span><br \/>\n<span style=\"color: #00ff00;\">sudo systemctl start ollama &amp;&gt;\/dev\/null &amp;&amp; echo \"ollama: $(sudo systemctl is-active ollama || echo 'failed')\" ;<\/span><br \/>\n<span style=\"color: #00ff00;\">sudo lsof -i :11434 2&gt;\/dev\/null | grep \"LISTEN\" ; echo \"Starting Flask server (this will occupy the terminal)...\" ;<\/span><br \/>\n<span style=\"color: #00ff00;\">\/var\/www\/my-llm-project\/llm_venv\/bin\/python semantic_search_api.py<\/span><\/p>\n<p>---------- SUDO CHANGES USER PATHS PERMS!; SO FULL PATH REQUIRED FOR PYTHON ...py files<\/p>\n<p>OUTPUT:<\/p>\n<p>[sudo] password for stevee:<br \/>\nApache2: active<br \/>\nactive<br \/>\nMySQL\/MariaDB: active<br \/>\nactive<br \/>\nOllama: active<br \/>\nactive<br \/>\nStarting Flask server (this will occupy the terminal)...<br \/>\nLoaded 148 embeddings and post data.<br \/>\nGemini model initialized successfully using 'gemini-1.5-flash-latest'.<br \/>\n* Serving Flask app 'semantic_search_api'<br \/>\n* Debug mode: on<br \/>\nWARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.<br \/>\n* Running on all addresses (0.0.0.0)<br \/>\n* Running on https:\/\/127.0.0.1:5000<br \/>\n* Running on https:\/\/stevepedwards.today:5000<br \/>\nPress CTRL+C to quit<br \/>\n* Restarting with stat<br \/>\nLoaded 148 embeddings and post data.<br \/>\nGemini model initialized successfully using 'gemini-1.5-flash-latest'.<br \/>\n* Debugger is active!<br \/>\n* Debugger PIN: 203-532-454<br \/>\n127.0.0.1 - - [06\/Jul\/2025 12:25:51] \"GET \/socket.io\/?EIO=4&amp;transport=polling&amp;t=PVWnS-D HTTP\/1.1\" 200 -<br \/>\nClient connected via WebSocket!<br \/>\n127.0.0.1 - - [06\/Jul\/2025 12:25:51] \"POST \/socket.io\/?EIO=4&amp;transport=polling&amp;t=PVWnTPq&amp;sid=Qou_ABbX6pI_eGBwAAAA HTTP\/1.1\" 200 -<br \/>\n127.0.0.1 - - [06\/Jul\/2025 12:25:51] \"GET \/socket.io\/?EIO=4&amp;transport=polling&amp;t=PVWnTPr&amp;sid=Qou_ABbX6pI_eGBwAAAA HTTP\/1.1\" 200 -<br \/>\n127.0.0.1 - - [06\/Jul\/2025 12:25:51] \"GET \/socket.io\/?EIO=4&amp;transport=polling&amp;t=PVWnTPy&amp;sid=Qou_ABbX6pI_eGBwAAAA HTTP\/1.1\" 200 -<\/p>\n<p>Here's how it works in your startup script:<\/p>\n<ul>\n<li><b><code>sudo systemctl is-active apache2 &amp;&amp; echo 'active' || (sudo service apache2 start &amp;&amp; echo 'restarting\/started') || echo 'failed to start'<\/code><\/b>\n<ul>\n<li><code>sudo systemctl is-active apache2<\/code>: This command checks if Apache2 is active. If it <i>succeeds<\/i> (Apache is active), it returns a zero exit status.<\/li>\n<li><code>&amp;&amp; echo 'active'<\/code>: If <code>is-active<\/code> succeeds, then <code>echo 'active'<\/code> runs, and the rest of the line is skipped because the condition (Apache active) has been met.<\/li>\n<li><code>|| (sudo service apache2 start &amp;&amp; echo 'restarting\/started')<\/code>: If <code>is-active<\/code> <i>fails<\/i> (Apache is not active), then this part executes. It attempts to start Apache, and if <i>that<\/i> succeeds, it prints 'restarting\/started'.<\/li>\n<li><code>|| echo 'failed to start'<\/code>: If <i>both<\/i> <code>is-active<\/code> <i>and<\/i> the <code>start<\/code> command fail, then this last part executes, printing 'failed to start'.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p>So, <code>||<\/code> provides a way to define alternative actions or fallback options if a preceding command doesn't succeed.<\/p>\n<p><span style=\"color: #00ff00;\">Your project seamlessly integrates a local Large Language Model (LLM) with your WordPress website, enabling voice-activated semantic search and AI-powered summarization of your site's content.<\/span><\/p>\n<h3><span style=\"color: #00ff00;\">General Function<\/span><\/h3>\n<p><span style=\"color: #00ff00;\">The system allows users to speak (or type) a query into a search bar on your WordPress site. Instead of a traditional keyword search, it uses a local LLM to understand the <i>meaning<\/i> of the query. This semantic understanding allows it to find the most relevant posts and pages on your site, even if they don't contain the exact keywords. It then displays these results as clickable links, and offers an option to generate an AI-powered summary of the content using an online Gemini model. Real-time feedback on backend processes is shown in a terminal-like display on the webpage.<\/span><\/p>\n<h3><span style=\"color: #00ff00;\">Stages of Construction and Script Roles<\/span><\/h3>\n<p><span style=\"color: #00ff00;\">The project's functionality is built across several interconnected stages, involving WordPress (PHP, MySQL), a Python Flask API, a local Ollama LLM, and browser-side JavaScript and CSS.<\/span><\/p>\n<p><span style=\"color: #00ff00;\"><b>Stage 1: Content Extraction &amp; Embedding Generation<\/b> This is the foundational step where your WordPress content is prepared for semantic understanding.<\/span><\/p>\n<ul>\n<li><span style=\"color: #00ff00;\"><b>Trigger:<\/b> A new Post or Page is added\/updated on your WordPress site.<\/span><\/li>\n<li><span style=\"color: #00ff00;\"><b>Need for Update:<\/b> The LLM system needs to be aware of this new content to include it in future semantic searches.<\/span><\/li>\n<li><span style=\"color: #00ff00;\"><b>Script:<\/b> <code>generate_embeddings.py<\/code><\/span>\n<ul>\n<li><span style=\"color: #00ff00;\"><b>Role:<\/b> This Python script is responsible for:<\/span>\n<ol start=\"1\">\n<li><span style=\"color: #00ff00;\"><b>Connecting to WordPress's MySQL Database:<\/b> It queries your <code>wp_xubg_posts<\/code> table to fetch the <code>ID<\/code>, <code>post_title<\/code>, <code>post_content<\/code>, <code>post_type<\/code>, and <code>post_name<\/code> (slug) of all published posts and pages.<\/span><\/li>\n<li><span style=\"color: #00ff00;\"><b>Cleaning Content:<\/b> It removes HTML tags and WordPress shortcodes from the raw <code>post_content<\/code> to get clean text suitable for the LLM. It also decodes HTML entities.<\/span><\/li>\n<li><span style=\"color: #00ff00;\"><b>Saving Full Post Texts:<\/b> For each cleaned post, it saves the full text into individual <code>.txt<\/code> files in the <code>full_posts_text\/<\/code> directory (e.g., <code>12345.txt<\/code>). Before doing so, it <b>clears the entire <code>full_posts_text\/<\/code> directory<\/b> to ensure only current and published posts are stored, preventing stale data buildup.<\/span><\/li>\n<li><span style=\"color: #00ff00;\"><b>Generating Embeddings:<\/b> For each cleaned post's text, it sends the text to your locally running <b>Ollama server<\/b>, specifically using the <code>nomic-embed-text<\/code> model. Ollama returns a numerical vector (embedding) that represents the semantic meaning of the text.<\/span><\/li>\n<li><span style=\"color: #00ff00;\"><b>Storing Embeddings &amp; Metadata:<\/b> It compiles all this information (Post ID, Title, Slug, Content Snippet, Word Count, and the generated Embedding) into a single JSON file: <code>wordpress_embeddings.json<\/code>.<\/span><\/li>\n<\/ol>\n<\/li>\n<li><span style=\"color: #00ff00;\"><b>Why it runs:<\/b> To create or refresh the \"knowledge base\" (the embeddings) that your semantic search API will use. This must be done whenever WordPress content changes to keep the search accurate.<\/span><\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p><span style=\"color: #00ff00;\"><b>Stage 2: Backend API Server (Semantic Search &amp; Summarization)<\/b> This stage provides the intelligent services that the WordPress frontend will communicate with.<\/span><\/p>\n<ul>\n<li><span style=\"color: #00ff00;\"><b>Trigger:<\/b> Your Flask server needs to be running in the background. It needs to be restarted whenever <code>wordpress_embeddings.json<\/code> is updated or <code>semantic_search_api.py<\/code> itself is changed.<\/span><\/li>\n<li><span style=\"color: #00ff00;\"><b>Script:<\/b> <code>semantic_search_api.py<\/code><\/span>\n<ul>\n<li><span style=\"color: #00ff00;\"><b>Role:<\/b> This Python Flask application acts as the bridge between your WordPress frontend and the LLM services.<\/span>\n<ol start=\"1\">\n<li><span style=\"color: #00ff00;\"><b>Loads Knowledge Base:<\/b> On startup, it reads the <code>wordpress_embeddings.json<\/code> file into memory. It stores all the post metadata and their corresponding embeddings.<\/span><\/li>\n<li><span style=\"color: #00ff00;\"><b>Initializes Ollama Connection:<\/b> Sets up the connection to your local Ollama server to handle embedding requests for search queries.<\/span><\/li>\n<li><span style=\"color: #00ff00;\"><b>Initializes Gemini Connection:<\/b> Configures the connection to the Google Gemini API, specifically using the <code>models\/gemini-1.5-flash-latest<\/code> model for summarization.<\/span><\/li>\n<li><span style=\"color: #00ff00;\"><b>Semantic Search Endpoint (<code>\/semantic_search<\/code>):<\/b> When a search query is received from the frontend:<\/span>\n<ul>\n<li><span style=\"color: #00ff00;\">It sends the user's query to Ollama (using <code>nomic-embed-text<\/code>) to generate an embedding for the query.<\/span><\/li>\n<li><span style=\"color: #00ff00;\">It compares this query embedding to all the stored embeddings from your WordPress posts using cosine similarity.<\/span><\/li>\n<li><span style=\"color: #00ff00;\">It identifies the top 3 most semantically similar posts from your site.<\/span><\/li>\n<li><span style=\"color: #00ff00;\">It returns the metadata (Title, Slug, Word Count, Score, Content Snippet) of these top 3 results to the frontend.<\/span><\/li>\n<\/ul>\n<\/li>\n<li><span style=\"color: #00ff00;\"><b>Summarization Endpoint (<code>\/summarize_article<\/code>):<\/b> When the \"Summarise Article\" button is clicked for a specific post:<\/span>\n<ul>\n<li><span style=\"color: #00ff00;\">It reads the full content of that post from the <code>.txt<\/code> file in <code>full_posts_text\/<\/code>.<\/span><\/li>\n<li><span style=\"color: #00ff00;\">It sends this full content as a prompt to the <b>online Google Gemini API<\/b> (<code>gemini-1.5-flash-latest<\/code>) to generate a concise summary.<\/span><\/li>\n<li><span style=\"color: #00ff00;\">It returns the generated summary back to the frontend.<\/span><\/li>\n<\/ul>\n<\/li>\n<li><span style=\"color: #00ff00;\"><b>Real-time Communication:<\/b> Uses Socket.IO to send real-time progress updates from the backend Python scripts directly to the terminal display on your WordPress page.<\/span><\/li>\n<\/ol>\n<\/li>\n<li><span style=\"color: #00ff00;\"><b>Why it runs:<\/b> It continuously listens for requests from your WordPress site and provides the semantic search and summarization intelligence.<\/span><\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p><span style=\"color: #00ff00;\"><b>Stage 3: Frontend User Interface &amp; Interaction<\/b> This stage handles how users interact with the system on your WordPress site.<\/span><\/p>\n<ul>\n<li><span style=\"color: #00ff00;\"><b>Trigger:<\/b> User visits your WordPress page.<\/span><\/li>\n<li><span style=\"color: #00ff00;\"><b>Scripts:<\/b><\/span>\n<ul>\n<li><span style=\"color: #00ff00;\"><code>my_voice_search.php<\/code> (WordPress Plugin PHP)<\/span>\n<ul>\n<li><span style=\"color: #00ff00;\"><b>Role:<\/b> This WordPress plugin handles the display of the search interface.<\/span>\n<ol start=\"1\">\n<li><span style=\"color: #00ff00;\"><b>Enqueues Assets:<\/b> It loads your <code>style.css<\/code> (for styling), <code>socket.io.min.js<\/code> (for real-time updates), and <code>speech-recognition.js<\/code> (for logic) into your WordPress page.<\/span><\/li>\n<li><span style=\"color: #00ff00;\"><b>Registers Shortcodes:<\/b> It defines two shortcodes:<\/span>\n<ul>\n<li><span style=\"color: #00ff00;\"><code>    <script src=\"https:\/\/cdn.jsdelivr.net\/npm\/socket.io-client@4.7.5\/dist\/socket.io.min.js\"><\/script>\n\n    <div id=\"my-voice-search-container\">\n        <input type=\"text\" id=\"voice-search-input\" placeholder=\"Speak or type your search query...\">\n        <button id=\"voice-search-button\">\ud83c\udfa4 Speak to Search<\/button>\n        <div id=\"voice-search-feedback\"><\/div>\n\n        <div id=\"real-time-output-container\">\n            <h3>Backend Process Output:<\/h3>\n            <pre id=\"real-time-output\"><\/pre>\n        <\/div>\n    <\/div>\n    <\/code>: This shortcode renders the HTML for the <b>voice search input box, microphone button, and a feedback message area<\/b>. Crucially, it also renders the <b>\"Backend Process Output\" terminal display<\/b> directly below the mic input, which shows real-time messages from the Flask server.<\/span><\/li>\n<li><span style=\"color: #00ff00;\"><code>    <div id=\"my-voice-search-results-area\">\n        <h3>Found Semantic Results:<\/h3>\n        <div id=\"voice-search-results\">\n            <p>Your semantic search results will appear here after you speak or type a query.<\/p>\n        <\/div>\n    <\/div>\n    <\/code>: This shortcode renders the HTML container (<code>&lt;div id=\"voice-search-results\"&gt;<\/code>) where the semantic search results (clickable links, snippets, summarize buttons) will be dynamically inserted by JavaScript. It's placed separately on your WordPress page.<\/span><\/li>\n<\/ul>\n<\/li>\n<\/ol>\n<\/li>\n<li><span style=\"color: #00ff00;\"><b>Why it runs:<\/b> It's a WordPress plugin, so it's loaded by WordPress to display the user interface elements on your designated page.<\/span><\/li>\n<\/ul>\n<\/li>\n<li><span style=\"color: #00ff00;\"><code>speech-recognition.js<\/code> (JavaScript)<\/span>\n<ul>\n<li><span style=\"color: #00ff00;\"><b>Role:<\/b> This JavaScript file brings the frontend to life:<\/span>\n<ol start=\"1\">\n<li><span style=\"color: #00ff00;\"><b>Web Speech API Integration:<\/b> It uses the browser's built-in Web Speech API to capture audio from the user's microphone and convert it into text.<\/span><\/li>\n<li><span style=\"color: #00ff00;\"><b>Sends Queries to Flask:<\/b> When a voice input is transcribed (or text is typed into the search box and Enter is pressed), it sends this query via an AJAX POST request to your <code>semantic_search_api.py<\/code>'s <code>\/semantic_search<\/code> endpoint.<\/span><\/li>\n<li><span style=\"color: #00ff00;\"><b>Displays Search Results:<\/b> When it receives the JSON response from Flask (containing the top 3 semantic results, including Post Title, URL Slug, Word Count, and Snippet), it dynamically generates HTML elements for each result and inserts them into the <code>&lt;div id=\"voice-search-results\"&gt;<\/code> on your WordPress page. It correctly formats \"Source: [Post Title]\" and \"Words: [Word Count]\".<\/span><\/li>\n<li><span style=\"color: #00ff00;\"><b>Handles Summarization Requests:<\/b> It listens for clicks on the \"Summarise Article\" buttons. When clicked, it sends a request to Flask's <code>\/summarize_article<\/code> endpoint for that specific post's ID. Upon receiving the summary, it updates the post's snippet text directly on the page.<\/span><\/li>\n<li><span style=\"color: #00ff00;\"><b>Manages Real-time Terminal:<\/b> It uses Socket.IO to connect to your Flask server's WebSocket, receiving <code>progress<\/code> messages and <code>server_message<\/code>s, and appends them to the <code>#real-time-output<\/code> (the terminal display), automatically scrolling to the bottom.<\/span><\/li>\n<\/ol>\n<\/li>\n<li><span style=\"color: #00ff00;\"><b>Why it runs:<\/b> It's the client-side logic that handles user interaction, communicates with the backend, and updates the webpage dynamically.<\/span><\/li>\n<\/ul>\n<\/li>\n<li><span style=\"color: #00ff00;\"><code>style.css<\/code> (CSS)<\/span>\n<ul>\n<li><span style=\"color: #00ff00;\"><b>Role:<\/b> Provides all the visual styling for the search bar, mic button, feedback area, search results, summarization snippets, and the real-time terminal display. It uses <code>!important<\/code> declarations where necessary to ensure its styles override conflicting rules from your WordPress \"Dark Theme,\" ensuring visibility and consistent appearance.<\/span><\/li>\n<li><span style=\"color: #00ff00;\"><b>Why it runs:<\/b> Loaded by <code>my_voice_search.php<\/code> to define the appearance of the plugin's elements.<\/span><\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<h3><span style=\"color: #00ff00;\">Order of Operations for System Update &amp; Use:<\/span><\/h3>\n<ol start=\"1\">\n<li><span style=\"color: #00ff00;\"><b>Local Machine \/ WSL2 Startup:<\/b><\/span>\n<ul>\n<li><span style=\"color: #00ff00;\">You run your combined startup command: <code>sudo service apache2 start &amp;&gt;\/dev\/null; sudo service mysql start &amp;&gt;\/dev\/null; sudo systemctl start ollama &amp;&gt;\/dev\/null; sleep 3; cd \/var\/www\/my-llm-project\/ &amp;&amp; source llm_venv\/bin\/activate &amp;&amp; echo \"Apache2: $(...)\" &amp;&amp; echo \"MySQL\/MariaDB: $(...)\" &amp;&amp; echo \"Ollama: $(...)\" &amp;&amp; echo \"Starting Flask server...\" &amp;&amp; python3 semantic_search_api.py<\/code><\/span><\/li>\n<li><span style=\"color: #00ff00;\"><b>This command first ensures Apache2, MySQL, and Ollama services are running.<\/b> It gives you immediate feedback on their status.<\/span><\/li>\n<li><span style=\"color: #00ff00;\"><b>Then, it activates your <code>llm_venv<\/code> and starts your <code>semantic_search_api.py<\/code> (Flask server) in the foreground.<\/b> This Flask server will load your <code>wordpress_embeddings.json<\/code> and initialize the Gemini model.<\/span><\/li>\n<\/ul>\n<\/li>\n<li><span style=\"color: #00ff00;\"><b>Adding\/Updating WordPress Content (Needs Update of LLM Knowledge Base):<\/b><\/span>\n<ul>\n<li><span style=\"color: #00ff00;\">You add a new Post\/Page or modify existing ones in WordPress.<\/span><\/li>\n<li><span style=\"color: #00ff00;\"><b>You run <code>update_agent.py<\/code>:<\/b> <code>cd \/var\/www\/my-llm-project; source llm_venv\/bin\/activate; python3 update_agent.py<\/code><\/span>\n<ul>\n<li><span style=\"color: #00ff00;\">This script will automatically:<\/span>\n<ul>\n<li><span style=\"color: #00ff00;\">Run <code>generate_embeddings.py<\/code>. This script will connect to MySQL, clear <code>full_posts_text\/<\/code>, extract all current WordPress content, generate new embeddings using Ollama, and save them to <code>wordpress_embeddings.json<\/code>.<\/span><\/li>\n<li><span style=\"color: #00ff00;\">Kill any running Flask process.<\/span><\/li>\n<li><span style=\"color: #00ff00;\">Start a new Flask server (using <code>semantic_search_api.py<\/code>), ensuring it loads the <i>newly generated<\/i> <code>wordpress_embeddings.json<\/code>.<\/span><\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<\/li>\n<li><span style=\"color: #00ff00;\"><b>User Interacts on WordPress Site:<\/b><\/span>\n<ul>\n<li><span style=\"color: #00ff00;\">The user visits your WordPress page.<\/span><\/li>\n<li><span style=\"color: #00ff00;\"><code>my_voice_search.php<\/code> loads the necessary CSS and JavaScript.<\/span><\/li>\n<li><span style=\"color: #00ff00;\">The <code>    <script src=\"https:\/\/cdn.jsdelivr.net\/npm\/socket.io-client@4.7.5\/dist\/socket.io.min.js\"><\/script>\n\n    <div id=\"my-voice-search-container\">\n        <input type=\"text\" id=\"voice-search-input\" placeholder=\"Speak or type your search query...\">\n        <button id=\"voice-search-button\">\ud83c\udfa4 Speak to Search<\/button>\n        <div id=\"voice-search-feedback\"><\/div>\n\n        <div id=\"real-time-output-container\">\n            <h3>Backend Process Output:<\/h3>\n            <pre id=\"real-time-output\"><\/pre>\n        <\/div>\n    <\/div>\n    <\/code> shortcode renders the input field, mic button, and the terminal.<\/span><\/li>\n<li><span style=\"color: #00ff00;\">The <code>    <div id=\"my-voice-search-results-area\">\n        <h3>Found Semantic Results:<\/h3>\n        <div id=\"voice-search-results\">\n            <p>Your semantic search results will appear here after you speak or type a query.<\/p>\n        <\/div>\n    <\/div>\n    <\/code> shortcode renders the container for search results.<\/span><\/li>\n<li><span style=\"color: #00ff00;\">The <code>speech-recognition.js<\/code> script takes over:<\/span>\n<ul>\n<li><span style=\"color: #00ff00;\">Connects to Flask via Socket.IO for real-time terminal updates.<\/span><\/li>\n<li><span style=\"color: #00ff00;\">Enables voice input via the mic button.<\/span><\/li>\n<li><span style=\"color: #00ff00;\">Sends transcribed queries to the Flask <code>semantic_search_api.py<\/code>.<\/span><\/li>\n<li><span style=\"color: #00ff00;\">Receives and displays the top 3 semantic search results from Flask, including the Post Title, Word Count, and Score.<\/span><\/li>\n<li><span style=\"color: #00ff00;\">Manages the \"Summarise Article\" button clicks, sending requests to Flask and displaying the Gemini-generated summaries.<\/span><\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n<p><span style=\"color: #00ff00;\">This comprehensive setup provides a powerful, voice-activated, and AI-enhanced search experience for your WordPress content!<\/span><\/p>\n","protected":false},"excerpt":{"rendered":"<div class=\"pvc_clear\"><\/div>\n<p id=\"pvc_stats_10435\" class=\"pvc_stats all  \" data-element-id=\"10435\" style=\"\"><i class=\"pvc-stats-icon medium\" aria-hidden=\"true\"><svg aria-hidden=\"true\" focusable=\"false\" data-prefix=\"far\" data-icon=\"chart-bar\" role=\"img\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" viewBox=\"0 0 512 512\" class=\"svg-inline--fa fa-chart-bar fa-w-16 fa-2x\"><path fill=\"currentColor\" d=\"M396.8 352h22.4c6.4 0 12.8-6.4 12.8-12.8V108.8c0-6.4-6.4-12.8-12.8-12.8h-22.4c-6.4 0-12.8 6.4-12.8 12.8v230.4c0 6.4 6.4 12.8 12.8 12.8zm-192 0h22.4c6.4 0 12.8-6.4 12.8-12.8V140.8c0-6.4-6.4-12.8-12.8-12.8h-22.4c-6.4 0-12.8 6.4-12.8 12.8v198.4c0 6.4 6.4 12.8 12.8 12.8zm96 0h22.4c6.4 0 12.8-6.4 12.8-12.8V204.8c0-6.4-6.4-12.8-12.8-12.8h-22.4c-6.4 0-12.8 6.4-12.8 12.8v134.4c0 6.4 6.4 12.8 12.8 12.8zM496 400H48V80c0-8.84-7.16-16-16-16H16C7.16 64 0 71.16 0 80v336c0 17.67 14.33 32 32 32h464c8.84 0 16-7.16 16-16v-16c0-8.84-7.16-16-16-16zm-387.2-48h22.4c6.4 0 12.8-6.4 12.8-12.8v-70.4c0-6.4-6.4-12.8-12.8-12.8h-22.4c-6.4 0-12.8 6.4-12.8 12.8v70.4c0 6.4 6.4 12.8 12.8 12.8z\" class=\"\"><\/path><\/svg><\/i> <img loading=\"lazy\" decoding=\"async\" width=\"16\" height=\"16\" alt=\"Loading\" src=\"https:\/\/stevepedwards.today\/DebianAdmin\/wp-content\/plugins\/page-views-count\/ajax-loader-2x.gif\" border=0 \/><\/p>\n<div class=\"pvc_clear\"><\/div>\n<p>STOP ALL: sudo pkill -f \"python3 rag_api_server.py\"; sudo pkill -f \"ollama serve\"; sudo systemctl stop apache2; sudo systemctl stop mysql; CHECK STATUS: sudo ps aux | grep -E 'apache2|mysqld|ollama|rag_api_server.py' | grep -v grep stevee@hplaptop:~$ curl https:\/\/127.0.0.1:11434 Ollama is runningstevee@hplaptop:~$ Reason: This command uses ps aux to list all running processes on your system. It then <a href=\"https:\/\/stevepedwards.today\/DebianAdmin\/ai-powered-semantic-search-for-wordpress\/\" class=\"more-link\">...<span class=\"screen-reader-text\">\u00a0 AI Semantic Search Project Summary &#8211; Local PC Version<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[4],"tags":[],"class_list":["post-10435","post","type-post","status-publish","format-standard","hentry","category-post"],"a3_pvc":{"activated":true,"total_views":5,"today_views":0},"_links":{"self":[{"href":"https:\/\/stevepedwards.today\/DebianAdmin\/wp-json\/wp\/v2\/posts\/10435","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/stevepedwards.today\/DebianAdmin\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/stevepedwards.today\/DebianAdmin\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/stevepedwards.today\/DebianAdmin\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/stevepedwards.today\/DebianAdmin\/wp-json\/wp\/v2\/comments?post=10435"}],"version-history":[{"count":20,"href":"https:\/\/stevepedwards.today\/DebianAdmin\/wp-json\/wp\/v2\/posts\/10435\/revisions"}],"predecessor-version":[{"id":10854,"href":"https:\/\/stevepedwards.today\/DebianAdmin\/wp-json\/wp\/v2\/posts\/10435\/revisions\/10854"}],"wp:attachment":[{"href":"https:\/\/stevepedwards.today\/DebianAdmin\/wp-json\/wp\/v2\/media?parent=10435"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/stevepedwards.today\/DebianAdmin\/wp-json\/wp\/v2\/categories?post=10435"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/stevepedwards.today\/DebianAdmin\/wp-json\/wp\/v2\/tags?post=10435"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}