Initial commit of Websearch
This commit is contained in:
111
main.ts
Normal file
111
main.ts
Normal file
@@ -0,0 +1,111 @@
|
||||
import { parseArgs } from "@std/cli/parse-args";
|
||||
import type { Args } from "@std/cli/parse-args";
|
||||
import { ensureDir } from "@std/fs";
|
||||
import { parse, stringify } from "@std/yaml";
|
||||
import { answerQuery, cleanTextFromHtml, getNewsUrls } from "./websearch.ts";
|
||||
|
||||
export interface Config {
|
||||
model?: string;
|
||||
search_url?: string;
|
||||
}
|
||||
|
||||
const parsed: Args = parseArgs(Deno.args, {
|
||||
boolean: ["help"],
|
||||
string: ["model", "search_url"],
|
||||
});
|
||||
|
||||
if (parsed.help) {
|
||||
console.log(`
|
||||
Usage:
|
||||
websearch [--model MODEL] [--search_url SEARCH_URL] QUERY
|
||||
|
||||
Options:
|
||||
--model Ollama model to use
|
||||
--search_url URL for SearXNG endpoint
|
||||
|
||||
Arguments:
|
||||
QUERY The topic to search for news to summarize
|
||||
|
||||
Configuration:
|
||||
The websearch configuration file is stored in the XDG Config directory
|
||||
/home/$USER/.config/websearch/config.yml. Both the model and search_url
|
||||
can be customized as an alternative to providing the options for each.
|
||||
If both the Ollama model and SearXNG endpoint are successful, the
|
||||
configuration is automatically saved/updated.
|
||||
`);
|
||||
Deno.exit();
|
||||
}
|
||||
|
||||
const configDir = `${Deno.env.get("HOME")}/.config/websearch`;
|
||||
const configPath = `${Deno.env.get("HOME")}/.config/websearch/config.yml`;
|
||||
|
||||
async function loadConfig(): Promise<Config> {
|
||||
try {
|
||||
const yamlString = await Deno.readTextFile(configPath);
|
||||
return parse(yamlString) as Config;
|
||||
} catch {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
async function saveConfig(config: Config) {
|
||||
await ensureDir(configDir);
|
||||
await Deno.writeTextFile(
|
||||
configPath,
|
||||
stringify(config),
|
||||
);
|
||||
}
|
||||
|
||||
async function main(args: Args) {
|
||||
const query = args._.join(" ");
|
||||
if (!query) {
|
||||
throw new Error("Please provide a search query");
|
||||
}
|
||||
console.log(`Query: ${query}`);
|
||||
|
||||
try {
|
||||
const config = await loadConfig();
|
||||
if (!config.model) {
|
||||
if (args.model) {
|
||||
config.model = args.model;
|
||||
} else {
|
||||
throw new Error("Provide --model or add Ollama model to configuration");
|
||||
}
|
||||
} else if (args.model && args.model !== config.model) {
|
||||
config.model = args.model;
|
||||
}
|
||||
if (!config.search_url) {
|
||||
if (args.search_url) {
|
||||
config.search_url = args.search_url;
|
||||
} else {
|
||||
throw new Error(
|
||||
"Provide --search_url or add search_url to configuration",
|
||||
);
|
||||
}
|
||||
} else if (args.search_url && args.search_url !== config.search_url) {
|
||||
config.search_url = args.search_url;
|
||||
}
|
||||
|
||||
const urls = await getNewsUrls(config, query);
|
||||
if (!urls || urls.length === 0) {
|
||||
console.log("No results");
|
||||
Deno.exit(1);
|
||||
}
|
||||
|
||||
const cleanedTexts = await Promise.all(
|
||||
urls.map((url) => cleanTextFromHtml(url)),
|
||||
);
|
||||
await answerQuery(config, query, cleanedTexts.join("\n\n"));
|
||||
await saveConfig(config);
|
||||
} catch (error: any) {
|
||||
console.error(`Error processing query "${query}":`, error.message);
|
||||
Deno.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (import.meta.main) {
|
||||
main(parsed).catch((error) => {
|
||||
console.error("Unhandled exception:", error);
|
||||
Deno.exit(1);
|
||||
});
|
||||
}
|
Reference in New Issue
Block a user