Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
151 changes: 151 additions & 0 deletions MVP_README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
# Smart Notes (Local AI Notes App)

Hi! This project is a small but meaningful attempt to build a local, privacy-first note-taking system with AI features. It is inspired by the Smart Notes idea from AOSSIE for GSoC.

Instead of relying on cloud services, everything here runs locally on your machine. The idea is simple β€” your notes are yours, and the intelligence around them should also stay with you.

---

## 🌱 What this project does

This app lets you:

* Write and store notes
* Ask questions based on your notes
* Get short summaries of your notes
* See related notes automatically

All of this is powered by a basic Retrieval-Augmented Generation (RAG) pipeline running locally.

---

## 🧠 Features

### 1. Ask Questions (Q&A)

You can ask questions about your notes, and the system will try to answer using only the content you’ve written.

### 2. Smart Summarization

Notes can be summarized into a short, clean sentence instead of just repeating the same text.

### 3. Related Notes

When you add a new note, the system suggests other notes that are similar in meaning.

### 4. Local First

Everything runs on your system β€” no mandatory APIs, no cloud dependency.

### 5. Desktop App

The app is wrapped using Electron so it can run like a desktop application.

---

## βš™οΈ Tech Stack

* Python (Flask)
* HTML + CSS (simple UI)
* HuggingFace Transformers
* Sentence Transformers (for embeddings)
* Electron (for desktop wrapper)

---

## πŸ—οΈ How it works (simple view)

1. Notes are stored locally
2. Each note is converted into embeddings
3. When you ask a question:

* relevant notes are retrieved
* a model generates an answer from that context

---

## πŸš€ How to run the project

### 1. Clone the repo

```
git clone https://github.com/KRISHNPRIY2820/smart-notes-mvp.git
cd smart-notes
```
Comment on lines +71 to +74
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟑 Minor

Directory name mismatch in clone instructions.

The clone URL is smart-notes-mvp.git but the cd command uses smart-notes. This will fail for users following the instructions.

πŸ”§ Proposed fix
 ```bash
 git clone https://github.com/KRISHNPRIY2820/smart-notes-mvp.git
-cd smart-notes
+cd smart-notes-mvp
πŸ“ Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
```
git clone https://github.com/KRISHNPRIY2820/smart-notes-mvp.git
cd smart-notes
```
🧰 Tools
πŸͺ› markdownlint-cli2 (0.22.0)

[warning] 71-71: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

πŸ€– Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@MVP_README.md` around lines 71 - 74, The README has a directory name
mismatch: the clone command uses smart-notes-mvp while the following cd uses
smart-notes; update the cd command in MVP_README.md to "cd smart-notes-mvp" so
the two commands match (adjust the line containing "cd smart-notes" to "cd
smart-notes-mvp" next to the existing "git clone
https://github.com/KRISHNPRIY2820/smart-notes-mvp.git" command).


### 2. Create virtual environment

```
python -m venv venv
venv\Scripts\activate
```
Comment on lines +78 to +81
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟑 Minor

Windows-specific activation command.

venv\Scripts\activate only works on Windows. Consider including cross-platform instructions.

πŸ”§ Proposed cross-platform instructions
 ```bash
 python -m venv venv
-venv\Scripts\activate
+# Windows:
+venv\Scripts\activate
+# macOS/Linux:
+source venv/bin/activate
πŸ“ Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
```
python -m venv venv
venv\Scripts\activate
```
🧰 Tools
πŸͺ› markdownlint-cli2 (0.22.0)

[warning] 78-78: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

πŸ€– Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@MVP_README.md` around lines 78 - 81, The README currently shows a
Windows-only activation command ("venv\Scripts\activate"); update the
instructions to be explicit and cross-platform by keeping the Python venv
creation step and adding separate activation commands for Windows
("venv\\Scripts\\activate") and for macOS/Linux ("source venv/bin/activate"),
and label each platform so users know which activation command to run.


### 3. Install requirements

```
pip install -r requirements.txt
```

### 4. Run the backend

```
python app.py
```

Open in browser:

```
http://127.0.0.1:5000
```

---

## πŸ’» Run as Desktop App (Electron)

```
cd frontend
npm install
npm start
```
Comment on lines +71 to +109
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | πŸ”΅ Trivial

Add language specifiers to fenced code blocks.

Per markdownlint (MD040), fenced code blocks should have a language specified for syntax highlighting and accessibility. Add bash or shell to command blocks.

🧰 Tools
πŸͺ› markdownlint-cli2 (0.22.0)

[warning] 71-71: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


[warning] 78-78: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


[warning] 85-85: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


[warning] 91-91: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


[warning] 97-97: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


[warning] 105-105: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

πŸ€– Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@MVP_README.md` around lines 71 - 109, Update the fenced code blocks in the
README to include language specifiers for syntax highlighting (e.g., change the
triple-backtick blocks that contain the git clone command, the
virtualenv/activation commands, the pip install line, the python app.py run
command, the URL block, and the Electron frontend commands to use appropriate
languages like bash or shell for shell commands and possibly http for the URL);
ensure every fenced block in MVP_README.md that shows commands or snippets
starts with ```bash or ```shell (or another suitable language tag) to satisfy
MD040.


---

## πŸ§ͺ Current limitations

* UI is basic (focused more on functionality)
* Models are simple and not heavily optimized
* No persistent vector database yet

---

## 🌟 Why this project

Most note-taking tools today depend heavily on the cloud. This project explores a different direction β€” keeping everything local while still providing AI assistance.
>This MVP focuses on building a strong local-first foundation, with scalability planned in future iterations.

---

## 🚧 Future Improvements

- Multi-page UI instead of a single screen for better feature separation
- Persistent storage so notes are saved locally and do not vanish after restarting the app
- Knowledge graph visualization to explore connections between notes
- Improved retrieval using hybrid search (keyword + semantic)
- Enhanced UI using React + Electron
- Optional multi-device sync while maintaining privacy

---

## 🀝 Contribution

This is part of my GSoC preparation with AOSSIE. Any feedback or suggestions are genuinely welcome.

---

## πŸ“œ License

GNU GPL v3

---

Thanks for checking this out πŸ™‚
55 changes: 55 additions & 0 deletions app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
from flask import Flask, render_template, request
from logic.notes import add_note, get_notes
from logic.qa import answer
from logic.linking import suggest
from logic.context import update_embeddings
from logic.summarizer import summarize_notes

app = Flask(__name__)

@app.route("/", methods=["GET", "POST"])
def index():
answer_text = ""
links = []
summary_text = ""

# Always get latest notes
notes = get_notes()

# Ensure embeddings are synced
update_embeddings(notes)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Remove redundant embedding recomputation on request entry.

Line 20 recomputes embeddings for every request, and the add-note flow recomputes again via logic/notes.py (add_note β†’ update_embeddings). This doubles O(n) work on POST and grows poorly with note count.

Proposed fix
-    # Ensure embeddings are synced
-    update_embeddings(notes)
@@
         elif "question" in request.form and request.form["question"].strip():
             question = request.form["question"].strip()
+            update_embeddings(notes)
 
             answer_text = answer(question, notes)

Also applies to: 28-31

πŸ€– Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app.py` at line 20, The call to update_embeddings in app.py is redundant
because add_note in logic/notes.py already calls update_embeddings; remove the
update_embeddings(...) invocation(s) in app.py (including the ones corresponding
to lines 28-31) so embeddings are only recomputed inside add_note (or other
note-changing functions) to avoid duplicate O(n) work; if any other route in
app.py must trigger embeddings, replace the direct call with a clear delegate to
the logic layer (e.g., call a single exported function in logic/notes.py) or add
a guard to avoid double computation.


Comment on lines +19 to +21
Copy link

Copilot AI Mar 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

update_embeddings(notes) is called on every request, even for GETs and even though add_note() already updates embeddings on note insertion. Since embedding generation is expensive, consider only syncing embeddings when notes change (or only on first request/startup) to avoid unnecessary recomputation.

Suggested change
# Ensure embeddings are synced
update_embeddings(notes)

Copilot uses AI. Check for mistakes.
if request.method == "POST":

# Add Note
if "note" in request.form and request.form["note"].strip():
note = request.form["note"].strip()

add_note(note)

# Refresh notes
notes = get_notes()

# Suggest related notes
links = suggest(note, notes)

# Ask Question
elif "question" in request.form and request.form["question"].strip():
question = request.form["question"].strip()

answer_text = answer(question, notes)

# Summarize Notes
elif "summarize" in request.form:
summary_text = summarize_notes(notes)

return render_template(
"index.html",
notes=notes,
answer=answer_text,
links=links,
summary=summary_text
)

if __name__ == "__main__":
app.run(debug=True)
Comment on lines +54 to +55
Copy link

Copilot AI Mar 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

app.run(debug=True) enables the Flask debugger and interactive console, which should not be committed as the default for anything beyond local development. Please default to debug=False (or read from an environment variable) and document how to enable debug mode locally.

Copilot uses AI. Check for mistakes.
Comment on lines +54 to +55
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | πŸ”΄ Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify whether debug mode is hardcoded in Flask startup paths.
rg -nP --type=py -C2 'app\.run\([^)]*debug\s*=\s*True'

Repository: AOSSIE-Org/SmartNotes

Length of output: 146


Remove hardcoded debug=True from Flask startup.

Line 55 unconditionally enables debug mode, which exposes sensitive data if used outside local development.

Proposed fix
+import os
@@
 if __name__ == "__main__":
-    app.run(debug=True)
+    app.run(debug=os.getenv("FLASK_DEBUG") == "1")
πŸ“ Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if __name__ == "__main__":
app.run(debug=True)
if __name__ == "__main__":
app.run(debug=os.getenv("FLASK_DEBUG") == "1")
🧰 Tools
πŸͺ› ast-grep (0.41.1)

[warning] 54-54: Detected Flask app with debug=True. Do not deploy to production with this flag enabled as it will leak sensitive information. Instead, consider using Flask configuration variables or setting 'debug' using system environment variables.
Context: app.run(debug=True)
Note: [CWE-489] Active Debug Code. [REFERENCES]
- https://labs.detectify.com/2015/10/02/how-patreon-got-hacked-publicly-exposed-werkzeug-debugger/

(debug-enabled-python)

πŸͺ› Ruff (0.15.7)

[error] 55-55: Use of debug=True in Flask app detected

(S201)

πŸ€– Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app.py` around lines 54 - 55, The startup currently forces Flask into debug
mode via the hardcoded debug=True in the "__main__" block (app.run), which must
be removed; change the app.run call to read the debug flag from configuration or
environment (e.g. app.config['DEBUG'] or an env var like FLASK_DEBUG) and pass
that value to app.run (or omit the debug argument entirely and ensure config
sets DEBUG), so debug is enabled only when explicitly configured for development
rather than always.

12 changes: 12 additions & 0 deletions frontend/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
const { app, BrowserWindow } = require('electron');

function createWindow() {
const win = new BrowserWindow({
width: 1200,
height: 800,
});

win.loadURL('http://127.0.0.1:5000');
Comment on lines +2 to +9
Copy link

Copilot AI Mar 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BrowserWindow is created without explicit security-related webPreferences. For Electron apps, it's recommended to explicitly set contextIsolation, sandbox, and nodeIntegration (disabled) and to restrict navigation/openExternal behavior to reduce risk if any content is compromised. Please harden the BrowserWindow configuration accordingly.

Suggested change
function createWindow() {
const win = new BrowserWindow({
width: 1200,
height: 800,
});
win.loadURL('http://127.0.0.1:5000');
const { shell } = require('electron');
function createWindow() {
const win = new BrowserWindow({
width: 1200,
height: 800,
webPreferences: {
contextIsolation: true,
nodeIntegration: false,
sandbox: true,
},
});
const appUrl = 'http://127.0.0.1:5000';
win.webContents.on('will-navigate', (event, url) => {
if (!url.startsWith(appUrl)) {
event.preventDefault();
shell.openExternal(url);
}
});
win.webContents.setWindowOpenHandler(({ url }) => {
if (url.startsWith(appUrl)) {
return { action: 'allow' };
}
shell.openExternal(url);
return { action: 'deny' };
});
win.loadURL(appUrl);

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟑 Minor

No error handling if Flask backend is unavailable.

win.loadURL() will show an error page if the Flask server isn't running. Consider adding error handling to provide a better user experience or retry logic.

πŸ”§ Proposed error handling
-  win.loadURL('http://127.0.0.1:5000');
+  win.loadURL('http://127.0.0.1:5000').catch((err) => {
+    console.error('Failed to load backend:', err);
+    // Optionally show a helpful error page or retry
+  });
πŸ“ Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
win.loadURL('http://127.0.0.1:5000');
win.loadURL('http://127.0.0.1:5000').catch((err) => {
console.error('Failed to load backend:', err);
// Optionally show a helpful error page or retry
});
πŸ€– Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/main.js` at line 9, The call to win.loadURL('http://127.0.0.1:5000')
has no handling for a down Flask backend; update the startup to detect load
failures (use win.webContents.on('did-fail-load', ...) and/or the Promise
returned by win.loadURL) and implement fallback/retry behavior: attempt a few
retries with backoff to the same URL, and if still failing load a local error
page (via win.loadFile or serve an inline HTML) that explains the backend is
unreachable and provides a retry button; reference the BrowserWindow instance
variable win, its webContents event 'did-fail-load', and the win.loadURL call
when implementing these changes.

}
Comment on lines +3 to +10
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

πŸ› οΈ Refactor suggestion | 🟠 Major

Add explicit security settings for BrowserWindow.

The BrowserWindow lacks explicit webPreferences security settings. While recent Electron defaults are secure (nodeIntegration: false), explicitly setting security options is a best practice and makes the security posture clear.

πŸ”’ Proposed security hardening
 function createWindow() {
   const win = new BrowserWindow({
     width: 1200,
     height: 800,
+    webPreferences: {
+      nodeIntegration: false,
+      contextIsolation: true,
+    },
   });

   win.loadURL('http://127.0.0.1:5000');
 }
πŸ“ Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
function createWindow() {
const win = new BrowserWindow({
width: 1200,
height: 800,
});
win.loadURL('http://127.0.0.1:5000');
}
function createWindow() {
const win = new BrowserWindow({
width: 1200,
height: 800,
webPreferences: {
nodeIntegration: false,
contextIsolation: true,
},
});
win.loadURL('http://127.0.0.1:5000');
}
πŸ€– Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/main.js` around lines 3 - 10, The BrowserWindow created in
createWindow is missing explicit security webPreferences; update the
BrowserWindow options in createWindow to include secure settings such as
webPreferences: { nodeIntegration: false, contextIsolation: true,
enableRemoteModule: false, sandbox: true, nativeWindowOpen: false, webSecurity:
true, allowRunningInsecureContent: false } and ensure any devtools enablement is
explicit (only enable when needed) before calling
win.loadURL('http://127.0.0.1:5000').


app.whenReady().then(createWindow);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | πŸ”΅ Trivial

Missing macOS app lifecycle handling.

On macOS, apps typically stay active even when all windows are closed. The standard Electron pattern handles window-all-closed and activate events for cross-platform behavior.

🍎 Proposed lifecycle handling
 app.whenReady().then(createWindow);
+
+app.on('window-all-closed', () => {
+  if (process.platform !== 'darwin') {
+    app.quit();
+  }
+});
+
+app.on('activate', () => {
+  if (BrowserWindow.getAllWindows().length === 0) {
+    createWindow();
+  }
+});
πŸ€– Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/main.js` at line 12, The app currently only calls
app.whenReady().then(createWindow) and lacks macOS lifecycle handling; add
standard Electron event handlers for 'window-all-closed' (call app.quit() on
non-darwin platforms) and for 'activate' (recreate the window by calling
createWindow if no BrowserWindow exists) so the createWindow function is used on
activate and the app stays running on macOS when all windows are closed;
reference the existing createWindow and the app.whenReady().then(createWindow)
call to insert the 'window-all-closed' and 'activate' listeners.

Loading
Loading