The Mannheim Intelligent Discovery System is an experimental web application that adds AI assisted search to discovery systems like Primo or VuFind®.
The installation is based on macOS, Linux, WSL, or a similar host system with Git and a sufficiently recent Python3.
Clone this repository and run these commands in your local working directory:
# Install required software.
python3 -m venv venv
source venv/bin/activate
pip install -U pip -r requirements.txtCopy the file sample.env to .env and provide your local settings
in the .env file.
Then, start the web application:
# Run web application (supports both VuFind and Primo).
./app.pyConnect to the running web application in your browser:
The application automatically detects which discovery system to use:
- VuFind is used by default if
VUFIND_SEARCH_ENDPOINTis configured - Primo is used if
PRIMO_SEARCH_ENDPOINTis configured and VuFind is not - Primo can be forced by including "primo" (case-insensitive) in the search query
A JSON API is available for programmatic access (e.g. phone applications).
Send a natural language query and receive a summary, follow-up suggestions, and results.
Request
| Field | Type | Required | Description |
|---|---|---|---|
query |
string | yes | Natural language search query |
model |
string | no | LLM model name (defaults to first in LLM_MODELS) |
Response
| Field | Type | Description |
|---|---|---|
summary |
string | Plain text summary of the search results |
follow_up_queries |
string[] | Suggested follow-up questions |
results |
object[] | Matching records (title, author, url, year) |
Rate limiting: 10 requests per minute per IP (configurable via API_RATE_LIMIT).
Example
curl -s -X POST http://127.0.0.1:5001/api/search \
-H "Content-Type: application/json" \
-d '{"query": "Bücher über Künstliche Intelligenz"}' | python3 -m json.tool{
"follow_up_queries": [
"Gibt es Neuerscheinungen zu diesem Thema?"
],
"results": [
{
"author": "Stuart Russell",
"title": "Artificial Intelligence: A Modern Approach",
"url": "https://example.com/...",
"year": "2021"
}
],
"summary": "Es wurden 3 Treffer gefunden. Das bekannteste Werk ist ..."
}Error responses use appropriate HTTP status codes (400, 429, 502, 503) with a JSON body {"error": "..."}.
For running as a system service (Linux), a systemd unit file is included.
# Create system user
sudo useradd -r -s /sbin/nologin ai
# Deploy application
sudo mkdir -p /opt/maidisco
sudo cp -r . /opt/maidisco/
sudo chown -R ai:ai /opt/maidisco
# Set up virtual environment
sudo -u ai python3 -m venv /opt/maidisco/venv
sudo -u ai /opt/maidisco/venv/bin/pip install -U pip -r /opt/maidisco/requirements.txt
# Configure
sudo -u ai cp /opt/maidisco/sample.env /opt/maidisco/.env
sudo nano /opt/maidisco/.env # edit settings
# Install and start service
sudo cp /opt/maidisco/maidisco.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now maidiscoTo serve under a subpath (e.g. /maidisco), set APPLICATION_ROOT=/maidisco in .env
and configure the WSGI server accordingly. For gunicorn, the systemd service already
passes SCRIPT_NAME=/maidisco. An Apache reverse proxy configuration:
ProxyPass /maidisco/ http://127.0.0.1:5001/
ProxyPassReverse /maidisco/ http://127.0.0.1:5001/Key environment variables in .env:
| Variable | Description |
|---|---|
OPENAI_API_KEY |
API key for OpenAI-compatible LLM (required) |
OPENAI_API_URL |
Base URL for the LLM API (e.g., http://localhost:11434/v1 for Ollama) |
LLM_MODELS |
Comma-separated list of available models (first is default, e.g. gpt-4,llama3,mistral) |
VUFIND_SEARCH_ENDPOINT |
VuFind API search endpoint URL |
PRIMO_SEARCH_ENDPOINT |
Primo API search endpoint URL |
PRIMO_APIKEY |
Primo API key (optional) |
PRIMO_SCOPE |
Primo scope parameter |
PRIMO_TAB |
Primo tab parameter |
PRIMO_VID |
Primo view ID |
HOST |
Server host (default: 127.0.0.1) |
PORT |
Server port (default: 5001) |
APPLICATION_ROOT |
URL prefix for subpath deployment (default: /) |
MAX_RESULTS |
Maximum number of search results (default: 10) |
API_RATE_LIMIT |
API rate limit: requests per minute per IP (default: 10) |
DEBUGMODE |
Enable Flask debug mode (default: False) |
MATOMO_URL |
Matomo tracking URL (optional, e.g. https://analytics.example.com/) |
MATOMO_SITE_ID |
Matomo site ID (optional) |
LEGAL_NOTICE_URL |
URL to legal notice/Impressum page (optional) |
PRIVACY_URL |
URL to privacy policy/Datenschutz page (optional) |
ACCESSIBILITY_URL |
URL to accessibility statement/Barrierefreiheit page (optional) |
SIGN_LANGUAGE_URL |
URL to sign language/Gebärdensprache page (optional) |
EASY_LANGUAGE_URL |
URL to easy language/Leichte Sprache page (optional) |
- CSRF protection via Sec-Fetch-Site header validation
- Rate limiting: 30 POST requests per minute per IP
- HTML sanitization in LLM summaries (XSS prevention)
- URL validation (blocks
javascript:and other dangerous schemes) - SSRF prevention (validates endpoint URLs at startup)
- Structured LLM prompts to mitigate prompt injection attacks
This is an experimental proof of concept. It is not intended for production use. Many features are missing, and the software may have bugs and security issues.
maidisco – Mannheim Intelligent Discovery System for AI assisted search
Copyright (C) 2025–2026 Universitätsbibliothek Mannheim
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License along with this program. If not, see https://www.gnu.org/licenses/.