Add brave search.

This commit is contained in:
Bartosz Taudul
2026-03-06 01:39:03 +01:00
parent bbc937c309
commit db0082de3f
5 changed files with 67 additions and 0 deletions

View File

@@ -47,6 +47,7 @@ void LoadConfig()
if( v2 = ini_get( ini, "llm", "useragent" ); v2 ) s_config.llmUserAgent = v2;
if( v2 = ini_get( ini, "llm", "searchIdentifier" ); v2 ) s_config.llmSearchIdentifier = v2;
if( v2 = ini_get( ini, "llm", "searchApiKey" ); v2 ) s_config.llmSearchApiKey = v2;
if( v2 = ini_get( ini, "llm", "searchBraveApiKey" ); v2 ) s_config.llmSearchBraveApiKey = v2;
if( ini_sget( ini, "llm", "annotateCallstacks", "%d", &v ) ) s_config.llmAnnotateCallstacks = v;
if( ini_sget( ini, "llm", "limitToolReplySize", "%d", &v ) ) s_config.llmLimitToolReplySize = v;
if( ini_sget( ini, "llm", "maxToolReplySizeValue", "%d", &v ) ) s_config.llmMaxToolReplySizeValue = v;
@@ -98,6 +99,7 @@ bool SaveConfig()
fprintf( f, "useragent = %s\n", s_config.llmUserAgent.c_str() );
fprintf( f, "searchIdentifier = %s\n", s_config.llmSearchIdentifier.c_str() );
fprintf( f, "searchApiKey = %s\n", s_config.llmSearchApiKey.c_str() );
fprintf( f, "searchBraveApiKey = %s\n", s_config.llmSearchBraveApiKey.c_str() );
fprintf( f, "annotateCallstacks = %i\n", (int)s_config.llmAnnotateCallstacks );
fprintf( f, "limitToolReplySize = %i\n", (int)s_config.llmLimitToolReplySize );
fprintf( f, "maxToolReplySizeValue = %i\n", s_config.llmMaxToolReplySizeValue );

View File

@@ -43,6 +43,7 @@ struct Config
std::string llmUserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36";
std::string llmSearchIdentifier;
std::string llmSearchApiKey;
std::string llmSearchBraveApiKey;
bool llmAnnotateCallstacks = false;
bool llmLimitToolReplySize = false;
int llmMaxToolReplySizeValue = 48*1024;

View File

@@ -392,6 +392,19 @@ void TracyLlm::Draw()
ImGui::SameLine();
if( ImGui::Button( ICON_FA_HOUSE "##csekey" ) ) OpenWebpage( "https://developers.google.com/custom-search/v1/overview" );
ImGui::AlignTextToFramePadding();
ImGui::TextUnformatted( "Brave Search API Key:" );
ImGui::SameLine();
snprintf( buf, sizeof( buf ), "%s", s_config.llmSearchBraveApiKey.c_str() );
ImGui::SetNextItemWidth( ImGui::GetContentRegionAvail().x - ImGui::CalcTextSize( ICON_FA_HOUSE ).x - ImGui::GetStyle().FramePadding.x * 2 - ImGui::GetStyle().ItemSpacing.x );
if( ImGui::InputTextWithHint( "##bravekey", "Brave API key", buf, sizeof( buf ) ) )
{
s_config.llmSearchBraveApiKey = buf;
SaveConfig();
}
ImGui::SameLine();
if( ImGui::Button( ICON_FA_HOUSE "##bravekey" ) ) OpenWebpage( "https://brave.com/search/api/" );
ImGui::TreePop();
}

View File

@@ -522,6 +522,12 @@ std::string TracyLlmTools::SearchWeb( std::string query )
NetworkCheck;
query = UrlEncode( query );
if( !s_config.llmSearchBraveApiKey.empty() )
{
const auto result = SearchWebBrave( query );
if( !result.starts_with( "Error:" ) && !result.starts_with( "No results" ) ) return result;
}
if( !s_config.llmSearchApiKey.empty() && !s_config.llmSearchIdentifier.empty() )
{
const auto result = SearchWebGoogle( query );
@@ -557,6 +563,50 @@ std::string TracyLlmTools::SearchWebGoogle( std::string query )
return "Error: Google search failed";
}
std::string TracyLlmTools::SearchWebBrave( std::string query )
{
const std::string header = "X-Subscription-Token: " + s_config.llmSearchBraveApiKey;
const std::vector<const char*> headers = { header.c_str() };
const auto response = FetchHttp( "https://api.search.brave.com/res/v1/web/search?q=" + query, headers );
try
{
auto json = nlohmann::json::parse( response );
nlohmann::json results;
if( json.contains( "web" ) && json["web"].contains( "results" ) && json["web"]["results"].size() != 0 )
{
auto& webResults = json["web"]["results"];
for( auto& item : webResults )
{
nlohmann::json result;
if( item.contains( "age" ) ) result["age"] = RemoveNewline( item["age"].get_ref<const std::string&>() );
result["title"] = RemoveNewline( item["title"].get_ref<const std::string&>() );
result["preview"] = RemoveNewline( item["description"].get_ref<const std::string&>() );
result["url"] = RemoveNewline( item["url"].get_ref<const std::string&>() );
results.emplace_back( result );
}
}
if( json.contains( "discussions" ) && json["discussions"].contains( "results" ) && json["discussions"]["results"].size() != 0 )
{
auto& webResults = json["discussions"]["results"];
for( auto& item : webResults )
{
nlohmann::json result;
if( item.contains( "age" ) ) result["age"] = RemoveNewline( item["age"].get_ref<const std::string&>() );
result["title"] = RemoveNewline( item["title"].get_ref<const std::string&>() );
result["preview"] = RemoveNewline( item["description"].get_ref<const std::string&>() );
result["url"] = RemoveNewline( item["url"].get_ref<const std::string&>() );
results.emplace_back( result );
}
}
if( !results.empty() ) return results.dump( -1, ' ', false, nlohmann::json::error_handler_t::replace );
}
catch( const nlohmann::json::exception& e ) {}
return "Error: Brave search failed";
}
std::string TracyLlmTools::SearchWebDuckDuckGo( std::string query )
{
auto response = FetchHttp( "https://lite.duckduckgo.com/lite?q=" + query );

View File

@@ -56,6 +56,7 @@ private:
std::string GetDictionary( std::string word, const std::string& lang );
std::string SearchWeb( std::string query );
std::string SearchWebGoogle( std::string query );
std::string SearchWebBrave( std::string query );
std::string SearchWebDuckDuckGo( std::string query );
std::string GetWebpage( const std::string& url );
std::string SearchManual( const std::string& query, TracyLlmApi& api, bool hasEmbeddingsModel );