UNPKG

@mseep/mcp-omnisearch

Version:

MCP server for integrating Omnisearch with LLMs

175 lines (174 loc) 7.12 kB
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}`); } } }