@mseep/mcp-omnisearch
Version:
MCP server for integrating Omnisearch with LLMs
175 lines (174 loc) • 7.12 kB
JavaScript
import { validate_api_key } from '../../../common/utils.js';
import { config } from '../../../config/env.js';
export class PerplexityProvider {
constructor() {
this.name = 'perplexity';
this.description = 'AI-powered response generation combining real-time web search with advanced language models. Best for complex queries requiring reasoning and synthesis across multiple sources. Features contextual memory for follow-up questions.';
}
async search(params) {
const response = await this.get_answer(params.query, {
include_sources: true,
max_tokens: params.limit || 1024,
});
// Return the full answer as a single result
const results = [
{
title: 'Perplexity AI',
url: 'https://perplexity.ai',
snippet: response.answer,
source_provider: this.name,
},
];
// Add sources if available
if (response.context?.sources &&
response.context.sources.length > 0) {
results.push(...response.context.sources.map((source) => ({
title: source.title || 'Source',
url: source.url || 'https://perplexity.ai',
snippet: source.content,
source_provider: this.name,
})));
}
// Filter out any results with missing required fields
const filtered_results = results.filter((result) => result.title && result.url && result.snippet);
// Respect the limit parameter
if (params.limit && params.limit > 0) {
return filtered_results.slice(0, params.limit);
}
return filtered_results;
}
async get_answer(query, options = {}) {
const api_key = validate_api_key(config.ai_response.perplexity.api_key, this.name);
const default_options = {
model: 'sonar-pro',
max_tokens: 1024,
temperature: 0.7,
include_sources: true,
include_follow_up: false,
top_p: 0.8,
top_k: 40,
};
const final_options = { ...default_options, ...options };
try {
const response = await fetch(`${config.ai_response.perplexity.base_url}/chat/completions`, {
method: 'POST',
headers: {
accept: 'application/json',
'content-type': 'application/json',
Authorization: `Bearer ${api_key}`,
},
body: JSON.stringify({
model: 'sonar-pro',
messages: [
{
role: 'user',
content: query,
},
],
temperature: 0.2,
max_tokens: 1024,
}),
});
if (!response.ok) {
const error_data = await response.json();
throw new Error(`Perplexity API error: ${error_data.error?.message || response.statusText}`);
}
const data = await response.json();
// Extract the full content from choices
if (!data.choices?.[0]?.message?.content) {
throw new Error('Invalid response format from Perplexity API');
}
const answer = data.choices[0].message.content;
const citations = data.citations || [];
return {
answer,
context: {
sources: citations.map((citation) => ({
title: 'Citation',
url: citation,
content: 'Source citation',
})),
follow_up_questions: [],
},
metadata: {
model: final_options.model,
processing_time: 0,
token_count: data.usage?.total_tokens || 0,
},
};
}
catch (error) {
const error_message = error instanceof Error ? error.message : String(error);
throw new Error(`Failed to get Perplexity answer: ${error_message}`);
}
}
async get_answer_with_context(query, context, options = {}) {
const api_key = validate_api_key(config.ai_response.perplexity.api_key, this.name);
const default_options = {
model: 'sonar-pro',
max_tokens: 1024,
temperature: 0.7,
include_sources: true,
include_follow_up: false,
top_p: 0.8,
top_k: 40,
};
const final_options = { ...default_options, ...options };
try {
const response = await fetch(`${config.ai_response.perplexity.base_url}/chat/completions`, {
method: 'POST',
headers: {
accept: 'application/json',
'content-type': 'application/json',
Authorization: `Bearer ${api_key}`,
},
body: JSON.stringify({
model: 'sonar-pro',
messages: [
{
role: 'system',
content: context,
},
{
role: 'user',
content: query,
},
],
max_tokens: final_options.max_tokens,
temperature: final_options.temperature,
top_p: final_options.top_p,
top_k: final_options.top_k,
presence_penalty: final_options.presence_penalty,
frequency_penalty: final_options.frequency_penalty,
}),
});
if (!response.ok) {
const error_data = await response.json();
throw new Error(`Perplexity API error: ${error_data.error?.message || response.statusText}`);
}
const data = await response.json();
const answer = data.choices[0].message.content;
const citations = data.citations || [];
return {
answer,
context: {
sources: citations.map((citation) => ({
title: 'Citation',
url: citation,
content: 'Source citation',
})),
follow_up_questions: [],
},
metadata: {
model: final_options.model,
processing_time: 0,
token_count: data.usage?.total_tokens || 0,
},
};
}
catch (error) {
const error_message = error instanceof Error ? error.message : String(error);
throw new Error(`Failed to get Perplexity answer with context: ${error_message}`);
}
}
}