Skip to content

CrispStrobe/AIToolkit

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

254 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

KI Suite - Deployment Guide

This documentation covers the deployment of a (mostly) GDPR-compliant Multi-Provider AI Suite with:

  • πŸ’¬ Chat (Multiple LLM providers with context-aware history, tool calling, web search)
  • πŸ” Web Search (Agentic tool-calling loop via Tavily, Brave Search, DuckDuckGo, or self-hosted SearXNG)
  • πŸŽ™οΈ Audio Transcription (Gladia, Whisper, Mistral, Deepgram, AssemblyAI; Speaker Diarization; Chunking; real-time Dictation)
  • πŸ“„ Content Extraction for uploads (text extraction from PPTX, DOCX, XLSX, PDF; OCR for images/scans) and OCR (with Mistral OCR, local Tesseract, Vision LLMs etc)
  • πŸ”€ Translation (NMT + LLM-based DOCX translation via translator.py)
  • πŸ“‹ Format-Transplant (Apply formatting/styles of one DOCX to the content of another)
  • πŸ“¦ Cloud Storage (Hetzner Storage Box integration via SMB)
  • πŸ”„ Resumable Jobs (Job tracking for large files)
  • πŸ‘οΈ Vision Analysis (Image understanding)
  • 🎨 Image Generation (e.g. FLUX models via Nebius and directly per Black Forest Labs API)
  • πŸ’Ύ Database Integration (SQLite with per-user AES-256-GCM encryption)
  • πŸ“± PWA Support (Progressive Web App for mobile installation)
  • πŸ›‘οΈ Security (Fail2Ban protection, EU-only mode, per-user key wrapping)

The application runs as a Python/Gradio service on localhost:7860, managed by systemd, and exposed via Apache reverse proxy with SSL.


🌍 LLM Providers & EU Compliance

The suite supports multiple LLM providers. EU_ONLY_MODE = True in config.py restricts which providers regular users can access. Admins and Medienverwalter bypass this restriction.

Provider EU Status Notes
Mistral πŸ‡«πŸ‡· EU (Paris) Chat, Vision, OCR, Audio
Scaleway πŸ‡«πŸ‡· EU (Paris) Chat, Vision, Transcription
Nebius πŸ‡³πŸ‡± EU (Amsterdam) Chat, Vision, Image Generation
Gladia πŸ‡«πŸ‡· EU Transcription
Deepgram πŸ‡ͺπŸ‡Ί EU endpoint Transcription (api.eu.deepgram.com)
AssemblyAI πŸ‡ͺπŸ‡Ί EU endpoint Transcription (api.eu.assemblyai.com)
BFL πŸ‡©πŸ‡ͺ EU (Germany) Image Generation (FLUX)
Requesty πŸ‡ͺπŸ‡Ί EU router Chat β€” EU-filtered (see below)
Langdock πŸ‡©πŸ‡ͺ EU (Hamburg, Azure) Chat β€” DSGVO-konform, OpenAI-compatible
OpenRouter πŸ‡ΊπŸ‡Έ US Chat, Vision, Image β€” restricted in EU mode
Groq πŸ‡ΊπŸ‡Έ US Chat, Transcription β€” restricted in EU mode
Poe πŸ‡ΊπŸ‡Έ US Chat, Vision β€” restricted in EU mode

Requesty EU Router

Requesty (router.eu.requesty.ai) is a model aggregator routing to 20+ backend providers. The suite applies client-side EU filtering based on model ID prefix and @region suffix:

  • EU-native (always allowed): nebius/…, mistral/…
  • EU-regional (allowed only with explicit EU region in model ID):
    • azure/model@swedencentral, azure/model@francecentral, azure/model@uksouth
    • bedrock/model@eu-central-1, bedrock/model@eu-west-1, etc.
    • vertex/model@europe-west1, vertex/model@europe-central2, etc.
  • Blocked: openai/…, anthropic/…, novita/…, groq/…, xai/…, moonshot/…, deepseek/…, alibaba/…, and others

Role-based access: Admins and Medienverwalter see all 430+ Requesty models (incl. non-EU). Regular users see only the ~117 EU-routed models.

Langdock

Langdock is a German company (Hamburg) providing an OpenAI-compatible API backed by EU Azure infrastructure, fully DSGVO-compliant.

  • All models served by Langdock are chat models (no image-gen, no embeddings)
  • No additional EU filtering required β€” all models are on EU Azure by definition
  • Use Fetch Models to always get the live list from Langdock's API

πŸ” Web Search / Tool Calling

The chat supports an agentic tool-calling loop via tool_executor.py. When enabled, the model can call tools (currently: web_search) mid-conversation and use the results to ground its final answer.

Supported providers for tool calling: Mistral, Scaleway, Nebius, OpenRouter

Search backends (selectable in the βš™οΈ Konfiguration tab):

Backend Key Required Notes
tavily TAVILY_API_KEY Default. AI-optimised results, free 1 000 req/month
brave_web BRAVE_SEARCH_API_KEY Web snippets, own index, EU-friendly, ~1 000 free/month via $5 credit
brave_llm BRAVE_SEARCH_API_KEY Pre-extracted text chunks optimised for LLM grounding / RAG
brave_answers BRAVE_ANSWERS_API_KEY AI-generated answer with citations (separate Brave subscription)
brave_images BRAVE_SEARCH_API_KEY Image search
duckduckgo β€” No key needed, rate-limited, production fallback
searxng SEARXNG_URL Self-hosted meta-search (future option)

Fallback chain: if the primary backend fails, the router automatically tries duckduckgo before surfacing an error.

Options exposed per search call: freshness (24h/7d/31d/365d), country, search_lang, safesearch, extra_snippets, max_tokens (LLM context), enable_citations (Answers).

The tool_executor.py module is standalone-testable without running the full app:

python tool_executor.py --query "What is the latest news about Mistral AI?" --backend tavily
python tool_executor.py --query "..." --backend brave_web --provider Scaleway --model mistral-small-3.2-24b-instruct-2506

πŸ“‹ Prerequisites

  • OS: Ubuntu 20.04 LTS or newer
  • RAM: Minimum 8GB (for handling audio files)
  • Root/Sudo Access
  • Domain: DNS A-Record pointing to server IP (e.g., ai.yourdomain.de)
  • Storage: Hetzner Storage Box with sub-account access
  • API Keys (stored in .env file):
    • MISTRAL_API_KEY β€” multipurpose: chat, OCR, vision, audio
    • SCALEWAY_API_KEY β€” chat, transcription
    • NEBIUS_API_KEY β€” chat, image generation
    • GLADIA_API_KEY β€” long-form transcription
    • DEEPGRAM_API_KEY β€” transcription, EU endpoint
    • ASSEMBLYAI_API_KEY β€” transcription, EU endpoint
    • GROQ_API_KEY β€” transcription, chat (US, restricted in EU mode)
    • REQUESTY_API_KEY β€” EU router: chat across many providers
    • LANGDOCK_API_KEY β€” chat, DSGVO-konform, German company, EU Azure
    • OPENROUTER_API_KEY β€” optional, additional models (US, restricted in EU mode)
    • BFL_API_KEY β€” optional, FLUX image generation
    • POE_API_KEY β€” optional, additional models (US, restricted in EU mode)
    • TAVILY_API_KEY β€” web search, free 1 000 req/month
    • BRAVE_SEARCH_API_KEY β€” web search: snippets, LLM context, images
    • BRAVE_ANSWERS_API_KEY β€” web search: AI-generated answers (separate subscription)
    • SEARXNG_URL β€” optional, self-hosted SearXNG base URL (e.g. http://localhost:8888)

πŸ› οΈ Step 1: System Dependencies & Security

CRITICAL: FFmpeg must be in PATH. cifs-utils is required for Storage Box. OCR and document tools are required for the Content Extractor.

sudo apt update
sudo apt upgrade -y

# Install all required system packages
sudo apt install -y \
    wget \
    python3-pip \
    ffmpeg \
    apache2 \
    certbot \
    python3-certbot-apache \
    sqlite3 \
    fail2ban \
    cifs-utils \
    tesseract-ocr \
    tesseract-ocr-deu \
    poppler-utils \
    pandoc

Firewall Configuration (UFW)

CRITICAL: You must allow SSH before enabling the firewall, or you will lock yourself out.

# 1. Allow incoming SSH connections
sudo ufw allow OpenSSH

# 2. Allow Web Traffic (HTTP/HTTPS)
sudo ufw allow 'Apache Full'

# 3. Enable the Firewall
sudo ufw enable

# 4. Verify Status
sudo ufw status

Configure Swap Space (prevent OOM crashes)

sudo fallocate -l 4G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab

Verify critical installations:

which ffmpeg                    # Must show: /usr/bin/ffmpeg
sudo systemctl status fail2ban  # Must be: active (running)

πŸ“¦ Step 2: Storage Box Mounting (Hetzner)

2.1 Create Mount Point

sudo mkdir -p /mnt/storage

2.2 Create Credentials File

sudo nano /etc/cifs-credentials

Content:

username=u12345-sub1
password=YOUR_SUBACCOUNT_PASSWORD
sudo chmod 600 /etc/cifs-credentials

2.3 Configure Auto-Mount via fstab

sudo nano /etc/fstab

Add (single line):

//u12345-sub1.your-storagebox.de/u12345-sub1 /mnt/storage cifs credentials=/etc/cifs-credentials,uid=0,gid=0,file_mode=0770,dir_mode=0770,nounix,vers=3.0,x-systemd.automount,x-systemd.idle-timeout=60 0 0

Note: uid=0 assumes app runs as root. Change to 1000 for non-root user.

2.4 Mount and Verify

sudo systemctl daemon-reload
sudo systemctl restart remote-fs.target
ls -la /mnt/storage  # Should list files from Storage Box

🐍 Step 3: Application Setup

3.1 Create Directory Structure

sudo mkdir -p /var/www/transkript_app
sudo mkdir -p /var/www/transkript_app/static
sudo mkdir -p /var/www/transkript_app/generated_images
sudo mkdir -p /var/www/transkript_app/jobs
cd /var/www/transkript_app

3.2 Clone Repository or Copy Files

Option A: Clone from GitHub

git clone https://github.com/YOUR_USERNAME/YOUR_REPO.git .

Option B: Manual File Upload

Upload these files:

  • app.py β€” Main application (UI, event wiring, Gradio blocks)
  • config.py β€” Central provider & key configuration
  • crypto_utils.py β€” Encryption logic & key wrapping
  • db_models.py β€” SQLAlchemy models & schema migrations
  • db_ops.py β€” Database CRUD operations
  • provider_utils.py β€” LLM provider clients, compliance, routing
  • context_utils.py β€” Token estimation, context pruning, chunking
  • image_utils.py β€” Image encoding & resize helpers
  • image_gen_utils.py β€” Image generation & vision analysis
  • transcription_utils.py β€” Audio processing, transcription runners, YouTube/download helpers
  • storage_utils.py β€” File storage, pCloud, per-user directories
  • chat_handlers.py β€” Chat logic, content extraction (UniversalExtractor), attachments
  • ocr_utils.py β€” OCR engines (Mistral, Groq, OpenRouter, Ollama/GLM, Vision LLM)
  • translation_utils.py β€” Async DOCX translation with progress streaming
  • export_utils.py β€” Export to .docx / .md / .txt
  • tool_executor.py β€” Web search / tool-calling router
  • translator.py β€” DOCX translation engine (NMT + LLM)
  • format_transplant.py β€” DOCX format-transplant engine
  • dictation_manager.py β€” Real-time dictation (Gladia, Mistral)
  • requirements.txt β€” Python dependencies
  • static/ folder: custom.css, manifest.json, pwa.js, service-worker.js, icon-192.png, icon-512.png

3.3 Create Environment File

CRITICAL: Store all API keys in a secured .env file.

sudo nano /var/www/transkript_app/.env

Required content:

# LLM Providers
MISTRAL_API_KEY=...
SCALEWAY_API_KEY=...
NEBIUS_API_KEY=...
OPENROUTER_API_KEY=...
REQUESTY_API_KEY=rqsty-sk-...
LANGDOCK_API_KEY=sk-...

# Transcription
GLADIA_API_KEY=...
DEEPGRAM_API_KEY=...
ASSEMBLYAI_API_KEY=...
GROQ_API_KEY=gsk_...

# Image Generation
BFL_API_KEY=...

# Web Search (tool calling)
TAVILY_API_KEY=tvly-...          # Free 1 000 req/month β€” https://tavily.com
BRAVE_SEARCH_API_KEY=BSA...      # ~1 000 free/month via $5 credit β€” https://brave.com/search/api/
BRAVE_ANSWERS_API_KEY=BSA...     # Separate Brave Answers subscription
# SEARXNG_URL=http://localhost:8888  # Optional: self-hosted SearXNG

# Optional / US providers (restricted in EU mode)
POE_API_KEY=...
OPENAI_API_KEY=sk-...
ANTHROPIC_API_KEY=sk-ant-...

# Misc
GRADIO_ANALYTICS_ENABLED=False

Secure it:

sudo chmod 600 /var/www/transkript_app/.env

Local development: The app automatically loads .env via python-dotenv when running locally (python app.py). On the VPS the env vars are loaded by systemd's EnvironmentFile= directive instead.

3.4 Create Virtual Environment (Miniconda Method)

# 1. Download and Install Miniconda
wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh
bash Miniconda3-latest-Linux-x86_64.sh -b -p /opt/miniconda

# 2. Initialize Conda
/opt/miniconda/bin/conda init bash
source ~/.bashrc

# Accept TOS
conda tos accept --override-channels --channel https://repo.anaconda.com/pkgs/main
conda tos accept --override-channels --channel https://repo.anaconda.com/pkgs/r

# 3. Create the 'ak_suite' environment with Python 3.10
/opt/miniconda/bin/conda create -n ak_suite python=3.10 -y

# 4. Link it to the app directory
cd /var/www/transkript_app
rm -rf venv
ln -s /opt/miniconda/envs/ak_suite ./venv
conda activate ak_suite

3.5 Install Python Dependencies

conda activate ak_suite
pip install --upgrade pip wheel

pip install \
    "openai>=1.0" \
    "gradio>=5.0" \
    "yt-dlp>=2024.11" \
    requests \
    pillow \
    pydub \
    sqlalchemy \
    bcrypt \
    fastapi-poe \
    python-pptx \
    python-docx \
    pypdf \
    pymupdf \
    pdf2image \
    pytesseract \
    pandas \
    openpyxl \
    lxml \
    pycryptodome \
    cryptography \
    python-dotenv \
    ddgs

Optional but recommended:

pip install pqcrypto   # Post-quantum encryption (Kyber-512)

We use pycryptodome for AES-GCM and cryptography for Fernet/PBKDF2. python-dotenv enables .env loading locally. ddgs provides DuckDuckGo search as a free fallback (no API key).

Alternatively, for single installs without activating the environment:

/var/www/transkript_app/venv/bin/pip install [package]

3.6 Initialize Permissions

sudo touch /var/www/transkript_app/app.log
sudo chmod 666 /var/www/transkript_app/app.log
sudo chmod -R 755 /var/www/transkript_app
sudo chown -R www-data:www-data /var/www/transkript_app/static
sudo chmod -R 755 /var/www/transkript_app/static

🌐 Step 4: Apache Configuration

This configuration serves PWA files directly via Apache and proxies the Gradio app with proper HTTPS headers.

4.1 Enable Required Modules

sudo a2enmod proxy proxy_http proxy_wstunnel rewrite headers ssl

4.2 SSL Certificate Setup

sudo certbot --apache -d ai.yourdomain.de

4.3 HTTP Config (Port 80 - HTTPS Redirect)

Edit /etc/apache2/sites-available/transkript.conf:

<VirtualHost *:80>
    ServerName ai.yourdomain.de
    ErrorLog ${APACHE_LOG_DIR}/transkript_error.log
    CustomLog ${APACHE_LOG_DIR}/transkript_access.log combined
    RewriteEngine On
    RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]
</VirtualHost>

4.4 HTTPS Config (Port 443 - Main Config)

Edit /etc/apache2/sites-available/transkript-le-ssl.conf:

<IfModule mod_ssl.c>
<VirtualHost *:443>
    ServerName ai.yourdomain.de

    # =================================================
    # πŸ›‘οΈ SECURITY HEADERS
    # =================================================
    Header always unset Server
    Header always unset X-Powered-By
    Header unset Server
    Header unset X-Powered-By

    # =================================================
    # πŸ”’ BLOCK OPENAPI - FIRST PRIORITY
    # =================================================
    RewriteEngine On
    RewriteRule ^/openapi\.json$ - [F,L]
    RewriteRule ^/docs/?$ - [F,L]
    RewriteRule ^/redoc/?$ - [F,L]
    RewriteRule ^/api(/.*)?$ - [F,L]
    RewriteRule ^/gradio_api/openapi\.json$ - [F,L]

    # =================================================
    # 1. STATIC FILES (Served by Apache)
    # =================================================
    Alias /static /var/www/transkript_app/static
    <Directory /var/www/transkript_app/static>
        Require all granted
        Options -Indexes
        AddType text/css .css
        AddType application/javascript .js
        AddType image/png .png
        Header set Cache-Control "public, max-age=31536000, immutable"
    </Directory>

    Alias /manifest.json /var/www/transkript_app/static/manifest.json
    <Files "manifest.json">
        Require all granted
        Header set Content-Type "application/manifest+json"
        Header set Cache-Control "no-cache"
    </Files>

    Alias /service-worker.js /var/www/transkript_app/static/service-worker.js
    <Files "service-worker.js">
        Require all granted
        Header set Content-Type "application/javascript"
        Header set Cache-Control "no-cache"
        Header set Service-Worker-Allowed "/"
    </Files>

    # =================================================
    # 2. PROXY SETTINGS (Gradio)
    # =================================================
    ProxyPreserveHost On
    RequestHeader set X-Forwarded-Proto "https"
    RequestHeader set X-Forwarded-Port "443"
    RequestHeader set X-Forwarded-Host "ai.yourdomain.de"

    RewriteCond %{HTTP:Upgrade} =websocket [NC]
    RewriteRule /(.*)           ws://127.0.0.1:7860/$1 [P,L]

    ProxyPass /static !
    ProxyPass /manifest.json !
    ProxyPass /service-worker.js !
    ProxyPass / http://127.0.0.1:7860/
    ProxyPassReverse / http://127.0.0.1:7860/

    # =================================================
    # 3. SSL CONFIGURATION
    # =================================================
    SSLCertificateFile /etc/letsencrypt/live/ai.yourdomain.de/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/ai.yourdomain.de/privkey.pem
    Include /etc/letsencrypt/options-ssl-apache.conf

    LimitRequestBody 1048576000
    ProxyTimeout 600
    TimeOut 600
</VirtualHost>
</IfModule>

4.5 Enable Sites and Restart Apache

sudo a2ensite transkript.conf
sudo a2ensite transkript-le-ssl.conf
sudo apache2ctl configtest  # Should show "Syntax OK"
sudo systemctl restart apache2

βš™οΈ Step 5: Systemd Service

Create /etc/systemd/system/transkript.service:

[Unit]
Description=Gradio App
After=network.target

[Service]
Type=simple
User=root
WorkingDirectory=/var/www/transkript_app
Environment="PATH=/var/www/transkript_app/venv/bin:/usr/local/bin:/usr/bin:/bin"
Environment="GRADIO_ANALYTICS_ENABLED=False"
Environment="GRADIO_SERVER_NAME=127.0.0.1"
EnvironmentFile=/var/www/transkript_app/.env
ExecStart=/var/www/transkript_app/venv/bin/python app.py
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target

Key Points:

  • EnvironmentFile=/var/www/transkript_app/.env β€” loads API keys from .env (replaces load_dotenv for production)
  • User=root β€” runs as root (change if using non-root deployment)
  • Restart=always β€” auto-restart on crashes

Enable and start:

sudo systemctl daemon-reload
sudo systemctl enable transkript
sudo systemctl start transkript
sudo systemctl status transkript

πŸ›‘οΈ Step 6: Fail2Ban Configuration

6.1 Create Local Configuration

sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
sudo nano /etc/fail2ban/jail.local

6.2 Enable Apache Protections

[sshd]
enabled = true

[apache-auth]
enabled = true

[apache-badbots]
enabled = true

[apache-noscript]
enabled = true

[apache-overflows]
enabled = true

[apache-404-scan]
enabled  = true
port     = http,https
filter   = apache-404-scan
logpath  = /var/log/apache2/*access.log
maxretry = 5
findtime = 600
bantime  = 3600

6.3 Restart Fail2Ban

sudo systemctl restart fail2ban
sudo fail2ban-client status

πŸ”„ Step 7: Log Rotation

sudo nano /etc/logrotate.d/transkript_app

Content:

/var/www/transkript_app/app.log {
    daily
    missingok
    rotate 14
    compress
    delaycompress
    notifempty
    create 666 root root
    copytruncate
}

Test:

sudo logrotate -d /etc/logrotate.d/transkript_app

πŸ’» Local Development

The app runs locally without any server configuration:

# Clone repo
git clone https://github.com/YOUR_USERNAME/YOUR_REPO.git
cd AIToolkit

# Install dependencies
pip install -r requirements.txt
pip install python-dotenv ddgs

# Create .env with your API keys (see Step 3.3 for key names)
cp .env.example .env   # or create manually

# Run
python app.py
# β†’ http://127.0.0.1:7860

Local vs VPS differences:

  • .env is loaded automatically via python-dotenv locally; on VPS it's loaded by systemd
  • Storage mounts to ./storage/ locally instead of /mnt/akademie_storage
  • Encryption keys saved to ./.master_key locally instead of /var/www/transkript_app/.master_key
  • Both directories are created automatically if missing

Reset local passwords:

python -c "
import bcrypt, sqlite3
db = sqlite3.connect('akademie_suite.db')
for user, pw in [('admin123', 'admin123'), ('user123', 'user123')]:
    h = bcrypt.hashpw(pw.encode(), bcrypt.gensalt(12)).decode()
    db.execute('UPDATE users SET password_hash=? WHERE username=?', (h, user))
    print(f'Reset {user}')
db.commit(); db.close()
"

Test web search standalone:

python tool_executor.py --query "latest Mistral AI news" --backend tavily
python tool_executor.py --query "..." --backend brave_web --provider Scaleway

πŸ“ Final File Structure

/var/www/transkript_app/
β”œβ”€β”€ app.py                      # Main application (UI, Gradio blocks, event wiring)
β”‚
β”‚   ── Core ──────────────────────────────────────────────────────
β”œβ”€β”€ config.py                   # Provider & key configuration
β”œβ”€β”€ crypto_utils.py             # AES-256-GCM encryption & key wrapping
β”œβ”€β”€ db_models.py                # SQLAlchemy models & schema migrations
β”œβ”€β”€ db_ops.py                   # Database CRUD operations
β”‚
β”‚   ── Provider / Inference ──────────────────────────────────────
β”œβ”€β”€ provider_utils.py           # LLM provider clients, compliance, routing
β”œβ”€β”€ context_utils.py            # Token estimation, context pruning, chunking
β”œβ”€β”€ image_utils.py              # Image encoding & resize helpers
β”œβ”€β”€ image_gen_utils.py          # Image generation & vision analysis
β”‚
β”‚   ── Feature Modules ──────────────────────────────────────────
β”œβ”€β”€ transcription_utils.py      # Audio processing, transcription runners, YouTube/download helpers
β”œβ”€β”€ storage_utils.py            # File storage, pCloud, per-user directories
β”œβ”€β”€ chat_handlers.py            # Chat logic, UniversalExtractor, attachments
β”œβ”€β”€ ocr_utils.py                # OCR engines (Mistral, Groq, OpenRouter, Ollama/GLM, Vision LLM)
β”œβ”€β”€ translation_utils.py        # Async DOCX translation with progress streaming
β”œβ”€β”€ export_utils.py             # Export to .docx / .md / .txt
β”‚
β”‚   ── Standalone Tools ─────────────────────────────────────────
β”œβ”€β”€ tool_executor.py            # Web search / tool-calling router (standalone-testable)
β”œβ”€β”€ translator.py               # DOCX translation engine (NMT + LLM)
β”œβ”€β”€ format_transplant.py        # DOCX format-transplant engine
β”œβ”€β”€ dictation_manager.py        # Real-time dictation (Gladia, Mistral)
β”œβ”€β”€ fn2md.py                    # Function-to-markdown helper
β”‚
β”‚   ── Runtime ───────────────────────────────────────────────────
β”œβ”€β”€ requirements.txt            # Python dependencies
β”œβ”€β”€ .env                        # API keys (NOT in repo β€” create manually)
β”œβ”€β”€ .master_key                 # Global encryption key (CRITICAL β€” backup!)
β”œβ”€β”€ .pq_keypair                 # Optional post-quantum keypair
β”œβ”€β”€ akademie_suite.db           # SQLite database (auto-created)
β”œβ”€β”€ app.log                     # Application logs
β”œβ”€β”€ venv/                       # Python virtual environment (symlink to conda)
β”œβ”€β”€ jobs/                       # Resume job manifests (auto-created)
β”œβ”€β”€ generated_images/           # AI-generated images (auto-created)
β”œβ”€β”€ storage/                    # Local fallback when Storage Box unavailable
└── static/                     # PWA assets (owned by www-data)
    β”œβ”€β”€ custom.css
    β”œβ”€β”€ pwa.js
    β”œβ”€β”€ manifest.json
    β”œβ”€β”€ service-worker.js
    β”œβ”€β”€ icon-192.png
    └── icon-512.png

/mnt/akademie_storage/          # Hetzner Storage Box (mounted via CIFS)
└── users/[username]/           # Per-user storage

⚠️ Critical backup: Always back up .master_key together with akademie_suite.db. The database is encrypted β€” without the key, data is unrecoverable.


πŸ” Troubleshooting

Service Not Starting

sudo systemctl status transkript
sudo journalctl -u transkript -f
tail -f /var/www/transkript_app/app.log

# Common issues:
# - Missing .env β†’ Create /var/www/transkript_app/.env
# - Missing FFmpeg β†’ sudo apt install ffmpeg
# - Port in use β†’ sudo lsof -i :7860

API Keys Not Loading Locally

The app uses python-dotenv to load .env at startup. Verify:

python -c "from dotenv import load_dotenv; load_dotenv(); import os; print(os.environ.get('MISTRAL_API_KEY','MISSING')[:8])"

Web Search Not Working

# Test each backend directly
python tool_executor.py --query "test" --backend tavily
python tool_executor.py --query "test" --backend duckduckgo

# Check keys are loaded
python -c "from config import API_KEYS; print('TAVILY:', bool(API_KEYS.get('TAVILY')))"

OpenRouter 404 "No endpoints available"

This happens when your OpenRouter account privacy settings conflict with the selected model. The app automatically adds allow_fallbacks: true to all OpenRouter requests to mitigate this. If it persists, check your OpenRouter privacy settings at https://openrouter.ai/settings/privacy.

PWA Not Installing on Mobile

curl -I https://ai.yourdomain.de/manifest.json
curl -I https://ai.yourdomain.de/service-worker.js
curl -I https://ai.yourdomain.de/static/icon-192.png
# All should return 200 OK

Storage Box Not Mounting

mount | grep storage
sudo mount -t cifs //u12345-sub1.your-storagebox.de/u12345-sub1 /mnt/storage -o credentials=/etc/cifs-credentials,uid=0,gid=0

Apache Configuration Issues

sudo apache2ctl configtest
sudo tail -f /var/log/apache2/error.log
sudo systemctl restart apache2

πŸ“ Maintenance

Update Application

cd /var/www/transkript_app
git pull
source venv/bin/activate
pip install -r requirements.txt --upgrade
sudo systemctl restart transkript

Backup Database & Keys

mkdir -p /var/backups/transkript
DATE=$(date +%Y%m%d)
cp /var/www/transkript_app/akademie_suite.db /var/backups/transkript/db-$DATE.bak
cp /var/www/transkript_app/.master_key /var/backups/transkript/master_key-$DATE.bak
[ -f /var/www/transkript_app/.pq_keypair ] && \
    cp /var/www/transkript_app/.pq_keypair /var/backups/transkript/pq_keypair-$DATE.bak

SSL Certificate Renewal

sudo certbot renew --dry-run

Monitor Disk Space

df -h /mnt/akademie_storage
df -h /var/www/transkript_app

πŸš€ Quick Reference

Service Management

sudo systemctl start transkript
sudo systemctl stop transkript
sudo systemctl restart transkript
sudo systemctl status transkript

View Logs

sudo journalctl -u transkript -f
tail -f /var/www/transkript_app/app.log
sudo tail -f /var/log/apache2/error.log

Critical Files

  • Application: /var/www/transkript_app/app.py β€” UI & event wiring
  • Chat logic: /var/www/transkript_app/chat_handlers.py
  • OCR engines: /var/www/transkript_app/ocr_utils.py
  • Transcription: /var/www/transkript_app/transcription_utils.py
  • Tool Router: /var/www/transkript_app/tool_executor.py
  • Provider Config: /var/www/transkript_app/config.py
  • Environment: /var/www/transkript_app/.env ← secrets
  • Encryption Key: /var/www/transkript_app/.master_key ← backup this!
  • Service: /etc/systemd/system/transkript.service
  • Apache SSL: /etc/apache2/sites-available/transkript-le-ssl.conf

⚠️ Security Checklist

  • βœ… .env permissions set to 600
  • βœ… .master_key permissions set to 600 β€” backup regularly with the DB
  • βœ… /etc/cifs-credentials permissions set to 600
  • βœ… Fail2Ban enabled and running
  • βœ… SSL certificate valid and auto-renewing
  • βœ… Firewall configured (only ports 22, 80, 443 open)
  • βœ… Apache upload limits configured (1GB)
  • βœ… Storage Box mounted with restricted permissions
  • βœ… EU-only mode enabled (EU_ONLY_MODE = True in config.py)
  • βœ… Requesty configured with EU router endpoint (router.eu.requesty.ai)
  • βœ… OpenRouter allow_fallbacks: true set to avoid data-policy 404s
  • βœ… Web search keys stored in .env, never hardcoded

Last Updated: March 2026 β€” refactored to modular architecture (app.py ~5,300 lines, down from ~8,500)

About

Self-hosted AI Suite, GDPR-compliant, featuring Multi-LLM Chat (Mistral, Nebius, etc), Audio Transcription (Gladia, Deepgram, AssemblyAI, Voxtral, Whisper, etc), Image Gen (Flux, etc), Cloud Storage integration, OCR, etc

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages