From 4ffef1cc887d2fa9d49fb5de99f5d1f01f9c4e84 Mon Sep 17 00:00:00 2001 From: Spencer Date: Fri, 5 Sep 2025 14:38:22 -0500 Subject: [PATCH] v1.0 --- README.md | 63 ++++++++++++++++++++++++++++++++++++++++++++ SPEC.md | 28 ++++++++++++++++++++ index.js | 30 +++++++++++++++++++++ package.json | 22 ++++++++++++++++ src/aiProcessor.js | 37 ++++++++++++++++++++++++++ src/fileReader.js | 43 ++++++++++++++++++++++++++++++ src/noteOrganizer.js | 28 ++++++++++++++++++++ src/outputWriter.js | 21 +++++++++++++++ 8 files changed, 272 insertions(+) create mode 100644 README.md create mode 100644 SPEC.md create mode 100644 index.js create mode 100644 package.json create mode 100644 src/aiProcessor.js create mode 100644 src/fileReader.js create mode 100644 src/noteOrganizer.js create mode 100644 src/outputWriter.js diff --git a/README.md b/README.md new file mode 100644 index 0000000..e4b23c1 --- /dev/null +++ b/README.md @@ -0,0 +1,63 @@ + +# AI Language Note Organizer + +This project is a command-line application that uses the Google Gemini API to automatically organize your language class notes. It takes a directory of markdown files, identifies common themes and topics, and generates a single, well-structured markdown file with your notes grouped under relevant headings. + +## Features + +- **Recursive File Scanning:** Automatically scans through nested directories to find your note files. +- **Flexible Filtering:** Use a simple text pattern to specify which notes to process (e.g., "Japanese" or "Spanish_Class"). +- **AI-Powered Organization:** Leverages the Gemini API to intelligently categorize and structure your notes. +- **Non-Destructive:** Your original note files are never modified. + +## Installation + +1. **Clone the repository:** + ```bash + git clone https://github.com/your-username/language-note-organizer.git + cd language-note-organizer + ``` + +2. **Install the dependencies:** + ```bash + npm install + ``` + +3. **Set up your environment variables:** + - Create a `.env` file in the root of the project. + - Add your Google Gemini API key to the `.env` file: + ``` + GEMINI_API_KEY=your_api_key_here + ``` + +## Usage + +Run the application from your terminal with the following command: + +```bash +node index.js [file_pattern] +``` + +- ``: The path to the folder containing your note files. +- `[file_pattern]` (Optional): A keyword or pattern to filter the files. Only files with names containing this pattern will be processed. + +### Example + +Imagine you have a `notes/` directory with the following structure: + +``` +notes/ +├── japanese/ +│ ├── 2023-10-26_Japanese_Grammar.md +│ └── 2023-10-27_Japanese_Vocab.md +└── spanish/ + └── 2023-11-01_Spanish_Phrases.md +``` + +To organize only the Japanese notes, you would run: + +```bash +node index.js notes/ japanese +``` + +The script will create a new file named `organized_notes.md` in the project's root directory with the organized content from your Japanese notes. diff --git a/SPEC.md b/SPEC.md new file mode 100644 index 0000000..1029168 --- /dev/null +++ b/SPEC.md @@ -0,0 +1,28 @@ +# Project SPEC Sheet: AI Language Note Organizer + +## 1. Project Goals +- Develop an application to organize markdown-based language class notes from a specified directory. +- Use an AI to analyze, group, and create headings for related notes. +- Produce a single, organized markdown file for easy reference, without altering the original files. + +## 2. Core Functionality +- **File Input:** Accept a directory path and a file name pattern from the user. +- **Note Processing:** Scan for markdown files in the directory that match the specified pattern (e.g., containing "Chinese Class" or "Japanese Class"). Extract content from these files. +- **AI Organization:** + - Use an AI model (Primary: Google Gemini API) to understand the note content. + - The AI will identify themes and topics (e.g., "Verb Conjugation," "Cultural Notes"). +- **Output Generation:** Create a new, single markdown file with notes grouped under AI-generated headings. + +## 3. Technical Specifications +- **Language:** Node.js +- **AI Service:** Google Gemini API. I'll handle the integration; you'll just need to provide the key when the time comes. +- **User Interface:** A simple Command-Line Interface (CLI). + +## 4. Project Outline +1. **Setup:** Initialize a Node.js project. +2. **File Reader:** Build a module to find and read markdown files from a directory that match a user-provided naming pattern. +3. **AI Integration:** Create a module to communicate with the Gemini API. +4. **Note Organizer:** Implement logic to group notes based on the AI's analysis. +5. **Output Writer:** Write the organized notes to a new file. +6. **CLI:** Build the user interface. +7. **Testing:** Write tests to ensure all parts are working correctly. \ No newline at end of file diff --git a/index.js b/index.js new file mode 100644 index 0000000..e11fa50 --- /dev/null +++ b/index.js @@ -0,0 +1,30 @@ +const { processAndOrganizeNotes } = require('./src/noteOrganizer'); +const { writeOrganizedNotes } = require('./src/outputWriter'); + +async function main() { + try { + const args = process.argv.slice(2); + if (args.length < 1 || args.length > 2) { + console.log('Usage: node index.js [file_pattern]'); + return; + } + + const [dirPath, pattern] = args; + + console.log(`Starting to process notes in: ${dirPath}`); + if (pattern) { + console.log(`Filtering by pattern: ${pattern}`); + } + + const organizedNotes = await processAndOrganizeNotes(dirPath, pattern); + + if (organizedNotes) { + writeOrganizedNotes(__dirname, organizedNotes); + } + } catch (error) { + console.error('An unexpected error occurred:', error); + } +} + +main(); + diff --git a/package.json b/package.json new file mode 100644 index 0000000..f1262c2 --- /dev/null +++ b/package.json @@ -0,0 +1,22 @@ +{ + "name": "language_note_app", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC", + "type": "commonjs", + "dependencies": { + "@google/generative-ai": "^0.24.1", + "dotenv": "^17.2.2" + }, + "devDependencies": { + "babel-runtime": "^6.26.0", + "jest": "^30.1.3", + "jest-plugin-fs": "^2.9.0" + } +} diff --git a/src/aiProcessor.js b/src/aiProcessor.js new file mode 100644 index 0000000..65bdb31 --- /dev/null +++ b/src/aiProcessor.js @@ -0,0 +1,37 @@ +// Module for processing content with Google Gemini +require('dotenv').config(); + +const API_KEY = process.env.GEMINI_API_KEY; + +if (!API_KEY) { + console.error('Error: GEMINI_API_KEY environment variable not set.'); + process.exit(1); +} + +const { GoogleGenerativeAI } = require('@google/generative-ai'); +const genAI = new GoogleGenerativeAI(API_KEY); + +/** + * Sends note content to the Gemini API for organization. + * @param {string[]} noteContents - An array of strings, where each string is the content of a note. + * @returns {Promise} - The organized notes as a single string from the AI. + */ +async function organizeNotesWithAI(noteContents) { + const model = genAI.getGenerativeModel({ model: "gemini-2.5-pro"}); + const combinedNotes = noteContents.join('\n\n---\n\n'); + const prompt = `Please organize the following language notes. Group related topics under clear markdown headings (e.g., ## Grammar, ## Vocabulary, ## Cultural Notes). Here are the notes:\n\n${combinedNotes}`; + + try { + const result = await model.generateContent(prompt); + const response = await result.response; + const text = response.text(); + return text; + } catch (error) { + console.error('Error communicating with the Gemini API:', error); + return null; + } +} + +module.exports = { organizeNotesWithAI }; + + diff --git a/src/fileReader.js b/src/fileReader.js new file mode 100644 index 0000000..d38954e --- /dev/null +++ b/src/fileReader.js @@ -0,0 +1,43 @@ + +// Module for reading and filtering files +const fs = require('fs'); +const path = require('path'); + +/** + * Recursively scans a directory, filters files by a pattern, and reads their content. + * @param {string} dirPath - The path to the directory. + * @param {string} pattern - The keyword pattern to match in the file name. + * @returns {{filePath: string, content: string}[]} - An array of objects, each with the file path and its content. + */ +function getFileContents(dirPath, pattern) { + let fileData = []; + + function scan(directory) { + try { + const entries = fs.readdirSync(directory, { withFileTypes: true }); + for (const entry of entries) { + const fullPath = path.join(directory, entry.name); + if (entry.isDirectory()) { + scan(fullPath); + } else { + const regex = new RegExp(pattern, 'i'); + if (!pattern || regex.test(entry.name)) { + try { + const content = fs.readFileSync(fullPath, 'utf8'); + fileData.push({ filePath: fullPath, content }); + } catch (readError) { + console.error(`Error reading file ${fullPath}:`, readError); + } + } + } + } + } catch (scanError) { + console.error(`Error scanning directory ${directory}:`, scanError); + } + } + + scan(dirPath); + return fileData; +} + +module.exports = { getFileContents }; diff --git a/src/noteOrganizer.js b/src/noteOrganizer.js new file mode 100644 index 0000000..a20251e --- /dev/null +++ b/src/noteOrganizer.js @@ -0,0 +1,28 @@ +// Module to organize notes by bridging other modules +const path = require('path'); +const { getFileContents } = require('./fileReader'); +const { organizeNotesWithAI } = require('./aiProcessor'); + +/** + * Orchestrates the process of reading, processing, and organizing notes. + * @param {string} dirPath - The path to the directory containing notes. + * @param {string} pattern - The file name pattern to match. + * @returns {Promise} - The organized notes as a single markdown string, or null on error. + */ +async function processAndOrganizeNotes(dirPath, pattern) { + const fileData = getFileContents(dirPath, pattern); + if (fileData.length === 0) { + console.log('No matching files found to organize.'); + return null; + } + + const contextualizedNotes = fileData.map(data => { + const fileName = path.basename(data.filePath); + return `--- Note from ${fileName} ---\n\n${data.content}`; + }); + + const organizedNotes = await organizeNotesWithAI(contextualizedNotes); + return organizedNotes; +} + +module.exports = { processAndOrganizeNotes }; diff --git a/src/outputWriter.js b/src/outputWriter.js new file mode 100644 index 0000000..d08e8a6 --- /dev/null +++ b/src/outputWriter.js @@ -0,0 +1,21 @@ +// Module for writing the final output to a file +const fs = require('fs'); +const path = require('path'); + +/** + * Writes the organized notes to a markdown file. + * @param {string} outputDir - The directory to write the file in. + * @param {string} content - The markdown content to write. + */ +function writeOrganizedNotes(outputDir, content) { + const outputFilePath = path.join(outputDir, 'organized_notes.md'); + try { + fs.writeFileSync(outputFilePath, content, 'utf8'); + console.log(`Successfully wrote organized notes to ${outputFilePath}`); + } catch (error) { + console.error(`Error writing to file ${outputFilePath}:`, error); + } +} + +module.exports = { writeOrganizedNotes }; +