mirror of
https://github.com/yzh503/obsidian-aicommander-plugin.git
synced 2026-07-22 07:40:26 +00:00
Improve code quality.
This commit is contained in:
parent
aa6d48b68c
commit
85fff866fa
3 changed files with 69 additions and 86 deletions
|
|
@ -15,7 +15,7 @@ const context = await esbuild.context({
|
||||||
banner: {
|
banner: {
|
||||||
js: banner,
|
js: banner,
|
||||||
},
|
},
|
||||||
entryPoints: ["main.ts"],
|
entryPoints: ["src/main.ts"],
|
||||||
bundle: true,
|
bundle: true,
|
||||||
external: [
|
external: [
|
||||||
"obsidian",
|
"obsidian",
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
import { App, Editor, MarkdownView, normalizePath, Notice, Plugin, PluginSettingTab, Setting, loadPdfJs} from 'obsidian';
|
import { App, Editor, MarkdownView, normalizePath, Notice, Plugin, PluginSettingTab, Setting, loadPdfJs, requestUrl, arrayBufferToBase64, TFolder} from 'obsidian';
|
||||||
import { PromptModal } from "./modal";
|
import { PromptModal } from "./modal";
|
||||||
import { Configuration, OpenAIApi, CreateImageRequestSizeEnum, ChatCompletionRequestMessage } from "openai";
|
import { Configuration, OpenAIApi, CreateImageRequestSizeEnum, ChatCompletionRequestMessage } from "openai";
|
||||||
import axios from 'axios';
|
|
||||||
|
|
||||||
interface AICommanderPluginSettings {
|
interface AICommanderPluginSettings {
|
||||||
model: string;
|
model: string;
|
||||||
|
|
@ -35,12 +34,6 @@ export default class AICommanderPlugin extends Plugin {
|
||||||
settings: AICommanderPluginSettings;
|
settings: AICommanderPluginSettings;
|
||||||
|
|
||||||
async improvePrompt(prompt: string, targetModel: string) {
|
async improvePrompt(prompt: string, targetModel: string) {
|
||||||
const YOUR_GENERATED_SECRET = '9VFMTHCukRuT5WqOkAD1:8cde275ebde49165527e9c97ecc96abef1e34473458fe8f9f3ecad177a163538';
|
|
||||||
|
|
||||||
const headers = {
|
|
||||||
'x-api-key': `token ${YOUR_GENERATED_SECRET}`,
|
|
||||||
'Content-Type': 'application/json'
|
|
||||||
};
|
|
||||||
|
|
||||||
const data = {
|
const data = {
|
||||||
data: {
|
data: {
|
||||||
|
|
@ -49,10 +42,20 @@ export default class AICommanderPlugin extends Plugin {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const response = await axios.post('https://us-central1-prompt-ops.cloudfunctions.net/optimize', data, { headers })
|
const params = {
|
||||||
|
url: 'https://us-central1-prompt-ops.cloudfunctions.net/optimize',
|
||||||
|
method: 'POST',
|
||||||
|
contentType: 'application/json',
|
||||||
|
body: JSON.stringify(data),
|
||||||
|
headers: {
|
||||||
|
'x-api-key': `token ${this.settings.promptPerfectKey}`,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ('promptOptimized' in response.data.result) return response.data.result.promptOptimized as string;
|
const response = await requestUrl(params);
|
||||||
else return prompt;
|
|
||||||
|
if ('promptOptimized' in response.json.result) return response.json.result.promptOptimized as string;
|
||||||
|
else throw new Error('Prompt Perfect API: ' + JSON.stringify(response.json));
|
||||||
}
|
}
|
||||||
|
|
||||||
async generateText(prompt: string, contextPrompt?: string) {
|
async generateText(prompt: string, contextPrompt?: string) {
|
||||||
|
|
@ -109,32 +112,8 @@ export default class AICommanderPlugin extends Plugin {
|
||||||
}
|
}
|
||||||
|
|
||||||
async getImageBase64(url: string) {
|
async getImageBase64(url: string) {
|
||||||
return fetch(url)
|
const buffer = await requestUrl(url).arrayBuffer;
|
||||||
.then(response => response.blob())
|
return arrayBufferToBase64(buffer);
|
||||||
.then(blob => {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
const reader = new FileReader();
|
|
||||||
reader.onload = () => {
|
|
||||||
resolve(reader.result);
|
|
||||||
};
|
|
||||||
reader.onerror = () => {
|
|
||||||
reject(new Error("Failed to convert image to base64"));
|
|
||||||
};
|
|
||||||
reader.readAsDataURL(blob);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
generateRandomString(length: number): string {
|
|
||||||
const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
|
||||||
const charactersLength = characters.length;
|
|
||||||
let result = '';
|
|
||||||
|
|
||||||
for (let i = 0; i < length; i++) {
|
|
||||||
result += characters.charAt(Math.floor(Math.random() * charactersLength));
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async generateImage(prompt: string) {
|
async generateImage(prompt: string) {
|
||||||
|
|
@ -180,15 +159,11 @@ export default class AICommanderPlugin extends Plugin {
|
||||||
if (fileDir.length > 1) {
|
if (fileDir.length > 1) {
|
||||||
fileDir.pop();
|
fileDir.pop();
|
||||||
const dirPath = fileDir.join('/');
|
const dirPath = fileDir.join('/');
|
||||||
await this.app.vault.adapter.exists(dirPath).then((exists) => {
|
const exists = this.app.vault.getAbstractFileByPath(dirPath) instanceof TFolder;
|
||||||
if (exists) return;
|
if(!exists) await this.app.vault.createFolder(dirPath);
|
||||||
return this.app.vault.adapter.mkdir(dirPath);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.app.vault.adapter.writeBinary(filepath, buffer);
|
await this.app.vault.createBinary(filepath, buffer);
|
||||||
|
|
||||||
console.log(this.settings.saveImg);
|
|
||||||
|
|
||||||
if (this.settings.saveImg == 'attachment') {
|
if (this.settings.saveImg == 'attachment') {
|
||||||
return({
|
return({
|
||||||
|
|
@ -207,41 +182,49 @@ export default class AICommanderPlugin extends Plugin {
|
||||||
if (this.settings.apiKey.length <= 1) throw new Error('OpenAI API Key is not provided.');
|
if (this.settings.apiKey.length <= 1) throw new Error('OpenAI API Key is not provided.');
|
||||||
|
|
||||||
const baseUrl = 'https://api.openai.com/v1/audio/transcriptions';
|
const baseUrl = 'https://api.openai.com/v1/audio/transcriptions';
|
||||||
|
|
||||||
const blob = new Blob([audioBuffer]);
|
const blob = new Blob([audioBuffer]);
|
||||||
|
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
formData.append('file', blob, 'audio.' + filetype);
|
formData.append('file', blob, 'audio.' + filetype);
|
||||||
formData.append('model', 'whisper-1');
|
formData.append('model', 'whisper-1');
|
||||||
|
|
||||||
return axios.post(baseUrl, formData, {
|
const params = {
|
||||||
|
url: baseUrl,
|
||||||
|
method: 'POST',
|
||||||
|
contentType: 'multipart/form-data',
|
||||||
|
body: JSON.stringify(formData),
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'multipart/form-data',
|
|
||||||
'Authorization': 'Bearer ' + this.settings.apiKey
|
'Authorization': 'Bearer ' + this.settings.apiKey
|
||||||
}
|
}
|
||||||
}).then(response => response.data.text)
|
}
|
||||||
|
|
||||||
|
const text = await requestUrl(params).text;
|
||||||
|
return text;
|
||||||
}
|
}
|
||||||
|
|
||||||
async searchText(prompt: string) {
|
async searchText(prompt: string) {
|
||||||
const response = await axios.get('https://api.bing.microsoft.com/v7.0/search', {
|
|
||||||
|
const params = {
|
||||||
|
url: 'https://api.bing.microsoft.com/v7.0/search',
|
||||||
|
method: 'GET',
|
||||||
|
contentType: 'application/json',
|
||||||
|
body: JSON.stringify({
|
||||||
|
q: prompt,
|
||||||
|
count: 20
|
||||||
|
}),
|
||||||
headers: {
|
headers: {
|
||||||
'Ocp-Apim-Subscription-Key': this.settings.bingSearchKey
|
'Ocp-Apim-Subscription-Key': this.settings.bingSearchKey
|
||||||
},
|
|
||||||
params: {
|
|
||||||
q: prompt,
|
|
||||||
}
|
}
|
||||||
})
|
};
|
||||||
|
const response = await requestUrl(params);
|
||||||
return response.data.webPages.value;
|
if ('webPages' in response.json && 'value' in response.json.webPages) return response.json.webPages.value;
|
||||||
|
else throw new Error('No web search results: ' + JSON.stringify(response.json));
|
||||||
}
|
}
|
||||||
|
|
||||||
async getAttachmentDir() {
|
async getAttachmentDir() {
|
||||||
const attachmentFolder = await this.app.vault.adapter.read(`${this.app.vault.configDir}/app.json`).then((content: string) => {
|
const activeFile = this.app.workspace.getActiveFile();
|
||||||
const config = JSON.parse(content);
|
if (!activeFile) throw new Error('No active file');
|
||||||
if ('attachmentFolderPath' in config) return config.attachmentFolderPath;
|
const dir = this.app.vault.getAvaiablePathForAttachments(activeFile.basename, activeFile?.extension, activeFile );
|
||||||
else return '';
|
return dir;
|
||||||
});
|
|
||||||
return attachmentFolder as string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getCurrentPath() {
|
getCurrentPath() {
|
||||||
|
|
@ -253,19 +236,6 @@ export default class AICommanderPlugin extends Plugin {
|
||||||
return currentPathString;
|
return currentPathString;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test cases:
|
|
||||||
// 1. Attachment Folder: vault, Attachment: /audio.mp3
|
|
||||||
// 2. Attachment Folder: vault, Attachment: /folder/audio.mp3
|
|
||||||
// 3. Attachment Folder: specified, Attachment: /audio.mp3
|
|
||||||
// 4. Attachment Folder: specified, Attachment: /folder/audio.mp3
|
|
||||||
// 5. Attachment Folder: specified, Attachment: /specified/audio.mp3
|
|
||||||
// 6. Attachment Folder: same, Attachment: /audio.mp3
|
|
||||||
// 7. Attachment Folder: same, Attachment: /folder/audio.mp3
|
|
||||||
// 8. Attachment Folder: same, Attachment: /same/audio.mp3
|
|
||||||
// 9. Attachment Folder: subfolder, Attachment: /audio.mp3
|
|
||||||
// 10. Attachment Folder: subfolder, Attachment: /folder/audio.mp3
|
|
||||||
// 11. Attachment Folder: subfolder, Attachment: /same/subfolder/audio.mp3
|
|
||||||
// 12. Attachment Folder: subfolder, Attachment: /same/audio.mp3
|
|
||||||
async findFilePath(text: string, regex: RegExp[]) {
|
async findFilePath(text: string, regex: RegExp[]) {
|
||||||
const filepath = await this.getAttachmentDir().then((attachmentPath) => {
|
const filepath = await this.getAttachmentDir().then((attachmentPath) => {
|
||||||
let filename = '';
|
let filename = '';
|
||||||
|
|
@ -337,6 +307,18 @@ export default class AICommanderPlugin extends Plugin {
|
||||||
return this.generateText(prompt, context);
|
return this.generateText(prompt, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
generateRandomString(length: number): string {
|
||||||
|
const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
||||||
|
const charactersLength = characters.length;
|
||||||
|
let result = '';
|
||||||
|
|
||||||
|
for (let i = 0; i < length; i++) {
|
||||||
|
result += characters.charAt(Math.floor(Math.random() * charactersLength));
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
getNextEmptyLine(editor: Editor) {
|
getNextEmptyLine(editor: Editor) {
|
||||||
let line = editor.getCursor('to').line;
|
let line = editor.getCursor('to').line;
|
||||||
while (editor.getLine(line).trim() !== '') line++;
|
while (editor.getLine(line).trim() !== '') line++;
|
||||||
|
|
@ -360,6 +342,7 @@ export default class AICommanderPlugin extends Plugin {
|
||||||
this.generateText(prompt).then((data) => {
|
this.generateText(prompt).then((data) => {
|
||||||
this.processGeneratedText(editor, data, lineToInsert);
|
this.processGeneratedText(editor, data, lineToInsert);
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
|
console.log(error.message);
|
||||||
new Notice(error.message);
|
new Notice(error.message);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -376,9 +359,11 @@ export default class AICommanderPlugin extends Plugin {
|
||||||
this.generateTextWithPdf(prompt, path).then((data) => {
|
this.generateTextWithPdf(prompt, path).then((data) => {
|
||||||
this.processGeneratedText(editor, data, lineToInsert);
|
this.processGeneratedText(editor, data, lineToInsert);
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
|
console.log(error.message);
|
||||||
new Notice(error.message);
|
new Notice(error.message);
|
||||||
});
|
});
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
|
console.log(error.message);
|
||||||
new Notice(error.message);
|
new Notice(error.message);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -390,6 +375,7 @@ export default class AICommanderPlugin extends Plugin {
|
||||||
new Notice('Image Generated.');
|
new Notice('Image Generated.');
|
||||||
this.processGeneratedText(editor, data, lineToInsert);
|
this.processGeneratedText(editor, data, lineToInsert);
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
|
console.log(error.message);
|
||||||
new Notice(error.message);
|
new Notice(error.message);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -415,13 +401,16 @@ export default class AICommanderPlugin extends Plugin {
|
||||||
editor.setLine(position.line, `${line}${result}\n`);
|
editor.setLine(position.line, `${line}${result}\n`);
|
||||||
});
|
});
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
|
console.log(error.message);
|
||||||
new Notice(error.message);
|
new Notice(error.message);
|
||||||
});
|
});
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
|
console.log(error.message);
|
||||||
new Notice(error.message);
|
new Notice(error.message);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
|
console.log(error.message);
|
||||||
new Notice(error.message);
|
new Notice(error.message);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -562,12 +551,6 @@ export default class AICommanderPlugin extends Plugin {
|
||||||
// This adds a settings tab so the user can configure various aspects of the plugin
|
// This adds a settings tab so the user can configure various aspects of the plugin
|
||||||
this.addSettingTab(new ApiSettingTab(this.app, this));
|
this.addSettingTab(new ApiSettingTab(this.app, this));
|
||||||
|
|
||||||
// If the plugin hooks up any global DOM events (on parts of the app that doesn't belong to this plugin)
|
|
||||||
// Using this function will automatically remove the event listener when this plugin is disabled.
|
|
||||||
this.registerDomEvent(document, 'click', (evt: MouseEvent) => {
|
|
||||||
console.log('click', evt);
|
|
||||||
});
|
|
||||||
|
|
||||||
// When registering intervals, this function will automatically clear the interval when the plugin is disabled.
|
// When registering intervals, this function will automatically clear the interval when the plugin is disabled.
|
||||||
this.registerInterval(window.setInterval(() => console.log('setInterval'), 5 * 60 * 1000));
|
this.registerInterval(window.setInterval(() => console.log('setInterval'), 5 * 60 * 1000));
|
||||||
}
|
}
|
||||||
Loading…
Reference in a new issue