GitHub
Das Projekt ist in GitHub gespeichert.
Ausgangssituation
Ich möchte einen virtuellen Assistenten erstellen, der auf Informationen von mehreren Webseiten basiert. Ziel ist es, aus den Daten relevante Informationen bereitzustellen und auf Fragen der Benutzer zu antworten.
Da ich keine klaren Informationen über die Struktur der Webseiteninhalte hatte, wollte ich zunächst alle Seiten vollständig speichern und später bereinigen. Die Lösung soll dynamisch erweiterbar sein und folgende Schwerpunkte abdecken:
- Web Scraping: Automatisches Sammeln von Rohdaten von verschiedenen Webseiten.
- Speicherung: Daten in MongoDB speichern, sowohl Rohdaten als auch bereinigte Daten.
- Durchsuchbarkeit: Daten mit einem Full-Text-Index durchsuchbar machen.
- KI-Integration: Eine lokale KI-Instanz (Teuken-7B von OpenGPT-X) verwenden, die mit allen 24 europäischen Amtssprachen trainiert wurde, um Benutzerfragen in natürlicher Sprache zu beantworten.
- Benutzeroberfläche: Ein Web-Interface für eine einfache und intuitive Nutzung der Lösung.
Lösungsansatz
-
Web Scraping mit Scrapy:
- Automatisches Sammeln von HTML-Rohdaten von mehreren Webseiten.
- Dynamisches Einlesen von Start-URLs.
- Bereinigung der Daten während des Scrapings (HTML-Tags entfernen, Boilerplate entfernen, Texte kürzen).
-
Datenhaltung mit MongoDB:
- Rohdaten und bereinigte Texte wurden parallel gespeichert, um flexibel zu bleiben.
- Full-Text-Index mit deutscher Spracheinstellung eingerichtet, um die bereinigten Texte effizient zu durchsuchen.
-
KI-Integration mit Teuken-7B:
- Übergabe der MongoDB-Ergebnisse als Kontext an das Sprachmodell Teuken-7B.
- Das Modell generiert eine präzise Antwort auf die Benutzerfrage, basierend auf den bereitgestellten Daten.
-
Web-App mit Flask:
- Einfache Benutzeroberfläche, um Fragen zu stellen und KI-Antworten anzuzeigen.
- Verbindung von Flask mit MongoDB und der KI für dynamische Abfragen.
Architektur
1. Datensammlung
- Tool: Scrapy.
- Datenquellen: Liste von Start-URLs (mehrere Domains).
- Prozess:
- Besuch der Startseiten.
- Rekursive Erfassung aller Links innerhalb der erlaubten Domains.
- Speicherung der Rohdaten (HTML) und bereinigten Daten (Text).
2. Datenhaltung
- Datenbank: MongoDB.
- Struktur:
{ "url": "https://www.example.com/about", "raw_html": "...", "cleaned_text": "This is an example text.", "timestamp": "2024-11-26T12:00:00Z" }
- Full-Text-Index:
- Feld:
cleaned_text
. - Sprache: Deutsch.
- Feld:
3. Datenanalyse
- Abfragen:
- MongoDB-Textsuche mit Unterstützung für Wortstämme (z. B. „Dienstleistung“ und „Dienstleistungen“).
- Priorisierung der Ergebnisse nach Relevanz (
score
).
4. KI-Integration
- KI-Tool: Teuken-7B (OpenGPT-X).
- Prozess:
- Übergabe der MongoDB-Ergebnisse als Kontext an die KI.
- Generierung einer präzisen Antwort basierend auf der Benutzerfrage.
5. Benutzeroberfläche
- Framework: Flask.
- Funktionen:
- Eingabeformular für Benutzerfragen.
- Anzeige der KI-Antwort und der relevanten Daten.
- Einfache und intuitive Navigation.
Implementierung
1. Überblick über die Implementierungsschritte
Wir setzen die zuvor beschriebenen Schritte um:
- Web Scraping mit Scrapy: Erfassen von Daten von mehreren Webseiten.
- Datenhaltung mit MongoDB: Speicherung der Roh- und bereinigten Daten.
- Full-Text-Index: Einrichten eines deutschen Index in MongoDB.
- KI-Integration mit Teuken-7B: Verarbeitung von Benutzerfragen mit einer lokalen Instanz.
- Benutzeroberfläche mit Flask: Web-Interface zur Interaktion mit dem virtuellen Assistenten.
2. Web Scraping: FullSiteSpider
Erstelle einen Scrapy-Spider (spiders/fullsite_spider.py
), der mehrere Domains und Seiten crawlt.
import scrapy
from bs4 import BeautifulSoup
class FullSiteSpider(scrapy.Spider):
name = "fullsite"
# Liste der erlaubten Domains und Start-URLs
allowed_domains = ["example.com", "example2.com", "example3.org"]
start_urls = [
"https://www.example.com",
"https://www.example2.com",
"https://www.example3.org/start"
]
def parse(self, response):
# Rohdaten speichern
raw_html = response.body.decode('utf-8')
# Bereinigung der HTML-Daten
cleaned_text = self.clean_html(raw_html)
# Speichern der Daten
yield {
'url': response.url,
'raw_html': raw_html,
'cleaned_text': cleaned_text,
'timestamp': response.headers.get('Date', '').decode('utf-8'),
}
# Folge allen Links auf der Seite
for link in response.css('a::attr(href)').getall():
if link.startswith('http') or link.startswith('/'):
yield response.follow(link, self.parse)
def clean_html(self, html_content):
"""Bereinigt HTML und extrahiert lesbaren Text."""
soup = BeautifulSoup(html_content, 'html.parser')
text = soup.get_text(separator=" ").strip()
return " ".join(text.split())
3. Datenhaltung: MongoDB Pipeline
Speichere die gescrapten Daten direkt in MongoDB.
import pymongo
import json
class MongoPipeline:
def __init__(self):
# Konfiguration aus Datei laden
with open('config.json') as config_file:
config = json.load(config_file)
self.mongo_uri = config['MONGO_URI']
self.mongo_db = config['MONGO_DATABASE']
def open_spider(self, spider):
# Verbindung zur MongoDB herstellen
self.client = pymongo.MongoClient(self.mongo_uri)
self.db = self.client[self.mongo_db]
def close_spider(self, spider):
# Verbindung schließen
self.client.close()
def process_item(self, item, spider):
# Daten in MongoDB speichern
collection = self.db[spider.name]
collection.insert_one({
'url': item['url'],
'raw_html': item['raw_html'],
'cleaned_text': item['cleaned_text'],
'timestamp': item['timestamp'],
})
return item
Konfiguration (config.json
):
{
"MONGO_URI": "mongodb://localhost:27017",
"MONGO_DATABASE": "firmendaten"
}
Aktiviere die Pipeline in settings.py
:
ITEM_PIPELINES = {
'firmendaten.pipelines.MongoPipeline': 300,
}
4. Full-Text-Index in MongoDB
Richte den deutschen Full-Text-Index ein:
use firmendaten;
db.fullsite.createIndex(
{ cleaned_text: "text" },
{ default_language: "german" }
);
5. KI-Integration mit Teuken-7B
Implementiere die Integration in ki_helper.py
:
from openai import OpenAI
# Verbindung zur lokalen KI
local_ai = OpenAI(base_url="http://127.0.0.1:1234/v1", api_key="lm-studio")
def generate_response(question, results):
"""
Generiert eine Antwort mit der lokalen KI basierend auf den MongoDB-Ergebnissen.
"""
# Kontext aus den MongoDB-Ergebnissen erstellen
context = "\n".join(
[f"URL: {doc['url']}\nText: {doc['cleaned_text']}" for doc in results]
)
# Nachrichtenformat für die KI
messages = [
{"role": "system", "content": "Du bist ein virtueller Assistent für Firmendaten."},
{"role": "user", "content": f"Hier sind die Daten:\n{context}\n\nFrage: {question}"}
]
# Anfrage an die lokale KI
response = local_ai.chat.completions.create(
model="teuken-7b",
messages=messages,
temperature=0.7
)
return response.choices[0].message.content.strip()
6. Benutzeroberfläche mit Flask
Erstelle die Flask-App (app.py
):
from flask import Flask, render_template, request
from pymongo import MongoClient
from ki_helper import generate_response
# Flask-App initialisieren
app = Flask(__name__)
# Verbindung zur MongoDB
client = MongoClient("mongodb://localhost:27017/")
db = client["firmendaten"]
collection = db["fullsite"]
def search_mongodb(question):
"""
Führt eine Volltextsuche in MongoDB aus und gibt relevante Ergebnisse zurück.
"""
results = collection.find(
{"$text": {"$search": question}},
{"score": {"$meta": "textScore"}}
).sort("score", {"$meta": "textScore"}).limit(3)
return list(results)
@app.route('/', methods=['GET', 'POST'])
def index():
if request.method == 'POST':
question = request.form['question']
results = search_mongodb(question)
if not results:
return render_template('result.html', question=question, response="Keine relevanten Daten gefunden.")
response = generate_response(question, results)
return render_template('result.html', question=question, response=response)
return render_template('index.html')
if __name__ == '__main__':
app.run(debug=True)
HTML-Templates: Siehe GitHub im Ordner webapp.
7. Ausführung und Tests
-
Scrapy starten:
scrapy crawl fullsite
-
Flask-App starten:
python app.py
-
App im Browser öffnen:
- URL:
http://127.0.0.1:5000
- URL:
One reply on “Webseitendaten Assistent KI”
[…] möchte die Datenbank aus dem letzten Artikel Webseitendaten Assistent KI in die Cloud bringen. Die Datenmenge ist allerdings zu groß, so dass ich zuerste die Rohdaten […]