-
Notifications
You must be signed in to change notification settings - Fork 628
Description
simple_chatbot.py
Een compacte 'AI' chatbot: TF-IDF retrieval + eenvoudige leerfunctie.
Scherp, voorspellend en makkelijk uit te breiden.
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics.pairwise import cosine_similarity
import numpy as np
import readline # handig voor commandline historie op unix-achtige systemen
class SimpleChatBot:
def init(self, pairs=None):
"""
pairs: lijst van (user_tekst, bot_antwoord) tuples
De bot zoekt in de user_tekst voorbeelden naar de meest vergelijkbare zin
en geeft het corresponderende bot_antwoord terug.
"""
self.pairs = pairs or []
self._build_vectorizer()
def _build_vectorizer(self):
# Corpus = alle user-zinnen in de dataset
self.user_texts = [p[0] for p in self.pairs]
if self.user_texts:
self.vectorizer = TfidfVectorizer(ngram_range=(1,2), min_df=1)
self.user_tfidf = self.vectorizer.fit_transform(self.user_texts)
else:
# lege vectorizer (voorkomt errors voor nog geen data)
self.vectorizer = TfidfVectorizer(ngram_range=(1,2), min_df=1)
self.user_tfidf = None
def respond(self, text, top_k=1):
"""
Geef een antwoord op 'text'. Als er geen dataset is, antwoord simpele fallback.
top_k bepaalt hoeveel beste matches worden overwogen voor randomisatie (optioneel).
"""
text = text.strip()
if not text:
return "Zeg iets, of zwijg plechtig. (Maar zeg iets.)"
# Als we nog geen voorbeelden hebben:
if not self.user_texts:
return "Ik ben nog leerling. Leer me iets door 'learn: jouw zin => mijn antwoord' te typen."
# Transformeer en vergelijk
x = self.vectorizer.transform([text])
sims = cosine_similarity(x, self.user_tfidf).flatten()
best_idx = np.argmax(sims)
best_score = sims[best_idx]
# Drempel: als geen goede match, geef fallback
if best_score < 0.25:
return ("Dat is intrigerend maar ik heb daar geen goede zet voor. "
"Vertel me wat het betekent of leer me met: learn: vraag => antwoord")
# soms wil je variatie: kies uit de top_k best overeenkomende antwoorden
if top_k > 1:
top_indices = np.argsort(sims)[-top_k:]
chosen = np.random.choice(top_indices)
return self.pairs[chosen][1]
else:
return self.pairs[best_idx][1]
def learn_from_pair(self, user_text, bot_answer):
"""Voeg een nieuw voorbeeld toe en rebuild de vectorizer."""
self.pairs.append((user_text.strip(), bot_answer.strip()))
self._build_vectorizer()
def save_to_file(self, path):
"""Sla de dataset op (eenvoudig formaat)."""
with open(path, "w", encoding="utf-8") as f:
for u, b in self.pairs:
# tab-gescheiden, simpele escaping
u_escaped = u.replace("\t", " ").replace("\n", " ")
b_escaped = b.replace("\t", " ").replace("\n", " ")
f.write(u_escaped + "\t" + b_escaped + "\n")
def load_from_file(self, path):
"""Laad dataset van disk."""
new_pairs = []
try:
with open(path, "r", encoding="utf-8") as f:
for line in f:
if not line.strip(): continue
parts = line.rstrip("\n").split("\t")
if len(parts) >= 2:
new_pairs.append((parts[0], "\t".join(parts[1:])))
self.pairs = new_pairs
self._build_vectorizer()
except FileNotFoundError:
print(f"Geen dataset gevonden op {path}; start met lege dataset.")
def demo():
# Voorbeeld dataset: voeg hier je eigen moeilijke, schaakachtige zinnen toe.
initial_pairs = [
("hallo", "Salve. Wat wens je te weten?"),
("hoe gaat het", "Adequaat. En bij jou?"),
("wat is schaak", "Schaak is een strategisch bordspel waarin anticipatie essentieel is."),
("leer me schaken", "Begin met de basisprincipes: ontwikkel stukken, controleer centrum, en vermijd vroegtijdige koningszwakte."),
("vertel een mop", "Twee torens lopen naar het bord... de rest is vertelling."),
("bedankt", "Graag gedaan. Mijn circuits glimmen van voldoening.")
]
bot = SimpleChatBot(initial_pairs)
bot.load_from_file("my_bot_memory.txt") # optioneel: laad eerdere leerdata
print("Slimme ChatBot (TF-IDF retrieval). Type 'quit' om te stoppen.")
print("Leer de bot nieuw gedrag met: learn: jouw vraag => mijn antwoord")
print("Sla geheugen op met: save")
print("Laad geheugen met: load")
print("-" * 60)
while True:
try:
user = input("Jij: ").strip()
except (KeyboardInterrupt, EOFError):
print("\nEinde. Memory wordt automatisch opgeslagen.")
bot.save_to_file("my_bot_memory.txt")
break
if not user:
continue
if user.lower() in ("quit", "exit", "stop"):
print("Bot: Tot ziens. Je zet was goed, je eindezelfde mind ook.")
bot.save_to_file("my_bot_memory.txt")
break
# leer commando: learn: vraag => antwoord
if user.lower().startswith("learn:"):
payload = user[6:].strip()
if "=>" in payload:
q, a = payload.split("=>", 1)
bot.learn_from_pair(q.strip(), a.strip())
print("Bot: Acknowledged. Ik heb die zet opgeslagen.")
else:
print("Bot: Foutief leerformaat. Gebruik: learn: vraag => antwoord")
continue
if user.lower() == "save":
bot.save_to_file("my_bot_memory.txt")
print("Bot: geheugen opgeslagen naar my_bot_memory.txt")
continue
if user.lower() == "load":
bot.load_from_file("my_bot_memory.txt")
print("Bot: geheugen geladen (my_bot_memory.txt)")
continue
# normaal gesprek
reply = bot.respond(user, top_k=3)
print("Bot:", reply)
if name == "main":
demo()