Warning
This is the old development repository and is now archived.
The final, standalone, production-ready plugin is here:
The new repo has:
- ✅ Self-contained
.kpz— upload one file, no server needed - ✅ Clean
dist/+src/structure - ✅ Voice input, book cover scanning, Groq/Gemini/OpenAI
- ✅ Full setup guide and GitHub Release with direct download
- ✅ Koha 22.11+ compatible, no Python backend required
An intelligent, conversational search assistant for the Koha Library Management System
Replace your library's traditional search forms with a modern, conversational AI assistant that understands natural language — built natively for Koha.
🚀 Quick Start · 📖 API Reference · 🔌 Koha Integration · 🗺️ Roadmap
Koha OPAC AI Assistant is a production-ready plugin that embeds a floating AI-powered chatbot directly into the Koha OPAC interface. Rather than navigating traditional search forms, patrons can simply type natural language queries and receive instant, rich book results — complete with cover images, availability status, branch location, and call numbers.
The plugin consists of two tightly coupled components:
- FastAPI Backend — Intent detection, query processing, and direct MariaDB integration with Koha's database schema
- Vanilla JS Frontend — A self-contained floating chatbot widget, injected into Koha's OPAC theme via a single
<script>block
The system is fully modular, zero-dependency on the Koha Perl stack for search, and ships with a Koha Plugin Package (.kpz) for one-click installation.
| Search Type | Example Query | Intent |
|---|---|---|
| General / Full-text | Python books |
GENERAL_SEARCH |
| By Title | Find Clean Code |
TITLE_SEARCH |
| By Author | Books by Eric Matthes |
AUTHOR_SEARCH |
| By ISBN | 9781492056355 |
ISBN_SEARCH |
| By Publisher | Publisher O'Reilly |
PUBLISHER_SEARCH |
| By Barcode | Barcode 0001234 |
BARCODE_SEARCH |
| By Call Number | Call number 005.133 |
CALLNUMBER_SEARCH |
| By Branch | Books in Central Library |
BRANCH_SEARCH |
| By Language | Books in French |
LANGUAGE_SEARCH |
| By Year | Published in 2023 |
YEAR_SEARCH |
| Recommendations | Recommend books similar to Django |
RECOMMEND |
| By Subject / Topic | Books about history, Science fiction genre |
SUBJECT_SEARCH |
| Advanced Filters | Python books published in 2023, Books by Matthes in French |
FILTER_SEARCH |
| Fuzzy Search | Pyton books, Erroc Matthes → corrected automatically |
(fallback) |
| Query | Intent |
|---|---|
Library timings, What are opening hours? |
TIMINGS |
Membership, How do I join?, Register |
MEMBERSHIP |
- Floating chatbot widget — Accessible via a fixed-position toggle button, non-intrusive
- Skeleton loading — Animated placeholders while backend fetches results
- Live autocomplete suggestions — Debounced suggestions after 3 characters via
GET /api/suggestions - Quick-action buttons — Clickable chips in the welcome message for common queries
- Keyboard accessible — Full Tab/Shift+Tab focus trapping,
Escapeto close,Enterto send - Book cover integration — Fetches covers from Open Library Covers API by ISBN with graceful fallback
- Availability badges — Color-coded
Available/Checked Outstatus per title - Copy counts & branch — Shows
X of Y copiesand branch location inline - Rate limiting — 20 requests per 60-second window per IP with a friendly in-chat error
- Zero
console.login production — All debug output is gated behindCONFIG.DEBUG
┌─────────────────────────────────────────────────────────────────────┐
│ Browser (Patron) │
│ │
│ ┌──────────────────────────────────────────────────────────────┐ │
│ │ Koha OPAC (Apache) │ │
│ │ │ │
│ │ opac-bottom.inc │ │
│ │ └── CSS: variables → theme → chatbot → components → │ │
│ │ animations → responsive │ │
│ │ └── JS: config → knowledgeBase → faq → intentEngine → │ │
│ │ utils → api → chatController → ui → app │ │
│ │ │ │ │
│ │ Local FAQ / Intent │ │
│ │ (answered client-side) │ │
│ └────────────────────────────┬─────────────────────────────────┘ │
│ │ POST /api/chat │
└────────────────────────────────┼────────────────────────────────────┘
│
┌────────────▼────────────┐
│ FastAPI Backend │
│ │
│ main.py │
│ ├── Rate Limiter │
│ ├── intent_service │◄── Regex + keyword NLP
│ ├── koha_service │◄── Parameterized SQL
│ └── formatter_service │◄── HTML card renderer
└────────────┬────────────┘
│
┌────────────▼────────────┐
│ MariaDB / Koha DB │
│ │
│ biblio │
│ biblioitems │
│ items │
│ biblio_metadata (MARC) │
└─────────────────────────┘
User Message
│
▼
[Frontend: intentEngine.js] ──► Local FAQ / Knowledge Base answer (instant)
│ (no backend call)
│ (if not local)
▼
[Backend: intent_service.py]
├── TIMINGS / MEMBERSHIP ──► Static HTML response
├── ISBN regex \d{10,13} ──► ISBN_SEARCH
├── Year regex (19|20)\d{2} ──► YEAR_SEARCH
├── Keyword: "by", "author" ──► AUTHOR_SEARCH
├── Keyword: "publisher" ──► PUBLISHER_SEARCH
├── Keyword: "branch" ──► BRANCH_SEARCH
├── Keyword: "recommend" ──► RECOMMEND → AUTHOR_SEARCH fallback
└── Default ──► TITLE_SEARCH / GENERAL_SEARCH
│
▼
[koha_service.py] ──► Optimized SQL against Koha MariaDB
│
▼
[formatter_service.py] ──► HTML book cards with cover, status, branch
koha-opac-ai-plugin/
│
├── backend/ # FastAPI Python backend
│ ├── requirements.txt # Pinned dependencies
│ └── app/
│ ├── main.py # App entry, routes, rate limiter
│ ├── api/
│ │ └── chat.py # /api/chat route handler
│ ├── core/
│ │ ├── config.py # Settings via python-dotenv
│ │ └── database.py # PyMySQL connection factory
│ ├── intents/
│ │ └── engine.py # Knowledge-base intent matcher
│ ├── knowledge/ # Local knowledge base definitions
│ ├── llm/ # LLM integration (planned)
│ ├── models/ # Pydantic request/response models
│ ├── rag/ # RAG pipeline (planned)
│ ├── services/
│ │ ├── database.py # DB query helpers
│ │ ├── formatter_service.py# HTML book card renderer
│ │ ├── intent_service.py # NLP intent + keyword extractor
│ │ └── koha_service.py # All Koha DB search functions
│ └── utils/ # Shared utility helpers
│
├── frontend/ # Vanilla JS + CSS chatbot widget
│ ├── css/
│ │ ├── variables.css # CSS custom properties / design tokens
│ │ ├── theme.css # Color theme
│ │ ├── chatbot.css # Core chatbot shell styles
│ │ ├── components.css # Book cards, badges, skeleton, inputs
│ │ ├── animations.css # Keyframe animations
│ │ └── responsive.css # Mobile breakpoints
│ ├── js/
│ │ ├── config.js # Runtime config (API URL, debug flag)
│ │ ├── knowledgeBase.js # Local knowledge base
│ │ ├── faq.js # FAQ definitions
│ │ ├── intentEngine.js # Client-side intent detection
│ │ ├── utils.js # debounce, escapeHTML, sleep
│ │ ├── api.js # fetch wrappers for backend
│ │ ├── chatController.js # Message send/receive orchestration
│ │ ├── ui.js # DOM builder: chat shell, skeletons
│ │ └── app.js # Bootstrap, event listeners, observers
│ └── assets/ # Static assets (logo, icons)
│
├── Koha/
│ └── Plugin/
│ └── OPACChatBot.pm # Koha Plugin Package entry point (Perl)
│
├── docs/
│ ├── API_REFERENCE.md # REST endpoint reference
│ ├── ARCHITECTURE.md # System architecture
│ ├── INSTALL.md # Detailed installation guide
│ ├── KOHA_INTEGRATION.md # opac-bottom.inc injection guide
│ ├── Copy_Plugin_Assets.md # Manual asset copy commands
│ └── koha_api.json # Full Koha REST API spec (OpenAPI)
│
├── scripts/
│ ├── deploy.sh # One-command deploy (copy assets + restart)
│ ├── install.sh # Initial environment setup
│ ├── run_backend.sh # Start uvicorn dev server
│ ├── run_frontend.sh # Serve frontend locally
│ └── backup.sh # Backup plugin files
│
├── tests/
│ ├── test_api.py # API endpoint tests
│ ├── test_database.py # Database layer tests
│ ├── test_intents.py # Intent detection tests
│ └── test_search.py # Search function tests
│
├── KohaOPACAIAssistant.kpz # Koha Plugin Package (installable)
├── OPAC-AI-Assistant.kpz # Alternative plugin package
├── metadata.json # Plugin metadata (name, version, author)
├── CHANGELOG.md # Version history
└── README.md # This file
| Package | Version | Purpose |
|---|---|---|
| Python | 3.11 | Runtime |
| FastAPI | 0.139.0 | Web framework, OpenAPI, async routing |
| Uvicorn | 0.50.0 | ASGI server |
| PyMySQL | 1.2.0 | MariaDB / MySQL driver |
| Pydantic | 2.13.4 | Request/response validation |
| python-dotenv | 1.2.2 | Environment variable management |
| Starlette | 1.3.1 | ASGI toolkit (FastAPI core) |
| Technology | Purpose |
|---|---|
| Vanilla JavaScript (ES6+) | Chatbot logic, DOM management |
| CSS Custom Properties | Design token system |
| CSS Keyframe Animations | Skeleton loaders, transitions |
| Open Library Covers API | Book cover images by ISBN |
| Component | Technology |
|---|---|
| Web Server | Apache (with Koha Plack) |
| Database | MariaDB (Koha's existing instance) |
| OS | Debian 12 / Ubuntu 24.04 LTS |
| Plugin System | Koha Plugin Framework (Koha::Plugins::Base) |
| Component | Supported Versions |
|---|---|
| Koha | 26.05+ (minimum), no maximum |
| Debian | 12 (Bookworm) |
| Ubuntu | 24.04 LTS |
| MariaDB | 10.x, 11.x |
| Apache | 2.4+ |
| Python | 3.11 |
| Browsers | Chrome, Firefox, Edge, Safari |
- Koha ILS installed and running
- Python 3.11 installed on the server
- Access to the Koha MariaDB database
sudoaccess for copying assets to the Koha theme directory
git clone https://github.com/justatech-sleepy/koha-opac-ai-plugin.git
cd koha-opac-ai-plugincd backend
# Create and activate a virtual environment
python -m venv .venv
source .venv/bin/activate # Linux / macOS
# .venv\Scripts\activate # Windows
# Install pinned dependencies
pip install -r requirements.txtCreate the environment file:
cp backend/.env.example backend/.envEdit backend/.env:
# Application
APP_NAME=Koha OPAC AI Assistant
APP_VERSION=1.0.1
DEBUG=False
# Koha
KOHA_URL=http://localhost:8080
# Database (Koha MariaDB credentials)
DB_HOST=localhost
DB_PORT=3306
DB_NAME=koha_library
DB_USER=koha_library
DB_PASSWORD=your_secure_password_hereSecurity Note: Never commit
.envto version control. It is already listed in.gitignore.
# Development
uvicorn app.main:app --reload --host 0.0.0.0 --port 8000
# Production (recommended)
uvicorn app.main:app --host 0.0.0.0 --port 8000 --workers 2Or use the provided script:
bash scripts/run_backend.shVerify the backend is healthy:
curl http://localhost:8000/health
# {"status":"healthy"}Copy CSS and JavaScript files into the Koha OPAC theme directory:
sudo cp frontend/css/*.css \
/usr/share/koha/opac/htdocs/opac-tmpl/bootstrap/css/
sudo cp frontend/js/*.js \
/usr/share/koha/opac/htdocs/opac-tmpl/bootstrap/js/
sudo cp frontend/assets/logo.svg \
/usr/share/koha/opac/htdocs/opac-tmpl/bootstrap/Or use the automated deploy script:
bash scripts/deploy.shThe deploy script will copy assets, restart Apache, and restart Koha Plack automatically.
Edit the Koha OPAC bottom include file:
sudo nano /usr/share/koha/opac/htdocs/opac-tmpl/bootstrap/en/includes/opac-bottom.incAdd the following before the closing </body> tag:
<!-- Koha OPAC AI Assistant -->
<link rel="stylesheet" href="/opac-tmpl/bootstrap/css/variables.css">
<link rel="stylesheet" href="/opac-tmpl/bootstrap/css/theme.css">
<link rel="stylesheet" href="/opac-tmpl/bootstrap/css/chatbot.css">
<link rel="stylesheet" href="/opac-tmpl/bootstrap/css/components.css">
<link rel="stylesheet" href="/opac-tmpl/bootstrap/css/animations.css">
<link rel="stylesheet" href="/opac-tmpl/bootstrap/css/responsive.css">
<script src="/opac-tmpl/bootstrap/js/config.js"></script>
<script src="/opac-tmpl/bootstrap/js/knowledgeBase.js"></script>
<script src="/opac-tmpl/bootstrap/js/faq.js"></script>
<script src="/opac-tmpl/bootstrap/js/intentEngine.js"></script>
<script src="/opac-tmpl/bootstrap/js/utils.js"></script>
<script src="/opac-tmpl/bootstrap/js/api.js"></script>
<script src="/opac-tmpl/bootstrap/js/chatController.js"></script>
<script src="/opac-tmpl/bootstrap/js/ui.js"></script>
<script src="/opac-tmpl/bootstrap/js/app.js"></script>
<!-- End Koha OPAC AI Assistant -->Then restart services:
sudo systemctl restart apache2
sudo koha-plack --restart library # replace 'library' with your instance name- Log in to the Koha staff interface
- Go to Administration → Koha plugins
- Click Upload plugin
- Upload
KohaOPACAIAssistant.kpz - Enable the plugin
Update frontend/js/config.js to point to your backend:
// config.js
window.KohaChatPlugin.CONFIG = {
API_URL: "http://your-server:8000", // FastAPI backend URL
DEBUG: false, // Set true for development
TYPING_DELAY: 400, // Simulated typing delay (ms)
WELCOME_MESSAGE: "Hello! How can I help you find a book today?"
};Default: 20 requests per 60 seconds per IP address. Adjust in backend/app/main.py:
RATE_LIMIT_WINDOW = 60 # seconds
RATE_LIMIT_MAX_REQUESTS = 20 # max requests per windowBase URL: http://your-server:8000
GET /health{ "status": "healthy" }POST /api/chat
Content-Type: application/json
{ "message": "Find Python books" }Response:
{
"response": "<h3>Search Results (5)</h3><div class='books-container'>..."
}Returns rendered HTML book cards directly for injection into the chat window.
Rate limited: 20 requests / 60 seconds per IP.
GET /api/suggestions?q=pyt{
"suggestions": ["Python Crash Course", "Python for Data Analysis"]
}Minimum query length: 3 characters. Returns up to 7 suggestions by title match.
All errors return HTTP 200 with a user-friendly HTML error card (for seamless chat rendering):
| Condition | Message |
|---|---|
| Rate limit exceeded | Slow Down — You are searching too fast. |
| Database unreachable | Service Unavailable — The catalog is under maintenance. |
| No results | No books found — Try another keyword. |
See the full API specification at docs/API_REFERENCE.md.
Type any of these directly into the chat window:
# Title searches
Find Python books
Show me books about Artificial Intelligence
Clean Code
# Author searches
Books by Eric Matthes
Written by Robert C. Martin
# ISBN lookup
9781492056355
# Publisher search
Publisher O'Reilly
# Branch / location
Books in Central Library
# Language
Books in French
# Publication year
Published in 2023
Books from 2020
# Recommendations
Recommend books similar to Django
# Library information
Library timings
What are your opening hours?
Membership
How do I register?
- Database credentials are loaded from
.envviapython-dotenvand never hardcoded - SQL injection prevention — All queries use PyMySQL parameterized statements (
%splaceholders) - XSS prevention — Book titles, authors, and branch names are HTML-escaped via
html.escape()informatter_service.py - Rate limiting — Built-in per-IP rate limiter in
main.py; no external dependency required - No
console.login production — All frontend debug output is gated behindCONFIG.DEBUG - No stack traces exposed — Backend exceptions are caught and returned as friendly HTML messages
- CORS — Currently set to
allow_origins=["*"]; restrict this to your Koha OPAC domain in production
# backend/app/main.py — restrict CORS for production
allow_origins=["https://opac.yourlibrary.org"]| Phase | Feature | Status |
|---|---|---|
| Phase 1 — Core | Floating chatbot UI | ✅ Complete |
| Natural language intent detection | ✅ Complete | |
| Title, Author, ISBN, Publisher search | ✅ Complete | |
| Barcode, Call Number, Branch, Language, Year search | ✅ Complete | |
| Book availability & copy count | ✅ Complete | |
| Open Library cover integration | ✅ Complete | |
| Rate limiting | ✅ Complete | |
| Autocomplete suggestions | ✅ Complete | |
| Phase 2 — Advanced Search | Subject / topic search | ✅ Complete |
| Advanced filter combinations | ✅ Complete | |
| Fuzzy search tolerance | ✅ Complete | |
| Phase 3 — AI & Recommendations | LLM integration | 🔜 Planned |
| RAG pipeline | 🔜 Planned | |
| Vector search | 🔜 Planned | |
| Personalized recommendations | 🔜 Planned | |
| Phase 4 — Patron Features | User authentication | 🔜 Planned |
| Book reservation | 🔜 Planned | |
| Fine information | 🔜 Planned | |
| Reading history | 🔜 Planned | |
| Voice search | 🔜 Planned |
cd backend
source .venv/bin/activate
# Run all tests
python -m pytest tests/ -v
# Run specific test suites
python -m pytest tests/test_api.py -v
python -m pytest tests/test_intents.py -v
python -m pytest tests/test_search.py -v
python -m pytest tests/test_database.py -vContributions are welcome! Please follow these steps:
- Fork the repository
- Create a feature branch:
git checkout -b feature/your-feature-name - Commit your changes:
git commit -m "feat: add subject search support" - Push to your branch:
git push origin feature/your-feature-name - Open a Pull Request — please describe the problem and solution clearly
For major changes, please open an issue first to discuss the proposed approach.
Commit message convention:
feat: add new feature
fix: correct a bug
docs: update documentation
refactor: restructure code without changing behavior
test: add or update tests
This project is licensed under the MIT License — see the LICENSE file for details.
- Koha Community — The world's first free and open-source library system
- Open Library — Book cover images via the Covers API
- FastAPI — High-performance Python web framework
- MariaDB Foundation — The open-source relational database
- Apache Software Foundation — The web server powering Koha
Made with ❤️ for libraries and librarians
⭐ Star this repo if it helps your library!