Skip to content

Latest commit

Β 

History

9 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

🧠 ThinkStack

A local-first, RAG-powered AI chat platform β€” chat with your documents using a private LLM.

Next.js TypeScript Firebase ChromaDB Ollama License: MIT


πŸ€” What Problem Does ThinkStack Solve?

Most AI chat tools send your documents to third-party servers, making them unsuitable for private or sensitive data. ThinkStack runs entirely on your machine β€” your documents never leave your environment.

Beyond privacy, generic AI chat lacks context memory. ThinkStack organises your work into Projects, each with its own persistent knowledge base built from the documents you upload. When you ask a question, it doesn't just query an LLM blindly β€” it first retrieves the most relevant chunks from your documents and past conversations, then feeds that context to the model. This is Retrieval-Augmented Generation (RAG) in action.


✨ What ThinkStack Does

Feature Description
πŸ“ Project-based Knowledge Organise your work into projects. Each project has its own isolated document store and chat history.
πŸ“„ Document Ingestion Upload PDFs and text files to a project. They are parsed, chunked, embedded, and stored in a local vector database.
πŸ” RAG-Powered Chat Every query retrieves the most semantically relevant document chunks before the LLM responds β€” answers are grounded in your actual files.
🧡 Persistent Chat Memory Past conversations are also embedded and retrieved, giving the AI long-term context within a project.
πŸ”’ Fully Local LLM Uses Ollama to run language and embedding models on your own machine. No data leaves your environment.
πŸ” User Authentication Google OAuth via Firebase Authentication with secure session management.
πŸ“Š Streaming Responses LLM responses stream token-by-token to the UI for a real-time chat feel.
🎯 Career Coach Mode Detects CV/resume-related queries and switches to a specialised Career Coach prompt with structured output.

πŸ—οΈ Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                     Browser (User)                      β”‚
β”‚              Next.js App (React + TypeScript)           β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
               β”‚  API Routes (Next.js Server)
               β”‚
       β”Œβ”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”
       β”‚   RAG Pipeline  β”‚
       β”‚                 β”‚
       β”‚  1. Embed Query │──────────────▢ Ollama
       β”‚  2. Retrieve    │──────────────▢ ChromaDB (Vector Store)
       β”‚  3. Build Promptβ”‚
       β”‚  4. Stream LLM  │──────────────▢ Ollama (LLM)
       β”‚  5. Store Memory│──────────────▢ ChromaDB + Firestore
       β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
               β”‚
       β”Œβ”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”
       β”‚    Firebase     β”‚
       β”‚  Auth, Firestoreβ”‚
       β”‚  (Cloud)        β”‚
       β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

RAG Pipeline (step by step)

  1. Ingestion β€” When you upload a file, it is parsed (pdf-parse), split into overlapping chunks, embedded via nomic-embed-text on Ollama, and stored in ChromaDB tagged with project and file metadata.

  2. Inference β€” When you send a message:

    • The query is embedded using the same model.
    • ChromaDB performs a nearest-neighbour search to retrieve the top-8 relevant document chunks (project memory) and top-5 relevant past conversation snippets (chat memory).
    • A structured prompt is assembled with both memory types and recent chat history.
    • The prompt is streamed to the Ollama LLM.
    • The full response is stored back into ChromaDB as a new chat memory entry.

πŸ› οΈ Tech Stack

Layer Technology
Frontend Next.js 16, React 19, TypeScript, Tailwind CSS, shadcn/ui
State Management Zustand
Backend Next.js API Routes (serverless functions)
Auth Firebase Authentication (Google OAuth)
Database Firebase Firestore (projects, chats, file metadata)
Vector Store ChromaDB (local Docker container)
LLM Ollama (local β€” any compatible model)
Embeddings Ollama (nomic-embed-text)
File Parsing pdf-parse for PDFs, plain text support
Markdown Rendering react-markdown + rehype-raw

πŸš€ Getting Started

Prerequisites

Tool Version Purpose
Node.js 18+ Run the Next.js app
Docker Latest Run ChromaDB
Ollama Latest Run the LLM and embedding model locally
Firebase project β€” Auth and Firestore

1. Clone the Repository

git clone https://github.com/<your-username>/thinkstack.git
cd thinkstack
npm install

2. Start ChromaDB

docker run -p 8000:8000 chromadb/chroma

3. Start Ollama and Pull Models

# Pull the embedding model
ollama pull nomic-embed-text

# Pull a chat model (example)
ollama pull qwen2.5-coder:7b

4. Configure Environment

Create a .env.local file at the project root and fill in your Firebase credentials:

# Firebase
NEXT_PUBLIC_FIREBASE_API_KEY=your-key
NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN=your-project.firebaseapp.com
NEXT_PUBLIC_FIREBASE_PROJECT_ID=your-project-id
NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET=your-project.firebasestorage.app
NEXT_PUBLIC_FIREBASE_APP_ID=your-app-id
NEXT_PUBLIC_FIREBASE_DATABASE_URL=https://your-project-default-rtdb.region.firebasedatabase.app

# Services
OLLAMA_URL=http://localhost:11434
CHROMA_URL=http://localhost:8000

5. Run the App

npm run dev

Open http://localhost:3000.


πŸ“‚ Project Structure

thinkstack/
β”œβ”€β”€ app/
β”‚   β”œβ”€β”€ (auth)/                 # Login and Register pages
β”‚   β”‚   β”œβ”€β”€ login/
β”‚   β”‚   └── register/
β”‚   β”œβ”€β”€ api/                    # Next.js API Routes
β”‚   β”‚   β”œβ”€β”€ chat/               # RAG pipeline + Ollama streaming
β”‚   β”‚   β”œβ”€β”€ project_files/      # File upload, chunking, embedding, storage
β”‚   β”‚   β”œβ”€β”€ parse-file/         # File text extraction
β”‚   β”‚   └── upload/             # Firebase Storage upload
β”‚   β”œβ”€β”€ components/
β”‚   β”‚   β”œβ”€β”€ chat/               # Chat interface with streaming support
β”‚   β”‚   β”œβ”€β”€ layout/             # Dashboard layout, sidebar, header
β”‚   β”‚   β”œβ”€β”€ project/            # Project CRUD, file management, overview
β”‚   β”‚   └── prompt/             # Custom input, prompt helpers
β”‚   β”œβ”€β”€ dashboard/
β”‚   β”‚   └── [projectId]/
β”‚   β”‚       └── [chat]/         # Dynamic chat route per project/session
β”‚   β”œβ”€β”€ hooks/
β”‚   β”‚   └── useChat.ts          # Chat state + streaming logic
β”‚   β”œβ”€β”€ lib/
β”‚   β”‚   β”œβ”€β”€ chroma/             # ChromaDB client
β”‚   β”‚   β”œβ”€β”€ embeddings/         # Ollama embedding functions
β”‚   β”‚   β”œβ”€β”€ firebase/           # Firestore services (projects, chats, files)
β”‚   β”‚   β”œβ”€β”€ utils/
β”‚   β”‚   β”‚   └── chunkText.ts    # Sliding-window text chunker
β”‚   β”‚   β”œβ”€β”€ file-parser.ts      # PDF + text parsing
β”‚   β”‚   β”œβ”€β”€ prompt.ts           # Prompt builder (RAG + chat history)
β”‚   β”‚   └── rag.ts              # Vector retrieval and context assembly
β”‚   └── services/
β”‚       └── chat.service.ts     # Chat message persistence + memory storage
β”œβ”€β”€ components/
β”‚   └── ui/                     # shadcn/ui base components
β”œβ”€β”€ store/
β”‚   └── store.ts                # Zustand global store
β”œβ”€β”€ types/
β”‚   └── memory.ts               # TypeScript types for memory/chat
β”œβ”€β”€ config/
β”‚   └── env.ts                  # Environment variable helpers
└── middleware.ts               # Auth route protection

βš™οΈ Key Configuration

Chunking Strategy

Text is split using a sliding-window chunker in app/lib/utils/chunkText.ts:

  • Chunk size: 1000 characters (default)
  • Overlap: 200 characters

Overlap ensures that sentences near chunk boundaries appear in adjacent chunks, preventing context loss during retrieval.

Retrieval Settings

Configured in app/lib/rag.ts:

  • Project memory (document chunks): top 8 results
  • Chat memory (past conversations): top 5 results
  • Ranked by cosine distance β€” lower is better.

Changing the LLM Model

Update the model name in app/api/chat/route.ts:

model: "qwen2.5-coder:7b",  // replace with any model available via `ollama list`

πŸ”Œ API Reference

Method Endpoint Description
POST /api/chat Send a message; returns a streaming RAG response
POST /api/project_files Upload and index a file into a project
DELETE /api/project_files?fileId=&projectId= Remove a file from Firestore and ChromaDB
POST /api/parse-file Parse a file and return raw text
POST /api/upload Upload a file to Firebase Storage
GET /api/debug-chroma Debug endpoint to inspect ChromaDB collections

🐳 Docker (Coming Soon)

A full Docker Compose setup is in progress that will containerise the Next.js app alongside ChromaDB and Ollama, eliminating the need for any local native installs. See analysis_results.md for the planned architecture.


πŸ—ΊοΈ Roadmap

  • Full Docker Compose setup (Next.js + ChromaDB + Ollama)
  • Support for more file types (DOCX, TXT, Markdown)
  • Configurable chunking strategy per project
  • Model selection UI per project
  • Export chat history

🀝 Contributing

Pull requests are welcome. For major changes, please open an issue first to discuss what you'd like to change.

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/your-feature)
  3. Commit your changes (git commit -m 'Add your feature')
  4. Push to the branch (git push origin feature/your-feature)
  5. Open a Pull Request

πŸ“„ License

This project is licensed under the MIT License.


Built for developers who want AI that respects their privacy. πŸ”’

About

An AI Assistant for Learners πŸ˜ŠπŸš€

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages