mirror of
https://github.com/binxly/Atomizer.git
synced 2026-07-22 11:30:28 +00:00
Reformat files with tools
This commit is contained in:
parent
f7bae47850
commit
f0c22d65b0
7 changed files with 389 additions and 331 deletions
52
.github/workflows/release.yml
vendored
52
.github/workflows/release.yml
vendored
|
|
@ -1,35 +1,35 @@
|
|||
name: Release Obsidian plugin
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- "*"
|
||||
push:
|
||||
tags:
|
||||
- "*"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Use Node.js
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: "18.x"
|
||||
- name: Use Node.js
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: "18.x"
|
||||
|
||||
- name: Build plugin
|
||||
run: |
|
||||
npm install
|
||||
npm run build
|
||||
- name: Build plugin
|
||||
run: |
|
||||
npm install
|
||||
npm run build
|
||||
|
||||
- name: Create release
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
tag="${GITHUB_REF#refs/tags/}"
|
||||
- name: Create release
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
tag="${GITHUB_REF#refs/tags/}"
|
||||
|
||||
gh release create "$tag" \
|
||||
--title="$tag" \
|
||||
--draft \
|
||||
main.js manifest.json styles.css
|
||||
gh release create "$tag" \
|
||||
--title="$tag" \
|
||||
--draft \
|
||||
main.js manifest.json styles.css
|
||||
|
|
|
|||
|
|
@ -5,19 +5,24 @@
|
|||
This plugin helps break down large notes into smaller, "atomic" style notes and ideas, using the OpenAI API.
|
||||
|
||||
## Requirements
|
||||
|
||||
- An OpenAI API key is required for full functionality
|
||||
|
||||
## Usage
|
||||
|
||||
- Set your OpenAI API key in settings.
|
||||
- Open the command palette and select "Atomize Selected Note" to process the currently selected note; Alternatively, you can use the icon in the left sidebar.
|
||||
- Sends selected note to OpenAI for processing, where it will be broken down into "atomic notes" that aim to extract key insights from the original note.
|
||||
- Frontmatter will be added to each new note, including the date and any custom tags you've configured from the settings menu.
|
||||
|
||||
|
||||
### Models supported
|
||||
|
||||
- `gpt-4o-mini`
|
||||
- `gpt-4o`
|
||||
|
||||
## Network Usage Disclosure
|
||||
|
||||
This plugin makes network requests to:
|
||||
|
||||
- OpenAI API (api.openai.com) for generating atomic notes from your content
|
||||
- Your notes' content is sent to OpenAI for processing. Please review OpenAI's privacy policy.
|
||||
|
|
|
|||
|
|
@ -2,14 +2,13 @@ import esbuild from "esbuild";
|
|||
import process from "process";
|
||||
import builtins from "builtin-modules";
|
||||
|
||||
const banner =
|
||||
`/*
|
||||
const banner = `/*
|
||||
THIS IS A GENERATED/BUNDLED FILE BY ESBUILD
|
||||
if you want to view the source, please visit the github repository of this plugin
|
||||
*/
|
||||
`;
|
||||
|
||||
const prod = (process.argv[2] === "production");
|
||||
const prod = process.argv[2] === "production";
|
||||
|
||||
const context = await esbuild.context({
|
||||
banner: {
|
||||
|
|
@ -31,7 +30,8 @@ const context = await esbuild.context({
|
|||
"@lezer/common",
|
||||
"@lezer/highlight",
|
||||
"@lezer/lr",
|
||||
...builtins],
|
||||
...builtins,
|
||||
],
|
||||
format: "cjs",
|
||||
target: "es2018",
|
||||
logLevel: "info",
|
||||
|
|
|
|||
|
|
@ -3,12 +3,11 @@ import pluginJs from "@eslint/js";
|
|||
import tseslint from "typescript-eslint";
|
||||
import pluginReact from "eslint-plugin-react";
|
||||
|
||||
|
||||
/** @type {import('eslint').Linter.Config[]} */
|
||||
export default [
|
||||
{files: ["**/*.{js,mjs,cjs,ts,jsx,tsx}"]},
|
||||
{languageOptions: { globals: globals.browser }},
|
||||
pluginJs.configs.recommended,
|
||||
...tseslint.configs.recommended,
|
||||
pluginReact.configs.flat.recommended,
|
||||
];
|
||||
{ files: ["**/*.{js,mjs,cjs,ts,jsx,tsx}"] },
|
||||
{ languageOptions: { globals: globals.browser } },
|
||||
pluginJs.configs.recommended,
|
||||
...tseslint.configs.recommended,
|
||||
pluginReact.configs.flat.recommended,
|
||||
];
|
||||
|
|
|
|||
|
|
@ -2,26 +2,26 @@ import globals from "globals";
|
|||
import tseslint from "typescript-eslint";
|
||||
|
||||
export default [
|
||||
{
|
||||
files: ["**/*.{js,mjs,cjs,ts}"],
|
||||
ignores: ["node_modules/**", "main.js"],
|
||||
languageOptions: {
|
||||
globals: globals.browser,
|
||||
parser: tseslint.parser,
|
||||
parserOptions: {
|
||||
project: "./tsconfig.json"
|
||||
}
|
||||
},
|
||||
plugins: {
|
||||
"@typescript-eslint": tseslint.plugin
|
||||
},
|
||||
rules: {
|
||||
...tseslint.configs.recommended.rules,
|
||||
"no-unused-vars": "off",
|
||||
"@typescript-eslint/no-unused-vars": ["error", { "args": "none" }],
|
||||
"@typescript-eslint/ban-ts-comment": "off",
|
||||
"no-prototype-builtins": "off",
|
||||
"@typescript-eslint/no-empty-function": "off"
|
||||
}
|
||||
}
|
||||
];
|
||||
{
|
||||
files: ["**/*.{js,mjs,cjs,ts}"],
|
||||
ignores: ["node_modules/**", "main.js"],
|
||||
languageOptions: {
|
||||
globals: globals.browser,
|
||||
parser: tseslint.parser,
|
||||
parserOptions: {
|
||||
project: "./tsconfig.json",
|
||||
},
|
||||
},
|
||||
plugins: {
|
||||
"@typescript-eslint": tseslint.plugin,
|
||||
},
|
||||
rules: {
|
||||
...tseslint.configs.recommended.rules,
|
||||
"no-unused-vars": "off",
|
||||
"@typescript-eslint/no-unused-vars": ["error", { args: "none" }],
|
||||
"@typescript-eslint/ban-ts-comment": "off",
|
||||
"no-prototype-builtins": "off",
|
||||
"@typescript-eslint/no-empty-function": "off",
|
||||
},
|
||||
},
|
||||
];
|
||||
|
|
|
|||
557
main.ts
557
main.ts
|
|
@ -1,47 +1,58 @@
|
|||
import { App, Editor, MarkdownView, Modal, Notice, Plugin, PluginSettingTab, Setting, normalizePath } from 'obsidian';
|
||||
import OpenAI from 'openai';
|
||||
import {
|
||||
App,
|
||||
Editor,
|
||||
MarkdownView,
|
||||
Modal,
|
||||
Notice,
|
||||
Plugin,
|
||||
PluginSettingTab,
|
||||
Setting,
|
||||
normalizePath,
|
||||
} from "obsidian";
|
||||
import OpenAI from "openai";
|
||||
|
||||
// Types and Interfaces
|
||||
interface APIError extends Error {
|
||||
response?: {
|
||||
status: number;
|
||||
data: any;
|
||||
};
|
||||
response?: {
|
||||
status: number;
|
||||
data: any;
|
||||
};
|
||||
}
|
||||
|
||||
interface AtomicPluginSettings {
|
||||
apiKey: string;
|
||||
outputFolder: string;
|
||||
model: string;
|
||||
enableAtomizedTag: boolean;
|
||||
customTags: string;
|
||||
apiKey: string;
|
||||
outputFolder: string;
|
||||
model: string;
|
||||
enableAtomizedTag: boolean;
|
||||
customTags: string;
|
||||
}
|
||||
|
||||
// Constants
|
||||
const DEFAULT_SETTINGS: AtomicPluginSettings = {
|
||||
apiKey: '',
|
||||
outputFolder: 'atomic-notes',
|
||||
model: 'gpt-4o-mini',
|
||||
enableAtomizedTag: true,
|
||||
customTags: ''
|
||||
}
|
||||
apiKey: "",
|
||||
outputFolder: "atomic-notes",
|
||||
model: "gpt-4o-mini",
|
||||
enableAtomizedTag: true,
|
||||
customTags: "",
|
||||
};
|
||||
|
||||
const getCurrentDateTime = (): string => {
|
||||
const date = new Date();
|
||||
return date.toISOString()
|
||||
.replace('T', ' ')
|
||||
.replace(/\.\d+Z$/, '');
|
||||
const date = new Date();
|
||||
return date
|
||||
.toISOString()
|
||||
.replace("T", " ")
|
||||
.replace(/\.\d+Z$/, "");
|
||||
};
|
||||
|
||||
// Move SYSTEM_PROMPT into a function that takes settings as a parameter
|
||||
const getSystemPrompt = (settings: AtomicPluginSettings): string => {
|
||||
return `You are an expert at creating atomic notes from a single, larger note.
|
||||
return `You are an expert at creating atomic notes from a single, larger note.
|
||||
Take the content from a larger note and break it down into separate compact yet detailed atomic notes. Each note MUST be separated by placing '<<<>>>' on its own line between notes. Do not include an index or main note. Follow these rules:
|
||||
1. Each note should contain exactly one clear idea. This can contain multiple lines.
|
||||
2. Each note must have a YAML frontmatter section at the top with:
|
||||
---
|
||||
date: "${getCurrentDateTime()}"
|
||||
tags: ${settings.enableAtomizedTag ? 'atomized' : ''}${settings.customTags ? (settings.enableAtomizedTag ? ', ' : '') + settings.customTags : ''}
|
||||
tags: ${settings.enableAtomizedTag ? "atomized" : ""}${settings.customTags ? (settings.enableAtomizedTag ? ", " : "") + settings.customTags : ""}
|
||||
---
|
||||
3. You MUST separate each note by placing '<<<>>>' on its own line between notes
|
||||
4. After the frontmatter, each note must start with a level 1 heading (# Title)
|
||||
|
|
@ -52,282 +63,332 @@ tags: ${settings.enableAtomizedTag ? 'atomized' : ''}${settings.customTags ? (se
|
|||
|
||||
// OpenAI Service
|
||||
class OpenAIService {
|
||||
constructor(private apiKey: string, private model: string, private settings: AtomicPluginSettings) {}
|
||||
constructor(
|
||||
private apiKey: string,
|
||||
private model: string,
|
||||
private settings: AtomicPluginSettings,
|
||||
) {}
|
||||
|
||||
async generateAtomicNotes(content: string, timestamp: string): Promise<string> {
|
||||
if (!this.apiKey) {
|
||||
new Notice('OpenAI API key is not set. Please configure it in plugin settings.');
|
||||
return '';
|
||||
}
|
||||
async generateAtomicNotes(
|
||||
content: string,
|
||||
timestamp: string,
|
||||
): Promise<string> {
|
||||
if (!this.apiKey) {
|
||||
new Notice(
|
||||
"OpenAI API key is not set. Please configure it in plugin settings.",
|
||||
);
|
||||
return "";
|
||||
}
|
||||
|
||||
// Inform user about network request
|
||||
new Notice('Sending request to OpenAI...', 3000);
|
||||
// Inform user about network request
|
||||
new Notice("Sending request to OpenAI...", 3000);
|
||||
|
||||
const openai = new OpenAI({
|
||||
apiKey: this.apiKey,
|
||||
dangerouslyAllowBrowser: true
|
||||
});
|
||||
const openai = new OpenAI({
|
||||
apiKey: this.apiKey,
|
||||
dangerouslyAllowBrowser: true,
|
||||
});
|
||||
|
||||
const completion = await openai.chat.completions.create({
|
||||
model: this.model,
|
||||
messages: [{
|
||||
role: "system",
|
||||
content: getSystemPrompt(this.settings)
|
||||
}, {
|
||||
role: "user",
|
||||
content: content
|
||||
}],
|
||||
temperature: 0.7,
|
||||
max_tokens: 4000
|
||||
});
|
||||
const completion = await openai.chat.completions.create({
|
||||
model: this.model,
|
||||
messages: [
|
||||
{
|
||||
role: "system",
|
||||
content: getSystemPrompt(this.settings),
|
||||
},
|
||||
{
|
||||
role: "user",
|
||||
content: content,
|
||||
},
|
||||
],
|
||||
temperature: 0.7,
|
||||
max_tokens: 4000,
|
||||
});
|
||||
|
||||
return completion.choices[0]?.message?.content ?? '';
|
||||
}
|
||||
return completion.choices[0]?.message?.content ?? "";
|
||||
}
|
||||
}
|
||||
|
||||
// Notes Manager
|
||||
class NotesManager {
|
||||
private usedTitles = new Set<string>();
|
||||
private usedTitles = new Set<string>();
|
||||
|
||||
constructor(private app: App, private folderPath: string) {}
|
||||
constructor(
|
||||
private app: App,
|
||||
private folderPath: string,
|
||||
) {}
|
||||
|
||||
async createFolder(): Promise<void> {
|
||||
if (!(await this.app.vault.adapter.exists(this.folderPath))) {
|
||||
await this.app.vault.createFolder(this.folderPath);
|
||||
}
|
||||
}
|
||||
async createFolder(): Promise<void> {
|
||||
if (!(await this.app.vault.adapter.exists(this.folderPath))) {
|
||||
await this.app.vault.createFolder(this.folderPath);
|
||||
}
|
||||
}
|
||||
|
||||
async saveNote(note: string): Promise<void> {
|
||||
const titleMatch = note.match(/^#\s+(.+)$/m);
|
||||
if (!titleMatch) {
|
||||
console.warn('No title found in note:', note.slice(0, 100));
|
||||
return;
|
||||
}
|
||||
async saveNote(note: string): Promise<void> {
|
||||
const titleMatch = note.match(/^#\s+(.+)$/m);
|
||||
if (!titleMatch) {
|
||||
console.warn("No title found in note:", note.slice(0, 100));
|
||||
return;
|
||||
}
|
||||
|
||||
const title = this.getUniqueTitle(titleMatch[1].trim());
|
||||
const fileName = `${this.folderPath}/${normalizePath(title)}.md`;
|
||||
await this.app.vault.create(fileName, note.trim());
|
||||
}
|
||||
const title = this.getUniqueTitle(titleMatch[1].trim());
|
||||
const fileName = `${this.folderPath}/${normalizePath(title)}.md`;
|
||||
await this.app.vault.create(fileName, note.trim());
|
||||
}
|
||||
|
||||
private getUniqueTitle(baseTitle: string): string {
|
||||
let title = baseTitle;
|
||||
let counter = 1;
|
||||
while (this.usedTitles.has(title)) {
|
||||
title = `${baseTitle} ${counter}`;
|
||||
counter++;
|
||||
}
|
||||
return normalizePath(title);
|
||||
}
|
||||
private getUniqueTitle(baseTitle: string): string {
|
||||
let title = baseTitle;
|
||||
let counter = 1;
|
||||
while (this.usedTitles.has(title)) {
|
||||
title = `${baseTitle} ${counter}`;
|
||||
counter++;
|
||||
}
|
||||
return normalizePath(title);
|
||||
}
|
||||
}
|
||||
|
||||
// Main Plugin Class
|
||||
export default class AtomicNotesPlugin extends Plugin {
|
||||
settings: AtomicPluginSettings;
|
||||
private statusBarItem: HTMLElement;
|
||||
settings: AtomicPluginSettings;
|
||||
private statusBarItem: HTMLElement;
|
||||
|
||||
async onload() {
|
||||
await this.loadSettings();
|
||||
async onload() {
|
||||
await this.loadSettings();
|
||||
|
||||
// Add ribbon icon
|
||||
this.addRibbonIcon('atom', 'Atomize note', async () => {
|
||||
const activeView = this.app.workspace.getActiveViewOfType(MarkdownView);
|
||||
if (activeView) {
|
||||
await this.atomizeNote(activeView);
|
||||
} else {
|
||||
new Notice('Please open a note to atomize');
|
||||
}
|
||||
});
|
||||
// Add ribbon icon
|
||||
this.addRibbonIcon("atom", "Atomize note", async () => {
|
||||
const activeView =
|
||||
this.app.workspace.getActiveViewOfType(MarkdownView);
|
||||
if (activeView) {
|
||||
await this.atomizeNote(activeView);
|
||||
} else {
|
||||
new Notice("Please open a note to atomize");
|
||||
}
|
||||
});
|
||||
|
||||
// Add command
|
||||
this.addCommand({
|
||||
id: 'atomize-current-note',
|
||||
name: 'Atomize current note',
|
||||
editorCallback: async (editor: Editor, view: MarkdownView) => {
|
||||
await this.atomizeNote(view);
|
||||
}
|
||||
});
|
||||
// Add command
|
||||
this.addCommand({
|
||||
id: "atomize-current-note",
|
||||
name: "Atomize current note",
|
||||
editorCallback: async (editor: Editor, view: MarkdownView) => {
|
||||
await this.atomizeNote(view);
|
||||
},
|
||||
});
|
||||
|
||||
// Add settings tab
|
||||
this.addSettingTab(new AtomicSettingTab(this.app, this));
|
||||
// Add settings tab
|
||||
this.addSettingTab(new AtomicSettingTab(this.app, this));
|
||||
|
||||
this.statusBarItem = this.addStatusBarItem();
|
||||
this.statusBarItem.setText('Atomic notes: ready');
|
||||
}
|
||||
this.statusBarItem = this.addStatusBarItem();
|
||||
this.statusBarItem.setText("Atomic notes: ready");
|
||||
}
|
||||
|
||||
async atomizeNote(view: MarkdownView) {
|
||||
if (!this.validateSettings()) return;
|
||||
async atomizeNote(view: MarkdownView) {
|
||||
if (!this.validateSettings()) return;
|
||||
|
||||
const content = view.getViewData();
|
||||
if (!content.trim()) {
|
||||
new Notice('The current note is empty');
|
||||
return;
|
||||
}
|
||||
const content = view.getViewData();
|
||||
if (!content.trim()) {
|
||||
new Notice("The current note is empty");
|
||||
return;
|
||||
}
|
||||
|
||||
new ConfirmationModal(this.app, async () => {
|
||||
const loadingNotice = new Notice('Processing note...', 0);
|
||||
new ConfirmationModal(this.app, async () => {
|
||||
const loadingNotice = new Notice("Processing note...", 0);
|
||||
|
||||
try {
|
||||
const openAIService = new OpenAIService(
|
||||
this.settings.apiKey,
|
||||
this.settings.model,
|
||||
this.settings
|
||||
);
|
||||
const notesManager = new NotesManager(this.app, this.settings.outputFolder);
|
||||
try {
|
||||
const openAIService = new OpenAIService(
|
||||
this.settings.apiKey,
|
||||
this.settings.model,
|
||||
this.settings,
|
||||
);
|
||||
const notesManager = new NotesManager(
|
||||
this.app,
|
||||
this.settings.outputFolder,
|
||||
);
|
||||
|
||||
const responseContent = await openAIService.generateAtomicNotes(content, this.getCurrentDateTime());
|
||||
if (!responseContent) throw new Error('No content received from OpenAI');
|
||||
const responseContent = await openAIService.generateAtomicNotes(
|
||||
content,
|
||||
this.getCurrentDateTime(),
|
||||
);
|
||||
if (!responseContent)
|
||||
throw new Error("No content received from OpenAI");
|
||||
|
||||
const atomicNotes = responseContent
|
||||
.split('<<<>>>')
|
||||
.map(note => note.trim())
|
||||
.filter(note => note.length > 0);
|
||||
const atomicNotes = responseContent
|
||||
.split("<<<>>>")
|
||||
.map((note) => note.trim())
|
||||
.filter((note) => note.length > 0);
|
||||
|
||||
if (atomicNotes.length === 0) {
|
||||
throw new Error('No atomic notes were generated. The response may not be properly formatted.');
|
||||
}
|
||||
if (atomicNotes.length === 0) {
|
||||
throw new Error(
|
||||
"No atomic notes were generated. The response may not be properly formatted.",
|
||||
);
|
||||
}
|
||||
|
||||
await notesManager.createFolder();
|
||||
await notesManager.createFolder();
|
||||
|
||||
for (const note of atomicNotes) {
|
||||
await notesManager.saveNote(note);
|
||||
}
|
||||
for (const note of atomicNotes) {
|
||||
await notesManager.saveNote(note);
|
||||
}
|
||||
|
||||
new Notice(`Successfully created ${atomicNotes.length} atomic notes`);
|
||||
} catch (error) {
|
||||
this.handleError(error);
|
||||
} finally {
|
||||
loadingNotice.hide();
|
||||
this.statusBarItem.setText('Atomic Notes: Ready');
|
||||
}
|
||||
}).open();
|
||||
}
|
||||
new Notice(
|
||||
`Successfully created ${atomicNotes.length} atomic notes`,
|
||||
);
|
||||
} catch (error) {
|
||||
this.handleError(error);
|
||||
} finally {
|
||||
loadingNotice.hide();
|
||||
this.statusBarItem.setText("Atomic Notes: Ready");
|
||||
}
|
||||
}).open();
|
||||
}
|
||||
|
||||
private validateSettings(): boolean {
|
||||
if (!this.settings.apiKey) {
|
||||
new Notice('Please set your OpenAI API key in settings');
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
private validateSettings(): boolean {
|
||||
if (!this.settings.apiKey) {
|
||||
new Notice("Please set your OpenAI API key in settings");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private handleError(error: APIError) {
|
||||
console.error('Detailed error:', error);
|
||||
new Notice(`Error: ${error.message || 'Unknown error occurred'}`);
|
||||
|
||||
if (error.response) {
|
||||
console.error('OpenAI API Error:', {
|
||||
status: error.response.status,
|
||||
data: error.response.data
|
||||
});
|
||||
}
|
||||
}
|
||||
private handleError(error: APIError) {
|
||||
console.error("Detailed error:", error);
|
||||
new Notice(`Error: ${error.message || "Unknown error occurred"}`);
|
||||
|
||||
async loadSettings() {
|
||||
this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());
|
||||
}
|
||||
if (error.response) {
|
||||
console.error("OpenAI API Error:", {
|
||||
status: error.response.status,
|
||||
data: error.response.data,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async saveSettings() {
|
||||
await this.saveData(this.settings);
|
||||
}
|
||||
async loadSettings() {
|
||||
this.settings = Object.assign(
|
||||
{},
|
||||
DEFAULT_SETTINGS,
|
||||
await this.loadData(),
|
||||
);
|
||||
}
|
||||
|
||||
private getCurrentDateTime(): string {
|
||||
return new Date().toISOString();
|
||||
}
|
||||
async saveSettings() {
|
||||
await this.saveData(this.settings);
|
||||
}
|
||||
|
||||
private getCurrentDateTime(): string {
|
||||
return new Date().toISOString();
|
||||
}
|
||||
}
|
||||
|
||||
class AtomicSettingTab extends PluginSettingTab {
|
||||
plugin: AtomicNotesPlugin;
|
||||
plugin: AtomicNotesPlugin;
|
||||
|
||||
constructor(app: App, plugin: AtomicNotesPlugin) {
|
||||
super(app, plugin);
|
||||
this.plugin = plugin;
|
||||
}
|
||||
constructor(app: App, plugin: AtomicNotesPlugin) {
|
||||
super(app, plugin);
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
display(): void {
|
||||
const {containerEl} = this;
|
||||
containerEl.empty();
|
||||
display(): void {
|
||||
const { containerEl } = this;
|
||||
containerEl.empty();
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName('OpenAI API key')
|
||||
.setDesc('Enter your OpenAI API key')
|
||||
.addText(text => text
|
||||
.setPlaceholder('sk-...')
|
||||
.setValue(this.plugin.settings.apiKey)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.apiKey = value;
|
||||
await this.plugin.saveSettings();
|
||||
}));
|
||||
new Setting(containerEl)
|
||||
.setName("OpenAI API key")
|
||||
.setDesc("Enter your OpenAI API key")
|
||||
.addText((text) =>
|
||||
text
|
||||
.setPlaceholder("sk-...")
|
||||
.setValue(this.plugin.settings.apiKey)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.apiKey = value;
|
||||
await this.plugin.saveSettings();
|
||||
}),
|
||||
);
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName('Model')
|
||||
.setDesc('Choose the OpenAI model to use')
|
||||
.addDropdown(dropdown => dropdown
|
||||
.addOption('gpt-4o-mini', 'GPT-4o Mini')
|
||||
.addOption('gpt-4o', 'GPT-4o')
|
||||
.setValue(this.plugin.settings.model)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.model = value;
|
||||
await this.plugin.saveSettings();
|
||||
}));
|
||||
new Setting(containerEl)
|
||||
.setName("Model")
|
||||
.setDesc("Choose the OpenAI model to use")
|
||||
.addDropdown((dropdown) =>
|
||||
dropdown
|
||||
.addOption("gpt-4o-mini", "GPT-4o Mini")
|
||||
.addOption("gpt-4o", "GPT-4o")
|
||||
.setValue(this.plugin.settings.model)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.model = value;
|
||||
await this.plugin.saveSettings();
|
||||
}),
|
||||
);
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName('Output folder')
|
||||
.setDesc('Folder where atomic notes will be created')
|
||||
.addText(text => text
|
||||
.setPlaceholder('atomic-notes')
|
||||
.setValue(this.plugin.settings.outputFolder)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.outputFolder = value;
|
||||
await this.plugin.saveSettings();
|
||||
}));
|
||||
new Setting(containerEl)
|
||||
.setName("Output folder")
|
||||
.setDesc("Folder where atomic notes will be created")
|
||||
.addText((text) =>
|
||||
text
|
||||
.setPlaceholder("atomic-notes")
|
||||
.setValue(this.plugin.settings.outputFolder)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.outputFolder = value;
|
||||
await this.plugin.saveSettings();
|
||||
}),
|
||||
);
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName('Enable "atomized" tag')
|
||||
.setDesc('Automatically add the "atomized" tag to generated notes')
|
||||
.addToggle(toggle => toggle
|
||||
.setValue(this.plugin.settings.enableAtomizedTag)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.enableAtomizedTag = value;
|
||||
await this.plugin.saveSettings();
|
||||
}));
|
||||
new Setting(containerEl)
|
||||
.setName('Enable "atomized" tag')
|
||||
.setDesc('Automatically add the "atomized" tag to generated notes')
|
||||
.addToggle((toggle) =>
|
||||
toggle
|
||||
.setValue(this.plugin.settings.enableAtomizedTag)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.enableAtomizedTag = value;
|
||||
await this.plugin.saveSettings();
|
||||
}),
|
||||
);
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName('Custom tags')
|
||||
.setDesc('Additional tags to add to generated notes (comma-separated)')
|
||||
.addText(text => text
|
||||
.setPlaceholder('tag1, tag2, tag3')
|
||||
.setValue(this.plugin.settings.customTags)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.customTags = value;
|
||||
await this.plugin.saveSettings();
|
||||
}));
|
||||
}
|
||||
new Setting(containerEl)
|
||||
.setName("Custom tags")
|
||||
.setDesc(
|
||||
"Additional tags to add to generated notes (comma-separated)",
|
||||
)
|
||||
.addText((text) =>
|
||||
text
|
||||
.setPlaceholder("tag1, tag2, tag3")
|
||||
.setValue(this.plugin.settings.customTags)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.customTags = value;
|
||||
await this.plugin.saveSettings();
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class ConfirmationModal extends Modal {
|
||||
constructor(app: App, private onConfirm: () => void) {
|
||||
super(app);
|
||||
}
|
||||
constructor(
|
||||
app: App,
|
||||
private onConfirm: () => void,
|
||||
) {
|
||||
super(app);
|
||||
}
|
||||
|
||||
onOpen() {
|
||||
const {contentEl} = this;
|
||||
contentEl.setText('This will create multiple atomic notes in your vault. Continue?');
|
||||
|
||||
new Setting(contentEl)
|
||||
.addButton(btn => btn
|
||||
.setButtonText('Cancel')
|
||||
.onClick(() => this.close()))
|
||||
.addButton(btn => btn
|
||||
.setButtonText('Continue')
|
||||
.setCta()
|
||||
.onClick(() => {
|
||||
this.close();
|
||||
this.onConfirm();
|
||||
}));
|
||||
}
|
||||
onOpen() {
|
||||
const { contentEl } = this;
|
||||
contentEl.setText(
|
||||
"This will create multiple atomic notes in your vault. Continue?",
|
||||
);
|
||||
|
||||
onClose() {
|
||||
const {contentEl} = this;
|
||||
contentEl.empty();
|
||||
}
|
||||
new Setting(contentEl)
|
||||
.addButton((btn) =>
|
||||
btn.setButtonText("Cancel").onClick(() => this.close()),
|
||||
)
|
||||
.addButton((btn) =>
|
||||
btn
|
||||
.setButtonText("Continue")
|
||||
.setCta()
|
||||
.onClick(() => {
|
||||
this.close();
|
||||
this.onConfirm();
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
onClose() {
|
||||
const { contentEl } = this;
|
||||
contentEl.empty();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,24 +1,17 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"inlineSourceMap": true,
|
||||
"inlineSources": true,
|
||||
"module": "ESNext",
|
||||
"target": "ES6",
|
||||
"allowJs": true,
|
||||
"noImplicitAny": true,
|
||||
"moduleResolution": "node",
|
||||
"importHelpers": true,
|
||||
"isolatedModules": true,
|
||||
"strictNullChecks": true,
|
||||
"lib": [
|
||||
"DOM",
|
||||
"ES5",
|
||||
"ES6",
|
||||
"ES7"
|
||||
]
|
||||
},
|
||||
"include": [
|
||||
"**/*.ts"
|
||||
]
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"inlineSourceMap": true,
|
||||
"inlineSources": true,
|
||||
"module": "ESNext",
|
||||
"target": "ES6",
|
||||
"allowJs": true,
|
||||
"noImplicitAny": true,
|
||||
"moduleResolution": "node",
|
||||
"importHelpers": true,
|
||||
"isolatedModules": true,
|
||||
"strictNullChecks": true,
|
||||
"lib": ["DOM", "ES5", "ES6", "ES7"]
|
||||
},
|
||||
"include": ["**/*.ts"]
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue