generated from obsidianmd/obsidian-sample-plugin
-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement flashcards generation with user input
- Refactoring: move FlashcardsSettings and FlashcardsSettingsTab into a separate file - Implement InputModal which lets the user specify custom settings on a per-command basis
Showing
4 changed files
with
397 additions
and
261 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
import { App, Modal, Setting } from "obsidian" | ||
import { FlashcardsSettings } from "./settings" | ||
|
||
|
||
export class InputModal extends Modal { | ||
configuration: FlashcardsSettings; | ||
multiline: boolean; | ||
onSubmit: (configuration: FlashcardsSettings, multiline: boolean) => void; | ||
|
||
constructor(app: App, plugin: FlashcardsLLMPlugin, onSubmit: (configuration: FlashcardsSettings, multiline: boolean) => void) { | ||
super(app); | ||
this.plugin = plugin; | ||
this.onSubmit = onSubmit; | ||
this.configuration = { ...this.plugin.settings }; | ||
} | ||
|
||
onOpen() { | ||
let { contentEl } = this; | ||
contentEl.createEl("h1", { text: "Prompt configuration" }); | ||
|
||
new Setting(contentEl) | ||
.setName("Number of flashcards to generate") | ||
.addText((text) => | ||
text | ||
.setValue(this.configuration.flashcardsCount.toString()) | ||
.onChange((value) => { | ||
this.configuration.flashcardsCount = Number(value) | ||
// TODO: check input | ||
}) | ||
); | ||
|
||
new Setting(contentEl) | ||
.setName("Additional prompt") | ||
.addText((text) => | ||
text | ||
.setValue(this.configuration.additionalPrompt) | ||
.onChange((value) => { | ||
this.configuration.additionalPrompt = value | ||
}) | ||
); | ||
|
||
new Setting(contentEl) | ||
.setName("Multiline") | ||
.addToggle((on) => | ||
on | ||
.setValue(false) | ||
.onChange(async (on) => { | ||
this.multiline = on | ||
}) | ||
); | ||
|
||
new Setting(contentEl) | ||
.addButton((btn) => | ||
btn | ||
.setButtonText("Submit") | ||
.setCta() | ||
.onClick(() => { | ||
this.close(); | ||
this.onSubmit(this.configuration, this.multiline); | ||
}) | ||
); | ||
|
||
} | ||
|
||
onClose() { | ||
let { contentEl } = this; | ||
contentEl.empty(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,158 @@ | ||
import { App, MarkdownView, PluginSettingTab, Setting } from 'obsidian'; | ||
import { availableChatModels, availableCompletionModels } from "./models"; | ||
|
||
export interface FlashcardsSettings { | ||
apiKey: string; | ||
model: string; | ||
inlineSeparator: string; | ||
multilineSeparator: string; | ||
flashcardsCount: number; | ||
additionalPrompt: string; | ||
maxTokens: number; | ||
streaming: boolean; | ||
hideInPreview: boolean; | ||
} | ||
|
||
|
||
export class FlashcardsSettingsTab extends PluginSettingTab { | ||
plugin: FlashcardsLLMPlugin; | ||
|
||
constructor(app: App, plugin: FlashcardsLLMPlugin) { | ||
super(app, plugin); | ||
this.plugin = plugin; | ||
} | ||
|
||
display(): void { | ||
const { containerEl } = this; | ||
|
||
containerEl.empty(); | ||
|
||
containerEl.createEl("h3", {text: "Model settings"}) | ||
|
||
new Setting(containerEl) | ||
.setName("OpenAI API key") | ||
.setDesc("Enter your OpenAI API key") | ||
.addText((text) => | ||
text | ||
.setPlaceholder("API key") | ||
.setValue(this.plugin.settings.apiKey) | ||
.onChange(async (value) => { | ||
this.plugin.settings.apiKey = value; | ||
await this.plugin.saveSettings(); | ||
}) | ||
); | ||
|
||
new Setting(containerEl) | ||
.setName("Model") | ||
.setDesc("Which language model to use") | ||
.addDropdown((dropdown) => | ||
dropdown | ||
.addOptions(Object.fromEntries(availableCompletionModels().map(k => [k, k]))) | ||
.addOptions(Object.fromEntries(availableChatModels().map(k => [k, k]))) | ||
.setValue(this.plugin.settings.model) | ||
.onChange(async (value) => { | ||
this.plugin.settings.model = value; | ||
await this.plugin.saveSettings(); | ||
}) | ||
); | ||
|
||
containerEl.createEl("h3", {text: "Preferences"}) | ||
|
||
new Setting(containerEl) | ||
.setName("Separator for inline flashcards") | ||
.setDesc("Note that after changing this you have to manually edit any flashcards you already have") | ||
.addText((text) => | ||
text | ||
.setPlaceholder("::") | ||
.setValue(this.plugin.settings.inlineSeparator) | ||
.onChange(async (value) => { | ||
this.plugin.settings.inlineSeparator = value; | ||
await this.plugin.saveSettings(); | ||
}) | ||
); | ||
new Setting(containerEl) | ||
.setName("Separator for multi-line flashcards") | ||
.setDesc("Note that after changing this you have to manually edit any flashcards you already have") | ||
.addText((text) => | ||
text | ||
.setPlaceholder("?") | ||
.setValue(this.plugin.settings.multilineSeparator) | ||
.onChange(async (value) => { | ||
this.plugin.settings.multilineSeparator = value; | ||
await this.plugin.saveSettings(); | ||
}) | ||
); | ||
|
||
new Setting(containerEl) | ||
.setName("Number of flashcards to generate") | ||
.setDesc("Set this to the total number of flashcards the model should "+ | ||
"generate each time a new `Generate Flashcards` command is issued") | ||
.addText((text) => | ||
text | ||
.setPlaceholder("3") | ||
.setValue(this.plugin.settings.flashcardsCount.toString()) | ||
.onChange(async (value) => { | ||
this.plugin.settings.flashcardsCount = Number(value); | ||
await this.plugin.saveSettings(); | ||
}) | ||
); | ||
|
||
new Setting(containerEl) | ||
.setName("Additional prompt") | ||
.setDesc("Provide additional instructions to the language model") | ||
.addText((text) => | ||
text | ||
.setPlaceholder("Additional instructions") | ||
.setValue(this.plugin.settings.additionalPrompt) | ||
.onChange(async (value) => { | ||
this.plugin.settings.additionalPrompt = value; | ||
await this.plugin.saveSettings(); | ||
}) | ||
); | ||
|
||
new Setting(containerEl) | ||
.setName("Maximum output tokens") | ||
.setDesc("Set this to the total number of tokens the model can generate") | ||
.addText((text) => | ||
text | ||
.setPlaceholder("300") | ||
.setValue(this.plugin.settings.maxTokens.toString()) | ||
.onChange(async (value) => { | ||
this.plugin.settings.maxTokens = Number(value); | ||
await this.plugin.saveSettings(); | ||
}) | ||
); | ||
|
||
new Setting(containerEl) | ||
.setName("Streaming") | ||
.setDesc("Enable/Disable streaming text completion") | ||
.addToggle((on) => | ||
on | ||
.setValue(this.plugin.settings.streaming) | ||
.onChange(async (on) => { | ||
this.plugin.settings.streaming = on; | ||
await this.plugin.saveSettings(); | ||
}) | ||
); | ||
|
||
new Setting(containerEl) | ||
.setName("Hide flashcards in preview mode") | ||
.setDesc("If enabled, you won't see flashcards when in preview mode, " | ||
+ "but you will still be able to edit them") | ||
.addToggle((on) => | ||
on | ||
.setValue(this.plugin.settings.hideInPreview) | ||
.onChange(async (on) => { | ||
this.plugin.settings.hideInPreview = on; | ||
|
||
await this.plugin.saveSettings(); | ||
|
||
const view = this.app.workspace.getActiveViewOfType(MarkdownView); | ||
if (view) { | ||
view.previewMode.rerender(true); | ||
} | ||
}) | ||
); | ||
|
||
} | ||
} |