mirror of
https://github.com/lossless-group/perplexed-plugin.git
synced 2026-07-22 06:49:50 +00:00
refactor(main): backed up main and fixed it relative to refactor
On branch fix/lmstudio Changes to be committed: modified: main.ts new file: main.ts.bak new file: src/core/PerplexedPlugin.ts modified: src/core/PerplexedPluginCore.ts modified: src/services/perplexityService.ts new file: src/settings/PerplexedSettingTab.ts modified: src/settings/PerplexedSettings.ts new file: src/settings/PerplexitySettings.ts
This commit is contained in:
parent
c4c75ad68b
commit
a6417ec351
8 changed files with 1370 additions and 1074 deletions
898
main.ts.bak
Normal file
898
main.ts.bak
Normal file
|
|
@ -0,0 +1,898 @@
|
|||
import { Notice } from 'obsidian';
|
||||
import { PerplexedPluginCore } from './src/core/PerplexedPluginCore';
|
||||
import { PerplexedSettingTab } from './src/settings/PerplexedSettingTab';
|
||||
|
||||
export default class PerplexedPlugin extends PerplexedPluginCore {
|
||||
private statusBarItemEl?: HTMLElement;
|
||||
private ribbonIconEl?: HTMLElement;
|
||||
|
||||
async onload(): Promise<void> {
|
||||
await super.onload();
|
||||
this.registerCommands();
|
||||
this.setupUI();
|
||||
}
|
||||
|
||||
protected registerCommands(): void {
|
||||
this.addCommand({
|
||||
id: 'show-perplexed-settings',
|
||||
name: 'Show Settings',
|
||||
callback: () => {
|
||||
new PerplexedSettingTab(this.app, this).display();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected setupUI(): void {
|
||||
if (this.settings.showStatusBar) {
|
||||
this.statusBarItemEl = this.addStatusBarItem();
|
||||
this.statusBarItemEl.setText('Perplexed');
|
||||
}
|
||||
|
||||
this.ribbonIconEl = this.addRibbonIcon(
|
||||
'zap',
|
||||
'Perplexed',
|
||||
() => new Notice('Perplexed plugin is ready')
|
||||
);
|
||||
}
|
||||
|
||||
onunload() {
|
||||
this.statusBarItemEl?.remove();
|
||||
this.ribbonIconEl?.remove();
|
||||
console.log('Perplexed plugin unloaded');
|
||||
}
|
||||
}
|
||||
mySetting: 'default',
|
||||
// Use host.docker.internal to connect to the host machine from Docker containers
|
||||
localLLMPath: 'http://host.docker.internal:3030/api/search',
|
||||
perplexicaEndpoint: 'http://localhost:3030/api/search',
|
||||
perplexityEndpoint: 'https://api.perplexity.ai/chat/completions',
|
||||
lmStudioEndpoint: 'http://localhost:1234/v1/chat/completions',
|
||||
requestBodyTemplate: `{
|
||||
"chatModel": {
|
||||
"provider": "ollama",
|
||||
"name": "llama3.2:latest"
|
||||
},
|
||||
"embeddingModel": {
|
||||
"provider": "ollama",
|
||||
"name": "llama3.2:latest"
|
||||
},
|
||||
"optimizationMode": "speed",
|
||||
"focusMode": "webSearch",
|
||||
"query": "What is Perplexica's architecture?",
|
||||
"history": [
|
||||
{
|
||||
"role": "user",
|
||||
"content": "What is Perplexica's architecture?"
|
||||
}
|
||||
],
|
||||
"systemInstructions": "{{PERPLEXICA_SYSTEM_PROMPT}}",
|
||||
"stream": false,
|
||||
"maxTokens": 2048,
|
||||
"temperature": 0.7
|
||||
}`,
|
||||
perplexityApiKey: process.env.PERPLEXITY_API_KEY || '',
|
||||
perplexityRequestTemplate: `{
|
||||
"model": "llama-3.1-sonar-small-128k-online",
|
||||
"messages": [
|
||||
{
|
||||
"role": "system",
|
||||
"content": "{{PERPLEXITY_SYSTEM_PROMPT}}"
|
||||
},
|
||||
{
|
||||
"role": "user",
|
||||
"content": "What is Perplexity AI's approach to search?"
|
||||
}
|
||||
],
|
||||
"max_tokens": 2048,
|
||||
"temperature": 0.7,
|
||||
"top_p": 0.9,
|
||||
"return_citations": true,
|
||||
"search_domain_filter": [],
|
||||
"return_images": false,
|
||||
"return_related_questions": false,
|
||||
"search_recency_filter": "month",
|
||||
"top_k": 0,
|
||||
"stream": false,
|
||||
"presence_penalty": 0,
|
||||
"frequency_penalty": 1
|
||||
}`,
|
||||
lmStudioRequestTemplate: `{
|
||||
"model": "ibm/granite-3.2-8b",
|
||||
"messages": [
|
||||
{
|
||||
"role": "user",
|
||||
"content": "Hello, can you help me with this question?"
|
||||
}
|
||||
],
|
||||
"max_tokens": 2048,
|
||||
"temperature": 0.7,
|
||||
"stream": false
|
||||
}`,
|
||||
defaultModel: 'llama3.2:latest',
|
||||
defaultOptimizationMode: 'speed',
|
||||
defaultFocusMode: 'webSearch',
|
||||
defaultLMStudioModel: 'ibm/granite-3.2-8b',
|
||||
|
||||
// Prompt Settings
|
||||
prompts: {
|
||||
// System prompts
|
||||
perplexitySystemPrompt: "You are a helpful AI assistant. Provide clear, concise, and accurate information with proper citations.",
|
||||
perplexicaSystemPrompt: "You are a helpful AI assistant. Provide clear, concise, and accurate information.",
|
||||
lmStudioDefaultSystemPrompt: "You are a helpful AI assistant. Provide clear, concise, and accurate information.",
|
||||
|
||||
// Placeholder text
|
||||
perplexityQueryPlaceholder: "What would you like to ask Perplexity?",
|
||||
perplexicaQueryPlaceholder: "What would you like to ask Perplexica?",
|
||||
lmStudioQueryPlaceholder: "What would you like to ask?",
|
||||
lmStudioSystemPromptPlaceholder: "You are a helpful AI assistant...",
|
||||
articleTermPlaceholder: "e.g., AI Copilots, AI Studios, Machine Learning, etc.",
|
||||
|
||||
// Descriptions and labels
|
||||
deepResearchDescription: "⚡ Deep Research: Exhaustive research across hundreds of sources with expert-level analysis. Higher cost but comprehensive results. Note: Streaming is disabled for this model.",
|
||||
imagesToggleDescription: "Include image results from search - images will be integrated throughout the response where appropriate",
|
||||
imagesToggleGenericDescription: "Include image references throughout the response where appropriate",
|
||||
articleTermDescription: "Enter a vocabulary term to generate a comprehensive one-page article with images.",
|
||||
|
||||
// Notices and messages
|
||||
deepResearchLoadingNotice: "🔍 Deep research in progress... This may take up to 60 seconds.",
|
||||
enterQuestionNotice: "Please enter a question",
|
||||
enterTermNotice: "Please enter a vocabulary term",
|
||||
|
||||
// Article generator template
|
||||
articleGeneratorTemplate: `Write a comprehensive one-page article about "{TERM}".
|
||||
|
||||
Structure the article as follows:
|
||||
|
||||
1. **Introduction** (2-3 sentences)
|
||||
- Define the term and its significance
|
||||
- Provide context for why it matters
|
||||
|
||||
2. **Main Content** (3-4 paragraphs)
|
||||
- Explain the concept in detail
|
||||
- Include practical examples and use cases
|
||||
- Discuss benefits and potential applications
|
||||
- Address any challenges or considerations
|
||||
|
||||
3. **Current State and Trends** (1-2 paragraphs)
|
||||
- Discuss current adoption and market status
|
||||
- Mention key players or technologies
|
||||
- Highlight recent developments
|
||||
|
||||
4. **Future Outlook** (1 paragraph)
|
||||
- Predict future developments
|
||||
- Discuss potential impact
|
||||
|
||||
5. **Conclusion** (1-2 sentences)
|
||||
- Summarize key points
|
||||
- End with a forward-looking statement
|
||||
|
||||
**Important Guidelines:**
|
||||
- Keep the total length to approximately one page (500-800 words)
|
||||
- Use clear, accessible language
|
||||
- Include specific examples and real-world applications
|
||||
- Make it engaging and informative for a general audience
|
||||
- Use markdown formatting for structure
|
||||
|
||||
**Image References:**
|
||||
Include [IMAGE 1: {TERM} concept diagram or illustration] after the introduction.
|
||||
Include [IMAGE 2: {TERM} practical example or use case] after the main content section.
|
||||
Include [IMAGE 3: {TERM} future trends or technology visualization] before the conclusion.
|
||||
|
||||
Replace "{TERM}" with the actual vocabulary term in the prompt.`,
|
||||
|
||||
// Image prompts
|
||||
imageReferencesPrompt: "**Image References:**\nPlease include the following image references throughout your response where appropriate:\n- [IMAGE 1: Relevant diagram or illustration related to the topic]\n- [IMAGE 2: Practical example or use case visualization]\n- [IMAGE 3: Additional supporting visual content]"
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
editor: Editor,
|
||||
options?: {
|
||||
max_tokens?: number;
|
||||
temperature?: number;
|
||||
top_p?: number;
|
||||
system_prompt?: string;
|
||||
return_images?: boolean;
|
||||
}
|
||||
): Promise<void> {
|
||||
// Use the provided model or fall back to the default from settings
|
||||
const modelToUse = model || this.settings.defaultLMStudioModel;
|
||||
|
||||
// Log the model being used for debugging
|
||||
console.log('Using model:', modelToUse);
|
||||
|
||||
await this.lmStudioService.queryLMStudio(
|
||||
query,
|
||||
modelToUse,
|
||||
stream,
|
||||
editor,
|
||||
options
|
||||
);
|
||||
}
|
||||
|
||||
// Getter for prompts service
|
||||
public getPromptsService(): PromptsService {
|
||||
return this.promptsService;
|
||||
}
|
||||
|
||||
private registerPerplexicaCommands(): void {
|
||||
// Command to update Perplexica URL
|
||||
this.addCommand({
|
||||
id: 'update-perplexica-url',
|
||||
name: 'Update Perplexica URL',
|
||||
callback: () => {
|
||||
const modal = new URLUpdateModal(this.app, {
|
||||
title: 'Update Perplexica API URL',
|
||||
label: 'Perplexica API URL',
|
||||
placeholder: 'http://localhost:3030/api/search',
|
||||
currentValue: this.settings.perplexicaEndpoint,
|
||||
onSave: async (newUrl: string) => {
|
||||
this.settings.perplexicaEndpoint = newUrl;
|
||||
await this.saveSettings();
|
||||
}
|
||||
});
|
||||
modal.open();
|
||||
}
|
||||
});
|
||||
|
||||
// Command to show current settings
|
||||
this.addCommand({
|
||||
id: 'show-perplexica-settings',
|
||||
name: 'Show Perplexica Settings',
|
||||
callback: () => {
|
||||
new Notice(`Current Perplexica URL: ${this.settings.perplexicaEndpoint}`);
|
||||
console.log('Perplexica Settings:', this.settings);
|
||||
}
|
||||
});
|
||||
|
||||
// Command to ask Perplexica
|
||||
this.addCommand({
|
||||
id: 'ask-perplexica',
|
||||
name: 'Ask Perplexica',
|
||||
editorCallback: (editor: Editor) => {
|
||||
const modal = new PerplexicaModal(this.app, editor, this.perplexicaService, this.promptsService);
|
||||
modal.open();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private registerPerplexityCommands(): void {
|
||||
// Command to update Perplexity URL
|
||||
this.addCommand({
|
||||
id: 'update-perplexity-url',
|
||||
name: 'Update Perplexity URL',
|
||||
callback: () => {
|
||||
const modal = new URLUpdateModal(this.app, {
|
||||
title: 'Update Perplexity API URL',
|
||||
label: 'Perplexity API URL',
|
||||
placeholder: 'https://api.perplexity.ai/chat/completions',
|
||||
currentValue: this.settings.perplexityEndpoint,
|
||||
onSave: async (newUrl: string) => {
|
||||
this.settings.perplexityEndpoint = newUrl;
|
||||
await this.saveSettings();
|
||||
}
|
||||
});
|
||||
modal.open();
|
||||
}
|
||||
});
|
||||
|
||||
// Command to show current Perplexity settings
|
||||
this.addCommand({
|
||||
id: 'show-perplexity-settings',
|
||||
name: 'Show Perplexity Settings',
|
||||
callback: () => {
|
||||
new Notice(`Current Perplexity URL: ${this.settings.perplexityEndpoint}`);
|
||||
console.log('Perplexity Settings:', this.settings);
|
||||
}
|
||||
});
|
||||
|
||||
// Command to ask Perplexity
|
||||
this.addCommand({
|
||||
id: 'ask-perplexity',
|
||||
name: 'Ask Perplexity',
|
||||
editorCallback: (editor: Editor) => {
|
||||
const modal = new PerplexityModal(this.app, editor, this.perplexityService, this.promptsService);
|
||||
modal.open();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private registerLMStudioCommands(): void {
|
||||
// Command to update LM Studio URL
|
||||
this.addCommand({
|
||||
id: 'update-lmstudio-url',
|
||||
name: 'Update LM Studio URL',
|
||||
callback: () => {
|
||||
const modal = new URLUpdateModal(this.app, {
|
||||
title: 'Update LM Studio API URL',
|
||||
label: 'LM Studio API URL',
|
||||
placeholder: 'http://localhost:1234/v1/chat/completions',
|
||||
currentValue: this.settings.lmStudioEndpoint,
|
||||
onSave: async (newUrl: string) => {
|
||||
this.settings.lmStudioEndpoint = newUrl;
|
||||
await this.saveSettings();
|
||||
}
|
||||
});
|
||||
modal.open();
|
||||
}
|
||||
});
|
||||
|
||||
// Command to show current LM Studio settings
|
||||
this.addCommand({
|
||||
id: 'show-lmstudio-settings',
|
||||
name: 'Show LM Studio Settings',
|
||||
callback: () => {
|
||||
new Notice(`Current LM Studio URL: ${this.settings.lmStudioEndpoint}`);
|
||||
console.log('LM Studio Settings:', this.settings);
|
||||
}
|
||||
});
|
||||
|
||||
// Command to ask LM Studio
|
||||
this.addCommand({
|
||||
id: 'ask-lmstudio',
|
||||
name: 'Ask LM Studio',
|
||||
editorCallback: (editor: Editor) => {
|
||||
const modal = new LMStudioModal(this.app, editor, this, this.lmStudioService, this.promptsService);
|
||||
modal.open();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private registerArticleGeneratorCommands(): void {
|
||||
// Register Article Generator command
|
||||
this.addCommand({
|
||||
id: 'generate-article',
|
||||
name: 'Generate One-Page Article',
|
||||
editorCallback: (editor: Editor) => {
|
||||
new ArticleGeneratorModal(this.app, editor, this.perplexityService, this.promptsService).open();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class PerplexedSettingTab extends PluginSettingTab {
|
||||
plugin: PerplexedPlugin;
|
||||
|
||||
constructor(app: App, plugin: PerplexedPlugin) {
|
||||
super(app, plugin);
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
display(): void {
|
||||
const { containerEl } = this;
|
||||
containerEl.empty();
|
||||
|
||||
containerEl.createEl('h2', { text: 'Perplexed Plugin Settings' });
|
||||
|
||||
// Perplexity Section
|
||||
const perplexityHeader = containerEl.createEl('h3', { text: 'Perplexity (Remote Service)' });
|
||||
perplexityHeader.style.color = 'var(--text-accent)';
|
||||
containerEl.createEl('p', {
|
||||
text: 'Configure settings for the hosted Perplexity AI service',
|
||||
cls: 'setting-item-description'
|
||||
});
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName('Endpoint')
|
||||
.setDesc('API endpoint for Perplexity service')
|
||||
.addText(text => text
|
||||
.setPlaceholder('https://api.perplexity.ai/chat/completions')
|
||||
.setValue(this.plugin.settings.perplexityEndpoint)
|
||||
.onChange(async (value: string) => {
|
||||
this.plugin.settings.perplexityEndpoint = value;
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
);
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName('API Key')
|
||||
.setDesc('Your Perplexity API key (required for remote service)')
|
||||
.addText(text => text
|
||||
.setPlaceholder('pplx-xxxxxxxxxxxxxxxxxxxxx')
|
||||
.setValue(this.plugin.settings.perplexityApiKey)
|
||||
.onChange(async (value: string) => {
|
||||
this.plugin.settings.perplexityApiKey = value;
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
);
|
||||
|
||||
// Perplexity Request Template
|
||||
const perplexityJsonSetting = new Setting(containerEl)
|
||||
.setName('Request Body Template')
|
||||
.setDesc('JSON template for Perplexity API requests');
|
||||
|
||||
// Create a textarea element for Perplexity
|
||||
const perplexityTextArea = document.createElement('textarea');
|
||||
perplexityTextArea.rows = 10;
|
||||
perplexityTextArea.cols = 50;
|
||||
perplexityTextArea.style.width = '100%';
|
||||
perplexityTextArea.style.minHeight = '300px';
|
||||
perplexityTextArea.style.fontFamily = 'monospace';
|
||||
perplexityTextArea.placeholder = 'Enter Perplexity JSON request template...';
|
||||
|
||||
// Set initial value if it exists
|
||||
if (this.plugin.settings.perplexityRequestTemplate) {
|
||||
try {
|
||||
const config = JSON.parse(this.plugin.settings.perplexityRequestTemplate);
|
||||
perplexityTextArea.value = JSON.stringify(config, null, 2);
|
||||
} catch (e) {
|
||||
// If not valid JSON, use as is
|
||||
perplexityTextArea.value = this.plugin.settings.perplexityRequestTemplate;
|
||||
}
|
||||
}
|
||||
|
||||
// Add input event listener for Perplexity
|
||||
perplexityTextArea.addEventListener('input', async () => {
|
||||
this.plugin.settings.perplexityRequestTemplate = perplexityTextArea.value;
|
||||
await this.plugin.saveSettings();
|
||||
});
|
||||
|
||||
// Add the textarea to the setting
|
||||
perplexityJsonSetting.settingEl.appendChild(perplexityTextArea);
|
||||
|
||||
// Perplexica Section
|
||||
const perplexicaHeader = containerEl.createEl('h3', { text: 'Perplexica (Self-Hosted)' });
|
||||
perplexicaHeader.style.color = 'var(--text-accent)';
|
||||
containerEl.createEl('p', {
|
||||
text: 'Configure settings for your local Perplexica installation',
|
||||
cls: 'setting-item-description'
|
||||
});
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName('Endpoint')
|
||||
.setDesc('API endpoint for your local Perplexica instance')
|
||||
.addText(text => text
|
||||
.setPlaceholder('http://localhost:3030/api/search')
|
||||
.setValue(this.plugin.settings.perplexicaEndpoint)
|
||||
.onChange(async (value: string) => {
|
||||
this.plugin.settings.perplexicaEndpoint = value;
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
);
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName('Fallback Container Path')
|
||||
.setDesc('Alternative endpoint for Docker container setups')
|
||||
.addText(text => text
|
||||
.setPlaceholder('http://host.docker.internal:3030/api/search')
|
||||
.setValue(this.plugin.settings.localLLMPath)
|
||||
.onChange(async (value: string) => {
|
||||
this.plugin.settings.localLLMPath = value;
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
);
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName('Default Model')
|
||||
.setDesc('Default AI model for Perplexica to use')
|
||||
.addText(text => text
|
||||
.setPlaceholder('llama3.2:latest')
|
||||
.setValue(this.plugin.settings.defaultModel)
|
||||
.onChange(async (value: string) => {
|
||||
this.plugin.settings.defaultModel = value;
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
);
|
||||
|
||||
// Perplexica Request Template
|
||||
const perplexicaJsonSetting = new Setting(containerEl)
|
||||
.setName('Request Body Template')
|
||||
.setDesc('JSON template for Perplexica API requests');
|
||||
|
||||
// Create a textarea element for Perplexica
|
||||
const perplexicaTextArea = document.createElement('textarea');
|
||||
perplexicaTextArea.rows = 10;
|
||||
perplexicaTextArea.cols = 50;
|
||||
perplexicaTextArea.style.width = '100%';
|
||||
perplexicaTextArea.style.minHeight = '300px';
|
||||
perplexicaTextArea.style.fontFamily = 'monospace';
|
||||
perplexicaTextArea.placeholder = 'Enter Perplexica JSON request template...';
|
||||
|
||||
// Set initial value if it exists
|
||||
if (this.plugin.settings.requestBodyTemplate) {
|
||||
try {
|
||||
const config = JSON.parse(this.plugin.settings.requestBodyTemplate);
|
||||
perplexicaTextArea.value = JSON.stringify(config, null, 2);
|
||||
} catch (e) {
|
||||
// If not valid JSON, use as is
|
||||
perplexicaTextArea.value = this.plugin.settings.requestBodyTemplate;
|
||||
}
|
||||
}
|
||||
|
||||
// Add input event listener for Perplexica
|
||||
perplexicaTextArea.addEventListener('input', async () => {
|
||||
this.plugin.settings.requestBodyTemplate = perplexicaTextArea.value;
|
||||
await this.plugin.saveSettings();
|
||||
});
|
||||
|
||||
// Add the textarea to the setting
|
||||
perplexicaJsonSetting.settingEl.appendChild(perplexicaTextArea);
|
||||
|
||||
// LM Studio Section
|
||||
const lmStudioHeader = containerEl.createEl('h3', { text: 'LM Studio (Local LLM)' });
|
||||
lmStudioHeader.style.color = 'var(--text-accent)';
|
||||
containerEl.createEl('p', {
|
||||
text: 'Configure settings for LM Studio local LLM service',
|
||||
cls: 'setting-item-description'
|
||||
});
|
||||
|
||||
// Base URL setting
|
||||
new Setting(containerEl)
|
||||
.setName('Base URL')
|
||||
.setDesc('Base URL for LM Studio API (e.g., http://localhost:1234)')
|
||||
.addText(text => text
|
||||
.setPlaceholder('http://localhost:1234')
|
||||
.setValue(this.plugin.settings.lmStudioEndpoint)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.lmStudioEndpoint = value.trim();
|
||||
await this.plugin.saveSettings();
|
||||
}));
|
||||
|
||||
// Endpoints configuration
|
||||
containerEl.createEl('h4', { text: 'API Endpoints' }).style.marginTop = '20px';
|
||||
|
||||
// Chat Completions Endpoint
|
||||
new Setting(containerEl)
|
||||
.setName('Chat Completions')
|
||||
.setDesc('Endpoint for chat completions')
|
||||
.addText(text => text
|
||||
.setValue('/v1/chat/completions')
|
||||
.setDisabled(true));
|
||||
|
||||
// Completions Endpoint
|
||||
new Setting(containerEl)
|
||||
.setName('Completions')
|
||||
.setDesc('Endpoint for completions')
|
||||
.addText(text => text
|
||||
.setValue('/v1/completions')
|
||||
.setDisabled(true));
|
||||
|
||||
// Embeddings Endpoint
|
||||
new Setting(containerEl)
|
||||
.setName('Embeddings')
|
||||
.setDesc('Endpoint for embeddings')
|
||||
.addText(text => text
|
||||
.setValue('/v1/embeddings')
|
||||
.setDisabled(true));
|
||||
|
||||
// Models Endpoint
|
||||
new Setting(containerEl)
|
||||
.setName('Models')
|
||||
.setDesc('Endpoint for listing available models')
|
||||
.addText(text => text
|
||||
.setValue('/v1/models')
|
||||
.setDisabled(true));
|
||||
|
||||
// Default Model
|
||||
new Setting(containerEl)
|
||||
.setName('Default Model')
|
||||
.setDesc('Default model to use with LM Studio')
|
||||
.addText(text => text
|
||||
.setPlaceholder('ibm/granite-3.2-8b')
|
||||
.setValue(this.plugin.settings.defaultLMStudioModel)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.defaultLMStudioModel = value.trim();
|
||||
await this.plugin.saveSettings();
|
||||
}));
|
||||
|
||||
// Test Connection Button
|
||||
const testConnectionSetting = new Setting(containerEl)
|
||||
.setName('Test Connection')
|
||||
.setDesc('Verify connection to LM Studio API');
|
||||
|
||||
testConnectionSetting.addButton(button => {
|
||||
button.setButtonText('Test Connection')
|
||||
.onClick(async () => {
|
||||
try {
|
||||
const response = await fetch(`${this.plugin.settings.lmStudioEndpoint}/v1/models`);
|
||||
if (response.ok) {
|
||||
new Notice('✅ Successfully connected to LM Studio API');
|
||||
} else {
|
||||
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
||||
}
|
||||
} catch (error: unknown) {
|
||||
console.error('LM Studio connection test failed:', error);
|
||||
const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';
|
||||
new Notice(`❌ Failed to connect to LM Studio: ${errorMessage}`);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// LM Studio Request Template
|
||||
const lmStudioJsonSetting = new Setting(containerEl)
|
||||
.setName('Request Body Template')
|
||||
.setDesc('JSON template for LM Studio API requests');
|
||||
|
||||
// Create a textarea element for LM Studio
|
||||
const lmStudioTextArea = document.createElement('textarea');
|
||||
lmStudioTextArea.rows = 10;
|
||||
lmStudioTextArea.cols = 50;
|
||||
lmStudioTextArea.style.width = '100%';
|
||||
lmStudioTextArea.style.minHeight = '300px';
|
||||
lmStudioTextArea.style.fontFamily = 'monospace';
|
||||
lmStudioTextArea.placeholder = 'Enter LM Studio JSON request template...';
|
||||
|
||||
// Set initial value if it exists
|
||||
if (this.plugin.settings.lmStudioRequestTemplate) {
|
||||
try {
|
||||
const config = JSON.parse(this.plugin.settings.lmStudioRequestTemplate);
|
||||
lmStudioTextArea.value = JSON.stringify(config, null, 2);
|
||||
} catch (e) {
|
||||
// If not valid JSON, use as is
|
||||
lmStudioTextArea.value = this.plugin.settings.lmStudioRequestTemplate;
|
||||
}
|
||||
}
|
||||
|
||||
// Add input event listener for LM Studio
|
||||
lmStudioTextArea.addEventListener('input', async () => {
|
||||
this.plugin.settings.lmStudioRequestTemplate = lmStudioTextArea.value;
|
||||
await this.plugin.saveSettings();
|
||||
});
|
||||
|
||||
// Add the textarea to the setting
|
||||
lmStudioJsonSetting.settingEl.appendChild(lmStudioTextArea);
|
||||
|
||||
// Prompts Section
|
||||
const promptsHeader = containerEl.createEl('h3', { text: 'Prompts & Text Configuration' });
|
||||
promptsHeader.style.color = 'var(--text-accent)';
|
||||
containerEl.createEl('p', {
|
||||
text: 'Customize all prompts, placeholders, descriptions, and messages used throughout the plugin',
|
||||
cls: 'setting-item-description'
|
||||
});
|
||||
|
||||
// System Prompts
|
||||
containerEl.createEl('h4', { text: 'System Prompts' });
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName('Perplexity System Prompt')
|
||||
.setDesc('System prompt used for Perplexity AI requests')
|
||||
.addTextArea(text => text
|
||||
.setPlaceholder('Enter system prompt for Perplexity...')
|
||||
.setValue(this.plugin.settings.prompts.perplexitySystemPrompt)
|
||||
.onChange(async (value: string) => {
|
||||
this.plugin.settings.prompts.perplexitySystemPrompt = value;
|
||||
this.plugin.getPromptsService().updateSettings(this.plugin.settings.prompts);
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
);
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName('Perplexica System Prompt')
|
||||
.setDesc('System prompt used for Perplexica requests')
|
||||
.addTextArea(text => text
|
||||
.setPlaceholder('Enter system prompt for Perplexica...')
|
||||
.setValue(this.plugin.settings.prompts.perplexicaSystemPrompt)
|
||||
.onChange(async (value: string) => {
|
||||
this.plugin.settings.prompts.perplexicaSystemPrompt = value;
|
||||
this.plugin.getPromptsService().updateSettings(this.plugin.settings.prompts);
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
);
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName('LM Studio Default System Prompt')
|
||||
.setDesc('Default system prompt used for LM Studio requests')
|
||||
.addTextArea(text => text
|
||||
.setPlaceholder('Enter default system prompt for LM Studio...')
|
||||
.setValue(this.plugin.settings.prompts.lmStudioDefaultSystemPrompt)
|
||||
.onChange(async (value: string) => {
|
||||
this.plugin.settings.prompts.lmStudioDefaultSystemPrompt = value;
|
||||
this.plugin.getPromptsService().updateSettings(this.plugin.settings.prompts);
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
);
|
||||
|
||||
// Placeholder Text
|
||||
containerEl.createEl('h4', { text: 'Placeholder Text' });
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName('Perplexity Query Placeholder')
|
||||
.setDesc('Placeholder text for Perplexity query input')
|
||||
.addText(text => text
|
||||
.setPlaceholder('Enter placeholder text...')
|
||||
.setValue(this.plugin.settings.prompts.perplexityQueryPlaceholder)
|
||||
.onChange(async (value: string) => {
|
||||
this.plugin.settings.prompts.perplexityQueryPlaceholder = value;
|
||||
this.plugin.getPromptsService().updateSettings(this.plugin.settings.prompts);
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
);
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName('Perplexica Query Placeholder')
|
||||
.setDesc('Placeholder text for Perplexica query input')
|
||||
.addText(text => text
|
||||
.setPlaceholder('Enter placeholder text...')
|
||||
.setValue(this.plugin.settings.prompts.perplexicaQueryPlaceholder)
|
||||
.onChange(async (value: string) => {
|
||||
this.plugin.settings.prompts.perplexicaQueryPlaceholder = value;
|
||||
this.plugin.getPromptsService().updateSettings(this.plugin.settings.prompts);
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
);
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName('LM Studio Query Placeholder')
|
||||
.setDesc('Placeholder text for LM Studio query input')
|
||||
.addText(text => text
|
||||
.setPlaceholder('Enter placeholder text...')
|
||||
.setValue(this.plugin.settings.prompts.lmStudioQueryPlaceholder)
|
||||
.onChange(async (value: string) => {
|
||||
this.plugin.settings.prompts.lmStudioQueryPlaceholder = value;
|
||||
this.plugin.getPromptsService().updateSettings(this.plugin.settings.prompts);
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
);
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName('LM Studio System Prompt Placeholder')
|
||||
.setDesc('Placeholder text for LM Studio system prompt input')
|
||||
.addText(text => text
|
||||
.setPlaceholder('Enter placeholder text...')
|
||||
.setValue(this.plugin.settings.prompts.lmStudioSystemPromptPlaceholder)
|
||||
.onChange(async (value: string) => {
|
||||
this.plugin.settings.prompts.lmStudioSystemPromptPlaceholder = value;
|
||||
this.plugin.getPromptsService().updateSettings(this.plugin.settings.prompts);
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
);
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName('Article Term Placeholder')
|
||||
.setDesc('Placeholder text for article generator term input')
|
||||
.addText(text => text
|
||||
.setPlaceholder('Enter placeholder text...')
|
||||
.setValue(this.plugin.settings.prompts.articleTermPlaceholder)
|
||||
.onChange(async (value: string) => {
|
||||
this.plugin.settings.prompts.articleTermPlaceholder = value;
|
||||
this.plugin.getPromptsService().updateSettings(this.plugin.settings.prompts);
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
);
|
||||
|
||||
// Descriptions and Labels
|
||||
containerEl.createEl('h4', { text: 'Descriptions & Labels' });
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName('Deep Research Description')
|
||||
.setDesc('Description shown for deep research model')
|
||||
.addTextArea(text => text
|
||||
.setPlaceholder('Enter description...')
|
||||
.setValue(this.plugin.settings.prompts.deepResearchDescription)
|
||||
.onChange(async (value: string) => {
|
||||
this.plugin.settings.prompts.deepResearchDescription = value;
|
||||
this.plugin.getPromptsService().updateSettings(this.plugin.settings.prompts);
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
);
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName('Images Toggle Description')
|
||||
.setDesc('Description for images toggle in Perplexity modal')
|
||||
.addTextArea(text => text
|
||||
.setPlaceholder('Enter description...')
|
||||
.setValue(this.plugin.settings.prompts.imagesToggleDescription)
|
||||
.onChange(async (value: string) => {
|
||||
this.plugin.settings.prompts.imagesToggleDescription = value;
|
||||
this.plugin.getPromptsService().updateSettings(this.plugin.settings.prompts);
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
);
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName('Images Toggle Generic Description')
|
||||
.setDesc('Generic description for images toggle in other modals')
|
||||
.addTextArea(text => text
|
||||
.setPlaceholder('Enter description...')
|
||||
.setValue(this.plugin.settings.prompts.imagesToggleGenericDescription)
|
||||
.onChange(async (value: string) => {
|
||||
this.plugin.settings.prompts.imagesToggleGenericDescription = value;
|
||||
this.plugin.getPromptsService().updateSettings(this.plugin.settings.prompts);
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
);
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName('Article Term Description')
|
||||
.setDesc('Description for article generator term input')
|
||||
.addTextArea(text => text
|
||||
.setPlaceholder('Enter description...')
|
||||
.setValue(this.plugin.settings.prompts.articleTermDescription)
|
||||
.onChange(async (value: string) => {
|
||||
this.plugin.settings.prompts.articleTermDescription = value;
|
||||
this.plugin.getPromptsService().updateSettings(this.plugin.settings.prompts);
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
);
|
||||
|
||||
// Notices and Messages
|
||||
containerEl.createEl('h4', { text: 'Notices & Messages' });
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName('Deep Research Loading Notice')
|
||||
.setDesc('Notice shown when deep research is in progress')
|
||||
.addText(text => text
|
||||
.setPlaceholder('Enter notice text...')
|
||||
.setValue(this.plugin.settings.prompts.deepResearchLoadingNotice)
|
||||
.onChange(async (value: string) => {
|
||||
this.plugin.settings.prompts.deepResearchLoadingNotice = value;
|
||||
this.plugin.getPromptsService().updateSettings(this.plugin.settings.prompts);
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
);
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName('Enter Question Notice')
|
||||
.setDesc('Notice shown when no question is entered')
|
||||
.addText(text => text
|
||||
.setPlaceholder('Enter notice text...')
|
||||
.setValue(this.plugin.settings.prompts.enterQuestionNotice)
|
||||
.onChange(async (value: string) => {
|
||||
this.plugin.settings.prompts.enterQuestionNotice = value;
|
||||
this.plugin.getPromptsService().updateSettings(this.plugin.settings.prompts);
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
);
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName('Enter Term Notice')
|
||||
.setDesc('Notice shown when no term is entered for article generator')
|
||||
.addText(text => text
|
||||
.setPlaceholder('Enter notice text...')
|
||||
.setValue(this.plugin.settings.prompts.enterTermNotice)
|
||||
.onChange(async (value: string) => {
|
||||
this.plugin.settings.prompts.enterTermNotice = value;
|
||||
this.plugin.getPromptsService().updateSettings(this.plugin.settings.prompts);
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
);
|
||||
|
||||
// Article Generator Template
|
||||
containerEl.createEl('h4', { text: 'Article Generator Template' });
|
||||
|
||||
const articleTemplateSetting = new Setting(containerEl)
|
||||
.setName('Article Generator Template')
|
||||
.setDesc('Template for generating articles. Use {TERM} as placeholder for the term.');
|
||||
|
||||
const articleTemplateTextArea = document.createElement('textarea');
|
||||
articleTemplateTextArea.rows = 15;
|
||||
articleTemplateTextArea.cols = 50;
|
||||
articleTemplateTextArea.style.width = '100%';
|
||||
articleTemplateTextArea.style.minHeight = '400px';
|
||||
articleTemplateTextArea.style.fontFamily = 'monospace';
|
||||
articleTemplateTextArea.placeholder = 'Enter article generator template...';
|
||||
articleTemplateTextArea.value = this.plugin.settings.prompts.articleGeneratorTemplate;
|
||||
|
||||
articleTemplateTextArea.addEventListener('input', async () => {
|
||||
this.plugin.settings.prompts.articleGeneratorTemplate = articleTemplateTextArea.value;
|
||||
this.plugin.getPromptsService().updateSettings(this.plugin.settings.prompts);
|
||||
await this.plugin.saveSettings();
|
||||
});
|
||||
|
||||
articleTemplateSetting.settingEl.appendChild(articleTemplateTextArea);
|
||||
|
||||
// Image Prompts
|
||||
containerEl.createEl('h4', { text: 'Image Prompts' });
|
||||
|
||||
const imagePromptsSetting = new Setting(containerEl)
|
||||
.setName('Image References Prompt')
|
||||
.setDesc('Prompt added to queries when images are enabled');
|
||||
|
||||
const imagePromptsTextArea = document.createElement('textarea');
|
||||
imagePromptsTextArea.rows = 8;
|
||||
imagePromptsTextArea.cols = 50;
|
||||
imagePromptsTextArea.style.width = '100%';
|
||||
imagePromptsTextArea.style.minHeight = '200px';
|
||||
imagePromptsTextArea.style.fontFamily = 'monospace';
|
||||
imagePromptsTextArea.placeholder = 'Enter image references prompt...';
|
||||
imagePromptsTextArea.value = this.plugin.settings.prompts.imageReferencesPrompt;
|
||||
|
||||
imagePromptsTextArea.addEventListener('input', async () => {
|
||||
this.plugin.settings.prompts.imageReferencesPrompt = imagePromptsTextArea.value;
|
||||
this.plugin.getPromptsService().updateSettings(this.plugin.settings.prompts);
|
||||
await this.plugin.saveSettings();
|
||||
});
|
||||
|
||||
imagePromptsSetting.settingEl.appendChild(imagePromptsTextArea);
|
||||
}
|
||||
}
|
||||
27
src/core/PerplexedPlugin.ts
Normal file
27
src/core/PerplexedPlugin.ts
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
import { App, Plugin, PluginSettingTab } from 'obsidian';
|
||||
import { PerplexedSettings, DEFAULT_SETTINGS } from '../settings/PerplexedSettings';
|
||||
import { PerplexedSettingTab } from '../settings/PerplexedSettingTab';
|
||||
|
||||
export default class PerplexedPlugin extends Plugin {
|
||||
settings: PerplexedSettings;
|
||||
|
||||
async onload() {
|
||||
await this.loadSettings();
|
||||
|
||||
// Add settings tab
|
||||
this.addSettingTab(new PerplexedSettingTab(this.app, this));
|
||||
}
|
||||
|
||||
async loadSettings(): Promise<void> {
|
||||
this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());
|
||||
}
|
||||
|
||||
async saveSettings(): Promise<void> {
|
||||
await this.saveData(this.settings);
|
||||
}
|
||||
|
||||
updateStatusBar(): void {
|
||||
// Implementation for status bar updates
|
||||
console.log('Status bar updated');
|
||||
}
|
||||
}
|
||||
|
|
@ -1,13 +1,13 @@
|
|||
import { App, Plugin } from 'obsidian';
|
||||
import { Plugin } from 'obsidian';
|
||||
import { PerplexedSettings, DEFAULT_SETTINGS } from '../settings/PerplexedSettings';
|
||||
import { PerplexedSettingTab } from '../settings/PerplexedSettings';
|
||||
import { PerplexedSettingTab } from '../settings/PerplexedSettingTab';
|
||||
import { LMStudioSettings, DEFAULT_LMSTUDIO_SETTINGS } from '../settings/LMStudioSettings';
|
||||
|
||||
export default class PerplexedPluginCore extends Plugin {
|
||||
settings: PerplexedSettings;
|
||||
lmStudioSettings: LMStudioSettings;
|
||||
export class PerplexedPluginCore extends Plugin {
|
||||
settings: PerplexedSettings = { ...DEFAULT_SETTINGS };
|
||||
lmStudioSettings: LMStudioSettings = { ...DEFAULT_LMSTUDIO_SETTINGS };
|
||||
|
||||
async onload() {
|
||||
async onload(): Promise<void> {
|
||||
await this.loadSettings();
|
||||
|
||||
// Add settings tab
|
||||
|
|
@ -17,30 +17,46 @@ export default class PerplexedPluginCore extends Plugin {
|
|||
this.registerCommands();
|
||||
}
|
||||
|
||||
async loadSettings() {
|
||||
// Load main settings
|
||||
this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());
|
||||
|
||||
// Load LM Studio settings
|
||||
this.lmStudioSettings = Object.assign(
|
||||
{},
|
||||
DEFAULT_LMSTUDIO_SETTINGS,
|
||||
await this.loadData()
|
||||
);
|
||||
|
||||
// Save any defaults that were missing
|
||||
await this.saveSettings();
|
||||
async loadSettings(): Promise<void> {
|
||||
try {
|
||||
// Load main settings
|
||||
const loadedSettings = await this.loadData();
|
||||
if (loadedSettings) {
|
||||
this.settings = { ...DEFAULT_SETTINGS, ...loadedSettings };
|
||||
}
|
||||
|
||||
// Load LM Studio settings
|
||||
const loadedLMStudioSettings = await this.loadData('lmstudio-settings');
|
||||
if (loadedLMStudioSettings) {
|
||||
this.lmStudioSettings = {
|
||||
...DEFAULT_LMSTUDIO_SETTINGS,
|
||||
...loadedLMStudioSettings
|
||||
};
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error loading settings:', error);
|
||||
}
|
||||
}
|
||||
|
||||
async saveSettings() {
|
||||
// Save main settings
|
||||
await this.saveData(this.settings);
|
||||
|
||||
// Save LM Studio settings
|
||||
await this.saveData(this.lmStudioSettings);
|
||||
async saveSettings(): Promise<void> {
|
||||
try {
|
||||
// Save main settings
|
||||
await this.saveData(this.settings);
|
||||
|
||||
// Save LM Studio settings with a separate key
|
||||
await this.saveData(this.lmStudioSettings, 'lmstudio-settings');
|
||||
} catch (error) {
|
||||
console.error('Error saving settings:', error);
|
||||
}
|
||||
}
|
||||
|
||||
private registerCommands() {
|
||||
|
||||
protected registerCommands(): void {
|
||||
// Base implementation - can be overridden by child classes
|
||||
}
|
||||
|
||||
protected setupUI(): void {
|
||||
// Base implementation - can be overridden by child classes
|
||||
} private registerCommands() {
|
||||
// Register your commands here
|
||||
// Example:
|
||||
this.addCommand({
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import { Editor, Notice } from 'obsidian';
|
||||
import { PerplexitySettings } from '../settings/PerplexitySettings';
|
||||
|
||||
export interface PerplexityOptions {
|
||||
return_citations?: boolean;
|
||||
|
|
@ -7,12 +8,7 @@ export interface PerplexityOptions {
|
|||
search_recency_filter?: string;
|
||||
}
|
||||
|
||||
export interface PerplexitySettings {
|
||||
perplexityApiKey: string;
|
||||
perplexityEndpoint: string;
|
||||
promptsService?: any; // Will be PromptsService type
|
||||
requestTemplate?: string;
|
||||
}
|
||||
// Use the imported PerplexitySettings interface from settings file
|
||||
|
||||
export class PerplexityService {
|
||||
private settings: PerplexitySettings;
|
||||
|
|
|
|||
107
src/settings/PerplexedSettingTab.ts
Normal file
107
src/settings/PerplexedSettingTab.ts
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
import { App, PluginSettingTab, Setting } from 'obsidian';
|
||||
import { PerplexedPluginCore } from '../core/PerplexedPluginCore';
|
||||
|
||||
export class PerplexedSettingTab extends PluginSettingTab {
|
||||
plugin: PerplexedPluginCore;
|
||||
|
||||
constructor(app: App, plugin: PerplexedPluginCore) {
|
||||
super(app, plugin);
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
display(): void {
|
||||
const { containerEl } = this;
|
||||
containerEl.empty();
|
||||
containerEl.createEl('h2', { text: 'Perplexed Plugin Settings' });
|
||||
|
||||
// Add general settings section
|
||||
this.addGeneralSettings(containerEl);
|
||||
|
||||
// Add Perplexity settings section
|
||||
this.addPerplexitySettings(containerEl);
|
||||
|
||||
// Add LM Studio settings section
|
||||
this.addLMStudioSettings(containerEl);
|
||||
}
|
||||
|
||||
private addGeneralSettings(containerEl: HTMLElement): void {
|
||||
containerEl.createEl('h3', { text: 'General Settings' });
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName('Status Bar Position')
|
||||
.setDesc('Position of the status bar item')
|
||||
.addDropdown(dropdown => {
|
||||
dropdown
|
||||
.addOption('left', 'Left')
|
||||
.addOption('right', 'Right')
|
||||
.setValue(this.plugin.settings.statusBarPosition || 'left')
|
||||
.onChange(async (value: string) => {
|
||||
if (value === 'left' || value === 'right') {
|
||||
this.plugin.settings.statusBarPosition = value;
|
||||
await this.plugin.saveSettings();
|
||||
}
|
||||
});
|
||||
return dropdown;
|
||||
});
|
||||
}
|
||||
|
||||
private addPerplexitySettings(containerEl: HTMLElement): void {
|
||||
containerEl.createEl('h3', { text: 'Perplexity Settings' });
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName('Enable Perplexity')
|
||||
.setDesc('Enable or disable the Perplexity provider')
|
||||
.addToggle(toggle => toggle
|
||||
.setValue(this.plugin.settings.enablePerplexity || false)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.enablePerplexity = value;
|
||||
await this.plugin.saveSettings();
|
||||
this.display(); // Refresh the settings view
|
||||
}));
|
||||
|
||||
if (this.plugin.settings.enablePerplexity) {
|
||||
new Setting(containerEl)
|
||||
.setName('API Key')
|
||||
.setDesc('Your Perplexity API key')
|
||||
.addText(text => text
|
||||
.setPlaceholder('Enter your API key')
|
||||
.setValue(this.plugin.settings.perplexitySettings?.apiKey || '')
|
||||
.onChange(async (value) => {
|
||||
if (!this.plugin.settings.perplexitySettings) {
|
||||
this.plugin.settings.perplexitySettings = {} as any;
|
||||
}
|
||||
this.plugin.settings.perplexitySettings.apiKey = value;
|
||||
await this.plugin.saveSettings();
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
private addLMStudioSettings(containerEl: HTMLElement): void {
|
||||
containerEl.createEl('h3', { text: 'LM Studio Settings' });
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName('Enable LM Studio')
|
||||
.setDesc('Enable or disable the LM Studio provider')
|
||||
.addToggle(toggle => toggle
|
||||
.setValue(this.plugin.settings.enableLMStudio || false)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.enableLMStudio = value;
|
||||
await this.plugin.saveSettings();
|
||||
this.display(); // Refresh the settings view
|
||||
}));
|
||||
|
||||
if (this.plugin.settings.enableLMStudio) {
|
||||
new Setting(containerEl)
|
||||
.setName('LM Studio Endpoint')
|
||||
.setDesc('The URL of your LM Studio server')
|
||||
.addText(text => text
|
||||
.setPlaceholder('http://localhost:1234')
|
||||
.setValue(this.plugin.settings.lmStudioSettings?.endpoint || '')
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.lmStudioSettings = this.plugin.settings.lmStudioSettings || {} as any;
|
||||
this.plugin.settings.lmStudioSettings.endpoint = value;
|
||||
await this.plugin.saveSettings();
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,60 +1,76 @@
|
|||
import { App, PluginSettingTab, Setting } from 'obsidian';
|
||||
import PerplexedPlugin from '../../main';
|
||||
import { PerplexitySettings, DEFAULT_PERPLEXITY_SETTINGS } from './PerplexitySettings';
|
||||
|
||||
export interface PerplexedSettings {
|
||||
// General Settings
|
||||
mySetting: string;
|
||||
localLLMPath: string;
|
||||
// General settings
|
||||
enablePerplexity: boolean;
|
||||
enablePerplexica: boolean;
|
||||
enableLMStudio: boolean;
|
||||
defaultProvider: 'perplexity' | 'perplexica' | 'lmstudio';
|
||||
|
||||
// Perplexity Settings
|
||||
perplexityApiKey: string;
|
||||
perplexityEndpoint: string;
|
||||
// UI Settings
|
||||
showStatusBar: boolean;
|
||||
statusBarPosition: 'left' | 'right';
|
||||
statusBarPriority: number;
|
||||
|
||||
// LM Studio Settings
|
||||
lmStudioEndpoint: string;
|
||||
defaultLMStudioModel: string;
|
||||
// Prompt settings
|
||||
defaultSystemPrompt: string;
|
||||
customPrompts: Record<string, string>;
|
||||
|
||||
// Default Models and Modes
|
||||
defaultModel: string;
|
||||
defaultOptimizationMode: string;
|
||||
defaultFocusMode: string;
|
||||
// Service-specific settings
|
||||
perplexitySettings: PerplexitySettings;
|
||||
|
||||
// Prompts
|
||||
prompts: {
|
||||
// System Prompts
|
||||
perplexitySystemPrompt: string;
|
||||
lmStudioDefaultSystemPrompt: string;
|
||||
|
||||
// Placeholders
|
||||
perplexityQueryPlaceholder: string;
|
||||
lmStudioQueryPlaceholder: string;
|
||||
// LM Studio specific settings
|
||||
lmStudioSettings: {
|
||||
endpoint: string;
|
||||
model: string;
|
||||
temperature: number;
|
||||
maxTokens: number;
|
||||
};
|
||||
|
||||
// Perplexica specific settings
|
||||
perplexicaSettings: {
|
||||
endpoint: string;
|
||||
apiKey: string;
|
||||
model: string;
|
||||
};
|
||||
}
|
||||
|
||||
export const DEFAULT_SETTINGS: PerplexedSettings = {
|
||||
mySetting: 'default',
|
||||
localLLMPath: 'http://host.docker.internal:3030/api/search',
|
||||
// General settings
|
||||
enablePerplexity: true,
|
||||
enablePerplexica: false,
|
||||
enableLMStudio: false,
|
||||
defaultProvider: 'perplexity',
|
||||
|
||||
// Perplexity Defaults
|
||||
perplexityApiKey: '',
|
||||
perplexityEndpoint: 'https://api.perplexity.ai',
|
||||
// UI Settings
|
||||
showStatusBar: true,
|
||||
statusBarPosition: 'left',
|
||||
statusBarPriority: 100,
|
||||
|
||||
// LM Studio Defaults
|
||||
lmStudioEndpoint: 'http://localhost:1234',
|
||||
defaultLMStudioModel: 'ibm/granite-3.2-8b',
|
||||
// Prompt settings
|
||||
defaultSystemPrompt: 'You are a helpful AI assistant.',
|
||||
customPrompts: {},
|
||||
|
||||
// Default Models and Modes
|
||||
defaultModel: 'sonar-medium-online',
|
||||
defaultOptimizationMode: 'balanced',
|
||||
defaultFocusMode: 'search',
|
||||
// Perplexity settings
|
||||
perplexitySettings: {
|
||||
...DEFAULT_PERPLEXITY_SETTINGS
|
||||
},
|
||||
|
||||
// Default Prompts
|
||||
prompts: {
|
||||
perplexitySystemPrompt: 'You are a helpful AI assistant that provides accurate and concise responses.',
|
||||
lmStudioDefaultSystemPrompt: 'You are a helpful AI assistant running locally.',
|
||||
|
||||
perplexityQueryPlaceholder: 'Ask me anything...',
|
||||
lmStudioQueryPlaceholder: 'Ask me anything...',
|
||||
// LM Studio settings
|
||||
lmStudioSettings: {
|
||||
endpoint: 'http://localhost:1234',
|
||||
model: 'lm-studio',
|
||||
temperature: 0.7,
|
||||
maxTokens: 2000
|
||||
},
|
||||
|
||||
// Perplexica settings
|
||||
perplexicaSettings: {
|
||||
endpoint: 'https://api.perplexica.com',
|
||||
apiKey: '',
|
||||
model: 'perplexica'
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -80,8 +96,41 @@ export class PerplexedSettingTab extends PluginSettingTab {
|
|||
containerEl.createEl('h3', { text: 'General Settings' });
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName('Local LLM Path')
|
||||
.setDesc('Path to your local LLM API endpoint')
|
||||
.setName('Default Provider')
|
||||
.setDesc('Select the default AI provider to use')
|
||||
.addDropdown(dropdown => dropdown
|
||||
.addOption('perplexity', 'Perplexity')
|
||||
.addOption('perplexica', 'Perplexica')
|
||||
.addOption('lmstudio', 'LM Studio')
|
||||
.setValue(this.plugin.settings.defaultProvider)
|
||||
.onChange(async (value: 'perplexity' | 'perplexica' | 'lmstudio') => {
|
||||
this.plugin.settings.defaultProvider = value;
|
||||
await this.plugin.saveSettings();
|
||||
}));
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName('Show Status Bar')
|
||||
.setDesc('Toggle the status bar visibility')
|
||||
.addToggle(toggle => toggle
|
||||
.setValue(this.plugin.settings.showStatusBar)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.showStatusBar = value;
|
||||
await this.plugin.saveSettings();
|
||||
this.plugin.updateStatusBar();
|
||||
}));
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName('Status Bar Position')
|
||||
.setDesc('Position of the status bar item')
|
||||
.addDropdown(dropdown => dropdown
|
||||
.addOption('left', 'Left')
|
||||
.addOption('right', 'Right')
|
||||
.setValue(this.plugin.settings.statusBarPosition)
|
||||
.onChange(async (value: 'left' | 'right') => {
|
||||
this.plugin.settings.statusBarPosition = value;
|
||||
await this.plugin.saveSettings();
|
||||
this.plugin.updateStatusBar();
|
||||
}));
|
||||
.addText(text => text
|
||||
.setPlaceholder('http://localhost:3030/api/search')
|
||||
.setValue(this.plugin.settings.localLLMPath)
|
||||
|
|
@ -95,15 +144,116 @@ export class PerplexedSettingTab extends PluginSettingTab {
|
|||
containerEl.createEl('h3', { text: 'Perplexity Settings' });
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName('API Key')
|
||||
.setDesc('Your Perplexity API key')
|
||||
.addText(text => text
|
||||
.setPlaceholder('Enter your API key')
|
||||
.setValue(this.plugin.settings.perplexityApiKey)
|
||||
.setName('Enable Perplexity')
|
||||
.setDesc('Enable or disable the Perplexity provider')
|
||||
.addToggle(toggle => toggle
|
||||
.setValue(this.plugin.settings.enablePerplexity)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.perplexityApiKey = value;
|
||||
this.plugin.settings.enablePerplexity = value;
|
||||
await this.plugin.saveSettings();
|
||||
this.display(); // Refresh the settings view
|
||||
}));
|
||||
|
||||
if (this.plugin.settings.enablePerplexity) {
|
||||
new Setting(containerEl)
|
||||
.setName('API Key')
|
||||
.setDesc('Your Perplexity API key')
|
||||
.addText(text => text
|
||||
.setPlaceholder('Enter your API key')
|
||||
.setValue(this.plugin.settings.perplexitySettings.apiKey)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.perplexitySettings.apiKey = value;
|
||||
await this.plugin.saveSettings();
|
||||
}));
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName('Default Model')
|
||||
.setDesc('Default model to use for Perplexity')
|
||||
.addText(text => text
|
||||
.setPlaceholder('pplx-7b-chat')
|
||||
.setValue(this.plugin.settings.perplexitySettings.defaultModel)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.perplexitySettings.defaultModel = value;
|
||||
await this.plugin.saveSettings();
|
||||
}));
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName('Endpoint')
|
||||
.setDesc('API endpoint for Perplexity')
|
||||
.addText(text => text
|
||||
.setPlaceholder('https://api.perplexity.ai')
|
||||
.setValue(this.plugin.settings.perplexitySettings.endpoint)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.perplexitySettings.endpoint = value;
|
||||
await this.plugin.saveSettings();
|
||||
}));
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName('Temperature')
|
||||
.setDesc('Controls randomness (0.0 to 2.0)')
|
||||
.addSlider(slider => slider
|
||||
.setLimits(0, 2, 0.1)
|
||||
.setValue(this.plugin.settings.perplexitySettings.temperature)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.perplexitySettings.temperature = value;
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
.setDynamicTooltip()
|
||||
);
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName('Max Tokens')
|
||||
.setDesc('Maximum number of tokens to generate')
|
||||
.addText(text => text
|
||||
.setPlaceholder('2048')
|
||||
.setValue(this.plugin.settings.perplexitySettings.maxTokens?.toString() || '2048')
|
||||
.onChange(async (value) => {
|
||||
const numValue = parseInt(value);
|
||||
if (!isNaN(numValue)) {
|
||||
this.plugin.settings.perplexitySettings.maxTokens = numValue;
|
||||
await this.plugin.saveSettings();
|
||||
}
|
||||
}));
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName('Top P')
|
||||
.setDesc('Controls diversity via nucleus sampling (0.0 to 1.0)')
|
||||
.addSlider(slider => slider
|
||||
.setLimits(0, 1, 0.05)
|
||||
.setValue(this.plugin.settings.perplexitySettings.topP)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.perplexitySettings.topP = value;
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
.setDynamicTooltip()
|
||||
);
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName('Frequency Penalty')
|
||||
.setDesc('Penalize new tokens based on their frequency (-2.0 to 2.0)')
|
||||
.addSlider(slider => slider
|
||||
.setLimits(-2, 2, 0.1)
|
||||
.setValue(this.plugin.settings.perplexitySettings.frequencyPenalty)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.perplexitySettings.frequencyPenalty = value;
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
.setDynamicTooltip()
|
||||
);
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName('Presence Penalty')
|
||||
.setDesc('Penalize new tokens based on their presence (-2.0 to 2.0)')
|
||||
.addSlider(slider => slider
|
||||
.setLimits(-2, 2, 0.1)
|
||||
.setValue(this.plugin.settings.perplexitySettings.presencePenalty)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.perplexitySettings.presencePenalty = value;
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
.setDynamicTooltip()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private addLMStudioSettings(containerEl: HTMLElement): void {
|
||||
|
|
@ -113,9 +263,9 @@ export class PerplexedSettingTab extends PluginSettingTab {
|
|||
.setName('Endpoint')
|
||||
.setDesc('LM Studio API endpoint (e.g., http://localhost:1234)')
|
||||
.addText(text => text
|
||||
.setValue(this.plugin.settings.lmStudioEndpoint)
|
||||
.setValue(this.plugin.settings.lmStudioSettings.endpoint)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.lmStudioEndpoint = value;
|
||||
this.plugin.settings.lmStudioSettings.endpoint = value;
|
||||
await this.plugin.saveSettings();
|
||||
}));
|
||||
|
||||
|
|
@ -123,9 +273,9 @@ export class PerplexedSettingTab extends PluginSettingTab {
|
|||
.setName('Default Model')
|
||||
.setDesc('Default model to use with LM Studio')
|
||||
.addText(text => text
|
||||
.setValue(this.plugin.settings.defaultLMStudioModel)
|
||||
.setValue(this.plugin.settings.lmStudioSettings.model)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.defaultLMStudioModel = value;
|
||||
this.plugin.settings.lmStudioSettings.model = value;
|
||||
await this.plugin.saveSettings();
|
||||
}));
|
||||
}
|
||||
|
|
|
|||
70
src/settings/PerplexitySettings.ts
Normal file
70
src/settings/PerplexitySettings.ts
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
export interface PerplexitySettings {
|
||||
// API Configuration
|
||||
apiKey: string;
|
||||
endpoint: string;
|
||||
defaultModel: string;
|
||||
|
||||
// Generation Parameters
|
||||
temperature: number;
|
||||
maxTokens: number;
|
||||
topP: number;
|
||||
frequencyPenalty: number;
|
||||
presencePenalty: number;
|
||||
|
||||
// UI Settings
|
||||
showStatusBar: boolean;
|
||||
autoSuggest: boolean;
|
||||
autoSuggestDelay: number;
|
||||
showContextMenu: boolean;
|
||||
|
||||
// Debugging & Performance
|
||||
debugMode: boolean;
|
||||
requestTimeout: number;
|
||||
maxRetries: number;
|
||||
retryDelay: number;
|
||||
|
||||
// Prompts
|
||||
defaultSystemPrompt: string;
|
||||
defaultUserPrompt: string;
|
||||
|
||||
// Service-specific properties
|
||||
perplexityApiKey: string;
|
||||
perplexityEndpoint: string;
|
||||
promptsService?: any; // Will be PromptsService type
|
||||
requestTemplate?: string;
|
||||
}
|
||||
|
||||
export const DEFAULT_PERPLEXITY_SETTINGS: PerplexitySettings = {
|
||||
// API Configuration
|
||||
apiKey: '',
|
||||
endpoint: 'https://api.perplexity.ai',
|
||||
defaultModel: 'pplx-7b-chat',
|
||||
perplexityApiKey: '',
|
||||
perplexityEndpoint: 'https://api.perplexity.ai',
|
||||
|
||||
// Generation Parameters
|
||||
temperature: 0.7,
|
||||
maxTokens: 2000,
|
||||
topP: 0.9,
|
||||
frequencyPenalty: 0.5,
|
||||
presencePenalty: 0.5,
|
||||
|
||||
// UI Settings
|
||||
showStatusBar: true,
|
||||
autoSuggest: false,
|
||||
autoSuggestDelay: 1000,
|
||||
showContextMenu: true,
|
||||
|
||||
// Debugging & Performance
|
||||
debugMode: false,
|
||||
requestTimeout: 30000,
|
||||
maxRetries: 3,
|
||||
retryDelay: 1000,
|
||||
|
||||
// Prompts
|
||||
defaultSystemPrompt: 'You are a helpful AI assistant.',
|
||||
defaultUserPrompt: 'How can I help you today?',
|
||||
|
||||
// Service-specific properties
|
||||
requestTemplate: ''
|
||||
};
|
||||
Loading…
Reference in a new issue