diff --git a/src/api.ts b/src/api.ts index e39bf52..438d7d7 100644 --- a/src/api.ts +++ b/src/api.ts @@ -2,8 +2,8 @@ import { ChatOpenAI } from "@langchain/openai"; import { ChatOllama } from "@langchain/ollama"; import { SystemMessage, HumanMessage, AIMessage } from "@langchain/core/messages"; -import { MyPluginSettings } from "./settings"; -import { App, MarkdownView } from "obsidian"; +import { InlineAISettings } from "./settings"; +import { App, MarkdownView, Notice } from "obsidian"; import { EditorView } from "@codemirror/view"; import { setGeneratedResponseEffect } from "./modules/AIExtension"; @@ -18,7 +18,7 @@ export class ChatApiManager { * Initializes the ChatApiManager with the given settings. * @param settings - Configuration settings for the chat API. */ - constructor(private settings: MyPluginSettings, app: App) { + constructor(private settings: InlineAISettings, app: App) { this.app = app; this.chatClient = this.initializeChatClient(settings); } @@ -29,26 +29,32 @@ export class ChatApiManager { * @returns An instance of ChatOpenAI or ChatOllama. * @throws Error if the provider is unsupported or required settings are missing. */ - private initializeChatClient(settings: MyPluginSettings): ChatOpenAI | ChatOllama { - switch (settings.provider) { - case "openai": - if (!settings.apiKey) { - throw new Error("OpenAI API key is required when using OpenAI as the provider."); - } - return new ChatOpenAI({ - modelName: settings.model, - temperature: 0, // Set temperature to 0 for deterministic outputs - apiKey: settings.apiKey, - }); + private initializeChatClient(settings: InlineAISettings): ChatOpenAI | ChatOllama { + try { + switch (settings.provider) { + case "openai": + if (!settings.apiKey) { + throw new Error("OpenAI API key is required when using OpenAI as the provider."); + } + return new ChatOpenAI({ + modelName: settings.model, + temperature: 0, // Set temperature to 0 for deterministic outputs + apiKey: settings.apiKey, + }); - case "ollama": - return new ChatOllama({ - model: settings.model, - // Add other necessary configurations for Ollama if needed - }); + case "ollama": + return new ChatOllama({ + model: settings.model, + // Add other necessary configurations for Ollama if needed + }); - default: - throw new Error(`Unsupported provider: ${settings.provider}`); + default: + throw new Error(`Unsupported provider: ${settings.provider}`); + } + } catch (error) { + console.error("Error initializing chat client:", error); + new Notice(`Failed to initialize chat client. ${error}`); + throw new Error("Failed to initialize chat client."); } } diff --git a/src/default_prompts.ts b/src/default_prompts.ts new file mode 100644 index 0000000..95dabda --- /dev/null +++ b/src/default_prompts.ts @@ -0,0 +1,35 @@ +export const selectionPrompt = ` +You are an advanced language model that performs text transformations based on specific instructions. Your task is to process input text to produce the desired output based on a given transformation type. You can handle tasks like adding emojis, making text longer or shorter, and converting text into tables, among many others. Use **Obsidian-flavored markdown** in all your transformations when applicable. Follow the examples provided to guide your responses. + +It is **very important** that you follow the examples. Do not add anything at the start of the output like "Output:" or "Here's a rephrased version of the input text:" or anything similar. Just provide the transformed text. + +**Examples:** + +--- + +**Task:** Add Emojis. +**Prompt:** Add relevant emojis to make the text more engaging. + +**Input:** +"Let's celebrate the success of our project." + +**Output:** +"🎉 Let's celebrate the success of our project! 🚀👏" + +--- + +**Task:** Convert to Table. +**Prompt:** Convert the text into an Obsidian table format. + +**Input:** +"Name: John, Age: 30, Profession: Engineer" + +**Output:** +| Name | Age | Profession | +|-------|-----|-------------| +| John | 30 | Engineer| + +--- +` + +export const cursorPrompt = "Generate text based on cursor position."; \ No newline at end of file diff --git a/src/main.ts b/src/main.ts index 9d0cccd..b62abde 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,7 +1,7 @@ // main.ts import { Plugin, MarkdownView, App } from "obsidian"; import { EditorView } from "@codemirror/view"; -import { MyPluginSettings, DEFAULT_SETTINGS, MyPluginSettingTab } from "./settings"; +import { InlineAISettings, DEFAULT_SETTINGS, MyPluginSettingTab } from "./settings"; import { commandEffect, FloatingTooltipExtension } from "./modules/WidgetExtension"; import { ChatApiManager } from "./api"; import { generatedResponseState } from "./modules/AIExtension"; @@ -9,7 +9,7 @@ import { buildSelectionHiglightState, currentSelectionState, setSelectionInfoEff import { diffExtension } from "./modules/diffExtension"; export default class MyPlugin extends Plugin { - settings: MyPluginSettings = DEFAULT_SETTINGS; + settings: InlineAISettings = DEFAULT_SETTINGS; async onload() { await this.loadSettings(); diff --git a/src/settings.ts b/src/settings.ts index f973e8d..a5e072e 100644 --- a/src/settings.ts +++ b/src/settings.ts @@ -1,19 +1,24 @@ // MyPluginSettings.ts import { App, PluginSettingTab, Setting } from "obsidian"; import MyPlugin from "./main"; +import { cursorPrompt, selectionPrompt } from "./default_prompts"; // Interface for the settings -export interface MyPluginSettings { +export interface InlineAISettings { provider: "openai" | "ollama"; model: string; apiKey?: string; + selectionPrompt: string; + cursorPrompt: string; } // Default settings values -export const DEFAULT_SETTINGS: MyPluginSettings = { - provider: "openai", - model: "text-davinci-003", +export const DEFAULT_SETTINGS: InlineAISettings = { + provider: "ollama", + model: "llama3.2", apiKey: "", + selectionPrompt: selectionPrompt, + cursorPrompt: cursorPrompt, }; // Settings tab class to display settings in Obsidian UI @@ -29,13 +34,13 @@ export class MyPluginSettingTab extends PluginSettingTab { const { containerEl } = this; containerEl.empty(); - containerEl.createEl("h2", { text: "My Plugin Settings" }); + // Provider setting new Setting(containerEl) .setName("Provider") .setDesc("Choose between OpenAI or Ollama as your provider.") - .addDropdown(dropdown => + .addDropdown(dropdown => dropdown .addOption("openai", "OpenAI") .addOption("ollama", "Ollama") @@ -51,7 +56,7 @@ export class MyPluginSettingTab extends PluginSettingTab { new Setting(containerEl) .setName("Model") .setDesc("Specify the model to use.") - .addText(text => + .addText(text => text .setPlaceholder("e.g., text-davinci-003") .setValue(this.plugin.settings.model) @@ -66,7 +71,7 @@ export class MyPluginSettingTab extends PluginSettingTab { new Setting(containerEl) .setName("OpenAI API Key") .setDesc("Enter your OpenAI API key.") - .addText(text => + .addText(text => text .setPlaceholder("sk-...") .setValue(this.plugin.settings.apiKey || "") @@ -76,5 +81,46 @@ export class MyPluginSettingTab extends PluginSettingTab { }) ); } + + // Advanced Section + containerEl.createEl("h3", { text: "Advanced Settings" }); + // Selection Prompt setting + new Setting(containerEl) + .setName("Selection Prompt") + .setDesc("System Prompt used when the tooltip is triggered with selected text.") + .addTextArea((textarea) => { + textarea + .setPlaceholder("e.g., Summarize the selected text.") + .setValue(this.plugin.settings.selectionPrompt) + .onChange(async (value) => { + this.plugin.settings.selectionPrompt = value; + await this.plugin.saveSettings(); + }); + + // Make the text area wider + textarea.inputEl.style.width = "25em"; + textarea.inputEl.style.height = "10em"; + + }); + + // Cursor Prompt setting + new Setting(containerEl) + .setName("Cursor Prompt") + .setDesc("System Prompt used when the tooltip is triggered with selected text.") + .addTextArea((textarea) => { + textarea + .setPlaceholder("e.g., Generate text based on cursor position.") + .setValue(this.plugin.settings.cursorPrompt) + .onChange(async (value) => { + this.plugin.settings.cursorPrompt = value; + await this.plugin.saveSettings(); + }); + + // Make the text area wider + textarea.inputEl.style.width = "25em"; + textarea.inputEl.style.height = "10em"; + + }); + } }