askexperts
Version:
AskExperts SDK: build and use AI experts - ask them questions and pay with bitcoin on an open protocol
110 lines • 3.98 kB
JavaScript
import { SimplePool } from "nostr-tools";
import { EVENT_KIND_EXPERT_PROFILE, SEARCH_RELAYS } from "../../../common/constants.js";
import { fetchFromRelays } from "../../../common/relay.js";
import { debugError } from "../../../common/debug.js";
import { parseExpertProfile } from "../../../experts/utils/Nostr.js";
import Table from "cli-table3";
import { addRemoteOptions } from "./index.js";
/**
* Search expert profiles from specified relays
*
* @param options Command options
*/
export async function searchExperts(options) {
try {
// Parse relays from comma-separated string or use default
const relays = options.relays
? options.relays.split(',')
: SEARCH_RELAYS;
// Parse tags if provided
const tags = options.tags ? options.tags.split(',') : [];
// Create a pool for relay operations
const pool = new SimplePool();
// Create a filter for expert profile events
const filter = {
kinds: [EVENT_KIND_EXPERT_PROFILE],
limit: 1000,
};
// Add tag filter if tags are specified
if (tags.length > 0) {
filter["#t"] = tags;
}
// Add search filter if search is specified
if (options.search) {
filter.search = options.search;
}
console.log(`Fetching expert profiles from ${relays.join(', ')}...`);
// Fetch expert profile events
const events = await fetchFromRelays(filter, relays, pool, 5000);
console.log(`Found ${events.length} expert profiles.`);
if (events.length === 0) {
console.log("No expert profiles found.");
pool.destroy();
return;
}
// Process events into Expert objects
const experts = [];
const seenPubkeys = new Set();
for (const event of events) {
// Only take the newest event for each pubkey
if (seenPubkeys.has(event.pubkey)) {
continue;
}
const expert = parseExpertProfile(event);
if (expert) {
experts.push(expert);
seenPubkeys.add(event.pubkey);
}
}
// Create a table for display
const table = new Table({
head: ['Pubkey', 'Name', 'Description'],
colWidths: [66, 30, 60],
wordWrap: true,
wrapOnWordBoundary: false,
});
// Add rows to the table
for (const expert of experts) {
const pubkeyShort = expert.pubkey;
const name = expert.name || '<Unnamed>';
// Truncate description if too long
const description = expert.description.length > 200
? expert.description.substring(0, 197) + '...'
: expert.description;
table.push([pubkeyShort, name, description]);
}
// Display the table
console.log(table.toString());
// Clean up
pool.destroy();
}
catch (error) {
debugError("Error searching experts:", error);
throw error;
}
}
/**
* Register the search command with the expert command group
*
* @param program The commander program or parent command
*/
export function registerSearchCommand(program) {
const command = program
.command("search")
.description("Search expert profiles from relays")
.option("--relays <urls>", "Comma-separated list of relay URLs")
.option("-s, --search <query>", "Search query for filtering experts")
.option("-t, --tags <tags>", "Comma-separated list of tags to filter by")
.action(async (options) => {
try {
await searchExperts(options);
}
catch (error) {
console.error("Error searching experts:", error);
process.exit(1);
}
});
// Add remote options
addRemoteOptions(command);
}
//# sourceMappingURL=search.js.map