Skip to content

Commit

Permalink
Web search capabilities added
Browse files Browse the repository at this point in the history
  • Loading branch information
manimohans committed Feb 11, 2025
1 parent 4856310 commit a6f13b9
Show file tree
Hide file tree
Showing 7 changed files with 780 additions and 340 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ Seamlessly integrate your local LLM with Obsidian. Process large text chunks, tr
* Custom Prompts: Allows users to define and execute their own prompts for specialized tasks.
* Prompt-as-Input: Uses the selected text directly as a prompt for creative text generation.
* Generate backlinks: Generate backlinks to your notes.
* Web Search: Search the web for selected text.
* News Search: Search the news for selected text.

<img width="704" alt="image" src="https://github.com/user-attachments/assets/b55e305f-2f5c-4dab-9e67-251613065c67">

Expand Down
138 changes: 137 additions & 1 deletion main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export interface OLocalLLMSettings {
responseFormatAppend: string;
lastVersion: string;
embeddingModelName: string;
braveSearchApiKey: string;
}

interface ConversationEntry {
Expand All @@ -55,6 +56,7 @@ const DEFAULT_SETTINGS: OLocalLLMSettings = {
responseFormatAppend: "\n\n```",
lastVersion: "0.0.0",
embeddingModelName: "nomic-embed-text",
braveSearchApiKey: "",
};

const personasDict: { [key: string]: string } = {
Expand Down Expand Up @@ -218,6 +220,29 @@ export default class OLocalLLMPlugin extends Plugin {
},
});

this.addCommand({
id: "web-search-selected-text",
name: "Search web for selected text",
editorCallback: (editor: Editor, view: MarkdownView) => {
this.isKillSwitchActive = false;
let selectedText = this.getSelectedText();
if (selectedText.length > 0) {
processWebSearch(selectedText, this);
}
},
});

this.addCommand({
id: "web-news-search",
name: "Search news (Web) for selected text",
editorCallback: (editor: Editor, view: MarkdownView) => {
let selectedText = this.getSelectedText();
if (selectedText.length > 0) {
processNewsSearch(selectedText, this);
}
},
});

this.addRibbonIcon("brain-cog", "LLM Context", (event) => {
const menu = new Menu();

Expand Down Expand Up @@ -333,6 +358,30 @@ export default class OLocalLLMPlugin extends Plugin {
})
);

menu.addItem((item) =>
item
.setTitle("Search (Web)")
.setIcon("globe")
.onClick(async () => {
let selectedText = this.getSelectedText();
if (selectedText.length > 0) {
processWebSearch(selectedText, this);
}
})
);

menu.addItem((item) =>
item
.setTitle("News Search (Web)")
.setIcon("newspaper")
.onClick(async () => {
let selectedText = this.getSelectedText();
if (selectedText.length > 0) {
processNewsSearch(selectedText, this);
}
})
);

menu.addItem((item) =>
item
.setTitle("Kill Switch")
Expand All @@ -343,7 +392,7 @@ export default class OLocalLLMPlugin extends Plugin {
})
);

menu.showAtMouseEvent(event);
menu.showAtMouseEvent(event as MouseEvent);
});

const statusBarItemEl = this.addStatusBarItem();
Expand Down Expand Up @@ -605,6 +654,19 @@ class OLLMSettingTab extends PluginSettingTab {
})
);

new Setting(containerEl)
.setName("Brave Search API Key")
.setDesc("API key for Brave Search integration")
.addText((text) =>
text
.setPlaceholder("Enter your Brave Search API key")
.setValue(this.plugin.settings.braveSearchApiKey)
.onChange(async (value) => {
this.plugin.settings.braveSearchApiKey = value;
await this.plugin.saveSettings();
})
);

new Setting(containerEl)
.setName("Index Notes (BETA)")
.setDesc("Manually index all notes in the vault")
Expand Down Expand Up @@ -1152,3 +1214,77 @@ function updateConversationHistory(prompt: string, response: string, conversatio
//TODO: add a button to save the chat history to a obsidian file

//TODO: kill switch

async function processWebSearch(query: string, plugin: OLocalLLMPlugin) {
if (!plugin.settings.braveSearchApiKey) {
new Notice("Please set your Brave Search API key in settings");
return;
}

new Notice("Searching the web...");

try {
const response = await requestUrl({
url: `https://api.search.brave.com/res/v1/web/search?q=${encodeURIComponent(query)}&count=5&summary=1&extra_snippets=1&text_decorations=1&result_filter=web,discussions,faq,news&spellcheck=1`,
method: "GET",
headers: {
"Accept": "application/json",
"Accept-Encoding": "gzip",
"X-Subscription-Token": plugin.settings.braveSearchApiKey,
}
});

if (response.status !== 200) {
throw new Error("Search failed: " + response.status);
}

const searchResults = response.json.web.results;
const context = searchResults.map((result: any) => {
let snippets = result.extra_snippets ?
'\nAdditional Context:\n' + result.extra_snippets.join('\n') : '';
return `${result.title}\n${result.description}${snippets}\nSource: ${result.url}\n\n`;
}).join('');

processText(
`Based on these comprehensive search results about "${query}":\n\n${context}`,
"You are a helpful assistant. Analyze these detailed search results and provide a thorough, well-structured response. Include relevant source citations and consider multiple perspectives if available.",
plugin
);

} catch (error) {
console.error("Web search error:", error);
new Notice("Web search failed. Check console for details.");
}
}

async function processNewsSearch(query: string, plugin: OLocalLLMPlugin) {
try {
const response = await requestUrl({
url: `https://api.search.brave.com/res/v1/news/search?q=${encodeURIComponent(query)}&count=5&search_lang=en&freshness=pd`,
method: "GET",
headers: {
"Accept": "application/json",
"Accept-Encoding": "gzip",
"X-Subscription-Token": plugin.settings.braveSearchApiKey,
}
});

if (response.status !== 200) {
throw new Error("News search failed: " + response.status);
}

const newsResults = response.json.results;
const context = newsResults.map((result: any) =>
`${result.title}\n${result.description}\nSource: ${result.url}\nPublished: ${result.published_time}\n\n`
).join('');

processText(
`Based on these news results about "${query}":\n\n${context}`,
"Analyze these news results and provide a comprehensive summary with key points and timeline. Include source citations.",
plugin
);
} catch (error) {
console.error("News search error:", error);
new Notice("News search failed. Check console for details.");
}
}
4 changes: 2 additions & 2 deletions manifest.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
{
"id": "local-llm-helper",
"name": "Local LLM Helper",
"version": "2.1.1",
"minAppVersion": "1.5.12",
"version": "2.1.2",
"minAppVersion": "1.7.0",
"description": "Use your own secure local LLM server to work with your text!",
"author": "Mani Mohan",
"authorUrl": "https:/warpcast.com/mani",
Expand Down
Loading

0 comments on commit a6f13b9

Please sign in to comment.