Skip to content

Commit 908c773

Browse files
Michael Borckclaude
andcommitted
Rework UX: preparation phase, auto-summarise, single-column chat
Replace the two-column chat+sources layout with a cleaner three-phase flow: landing → preparation → chat. - Add preparation phase with live progress steps (Searching, Reading, Summarising, Preparing) so students know what's happening - Auto-summarise sources when content exceeds 20K chars to fit smaller model context windows - Single-column chat with collapsed "Based on N sources" attribution - Remove Sources panel — sources are used for grounding but no longer shown as a noisy sidebar - Remove Full/Summary toggle — handled automatically - Keep paste-your-own-notes on landing page - Add /api/summariseSources endpoint for LLM-based source summarisation - Handle no-search and no-sources gracefully with fallback prompts - Rewrite README to make the case for privacy-first, local-first design Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent e693076 commit 908c773

8 files changed

Lines changed: 572 additions & 317 deletions

File tree

README.md

Lines changed: 76 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -1,158 +1,127 @@
1-
# Study Buddy AI
1+
# Study Buddy
22

33
<!-- BADGES:START -->
44
[![ai-tutor](https://img.shields.io/badge/-ai--tutor-blue?style=flat-square)](https://github.com/topics/ai-tutor) [![css](https://img.shields.io/badge/-css-1572b6?style=flat-square)](https://github.com/topics/css) [![desktop-application](https://img.shields.io/badge/-desktop--application-blue?style=flat-square)](https://github.com/topics/desktop-application) [![electron](https://img.shields.io/badge/-electron-47848f?style=flat-square)](https://github.com/topics/electron) [![javascript](https://img.shields.io/badge/-javascript-f7df1e?style=flat-square)](https://github.com/topics/javascript) [![local-inference](https://img.shields.io/badge/-local--inference-blue?style=flat-square)](https://github.com/topics/local-inference) [![privacy-focused](https://img.shields.io/badge/-privacy--focused-blue?style=flat-square)](https://github.com/topics/privacy-focused) [![typescript](https://img.shields.io/badge/-typescript-3178c6?style=flat-square)](https://github.com/topics/typescript) [![offline-application](https://img.shields.io/badge/-offline--application-blue?style=flat-square)](https://github.com/topics/offline-application) [![edtech](https://img.shields.io/badge/-edtech-4caf50?style=flat-square)](https://github.com/topics/edtech)
55
<!-- BADGES:END -->
66

7-
> 🎓 An open-source AI personal tutor that runs locally on your computer
8-
>
9-
> Based on [Llama Tutor](https://github.com/Nutlope/llamatutor) by [@nutlope](https://github.com/nutlope)
7+
> An open-source AI personal tutor that runs entirely on your computer. Private by design. Bring your own model.
108
119
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
1210
[![Next.js](https://img.shields.io/badge/Next.js-14-black)](https://nextjs.org/)
1311
[![Electron](https://img.shields.io/badge/Electron-Latest-9FEAF9)](https://www.electronjs.org/)
1412

15-
## About
13+
## Why Study Buddy?
1614

17-
Study Buddy is a desktop application that provides personalized AI tutoring without requiring internet access, accounts, or risking API abuse. It's a fork of the excellent Llama Tutor project, enhanced with:
15+
Most AI tutoring tools require you to create an account, hand over your data, and pay a subscription. NotebookLM needs a Google account. ChatGPT needs OpenAI. DeepTutor needs uploads and cloud processing. They're powerful, but they're not private, and they're not yours.
1816

19-
- 🔌 **Provider-agnostic architecture** - Use Ollama (local), OpenAI, Together AI, or others
20-
- 🖥️ **Desktop application** - Runs securely on your computer via Electron
21-
- 🔒 **Privacy-first** - Default local mode means your data never leaves your device
22-
- 💰 **Free to use** - No API costs with local Ollama mode
23-
- 🎯 **Student-focused** - Simple interface designed for learners
17+
Study Buddy takes a different approach:
2418

25-
## Features
19+
**You own the whole stack.** The app runs on your laptop. The AI runs on your laptop (via Ollama). Your questions, your notes, your learning — none of it leaves your machine. There's no account to create, no data to leak, no subscription to cancel.
2620

27-
- 📚 Generate comprehensive tutorials on any topic
28-
- 🔍 Smart search integration for enriched content
29-
- 💬 Interactive chat for follow-up questions
30-
- 🎨 Clean, intuitive interface
31-
- 📱 Works offline after initial setup
32-
- ⚡ Fast local inference with Ollama
21+
**It does one thing well.** Type a topic, get a grounded tutor. Study Buddy searches the web for sources, reads them, and uses that content to teach you — reducing hallucinations and keeping answers factual. It's a focused conversation, not a research platform. When the session ends, you take away what you learned. Like a real tutor.
3322

34-
## Installation
23+
**It's designed for students, not power users.** The interface uses plain language (not developer jargon), generous whitespace, and a calm visual style built specifically for university students — including ESL learners who are already spending mental energy working in a second language. Settings say "Secret key" not "API Key", "AI Brain" not "Model".
3524

36-
### Prerequisites
25+
**Bring your own key, or don't.** Works with Ollama locally (free, no key needed) or any cloud provider you prefer — OpenAI, Anthropic, Google, Groq, Together AI. You choose where your data goes.
3726

38-
- Node.js 18+ installed
39-
- (Optional) [Ollama](https://ollama.com/) for local AI - recommended for students
27+
## How it works
4028

41-
### Quick Start
29+
Study Buddy is a simple grounded tutor — a lightweight RAG (retrieval-augmented generation) pipeline that runs fresh for each session:
4230

43-
1. **Download the latest release** from the [Releases page](https://github.com/michael-borck/study-buddy/releases)
44-
- Windows: `StudyBuddy-Setup-x.x.x.exe`
45-
- macOS: `StudyBuddy-x.x.x.dmg`
46-
- Linux: `StudyBuddy-x.x.x.AppImage`
31+
1. **You type a topic** and choose an education level (Elementary through Graduate)
32+
2. **Study Buddy searches the web** for relevant sources (DuckDuckGo by default — free, no key needed)
33+
3. **It reads those pages** and extracts the content
34+
4. **If the content is too large** for your model's context window, it auto-summarises the sources
35+
5. **The AI teaches you** from that grounded material at your chosen level, with an interactive quiz-style conversation
36+
6. **You ask follow-up questions** and the tutor responds in context
4737

48-
2. **Install and run** - that's it! Study Buddy will use Ollama if installed, or prompt for API configuration.
38+
You can also paste your own notes (lecture slides, textbook excerpts) and the tutor will teach from those alongside the web sources.
4939

50-
### Development Setup
40+
There's no persistent knowledge base, no embeddings, no vector store. Each session starts fresh. The simplicity is deliberate — it keeps the app fast, private, and easy to understand.
5141

52-
```bash
53-
# Clone the repository
54-
git clone https://github.com/michael-borck/study-buddy.git
55-
cd study-buddy
42+
## What it's not
5643

57-
# Install dependencies
58-
npm install
44+
Study Buddy is not trying to be NotebookLM, DeepTutor, or a general-purpose research assistant. It doesn't do multi-document analysis, audio generation, collaborative notebooks, or knowledge graphs. Those tools are excellent at what they do, but they require accounts, cloud processing, and complexity.
5945

60-
# Run in development mode
61-
npm run electron-dev
46+
Study Buddy is for a student who wants to open an app, type "photosynthesis", and have a private, grounded conversation about it. Then close the app and get back to studying.
6247

63-
# Build for production
64-
npm run electron-pack
65-
```
66-
67-
## Configuration
68-
69-
### AI Providers
48+
## Installation
7049

71-
Study Buddy supports multiple AI providers. Configure in Settings or via environment variables:
50+
### Download
7251

73-
#### Local (Recommended for Students)
74-
```env
75-
AI_PROVIDER=ollama
76-
# No API key needed! Just install Ollama
77-
```
52+
Grab the latest release from the [Releases page](https://github.com/michael-borck/study-buddy/releases):
7853

79-
#### OpenAI
80-
```env
81-
AI_PROVIDER=openai
82-
OPENAI_API_KEY=your_api_key_here
83-
```
84-
85-
#### Together AI
86-
```env
87-
AI_PROVIDER=together
88-
TOGETHER_API_KEY=your_api_key_here
89-
```
54+
- **Windows:** `StudyBuddy-Setup-x.x.x.exe`
55+
- **macOS:** `StudyBuddy-x.x.x.dmg`
56+
- **Linux:** `StudyBuddy-x.x.x.AppImage`
9057

91-
### Adding New Providers
58+
### Set up a local AI (recommended)
9259

93-
1. Create a new provider in `utils/providers/`
94-
2. Implement the `LLMProvider` interface
95-
3. Add to the provider factory in `utils/provider-factory.ts`
60+
1. Install [Ollama](https://ollama.com/)
61+
2. Pull a model: `ollama pull llama3.1:8b`
62+
3. Open Study Buddy — it connects to Ollama automatically
9663

97-
## Usage
64+
That's it. No account, no API key, no internet required after the model is downloaded.
9865

99-
1. **Launch Study Buddy** from your Applications/Programs
100-
2. **Enter a topic** you want to learn about
101-
3. **Click "Generate"** to create your personalized tutorial
102-
4. **Ask follow-up questions** in the chat interface
103-
5. **Save or export** your sessions for later review
66+
### Or use a cloud provider
10467

105-
## For Educators
68+
Open Settings and choose your provider (OpenAI, Anthropic, Google, Groq, Together AI). Add your secret key. Study Buddy works with any provider, but your questions will leave your machine.
10669

107-
Study Buddy can be deployed institution-wide:
70+
## Development
10871

109-
- **Self-hosted option**: Deploy the web version on your school's servers
110-
- **Managed API keys**: Configure with your institution's API keys
111-
- **Custom models**: Use your preferred AI models
112-
- **Usage analytics**: Monitor usage with built-in observability
72+
```bash
73+
git clone https://github.com/michael-borck/study-buddy.git
74+
cd study-buddy
75+
npm install
76+
npm run electron-dev
77+
```
11378

114-
See our [Educator's Guide](docs/EDUCATORS.md) for deployment instructions.
79+
### Project structure
11580

116-
## Technical Stack
81+
```
82+
study-buddy/
83+
├── app/ # Next.js App Router
84+
│ ├── api/ # API routes (chat, search, settings)
85+
│ ├── settings/ # Settings page
86+
│ └── page.tsx # Main tutor interface
87+
├── components/ # React components
88+
├── utils/
89+
│ └── providers/ # LLM provider integrations
90+
├── main.js # Electron main process
91+
└── docs/ # Documentation
92+
```
11793

118-
- **Frontend**: Next.js 14, React, TypeScript, Tailwind CSS
119-
- **Desktop**: Electron
120-
- **AI Integration**: Configurable providers (Ollama, OpenAI, Together AI)
121-
- **Search**: Tavily API for enriched content
122-
- **Analytics**: Helicone (optional)
123-
- **Database**: Supabase (optional, for web deployment)
94+
### Technical stack
12495

125-
## Contributing
96+
- **Frontend:** Next.js 14, React, TypeScript, Tailwind CSS
97+
- **Desktop:** Electron
98+
- **Design:** Studio Calm (shared with [Talk Buddy](https://github.com/michael-borck/talk-buddy))
99+
- **AI:** Ollama, OpenAI, Anthropic, Google, Groq, Together AI
100+
- **Search:** DuckDuckGo (default), Brave, Bing, Serper, SearXNG
126101

127-
We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) for details.
102+
### Build for distribution
128103

129104
```bash
130-
# Fork the repo, then:
131-
git clone https://github.com/michael-borck/study-buddy.git
132-
cd study-buddy
133-
npm install
134-
npm run dev
105+
npm run build
106+
npm run electron-pack
135107
```
136108

137-
## Roadmap
109+
## The Buddy suite
138110

139-
- [ ] Additional AI provider support (Anthropic, Cohere, local GGUF)
140-
- [ ] Collaborative study sessions
141-
- [ ] PDF/Document upload and analysis
142-
- [ ] Study progress tracking
143-
- [ ] Flashcard generation
144-
- [ ] Mobile app (React Native)
111+
Study Buddy is part of a family of apps for university students:
145112

146-
## Credits
147-
148-
Study Buddy is based on [Llama Tutor](https://github.com/Nutlope/llamatutor) by Hassan El Mghari ([@nutlope](https://github.com/nutlope)). The original project showcased the power of AI in education, and we're building on that foundation to make it accessible to all students.
113+
| App | Purpose | Accent colour |
114+
|-----|---------|---------------|
115+
| [Talk Buddy](https://github.com/michael-borck/talk-buddy) | Speech practice for high-stakes scenarios | Eucalyptus sage |
116+
| **Study Buddy** | AI personal tutor | Dusty bluebell |
117+
| Career Compass (planned) | Career guidance and interview prep | Warm ochre |
149118

150-
See our [ACKNOWLEDGMENTS.md](ACKNOWLEDGMENTS.md) for a comprehensive list of all the amazing open source projects that make Study Buddy possible.
119+
All three share the same design system ([Studio Calm](https://github.com/michael-borck/talk-buddy/blob/main/docs/design/studio-calm.md)) — same font, same warm palette, same calm interface. The only difference is the accent colour. A student who uses one recognises the others instantly.
151120

152-
## License
121+
## Credits
153122

154-
MIT License - see [LICENSE](LICENSE) file for details.
123+
Study Buddy is based on [Llama Tutor](https://github.com/Nutlope/llamatutor) by Hassan El Mghari ([@nutlope](https://github.com/nutlope)). The original project demonstrated how simple and effective an AI tutor could be. Study Buddy builds on that foundation with local-first privacy, provider flexibility, and a design system built for the students who need it most.
155124

156-
---
125+
## Licence
157126

158-
**Note**: This is an independent fork and is not officially associated with the original Llama Tutor project.
127+
MIT — see [LICENSE](LICENSE).

app/api/summariseSources/route.ts

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
import { createProvider, LLMStreamPayload } from "@/utils/providers";
2+
import { getSettings } from "@/utils/settings";
3+
4+
export const maxDuration = 60;
5+
6+
async function collectStreamText(stream: ReadableStream): Promise<string> {
7+
const reader = stream.getReader();
8+
const decoder = new TextDecoder();
9+
let text = "";
10+
11+
try {
12+
while (true) {
13+
const { done, value } = await reader.read();
14+
if (done) break;
15+
const chunk = decoder.decode(value);
16+
const lines = chunk.split("\n");
17+
for (const line of lines) {
18+
if (line.startsWith("data: ")) {
19+
try {
20+
const data = JSON.parse(line.slice(6));
21+
text += data.text || "";
22+
} catch {
23+
// Skip malformed lines
24+
}
25+
}
26+
}
27+
}
28+
} finally {
29+
reader.releaseLock();
30+
}
31+
32+
return text;
33+
}
34+
35+
export async function POST(request: Request) {
36+
const { sources } = await request.json();
37+
38+
const settingsHeader = request.headers.get("X-StudyBuddy-Settings");
39+
if (settingsHeader) {
40+
try {
41+
const frontendSettings = JSON.parse(settingsHeader);
42+
const { updateSettings } = await import("@/utils/settings");
43+
updateSettings(frontendSettings);
44+
} catch (e) {
45+
console.warn("Failed to parse frontend settings:", e);
46+
}
47+
}
48+
49+
const settings = getSettings();
50+
const provider = createProvider();
51+
52+
const summaries = await Promise.all(
53+
sources.map(async (source: { name: string; url: string; fullContent: string }) => {
54+
if (
55+
!source.fullContent ||
56+
source.fullContent === "not available" ||
57+
source.fullContent === "Nothing found"
58+
) {
59+
return source;
60+
}
61+
62+
try {
63+
const payload: LLMStreamPayload = {
64+
model: settings.llmModel,
65+
messages: [
66+
{
67+
role: "system",
68+
content:
69+
"You are a helpful assistant. Summarise the following web page content in 200–300 words, keeping the key facts, concepts, and any definitions. Return only the summary, no preamble.",
70+
},
71+
{
72+
role: "user",
73+
content: source.fullContent.substring(0, 15000),
74+
},
75+
],
76+
stream: true,
77+
temperature: 0.3,
78+
};
79+
80+
const stream = await provider.stream(payload);
81+
const summary = await collectStreamText(stream);
82+
83+
return {
84+
...source,
85+
fullContent: summary || source.fullContent,
86+
};
87+
} catch (e) {
88+
console.error(`Error summarising ${source.name}:`, e);
89+
return source;
90+
}
91+
}),
92+
);
93+
94+
return Response.json(summaries);
95+
}

0 commit comments

Comments
 (0)