- Implement local backend AI provider with Ollama integration - Add Brave Search API integration for real-time search suggestions - Add image generation manager with multiple AI providers - Create hybrid provider system with local/cloud fallback - Add comprehensive settings UI with provider management - Implement Gutenberg sidebar with writing assistance controls - Add SEO schema generation for AI-generated content - Multiple provider support: OpenRouter, local backend, Codex
155 lines
4.0 KiB
PHP
155 lines
4.0 KiB
PHP
<?php
|
|
/**
|
|
* Brave Search API Integration
|
|
*
|
|
* Handles fetching web search results for models that do not natively support web search
|
|
*
|
|
* @package WP_Agentic_Writer
|
|
*/
|
|
|
|
if ( ! defined( 'ABSPATH' ) ) {
|
|
exit;
|
|
}
|
|
|
|
class WP_Agentic_Writer_Brave_Search_API {
|
|
|
|
/**
|
|
* Brave Search REST API Endpoint
|
|
*
|
|
* @var string
|
|
*/
|
|
private $api_endpoint = 'https://api.search.brave.com/res/v1/web/search';
|
|
|
|
/**
|
|
* Get singleton instance.
|
|
*
|
|
* @since 0.1.0
|
|
* @return WP_Agentic_Writer_Brave_Search_API
|
|
*/
|
|
public static function get_instance() {
|
|
static $instance = null;
|
|
|
|
if ( null === $instance ) {
|
|
$instance = new self();
|
|
}
|
|
|
|
return $instance;
|
|
}
|
|
|
|
/**
|
|
* Perform a web search.
|
|
*
|
|
* @since 0.1.0
|
|
* @param string $query Required. The user's search query.
|
|
* @param int $count Optional. Number of results to return. Default 3.
|
|
* @return array|WP_Error Array of formatted search results, or WP_Error on failure.
|
|
*/
|
|
public function search( $query, $count = 3 ) {
|
|
$settings = get_option( 'wp_agentic_writer_settings', array() );
|
|
$api_key = $settings['brave_search_api_key'] ?? '';
|
|
|
|
if ( empty( $api_key ) ) {
|
|
return new WP_Error(
|
|
'brave_api_key_missing',
|
|
__( 'Brave Search API Key is missing. Please configure it in WP Agentic Writer settings.', 'wp-agentic-writer' )
|
|
);
|
|
}
|
|
|
|
// Check cache first to prevent burning API limits on identical subsequent queries
|
|
$cache_key = 'wpaw_brave_search_' . md5( $query . '_' . $count );
|
|
$cached_results = get_transient( $cache_key );
|
|
if ( false !== $cached_results ) {
|
|
return $cached_results;
|
|
}
|
|
|
|
$url = add_query_arg(
|
|
array(
|
|
'q' => urlencode( $query ),
|
|
'count' => absint( $count ),
|
|
'text_decorations' => 0, // Disable HTML tags in descriptions
|
|
'spellcheck' => 1,
|
|
),
|
|
$this->api_endpoint
|
|
);
|
|
|
|
$response = wp_remote_get(
|
|
$url,
|
|
array(
|
|
'headers' => array(
|
|
'Accept' => 'application/json',
|
|
'Accept-Encoding' => 'gzip',
|
|
'X-Subscription-Token' => $api_key,
|
|
),
|
|
'timeout' => 15,
|
|
)
|
|
);
|
|
|
|
if ( is_wp_error( $response ) ) {
|
|
return $response;
|
|
}
|
|
|
|
$http_code = wp_remote_retrieve_response_code( $response );
|
|
$body = json_decode( wp_remote_retrieve_body( $response ), true );
|
|
|
|
if ( 200 !== $http_code ) {
|
|
return new WP_Error(
|
|
'brave_api_error',
|
|
sprintf(
|
|
/* translators: %1$d is HTTP status code, %2$s is error message */
|
|
__( 'Brave Search API Error %1$d: %2$s', 'wp-agentic-writer' ),
|
|
$http_code,
|
|
$body['message'] ?? __( 'Unknown Error', 'wp-agentic-writer' )
|
|
)
|
|
);
|
|
}
|
|
|
|
if ( empty( $body['web']['results'] ) ) {
|
|
return array(); // No results found
|
|
}
|
|
|
|
$formatted_results = array();
|
|
foreach ( $body['web']['results'] as $result ) {
|
|
$formatted_results[] = array(
|
|
'title' => $result['title'] ?? '',
|
|
'url' => $result['url'] ?? '',
|
|
'description' => $result['description'] ?? '',
|
|
);
|
|
}
|
|
|
|
// Cache results for 1 hour to prevent redundant API calls
|
|
set_transient( $cache_key, $formatted_results, HOUR_IN_SECONDS );
|
|
|
|
return $formatted_results;
|
|
}
|
|
|
|
/**
|
|
* Formats search results into a markdown context block for LLM System Prompt injection.
|
|
*
|
|
* @since 0.1.0
|
|
* @param array $results Search results array.
|
|
* @param string $query Original query.
|
|
* @return string Formatted markdown context string.
|
|
*/
|
|
public function format_results_for_llm( $results, $query ) {
|
|
if ( empty( $results ) || is_wp_error( $results ) ) {
|
|
return "No reliable web search results found for: {$query}";
|
|
}
|
|
|
|
$markdown = "## LIVE WEB SEARCH CONTEXT\n";
|
|
$markdown .= "> You successfully searched the internet for: \"{$query}\"\n";
|
|
$markdown .= "> Please incorporate the following real-time data into your answer:\n\n";
|
|
|
|
$counter = 1;
|
|
foreach ( $results as $item ) {
|
|
$markdown .= "{$counter}. **{$item['title']}**\n";
|
|
$markdown .= " URL: {$item['url']}\n";
|
|
$markdown .= " Summary: {$item['description']}\n\n";
|
|
$counter++;
|
|
}
|
|
|
|
$markdown .= "---------------------------\n";
|
|
|
|
return $markdown;
|
|
}
|
|
}
|