Skip to content

About

A local German FAQ chatbot pipeline for photovoltaic FAQ questions. The project combines a classic FAQ knowledge base with semantic retrieval and several local Hugging Face language models.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

1 Commit

Folders and files

Repository files navigation

QRQA-LM FAQ Chatbot

screenshot_faq_Chatbot.png

A local German FAQ chatbot pipeline for photovoltaic FAQ questions.

The project combines a classic FAQ knowledge base with semantic retrieval and several local Hugging Face language models. It extracts FAQ entries from prepared HTML files, stores them as a structured Python dataset, creates sentence embeddings, retrieves semantically similar FAQ entries for a user question, and generates a final answer with question-answering, paraphrasing, and answer optimization models.

The system is designed as a local-first pipeline. Models are downloaded once into a local model/ directory and are loaded from disk during runtime.


Core Idea

The chatbot does not answer from an unrestricted generative model alone. Instead, it follows a retrieval-augmented FAQ workflow:

  1. HTML FAQ pages are prepared locally.
  2. FAQ titles and contents are extracted into a structured dataset.
  3. FAQ questions are converted into sentence embeddings.
  4. A user question is embedded and compared with all FAQ questions.
  5. The most relevant FAQ contents are retrieved and merged into a context.
  6. German question-answering models extract candidate answer strings.
  7. A German paraphraser rewrites the intermediate answer.
  8. A German T5 model optimizes the prompted answer.
  9. A final paraphrasing step improves readability.
  10. The system returns the answer and the underlying sources.

workFlow_QRQA_LM_Phase_1_4.png

workFlow_QRQA_LM_Phase_5.png

This architecture keeps the answer grounded in the FAQ database while still using language models to improve fluency, coherence, and usability.


Used Models

The optimized code uses the following Hugging Face models.

Pipeline Role Model Name Local Folder Purpose
Sentence embeddings aari1995/German_Semantic_V3 model/German_Semantic_V3/ Creates semantic vector representations of FAQ questions and user questions.
Question answering 1 deepset/gelectra-base-germanquad model/gelectra-base-germanquad/ Extracts answer spans from the retrieved FAQ context.
Question answering 2 princetyagi/bert-base-german-cased-finetuned-squad model/bert-base-german-cased-finetuned-squad/ Extracts a second answer candidate from the same retrieved context.
Paraphrasing Lelon/t5-german-paraphraser-large model/t5-german-paraphraser-large/ Rewrites intermediate and final answers into more natural German.
Answer optimization Shahm/t5-small-german model/t5-small-german/ Generates a more coherent answer from a structured prompt.

Used Techniques

The project uses the following techniques and processing steps:

  • HTML parsing with BeautifulSoup
  • FAQ extraction from local/crawled HTML files
  • Structured dataset creation as a Python list[dict]
  • Optional merge of synthetic ChatGPT FAQ additions
  • Duplicate detection based on title, content, genre, and source
  • Sentence embeddings with SentenceTransformers
  • Semantic similarity search with cosine similarity
  • Top-k retrieval of FAQ entries
  • Similarity threshold filtering
  • Retrieval-augmented question answering
  • German transformer-based question answering
  • Multi-model QA output combination
  • German T5-based paraphrasing
  • Prompt construction with selectable prompt templates
  • German T5-based answer optimization/summarization
  • Runtime-only answer generation from local files and models
  • JSON output for CLI, Flask, or frontend usage

Python Version

Use Python 3.12.x. The project is intended for Python 3.12.8.

Check your Python version:

python3.12 --version

Create and activate a virtual environment:

python3.12 -m venv .venv
source .venv/bin/activate

Project Structure

flask_QRQA_LM/
├── faq_chatbot/
│   ├── faq_chatbot.py
│   ├── faq_source_configs.py
│   ├── faq_synthetic_dataset.py
│   ├── faq_dataset.py
│   └── faq_dataset_with_embeddings.py
├── html_files/
│   ├── html_1.html
│   ├── html_2.html
│   ├── html_3.html
│   └── ...
├── model/
│   ├── German_Semantic_V3/
│   ├── gelectra-base-germanquad/
│   ├── bert-base-german-cased-finetuned-squad/
│   ├── t5-german-paraphraser-large/
│   └── t5-small-german/
├── static/
│   ├── css/
│   ├── js/
│   └── img/
├── templates/
│   └── index.html
├── app.py
├── requirements.txt
├── README.md
└── .gitignore

Main Files

faq_chatbot.py

Main script and command-line entry point.

It contains:

  • runtime output configuration,
  • global path configuration,
  • model configuration,
  • dataset helpers,
  • HTML parsing functions,
  • FAQ dataset creation,
  • synthetic FAQ data merging,
  • model downloading,
  • local model loading,
  • embedding creation,
  • semantic retrieval,
  • question-answering pipeline,
  • paraphrasing and answer optimization,
  • CLI argument parsing,
  • command dispatching.

faq_source_configs.py

Contains the parsing configuration for the local HTML FAQ files.

Example:

FAQ_SOURCE_CONFIGS = [
    {
        "html_file": "html_1.html",
        "genre": "Photovoltaik",
        "source": "https://example.com/faq/",
        "title_tag": "h2",
        "title_class": "faq-title",
        "content_tag": "p",
        "content_class": "faq-content",
    },
]

faq_synthetic_dataset.py

Contains additional manually or synthetically created FAQ entries.

The script imports:

from faq_synthetic_dataset import CHATGPT_FAQ_DATA

Required structure:

CHATGPT_FAQ_DATA = [
    {
        "title": "Was kostet eine Photovoltaikanlage?",
        "content": "Die Kosten hängen unter anderem von Leistung, Modulen, Wechselrichter, Montage und optionalem Speicher ab.",
        "genre": "Photovoltaik",
        "source": "ChatGPT",
    },
]

faq_dataset.py

Generated plain FAQ dataset.

It contains:

data = [...]

This file is created from the configured HTML files. After running add_chatgpt_data_to_faq_dataset, it also contains the synthetic FAQ additions.

faq_dataset_with_embeddings.py

Generated FAQ dataset with embeddings.

Each FAQ entry receives an additional field:

"embedding": [...]

This file is used during semantic retrieval.


Installation

Create a virtual environment & Install Depencies:

python3 -m venv .venv
source .venv/bin/activate
pip install --upgrade pip
pip install -r requirements.txt

Full Setup Workflow

Use this sequence for a complete clean setup:

source .venv/bin/activate

python faq_chatbot.py download_all_models
python faq_chatbot.py create_faq_dataset --force-rebuild-dataset
python faq_chatbot.py add_chatgpt_data_to_faq_dataset
python faq_chatbot.py create_embeddings --force-rebuild-embeddings

Then test the chatbot:

python faq_chatbot.py ask --question "Was ist ein Batteriespeicher?"

One-Command Build

The optimized run_all command performs the full build pipeline:

python faq_chatbot.py run_all

This performs:

  1. checks/downloads all models,
  2. rebuilds the FAQ dataset from HTML files,
  3. merges ChatGPT FAQ additions,
  4. rebuilds the embedding dataset.

To skip synthetic ChatGPT FAQ additions:

python faq_chatbot.py run_all --skip-chatgpt-data

To force model re-download:

python faq_chatbot.py run_all --force-download-model

Dataset Workflow

1. Create or rebuild the crawled FAQ dataset

python faq_chatbot.py create_faq_dataset --force-rebuild-dataset

This reads all configured HTML files from:

html_files/

and writes:

faq_chatbot/faq_dataset.py

2. Add ChatGPT FAQ additions

python faq_chatbot.py add_chatgpt_data_to_faq_dataset

This combines:

faq_chatbot/faq_dataset.py
faq_chatbot/faq_synthetic_dataset.py

and writes the combined result back to:

faq_chatbot/faq_dataset.py

Duplicate entries are skipped based on:

  • title,
  • content,
  • genre,
  • source.

The older command name is still supported as an alias:

python faq_chatbot.py add_synthetic_data_to_dataset

3. Rebuild embeddings

python faq_chatbot.py create_embeddings --force-rebuild-embeddings

This creates:

faq_chatbot/faq_dataset_with_embeddings.py

After changing faq_dataset.py, always rebuild embeddings. Otherwise, new FAQ entries are not available during semantic retrieval.


Runtime Workflow

Runtime answering is triggered with:

python faq_chatbot.py ask --question "Muss eine Photovoltaikanlage gewartet werden?"

The runtime pipeline performs the following steps:

  1. Loads the existing embedded FAQ dataset from faq_dataset_with_embeddings.py.
  2. Loads the local embedding model aari1995/German_Semantic_V3.
  3. Embeds the user question.
  4. Compares the user question embedding with all FAQ question embeddings.
  5. Retrieves the top matching FAQ entries above the configured similarity threshold.
  6. Merges the retrieved FAQ contents into one context text.
  7. Loads the local QA models:
    • deepset/gelectra-base-germanquad
    • princetyagi/bert-base-german-cased-finetuned-squad
  8. Runs both QA models with the same user question and retrieved context.
  9. Combines both QA outputs into one answer seed.
  10. Paraphrases the answer seed with Lelon/t5-german-paraphraser-large.
  11. Creates a structured prompt from the question, context, and paraphrased QA output.
  12. Optimizes the answer with Shahm/t5-small-german.
  13. Paraphrases the optimized answer again with Lelon/t5-german-paraphraser-large.
  14. Returns the final answer and the source list as JSON.

The runtime pipeline does not download models, rebuild datasets, recreate embeddings, or modify project files.


CLI Commands

General syntax:

python faq_chatbot.py <command> [options]

Available commands:

download_embedding_model
download_qa_model_1
download_qa_model_2
download_paraphraser_model
download_optimizer_model
download_answer_models
download_all_models
create_faq_dataset
add_chatgpt_data_to_faq_dataset
add_synthetic_data_to_dataset
create_embeddings
ask
ask_detailed
run_all

Command Reference

Download one model

python faq_chatbot.py download_embedding_model
python faq_chatbot.py download_qa_model_1
python faq_chatbot.py download_qa_model_2
python faq_chatbot.py download_paraphraser_model
python faq_chatbot.py download_optimizer_model

Force model re-download

python faq_chatbot.py download_all_models --force-download-model

Download all answer-generation models

python faq_chatbot.py download_answer_models

This downloads:

  • deepset/gelectra-base-germanquad
  • princetyagi/bert-base-german-cased-finetuned-squad
  • Lelon/t5-german-paraphraser-large
  • Shahm/t5-small-german

It does not download the embedding model.

Download all models

python faq_chatbot.py download_all_models

This downloads:

  • aari1995/German_Semantic_V3
  • deepset/gelectra-base-germanquad
  • princetyagi/bert-base-german-cased-finetuned-squad
  • Lelon/t5-german-paraphraser-large
  • Shahm/t5-small-german

Create FAQ dataset

python faq_chatbot.py create_faq_dataset

Force rebuild:

python faq_chatbot.py create_faq_dataset --force-rebuild-dataset

Add ChatGPT FAQ data

python faq_chatbot.py add_chatgpt_data_to_faq_dataset

Create embeddings

python faq_chatbot.py create_embeddings

Force rebuild:

python faq_chatbot.py create_embeddings --force-rebuild-embeddings

Ask a question

python faq_chatbot.py ask --question "Muss eine Photovoltaikanlage gewartet werden?"

Example output:

{
    "user_question": "Muss eine Photovoltaikanlage gewartet werden?",
    "answer": "Eine Photovoltaikanlage sollte regelmäßig kontrolliert werden, damit sie zuverlässig arbeitet und mögliche Schäden früh erkannt werden.",
    "sources": ["https://example.com/faq/"]
}

Ask with debug output

python faq_chatbot.py ask_detailed --question "Muss eine Photovoltaikanlage gewartet werden?"

This prints:

  • final JSON answer,
  • raw output from QA model 1,
  • raw output from QA model 2,
  • selected prompt structure,
  • token settings,
  • optimizer output,
  • final paraphrased output.

CLI Flags

--question

Question for ask and ask_detailed.

Default:

Was ist eine Photovoltaikanlage?

Example:

python faq_chatbot.py ask --question "Was ist ein Wechselrichter?"

--amount

Number of similar FAQ entries to retrieve.

Default:

3

Example:

python faq_chatbot.py ask \
  --question "Was ist ein Batteriespeicher?" \
  --amount 5

--threshold

Minimum cosine-similarity threshold for FAQ retrieval.

Default:

0.9

Example:

python faq_chatbot.py ask \
  --question "Was ist ein Batteriespeicher?" \
  --threshold 0.8

Lower values retrieve more results. Higher values are stricter.

--prompt-choice

Prompt template selection for the optimizer model.

Default:

5

Allowed values:

0, 1, 2, 3, 4, 5, 6, 7, 8
Value Prompt structure
0 paraphrased QA output
1 question + paraphrased QA output
2 context + paraphrased QA output
3 paraphrased QA output + context
4 context + question + paraphrased QA output
5 question + context + paraphrased QA output
6 context + question
7 question + context
8 question + QA output 1 + QA output 2

Example:

python faq_chatbot.py ask \
  --question "Was ist ein Wechselrichter?" \
  --prompt-choice 7

--max-new-tokens

Maximum number of generated tokens.

Default:

120

Example:

python faq_chatbot.py ask \
  --question "Was ist ein Wechselrichter?" \
  --max-new-tokens 160

--show-warnings

Shows third-party warnings during script execution.

python faq_chatbot.py ask \
  --question "Was ist Photovoltaik?" \
  --show-warnings

--force-download-model

Forces model re-download.

python faq_chatbot.py download_all_models --force-download-model

--force-rebuild-dataset

Forces rebuilding the plain FAQ dataset.

python faq_chatbot.py create_faq_dataset --force-rebuild-dataset

--force-rebuild-embeddings

Forces rebuilding the embedded FAQ dataset.

python faq_chatbot.py create_embeddings --force-rebuild-embeddings

--skip-chatgpt-data

Only applies to run_all. Skips synthetic ChatGPT FAQ additions.

python faq_chatbot.py run_all --skip-chatgpt-data

Prompt Templates

The optimizer receives different prompt variants depending on --prompt-choice.

Value Prompt Content
0 Paraphrased QA output only
1 User question + paraphrased QA output
2 Retrieved context + paraphrased QA output
3 Paraphrased QA output + retrieved context
4 Retrieved context + user question + paraphrased QA output
5 User question + retrieved context + paraphrased QA output
6 Retrieved context + user question
7 User question + retrieved context
8 User question + QA output 1 + QA output 2

The default is:

5

This means:

user question + retrieved context + paraphrased QA output

Author

Development by Deniz Inan.

About

A local German FAQ chatbot pipeline for photovoltaic FAQ questions. The project combines a classic FAQ knowledge base with semantic retrieval and several local Hugging Face language models.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages