From 61859d5f1f2a81a9983506f28d13e2a69e594e26 Mon Sep 17 00:00:00 2001 From: Benjamin Shafii Date: Sun, 17 Nov 2024 19:08:16 +0100 Subject: [PATCH] fix: a bunch of stuff --- plugin/fileUtils.ts | 158 ++++++++++++++++++++++---------- plugin/inbox/index.ts | 130 +++++++------------------- plugin/services/logger.ts | 75 ++------------- plugin/someUtils.ts | 8 +- plugin/views/organizer/view.tsx | 6 +- 5 files changed, 157 insertions(+), 220 deletions(-) diff --git a/plugin/fileUtils.ts b/plugin/fileUtils.ts index 8aa93cdf..33f1a322 100644 --- a/plugin/fileUtils.ts +++ b/plugin/fileUtils.ts @@ -1,5 +1,6 @@ import { App, TFolder, TFile, normalizePath } from "obsidian"; import { FileOrganizerSettings } from "./settings"; + export async function ensureFolderExists(app: App, folderPath: string) { if (!(await app.vault.adapter.exists(folderPath))) { await app.vault.createFolder(folderPath); @@ -29,56 +30,46 @@ export async function checkAndCreateTemplates( if (!(await app.vault.adapter.exists(meetingNoteTemplatePath))) { await app.vault.create( meetingNoteTemplatePath, - `## Meeting Details - -- Date: {{date}} in format YYYY-MM-DD -- Participants: {{participants}} - -## Audio Reference - -![[{{audio_file}}]] - -## Key Points - -[Summarize the main points discussed in the meeting] - -## Action Items - -- [ ] Action item 1 - - [ ] Sub-action 1.1 - - [ ] Sub-action 1.2 -- [ ] Action item 2 - - [ ] Sub-action 2.1 - - [ ] Sub-action 2.2 - -## Detailed Notes - -[Add your meeting notes here, maintaining a hierarchical structure] - -## Transcription - -[Insert the full transcription below] - ---- - -AI Instructions: -1. Merge the transcription into the content, focusing on key points and action items. -2. Summarize the main discussion points in the "Key Points" section, using bullet points for clarity. -3. Extract and list any action items or tasks in the "Action Items" section: - - Use a hierarchical structure with main action items and sub-actions. - - Maintain the original level of detail from the transcript. - - Use indentation to show the relationship between main actions and sub-actions. -4. In the "Detailed Notes" section, create a hierarchical structure that reflects the meeting's flow: - - Use headings (###, ####) for main topics. - - Use bullet points and sub-bullets for detailed points under each topic. - - Preserve the granularity of the discussion, including specific examples or minor points. -5. Preserve the reference to the original audio file. -6. Maintain the overall structure of the note, including all headers and sections. -7. Delete transcription. Mention that it can be accessed in the Original file` + `Contextual Extraction of Discussion Points and Action Items + +Instruction: +Analyze the provided content, which includes: + • Transcript 1: The first transcript of the discussion. + • Transcript 2: The second transcript of the discussion. + • Written Notes: Notes taken by a participant summarizing the discussion. + +Task: +Extract the following while prioritizing the notes written by the participant to infer emphasis and key takeaways: + 1. Discussion Points: Summarize the key topics, ideas, or issues discussed. Prioritize points that appear in the written notes and cross-reference with the transcripts for completeness. + 2. Action Items: Identify specific tasks, responsibilities, or decisions agreed upon. For each action item, include: + • A brief description of the task. + • The person(s) responsible, if mentioned. + • Any deadlines, if stated. + +Output Format: + +**Discussion Points:** +1. [Point 1] +2. [Point 2] +... + +**Action Items:** +1. [Task description] - [Responsible person(s)] - [Deadline] +2. [Task description] - [Responsible person(s)] - [Deadline] +... + +**Supporting Context:** +- Key excerpts from Transcript 1: [Relevant excerpts related to discussion points and action items]. +- Key excerpts from Transcript 2: [Relevant excerpts related to discussion points and action items]. +- Key highlights from Written Notes: [Direct quotes or summaries from notes]. +` ); } } +/** + * @deprecated use safeMove instead + */ export async function moveFile( app: App, sourceFile: TFile, @@ -110,7 +101,9 @@ export async function moveFile( await app.fileManager.renameFile(sourceFile, normalizedFinalPath); // Get the moved file object and return it - const movedFile = app.vault.getAbstractFileByPath(normalizedFinalPath) as TFile; + const movedFile = app.vault.getAbstractFileByPath( + normalizedFinalPath + ) as TFile; return movedFile; } @@ -121,8 +114,75 @@ export function isTFolder(file: any): file is TFolder { export function getAllFolders(app: App): string[] { const allFiles = app.vault.getAllLoadedFiles(); const folderPaths = allFiles - .filter((file) => isTFolder(file)) - .map((folder) => folder.path); + .filter(file => isTFolder(file)) + .map(folder => folder.path); return [...new Set(folderPaths)]; } + +export async function getAvailablePath( + app: App, + desiredPath: string +): Promise { + let available = desiredPath; + let increment = 0; + + while (await app.vault.adapter.exists(available)) { + increment++; + const lastDotIndex = available.lastIndexOf("."); + const withoutExt = available.slice(0, lastDotIndex); + const ext = available.slice(lastDotIndex); + available = `${withoutExt} ${increment}${ext}`; + } + + return available; +} + +export async function safeCreate( + app: App, + desiredPath: string, + content = "" +): Promise { + const parentPath = desiredPath.substring(0, desiredPath.lastIndexOf("/")); + await ensureFolderExists(app, parentPath); + + const availablePath = await getAvailablePath(app, desiredPath); + return await app.vault.create(availablePath, content); +} + +export async function safeRename( + app: App, + file: TFile, + newName: string +): Promise { + const parentPath = file.parent.path; + const extension = file.extension; + const desiredPath = `${parentPath}/${newName}.${extension}`; + + const availablePath = await getAvailablePath(app, desiredPath); + await app.fileManager.renameFile(file, availablePath); +} + +export async function safeCopy( + app: App, + file: TFile, + destinationPath: string +): Promise { + await ensureFolderExists(app, destinationPath); + + const desiredPath = `${destinationPath}/${file.name}`; + const availablePath = await getAvailablePath(app, desiredPath); + return await app.vault.copy(file, availablePath); +} + +export async function safeMove( + app: App, + file: TFile, + destinationPath: string +): Promise { + await ensureFolderExists(app, destinationPath); + + const desiredPath = `${destinationPath}/${file.name}`; + const availablePath = await getAvailablePath(app, desiredPath); + await app.fileManager.renameFile(file, availablePath); +} diff --git a/plugin/inbox/index.ts b/plugin/inbox/index.ts index 149f1056..203ddf2c 100644 --- a/plugin/inbox/index.ts +++ b/plugin/inbox/index.ts @@ -8,7 +8,7 @@ import { FileStatus, } from "./services/record-manager"; import { QueueStatus } from "./types"; -import { cleanPath, logMessage } from "../someUtils"; +import { logMessage } from "../someUtils"; import { IdService } from "./services/id-service"; import { logger } from "../services/logger"; import { @@ -17,13 +17,16 @@ import { cleanup, } from "../utils/token-counter"; import { isValidExtension, VALID_MEDIA_EXTENSIONS } from "../constants"; -import { ensureFolderExists } from "../fileUtils"; -import { log } from "console"; +import { + safeCreate, + safeRename, + safeCopy, + safeMove, +} from "../fileUtils"; // Move constants to the top level and ensure they're used consistently const MAX_CONCURRENT_TASKS = 5; const MAX_CONCURRENT_MEDIA_TASKS = 2; -const TOKEN_LIMIT = 50000; // 50k tokens limit for formatting export interface FolderSuggestion { isNewFolder: boolean; @@ -309,7 +312,7 @@ async function moveAttachmentFile( if (VALID_MEDIA_EXTENSIONS.includes(context.inboxFile.extension)) { context.attachmentFile = context.inboxFile; await safeMove( - context, + context.plugin.app, context.inboxFile, context.plugin.settings.attachmentsPath ); @@ -328,7 +331,7 @@ async function getContainerFileStep( logger.info("Get container file step"); if (VALID_MEDIA_EXTENSIONS.includes(context.inboxFile?.extension)) { const containerFile = await safeCreate( - context, + context.plugin.app, context.inboxFile.basename + ".md", "" ); @@ -368,7 +371,11 @@ async function recommendNameStep( } context.recordManager.setNewName(context.hash, context.newName); context.recordManager.addAction(context.hash, Action.RENAME); - await safeRename(context, context.containerFile, context.newName); + await safeRename( + context.plugin.app, + context.containerFile, + context.newName + ); context.recordManager.addAction(context.hash, Action.RENAME, true); return context; } @@ -384,7 +391,11 @@ async function recommendFolderStep( context.newPath = newPath[0]?.folder; console.log("new path", context.newPath, context.containerFile); context.recordManager.addAction(context.hash, Action.MOVING); - await safeMove(context, context.containerFile, context.newPath); + await safeMove( + context.plugin.app, + context.containerFile, + context.newPath + ); context.recordManager.addAction(context.hash, Action.MOVING, true); console.log("moved file to", context.containerFile); @@ -475,7 +486,11 @@ async function handleBypass( // Then move the file const bypassedFolderPath = context.plugin.settings.bypassedFilePath; - await safeMove(context, context.inboxFile, bypassedFolderPath); + await safeMove( + context.plugin.app, + context.inboxFile, + bypassedFolderPath + ); context.queue.bypass(context.hash); context.recordManager.setStatus(context.hash, "bypassed"); @@ -545,7 +560,7 @@ async function formatContentStep( context.formattedContent = formattedContent; const referenceFile = await safeCopy( - context, + context.plugin.app, context.containerFile, context.plugin.settings.referencePath ); @@ -624,99 +639,22 @@ async function handleError( // moveToBackupFolder async function moveToBackupFolder(context: ProcessingContext): Promise { - const backupFolderPath = context.plugin.settings.backupFolderPath; - await safeMove(context, context.inboxFile, backupFolderPath); + await safeMove( + context.plugin.app, + context.inboxFile, + context.plugin.settings.backupFolderPath + ); } // Helper functions for file operations async function moveFileToErrorFolder( context: ProcessingContext ): Promise { - const errorFolderPath = context.plugin.settings.errorFilePath; - await safeMove(context, context.inboxFile, errorFolderPath); -} - -async function getAvailablePath( - desiredPath: string, - vault: Vault -): Promise { - let available = desiredPath; - let increment = 0; - - // Split path into directory and filename - const lastDotIndex = desiredPath.lastIndexOf("."); - const lastSlashIndex = desiredPath.lastIndexOf("/"); - const dir = desiredPath.substring(0, lastSlashIndex); - const nameWithoutExt = desiredPath.substring( - lastSlashIndex + 1, - lastDotIndex - ); - const ext = desiredPath.substring(lastDotIndex); - - // Keep incrementing until we find an available path - while (await vault.adapter.exists(available)) { - increment++; - available = `${dir}/${nameWithoutExt} ${increment}${ext}`; - } - - return available; -} -async function safeCreate( - context: ProcessingContext, - desiredPath: string, - content?: string -): Promise { - await ensureFolderExists(context.plugin.app, desiredPath); - const availablePath = await getAvailablePath( - desiredPath, - context.plugin.app.vault - ); - const createdFile = await context.plugin.app.vault.create( - availablePath, - content - ); - return createdFile; -} - -async function safeRename( - context: ProcessingContext, - file: TFile, - desiredNewName: string -): Promise { - const parentPath = file.parent.path; - const extension = file.extension; - const desiredPath = `${parentPath}/${desiredNewName}.${extension}`; - const availablePath = await getAvailablePath( - desiredPath, - context.plugin.app.vault - ); - await context.plugin.app.fileManager.renameFile(file, availablePath); -} -async function safeCopy( - context: ProcessingContext, - file: TFile, - desiredFolderPath: string -): Promise { - await ensureFolderExists(context.plugin.app, desiredFolderPath); - const availablePath = await getAvailablePath( - `${desiredFolderPath}/${file.name}`, - context.plugin.app.vault - ); - const copiedFile = await context.plugin.app.vault.copy(file, availablePath); - return copiedFile; -} - -async function safeMove( - context: ProcessingContext, - file: TFile, - desiredFolderPath: string -): Promise { - await ensureFolderExists(context.plugin.app, desiredFolderPath); - const availablePath = await getAvailablePath( - `${desiredFolderPath}/${file.name}`, - context.plugin.app.vault + await safeMove( + context.plugin.app, + context.inboxFile, + context.plugin.settings.errorFilePath ); - await context.plugin.app.fileManager.renameFile(file, availablePath); } // Helper functions for initialization and usage diff --git a/plugin/services/logger.ts b/plugin/services/logger.ts index 7c406740..d9f1cce5 100644 --- a/plugin/services/logger.ts +++ b/plugin/services/logger.ts @@ -8,92 +8,35 @@ export interface LogEntry { class LoggerService { private logs: LogEntry[] = []; private isEnabled = false; - private maxLogs = 1000; configure(enabled: boolean) { this.isEnabled = enabled; } - private addLog(level: LogEntry['level'], message: string, details?: any) { - if (!this.isEnabled) return; - const timestamp = new Date().toISOString(); - const entry = { - timestamp, - level, - message, - details: details ? JSON.stringify(details) : undefined - }; - - const consoleArgs = [`[${timestamp}] ${message}`, details].filter(Boolean); - - switch (level) { - case 'info': - console.info(...consoleArgs); - break; - case 'error': - console.error(...consoleArgs); - break; - case 'warn': - console.warn(...consoleArgs); - break; - case 'debug': - console.debug(...consoleArgs); - break; - } - - this.logs.push(entry); - - if (this.logs.length > this.maxLogs) { - this.logs = this.logs.slice(-this.maxLogs); - } - } - - info(message: string, details?: any) { - this.addLog('info', message, details); + info(...messages: any[]) { + console.info(...messages); } - error(message: string, details?: any) { - this.addLog('error', message, details); + error(...messages: any[]) { + console.error(...messages); } - warn(message: string, details?: any) { - this.addLog('warn', message, details); + warn(...messages: any[]) { + console.warn(...messages); } - debug(message: string, details?: any) { - this.addLog('debug', message, details); + debug(...messages: any[]) { + console.debug(...messages); } getLogs(): LogEntry[] { - return [...this.logs]; + return this.logs; } clearLogs() { this.logs = []; } - - exportToCSV(): string { - const headers = ['Timestamp', 'Level', 'Message', 'Details']; - const rows = this.logs.map(log => [ - log.timestamp, - log.level, - log.message, - log.details || '' - ]); - - return [ - headers.join(','), - ...rows.map(row => row.map(cell => `"${cell}"`).join(',')) - ].join('\n'); - } - - getStatus(): { enabled: boolean; logsCount: number } { - return { - enabled: this.isEnabled, - logsCount: this.logs.length - }; - } } export const logger = new LoggerService(); \ No newline at end of file diff --git a/plugin/someUtils.ts b/plugin/someUtils.ts index 9d490285..53800303 100644 --- a/plugin/someUtils.ts +++ b/plugin/someUtils.ts @@ -13,12 +13,8 @@ export function cleanPath(path: string) { return pathWithoutLeadingAndTrailingSlashes; } -export const logMessage = (...args: any[]) => { - const message = args - .map(arg => (typeof arg === "object" ? JSON.stringify(arg) : arg)) - .join(" "); - - logger.debug(message); +export const logMessage = (...messages: any[]) => { + logger.debug(...messages); }; export const logError = (error: Error | string, details?: any) => { diff --git a/plugin/views/organizer/view.tsx b/plugin/views/organizer/view.tsx index 3eacd2f4..6d2d60b7 100644 --- a/plugin/views/organizer/view.tsx +++ b/plugin/views/organizer/view.tsx @@ -6,7 +6,7 @@ import FileOrganizer from "../.."; import { InboxLogs } from "./components/inbox-logs"; import { SectionHeader } from "./components/section-header"; import { AppContext } from "./provider"; -import AIChatSidebar from '../ai-chat/container'; +import AIChatSidebar from "../ai-chat/container"; export const ORGANIZER_VIEW_TYPE = "fo2k.assistant.sidebar2"; @@ -29,7 +29,7 @@ function TabContent({ return ( <> - + ); } @@ -102,7 +102,7 @@ function OrganizerContent({
- +
);