Changeset 3457513
- Timestamp:
- 02/09/2026 09:59:36 PM (7 weeks ago)
- Location:
- visiblefirst
- Files:
-
- 6 edited
- 1 copied
-
tags/3.2.26 (copied) (copied from visiblefirst/trunk)
-
tags/3.2.26/includes/class-visibl-llms-generator.php (modified) (3 diffs)
-
tags/3.2.26/readme.txt (modified) (3 diffs)
-
tags/3.2.26/visiblefirst.php (modified) (2 diffs)
-
trunk/includes/class-visibl-llms-generator.php (modified) (3 diffs)
-
trunk/readme.txt (modified) (3 diffs)
-
trunk/visiblefirst.php (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
visiblefirst/tags/3.2.26/includes/class-visibl-llms-generator.php
r3457500 r3457513 685 685 } 686 686 687 687 688 /** 688 689 * Phase 2: AI Enhancement 689 690 * 690 * Send crawl data to Claude API for llms.txt generation 691 * Send crawl data to server API for llms.txt generation 692 * NOTE: System prompt is server-side - we only send crawl data 691 693 * 692 694 * @param array $crawl_data Output from Phase 1 … … 694 696 */ 695 697 public static function generate_with_ai($crawl_data) { 696 // Build the system prompt697 $system_prompt = self::get_system_prompt();698 699 698 // Truncate crawl data to fit within token limits 700 699 $truncated_data = self::truncate_crawl_data($crawl_data); 701 700 702 // Build the user message with crawl data 703 $user_message = "Here is the crawl data for {$truncated_data['site_url']}:\n\n" . 704 json_encode($truncated_data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES); 705 706 // Call Claude API via VF AI Gateway 707 $response = Visibl_AI::complete([ 708 'system' => $system_prompt, 709 'prompt' => $user_message, 710 'task' => 'llms_txt_generation', 701 // Build the crawl data JSON 702 $crawl_json = json_encode($truncated_data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES); 703 704 // Call server-side llms-generate endpoint (prompt is server-side) 705 $api_key = Visibl_AI::get_effective_api_key(); 706 707 $request_body = [ 708 'crawl_data' => $crawl_json, 709 'site_url' => home_url(), 710 'site_name' => get_bloginfo('name'), 711 'site_id' => Visibl_Licensing::get_site_id(), 711 712 'model' => 'claude-sonnet', 712 'temperature' => 0, 713 'max_tokens' => 2500, 713 'max_tokens' => 4000, 714 ]; 715 716 $response = wp_remote_post(VISIBL_API_BASE . '/ai/llms-generate', [ 717 'headers' => [ 718 'Content-Type' => 'application/json', 719 'X-API-Key' => $api_key, 720 'X-Site-Domain' => wp_parse_url(home_url(), PHP_URL_HOST), 721 ], 722 'body' => wp_json_encode($request_body), 723 'timeout' => 90, 714 724 ]); 715 725 716 726 if (is_wp_error($response)) { 717 return $response; 718 } 719 720 $content = $response['content'] ?? ''; 727 return new WP_Error('api_error', __('Could not connect to VisibleFirst API.', 'visiblefirst')); 728 } 729 730 $status_code = wp_remote_retrieve_response_code($response); 731 $body = json_decode(wp_remote_retrieve_body($response), true); 732 733 if ($status_code !== 200 || empty($body['success'])) { 734 $error_message = $body['message'] ?? __('Generation failed', 'visiblefirst'); 735 return new WP_Error('generation_failed', $error_message); 736 } 737 738 $content = $body['content'] ?? ''; 721 739 722 740 if (empty($content)) { … … 731 749 } 732 750 733 /**734 * Get the system prompt for Claude735 */736 private static function get_system_prompt() {737 $prompt = 'You are an expert at writing llms.txt files that help AI assistants understand and recommend businesses.' . "\n\n";738 $prompt .= 'You will receive structured data about a website. Generate a complete llms.txt file following the llms.txt specification.' . "\n\n";739 $prompt .= 'RULES:' . "\n";740 $prompt .= '1. ONLY use information from the provided data. Never invent or assume.' . "\n";741 $prompt .= '2. If data is missing, use [PLACEHOLDER: describe what\'s needed] so the user can fill it in.' . "\n";742 $prompt .= '3. The description should answer: "If someone asked an AI to recommend a business like this, what would the AI need to know to recommend THIS one specifically?"' . "\n";743 $prompt .= '4. Include differentiators, not category descriptions.' . "\n";744 $prompt .= ' BAD: "A restaurant in Austin"' . "\n";745 $prompt .= ' GOOD: "Family-owned Tex-Mex restaurant in Austin\'s East Side known for breakfast tacos and house-made salsas since 2015"' . "\n";746 $prompt .= '5. Every page listed must use the EXACT path from the crawl data.' . "\n";747 $prompt .= '6. Group pages logically (Core, Services/Products, Resources, Legal).' . "\n";748 $prompt .= '7. Include a "Recommended Queries" section — example questions a user might ask an AI where this business should appear in the answer.' . "\n\n";749 $prompt .= 'OUTPUT FORMAT (follow exactly):' . "\n";750 $prompt .= '---' . "\n";751 $prompt .= '# {Business Name}' . "\n\n";752 $prompt .= '## About' . "\n";753 $prompt .= '{2-3 sentence description that is SPECIFIC enough to differentiate this business from every competitor. Include: what they do, who they serve, where they operate, and what makes them different.}' . "\n\n";754 $prompt .= '## Specialties' . "\n";755 $prompt .= '{Bullet list of specific services/products/expertise areas}' . "\n\n";756 $prompt .= '## Key Facts' . "\n";757 $prompt .= '- Founded: {year or [PLACEHOLDER: founding year]}' . "\n";758 $prompt .= '- Location: {city, state or [PLACEHOLDER: location]}' . "\n";759 $prompt .= '- Service Area: {local/regional/national/global}' . "\n";760 $prompt .= '- Industry: {specific industry}' . "\n\n";761 $prompt .= '## Key Pages' . "\n\n";762 $prompt .= '### Core' . "\n";763 $prompt .= '{Main pages with path and description - only include pages that exist in crawl data}' . "\n\n";764 $prompt .= '### Services/Products' . "\n";765 $prompt .= '{Service and product pages with descriptions}' . "\n\n";766 $prompt .= '### Resources' . "\n";767 $prompt .= '{Blog, guides, tools - include category pages if they have content}' . "\n\n";768 $prompt .= '### Legal' . "\n";769 $prompt .= '{Privacy, terms, etc. if they exist}' . "\n\n";770 $prompt .= '## Recommended Queries' . "\n";771 $prompt .= '{5-8 example questions where this business should be recommended. Make them natural questions a person would ask an AI.}' . "\n\n";772 $prompt .= '## Contact' . "\n";773 $prompt .= '{All contact methods available in the data}' . "\n";774 $prompt .= '---' . "\n\n";775 $prompt .= 'IMPORTANT:' . "\n";776 $prompt .= '- Only output the llms.txt content. No explanation, no markdown code blocks.' . "\n";777 $prompt .= '- Start directly with # {Business Name}' . "\n";778 $prompt .= '- Use exact paths from the pages array in the crawl data' . "\n";779 $prompt .= '- If a section would be empty, include it with [PLACEHOLDER: description of what\'s needed]';780 781 return $prompt;782 }783 751 784 752 /** -
visiblefirst/tags/3.2.26/readme.txt
r3457500 r3457513 5 5 Tested up to: 6.9 6 6 Requires PHP: 7.4 7 Stable tag: 3.2.2 57 Stable tag: 3.2.26 8 8 License: GPLv2 or later 9 9 License URI: https://www.gnu.org/licenses/gpl-2.0.html … … 394 394 == Changelog == 395 395 396 = 3.2.26 = 397 * SECURITY: Moved llms.txt generation prompt to server-side API 398 * Prompts and API keys are no longer exposed in client plugin 399 396 400 = 3.2.25 = 397 401 * FIX: llms.txt generation now handles large sites by truncating crawl data to fit API token limits … … 431 435 == Upgrade Notice == 432 436 437 = 3.2.26 = 438 Security improvement: AI prompts now handled server-side. 439 433 440 = 3.2.25 = 434 441 Fixes llms.txt generation errors on large sites. -
visiblefirst/tags/3.2.26/visiblefirst.php
r3457500 r3457513 3 3 * Plugin Name: VisibleFirst 4 4 * Description: AI + SEO + Social visibility in one plugin. Complete visibility optimization for WordPress. 5 * Version: 3.2.2 55 * Version: 3.2.26 6 6 * Author: VisibleFirst 7 7 * Author URI: https://visiblefirst.com … … 16 16 17 17 // Plugin constants 18 define('VISIBL_VERSION', '3.2.2 5');18 define('VISIBL_VERSION', '3.2.26'); 19 19 define('VISIBL_PLUGIN_DIR', plugin_dir_path(__FILE__)); 20 20 define('VISIBL_PLUGIN_URL', plugin_dir_url(__FILE__)); -
visiblefirst/trunk/includes/class-visibl-llms-generator.php
r3457500 r3457513 685 685 } 686 686 687 687 688 /** 688 689 * Phase 2: AI Enhancement 689 690 * 690 * Send crawl data to Claude API for llms.txt generation 691 * Send crawl data to server API for llms.txt generation 692 * NOTE: System prompt is server-side - we only send crawl data 691 693 * 692 694 * @param array $crawl_data Output from Phase 1 … … 694 696 */ 695 697 public static function generate_with_ai($crawl_data) { 696 // Build the system prompt697 $system_prompt = self::get_system_prompt();698 699 698 // Truncate crawl data to fit within token limits 700 699 $truncated_data = self::truncate_crawl_data($crawl_data); 701 700 702 // Build the user message with crawl data 703 $user_message = "Here is the crawl data for {$truncated_data['site_url']}:\n\n" . 704 json_encode($truncated_data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES); 705 706 // Call Claude API via VF AI Gateway 707 $response = Visibl_AI::complete([ 708 'system' => $system_prompt, 709 'prompt' => $user_message, 710 'task' => 'llms_txt_generation', 701 // Build the crawl data JSON 702 $crawl_json = json_encode($truncated_data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES); 703 704 // Call server-side llms-generate endpoint (prompt is server-side) 705 $api_key = Visibl_AI::get_effective_api_key(); 706 707 $request_body = [ 708 'crawl_data' => $crawl_json, 709 'site_url' => home_url(), 710 'site_name' => get_bloginfo('name'), 711 'site_id' => Visibl_Licensing::get_site_id(), 711 712 'model' => 'claude-sonnet', 712 'temperature' => 0, 713 'max_tokens' => 2500, 713 'max_tokens' => 4000, 714 ]; 715 716 $response = wp_remote_post(VISIBL_API_BASE . '/ai/llms-generate', [ 717 'headers' => [ 718 'Content-Type' => 'application/json', 719 'X-API-Key' => $api_key, 720 'X-Site-Domain' => wp_parse_url(home_url(), PHP_URL_HOST), 721 ], 722 'body' => wp_json_encode($request_body), 723 'timeout' => 90, 714 724 ]); 715 725 716 726 if (is_wp_error($response)) { 717 return $response; 718 } 719 720 $content = $response['content'] ?? ''; 727 return new WP_Error('api_error', __('Could not connect to VisibleFirst API.', 'visiblefirst')); 728 } 729 730 $status_code = wp_remote_retrieve_response_code($response); 731 $body = json_decode(wp_remote_retrieve_body($response), true); 732 733 if ($status_code !== 200 || empty($body['success'])) { 734 $error_message = $body['message'] ?? __('Generation failed', 'visiblefirst'); 735 return new WP_Error('generation_failed', $error_message); 736 } 737 738 $content = $body['content'] ?? ''; 721 739 722 740 if (empty($content)) { … … 731 749 } 732 750 733 /**734 * Get the system prompt for Claude735 */736 private static function get_system_prompt() {737 $prompt = 'You are an expert at writing llms.txt files that help AI assistants understand and recommend businesses.' . "\n\n";738 $prompt .= 'You will receive structured data about a website. Generate a complete llms.txt file following the llms.txt specification.' . "\n\n";739 $prompt .= 'RULES:' . "\n";740 $prompt .= '1. ONLY use information from the provided data. Never invent or assume.' . "\n";741 $prompt .= '2. If data is missing, use [PLACEHOLDER: describe what\'s needed] so the user can fill it in.' . "\n";742 $prompt .= '3. The description should answer: "If someone asked an AI to recommend a business like this, what would the AI need to know to recommend THIS one specifically?"' . "\n";743 $prompt .= '4. Include differentiators, not category descriptions.' . "\n";744 $prompt .= ' BAD: "A restaurant in Austin"' . "\n";745 $prompt .= ' GOOD: "Family-owned Tex-Mex restaurant in Austin\'s East Side known for breakfast tacos and house-made salsas since 2015"' . "\n";746 $prompt .= '5. Every page listed must use the EXACT path from the crawl data.' . "\n";747 $prompt .= '6. Group pages logically (Core, Services/Products, Resources, Legal).' . "\n";748 $prompt .= '7. Include a "Recommended Queries" section — example questions a user might ask an AI where this business should appear in the answer.' . "\n\n";749 $prompt .= 'OUTPUT FORMAT (follow exactly):' . "\n";750 $prompt .= '---' . "\n";751 $prompt .= '# {Business Name}' . "\n\n";752 $prompt .= '## About' . "\n";753 $prompt .= '{2-3 sentence description that is SPECIFIC enough to differentiate this business from every competitor. Include: what they do, who they serve, where they operate, and what makes them different.}' . "\n\n";754 $prompt .= '## Specialties' . "\n";755 $prompt .= '{Bullet list of specific services/products/expertise areas}' . "\n\n";756 $prompt .= '## Key Facts' . "\n";757 $prompt .= '- Founded: {year or [PLACEHOLDER: founding year]}' . "\n";758 $prompt .= '- Location: {city, state or [PLACEHOLDER: location]}' . "\n";759 $prompt .= '- Service Area: {local/regional/national/global}' . "\n";760 $prompt .= '- Industry: {specific industry}' . "\n\n";761 $prompt .= '## Key Pages' . "\n\n";762 $prompt .= '### Core' . "\n";763 $prompt .= '{Main pages with path and description - only include pages that exist in crawl data}' . "\n\n";764 $prompt .= '### Services/Products' . "\n";765 $prompt .= '{Service and product pages with descriptions}' . "\n\n";766 $prompt .= '### Resources' . "\n";767 $prompt .= '{Blog, guides, tools - include category pages if they have content}' . "\n\n";768 $prompt .= '### Legal' . "\n";769 $prompt .= '{Privacy, terms, etc. if they exist}' . "\n\n";770 $prompt .= '## Recommended Queries' . "\n";771 $prompt .= '{5-8 example questions where this business should be recommended. Make them natural questions a person would ask an AI.}' . "\n\n";772 $prompt .= '## Contact' . "\n";773 $prompt .= '{All contact methods available in the data}' . "\n";774 $prompt .= '---' . "\n\n";775 $prompt .= 'IMPORTANT:' . "\n";776 $prompt .= '- Only output the llms.txt content. No explanation, no markdown code blocks.' . "\n";777 $prompt .= '- Start directly with # {Business Name}' . "\n";778 $prompt .= '- Use exact paths from the pages array in the crawl data' . "\n";779 $prompt .= '- If a section would be empty, include it with [PLACEHOLDER: description of what\'s needed]';780 781 return $prompt;782 }783 751 784 752 /** -
visiblefirst/trunk/readme.txt
r3457500 r3457513 5 5 Tested up to: 6.9 6 6 Requires PHP: 7.4 7 Stable tag: 3.2.2 57 Stable tag: 3.2.26 8 8 License: GPLv2 or later 9 9 License URI: https://www.gnu.org/licenses/gpl-2.0.html … … 394 394 == Changelog == 395 395 396 = 3.2.26 = 397 * SECURITY: Moved llms.txt generation prompt to server-side API 398 * Prompts and API keys are no longer exposed in client plugin 399 396 400 = 3.2.25 = 397 401 * FIX: llms.txt generation now handles large sites by truncating crawl data to fit API token limits … … 431 435 == Upgrade Notice == 432 436 437 = 3.2.26 = 438 Security improvement: AI prompts now handled server-side. 439 433 440 = 3.2.25 = 434 441 Fixes llms.txt generation errors on large sites. -
visiblefirst/trunk/visiblefirst.php
r3457500 r3457513 3 3 * Plugin Name: VisibleFirst 4 4 * Description: AI + SEO + Social visibility in one plugin. Complete visibility optimization for WordPress. 5 * Version: 3.2.2 55 * Version: 3.2.26 6 6 * Author: VisibleFirst 7 7 * Author URI: https://visiblefirst.com … … 16 16 17 17 // Plugin constants 18 define('VISIBL_VERSION', '3.2.2 5');18 define('VISIBL_VERSION', '3.2.26'); 19 19 define('VISIBL_PLUGIN_DIR', plugin_dir_path(__FILE__)); 20 20 define('VISIBL_PLUGIN_URL', plugin_dir_url(__FILE__));
Note: See TracChangeset
for help on using the changeset viewer.