Fix a bug in finding file for audio and pdf.

This commit is contained in:
Simon Yang 2023-03-14 15:43:36 +11:00
parent 90d15d45a6
commit 47fb63f0f4
3 changed files with 92 additions and 37 deletions

125
main.ts
View file

@ -124,12 +124,7 @@ export default class AICommanderPlugin extends Plugin {
} }
async generateImage(prompt: string) { async generateImage(prompt: string) {
if (this.settings.apiKey.length <= 1) throw new Error('OpenAI API Key is not provided.');
if (prompt.length > 1000) return({
success: false,
prompt: prompt,
text: 'Prompt needs to be shorter than 1000 characters.'
})
const configuration = new Configuration({ const configuration = new Configuration({
apiKey: this.settings.apiKey, apiKey: this.settings.apiKey,
@ -158,8 +153,8 @@ export default class AICommanderPlugin extends Plugin {
} }
async generateTranscript(audioBuffer: ArrayBuffer, filetype: string) { async generateTranscript(audioBuffer: ArrayBuffer, filetype: string) {
if (this.settings.apiKey.length <= 1) throw new Error('OpenAI API Key is not provided.');
// Workaround for issue https://github.com/openai/openai-node/issues/77
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]);
@ -192,34 +187,81 @@ export default class AICommanderPlugin extends Plugin {
async getAttachmentDir() { async getAttachmentDir() {
const attachmentFolder = await this.app.vault.adapter.read(`${this.app.vault.configDir}/app.json`).then((content: string) => { const attachmentFolder = await this.app.vault.adapter.read(`${this.app.vault.configDir}/app.json`).then((content: string) => {
const config = JSON.parse(content); const config = JSON.parse(content);
if (config.attachmentFolderPath === '/' || config.attachmentFolderPath === './') { if ('attachmentFolderPath' in config) return config.attachmentFolderPath;
return ''; else return '';
}
return config.attachmentFolderPath + '/' || '';
}); });
return attachmentFolder as string; return attachmentFolder as string;
} }
async findFilePath(text: string, regex: RegExp) { // Test cases:
// 1. Attachment Folder: vault, Attachment: /audio.mp3
const path = await this.getAttachmentDir().then((path) => { // 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[]) {
const filepath = await this.getAttachmentDir().then((attachmentPath) => {
let filename = ''; let filename = '';
let result: RegExpExecArray | null; let result: RegExpExecArray | null;
while ((result = regex.exec(text)) !== null) { for (const reg of regex) {
filename = decodeURI(result[0]); while ((result = reg.exec(text)) !== null) {
filename = normalizePath(decodeURI(result[0]));
}
}
const activeFile = this.app.workspace.getActiveFile();
if (!activeFile) throw new Error('No active file');
const currentPath = activeFile.path.split('/');
currentPath.pop();
const currentPathString = currentPath.join('/');
console.log('currentPathString', currentPathString);
console.log('attachmentPath', attachmentPath);
console.log('filename', filename);
const underRootFolder = attachmentPath === '' || attachmentPath === '/';
const underCurrentFolder = attachmentPath.startsWith('./');
const underSpecificFolder = !underCurrentFolder && !underRootFolder;
const fileInSpecificFolder = filename.contains('/');
console.log(underRootFolder, underCurrentFolder, underSpecificFolder, fileInSpecificFolder);
let filepath = '';
if (underRootFolder || fileInSpecificFolder) filepath = filename;
if (underSpecificFolder) filepath = attachmentPath + '/' + filename;
if (underCurrentFolder) {
const attFolder = attachmentPath.substring(2);
if (attFolder.length == 0) filepath = currentPathString + '/' + filename;
else filepath = currentPathString + '/' + attFolder + '/' + filename;
} }
if (filename.contains('/') || filename.contains('\\')) { return this.app.vault.adapter.exists(filepath).then((exists => {
return normalizePath(filename); if (exists) return filepath;
} else { else {
return normalizePath(path + filename); let path = '';
} let found = false;
this.app.vault.getFiles().forEach((file) => {
if (file.name === filename) {
path = file.path;
found = true;
}
});
if (found) return path;
else throw new Error('File not found');
}
}));
}); });
return path as string; return filepath as string;
} }
async generateTextWithPdf(prompt: string, filepath: string) { async generateTextWithPdf(prompt: string, filepath: string) {
const pdfBuffer = await this.app.vault.adapter.readBinary(filepath); const pdfBuffer = await this.app.vault.adapter.readBinary(filepath);
const pdfjs = await loadPdfJs(); const pdfjs = await loadPdfJs();
@ -266,12 +308,16 @@ export default class AICommanderPlugin extends Plugin {
commandGenerateTextWithPdf(editor: Editor, prompt: string, includePrompt: boolean, hasSelected: boolean) { commandGenerateTextWithPdf(editor: Editor, prompt: string, includePrompt: boolean, hasSelected: boolean) {
const position = editor.getCursor(); const position = editor.getCursor();
const text = editor.getRange({line: 0, ch: 0}, position); const text = editor.getRange({line: 0, ch: 0}, position);
const regex = /(?<=\[(.*)]\()(([^[\]])+)\.pdf(?=\))/g; const regex = [/(?<=\[(.*)]\()(([^[\]])+)\.pdf(?=\))/g,
/(?<=\[\[)(([^[\]])+)\.pdf(?=]])/g];
this.findFilePath(text, regex).then((path) => { this.findFilePath(text, regex).then((path) => {
console.log('path', path);
new Notice(`Generating text in context of ${path}...`); new Notice(`Generating text in context of ${path}...`);
this.generateTextWithPdf(prompt, path).then((data) => { this.generateTextWithPdf(prompt, path).then((data) => {
this.processGeneratedText(editor, position.line, data, includePrompt, hasSelected); this.processGeneratedText(editor, position.line, data, includePrompt, hasSelected);
}) }).catch(error => {
new Notice(error.message);
});
}).catch(error => { }).catch(error => {
new Notice(error.message); new Notice(error.message);
}); });
@ -292,20 +338,29 @@ export default class AICommanderPlugin extends Plugin {
const position = editor.getCursor(); const position = editor.getCursor();
const line = editor.getLine(position.line) const line = editor.getLine(position.line)
const text = editor.getRange({line: 0, ch: 0}, position); const text = editor.getRange({line: 0, ch: 0}, position);
const regex = /(?<=\[(.*)]\()(([^[\]])+)\.(mp3|mp4|mpeg|mpga|m4a|wav|webm)(?=\))/g; const regex = [/(?<=\[\[)(([^[\]])+)\.(mp3|mp4|mpeg|mpga|m4a|wav|webm)(?=]])/g,
/(?<=\[(.*)]\()(([^[\]])+)\.(mp3|mp4|mpeg|mpga|m4a|wav|webm)(?=\))/g];
this.findFilePath(text, regex).then((path) => { this.findFilePath(text, regex).then((path) => {
const fileType = path.split('.').pop(); const fileType = path.split('.').pop();
if (fileType == undefined || fileType == null || fileType == '') { if (fileType == undefined || fileType == null || fileType == '') {
new Notice('No audio file found'); new Notice('No audio file found');
return; } else {
} this.app.vault.adapter.exists(path).then((exists) => {
this.app.vault.adapter.readBinary(path).then((audioBuffer) => { console.log('Audio filepath', path);
new Notice("Generating transcript..."); if (!exists) throw new Error(path + ' does not exist');
this.generateTranscript(audioBuffer, fileType).then((result) => { this.app.vault.adapter.readBinary(path).then((audioBuffer) => {
new Notice('Transcript Generated.'); new Notice("Generating transcript...");
editor.setLine(position.line, `${line}${result}\n`); this.generateTranscript(audioBuffer, fileType).then((result) => {
new Notice('Transcript Generated.');
editor.setLine(position.line, `${line}${result}\n`);
});
}).catch(error => {
new Notice(error.message);
});
}).catch(error => {
new Notice(error.message);
}); });
}) }
}).catch(error => { }).catch(error => {
new Notice(error.message); new Notice(error.message);
}); });

View file

@ -1,7 +1,7 @@
{ {
"id": "ai-commander", "id": "ai-commander",
"name": "AI Commander", "name": "AI Commander",
"version": "1.1.1", "version": "1.1.2",
"minAppVersion": "1.0.0", "minAppVersion": "1.0.0",
"description": "Generate audio transcripts, images, and text in context of PDF attachments or web search results using OpenAI and Bing API.", "description": "Generate audio transcripts, images, and text in context of PDF attachments or web search results using OpenAI and Bing API.",
"author": "Simon Yang", "author": "Simon Yang",

View file

@ -1,3 +1,3 @@
{ {
"1.1.1": "1.0.0" "1.1.2": "1.0.0"
} }