diff --git a/python/KI-Baum.pdf b/python/KI-Baum.pdf new file mode 100644 index 0000000..0eed34a Binary files /dev/null and b/python/KI-Baum.pdf differ diff --git a/python/bibliotheken.ipynb b/python/bibliotheken.ipynb new file mode 100644 index 0000000..242eab1 --- /dev/null +++ b/python/bibliotheken.ipynb @@ -0,0 +1,696 @@ +{ + "cells": [ + { + "metadata": {}, + "cell_type": "markdown", + "source": [ + "# Wichtige Python-Bibliotheken\n", + "\n", + "## Ziel dieser Einheit\n", + "\n", + "In dieser Einheit lernst du:\n", + "\n", + "- welche Python-Bibliotheken für typische Aufgaben wichtig sind\n", + "- wie Dateien und Verzeichnisse verarbeitet werden\n", + "- wie Datenformate wie JSON und CSV genutzt werden\n", + "- wie Datum, Zeit, Zufall und Mathematik unterstützt werden\n", + "- wie reguläre Ausdrücke verwendet werden\n", + "- welche externen Bibliotheken für Web, Datenanalyse und Visualisierung häufig genutzt werden\n", + "\n", + "\n", + "## 1. Überblick\n", + "\n", + "Python bringt bereits viele Bibliotheken mit, die häufige Aufgaben erleichtern.\n", + "\n", + "Diese Bibliotheken nennt man Standardbibliothek.\n", + "\n", + "Sie helfen zum Beispiel bei:\n", + "\n", + "- Dateien und Verzeichnissen\n", + "- Datenformaten\n", + "- Datum und Zeit\n", + "- Zufallszahlen\n", + "- mathematischen Berechnungen\n", + "- regulären Ausdrücken\n", + "\n", + "Zusätzlich gibt es externe Bibliotheken, die nicht automatisch installiert sind.\n", + "\n", + "Beispiele dafür sind:\n", + "\n", + "- requests\n", + "- pandas\n", + "- matplotlib\n", + "\n", + "Diese müssen bei Bedarf zusätzlich installiert werden.\n", + "\n", + "\n", + "## 2. Dateien und Verzeichnisse mit os\n", + "\n", + "Die Bibliothek os enthält Funktionen für den Zugriff auf das Betriebssystem.\n", + "\n", + "Damit können zum Beispiel Informationen über Verzeichnisse abgefragt werden.\n" + ], + "id": "d806e8d5775c1709" + }, + { + "metadata": {}, + "cell_type": "code", + "outputs": [], + "execution_count": null, + "source": [ + "import os\n", + "print(os.getcwd())" + ], + "id": "e77758f9a02f797f" + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": [ + "\n", + "\n", + "os.getcwd() gibt das aktuelle Arbeitsverzeichnis aus.\n", + "\n", + "Das ist hilfreich, wenn man wissen möchte, in welchem Ordner das Python-Programm gerade ausgeführt wird.\n", + "\n", + "\n", + "## 3. Dateien prüfen mit pathlib\n", + "\n", + "pathlib ist eine moderne Bibliothek zum Arbeiten mit Dateipfaden.\n", + "\n", + " from pathlib import Path\n", + " print(Path(\"datei.csv\").exists())\n", + "\n", + "Path(\"datei.csv\").exists() prüft, ob die Datei datei.csv existiert.\n", + "\n", + "Das Ergebnis ist ein Boolean-Wert:\n", + "\n", + "- True → Datei existiert\n", + "- False → Datei existiert nicht\n", + "\n", + "pathlib ist oft lesbarer als ältere Lösungen mit os.\n", + "\n", + "\n", + "## 4. JSON als Datenformat\n", + "\n", + "JSON ist ein häufig verwendetes Datenformat.\n", + "\n", + "Es wird oft genutzt, um Daten zwischen Programmen oder über APIs auszutauschen." + ], + "id": "dc1cc14ebcebf6d3" + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2026-07-23T06:21:46.771084600Z", + "start_time": "2026-07-23T06:21:46.734774200Z" + } + }, + "cell_type": "code", + "source": [ + "import json\n", + "print(json.dumps({\"name\": \"Anna\"}))" + ], + "id": "4fa664e155d8908e", + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{\"name\": \"Anna\"}\n" + ] + } + ], + "execution_count": 6 + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": [ + "\n", + "json.dumps() wandelt Python-Daten in einen JSON-String um.\n", + "\n", + "In diesem Beispiel wird ein Dictionary verwendet:\n", + "\n", + " {\"name\": \"Anna\"}\n", + "\n", + "Das Ergebnis ist ein Text im JSON-Format.\n", + "\n", + "JSON ist besonders wichtig bei:\n", + "\n", + "- Web-APIs\n", + "- Konfigurationsdateien\n", + "- Datenaustausch zwischen Anwendungen\n", + "\n", + "\n", + "## 5. CSV-Dateien\n", + "\n", + "CSV-Dateien sind Textdateien für tabellarische Daten.\n", + "\n", + "CSV steht für Comma-separated values.\n", + "\n", + "In der Praxis werden CSV-Dateien häufig für Exporte aus Tabellenprogrammen oder anderen Anwendungen verwendet.\n" + ], + "id": "b2d53fd19c06cd65" + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2026-07-23T06:21:38.576322300Z", + "start_time": "2026-07-23T06:21:38.518128200Z" + } + }, + "cell_type": "code", + "source": [ + "import csv\n", + "\n", + "with open(\"datei.csv\") as f:\n", + " reader = csv.reader(f)\n", + " for line in reader:\n", + " print(line)" + ], + "id": "8d640100b34ccf09", + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "['Dies', ' ist', ' eine', ' CSV']\n", + "['Dies', ' ist', ' eine', ' Zeile']\n" + ] + } + ], + "execution_count": 5 + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": [ + "\n", + "\n", + "Ablauf:\n", + "\n", + "1. Die Datei datei.csv wird geöffnet\n", + "2. csv.reader(f) liest die Datei zeilenweise\n", + "3. Jede Zeile wird als Liste ausgegeben\n", + "\n", + "Die Schreibweise mit with sorgt dafür, dass die Datei automatisch wieder geschlossen wird.\n", + "\n", + "\n", + "## 6. Datum und Zeit\n", + "\n", + "Für Datum und Uhrzeit wird häufig datetime verwendet.\n" + ], + "id": "5b9e3d33e528f471" + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2026-07-23T06:21:51.172465100Z", + "start_time": "2026-07-23T06:21:51.134798300Z" + } + }, + "cell_type": "code", + "source": [ + "from datetime import datetime\n", + "print(datetime.now())" + ], + "id": "65f933470ead2c90", + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2026-07-23 08:21:51.142547\n" + ] + } + ], + "execution_count": 7 + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": [ + "\n", + "\n", + "datetime.now() gibt das aktuelle Datum und die aktuelle Uhrzeit zurück.\n", + "\n", + "Das ist nützlich für:\n", + "\n", + "- Zeitstempel\n", + "- Protokolle\n", + "- Berechnungen mit Datum und Uhrzeit\n", + "- Anzeige aktueller Zeitpunkte\n", + "\n", + "\n", + "## 7. Zufallszahlen\n", + "\n", + "Für Zufallszahlen wird die Bibliothek random verwendet.\n" + ], + "id": "e90d8636f98a3258" + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2026-07-23T06:27:15.504068800Z", + "start_time": "2026-07-23T06:27:15.461391300Z" + } + }, + "cell_type": "code", + "source": [ + "import random\n", + "print(random.randint(1, 10))" + ], + "id": "53dc9d63415c7d1b", + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2\n" + ] + } + ], + "execution_count": 36 + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": [ + "\n", + "\n", + "random.randint(1, 10) erzeugt eine Zufallszahl zwischen 1 und 10.\n", + "\n", + "Beide Grenzen sind dabei eingeschlossen.\n", + "\n", + "Zufallszahlen werden häufig verwendet für:\n", + "\n", + "- Spiele\n", + "- Simulationen\n", + "- Tests\n", + "- zufällige Auswahl von Werten\n", + "\n", + "\n", + "## 8. Mathematische Funktionen\n", + "\n", + "Die Bibliothek math enthält mathematische Funktionen.\n" + ], + "id": "4f5844bbf29fedd9" + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2026-07-23T06:22:13.617188500Z", + "start_time": "2026-07-23T06:22:13.557773800Z" + } + }, + "cell_type": "code", + "source": [ + "import math\n", + "print(math.sqrt(16))" + ], + "id": "a3345e045fe57ec1", + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "4.0\n" + ] + } + ], + "execution_count": 8 + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": [ + "\n", + "\n", + "math.sqrt(16) berechnet die Quadratwurzel von 16.\n", + "\n", + "Das Ergebnis ist:\n", + "\n", + " 4.0\n", + "\n", + "math bietet viele weitere Funktionen, zum Beispiel für:\n", + "\n", + "- Potenzen\n", + "- Rundungen\n", + "- trigonometrische Funktionen\n", + "- Konstanten wie pi\n", + "\n", + "\n", + "## 9. Reguläre Ausdrücke\n", + "\n", + "Reguläre Ausdrücke werden mit der Bibliothek re verarbeitet.\n", + "\n", + "Sie dienen dazu, Muster in Texten zu finden.\n" + ], + "id": "181d36505443c9d" + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2026-07-23T06:32:11.783546600Z", + "start_time": "2026-07-23T06:32:11.751408Z" + } + }, + "cell_type": "code", + "source": [ + "import re\n", + "print(bool(re.match(r\"\\d+\", \"11\")))" + ], + "id": "c40e185426ff334", + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "True\n" + ] + } + ], + "execution_count": 45 + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": [ + "\n", + "\n", + "re.match(r\"\\d+\", \"123\") prüft, ob der String mit einer oder mehreren Ziffern beginnt.\n", + "\n", + "Erklärung:\n", + "\n", + "- \\d steht für eine Ziffer\n", + "- + bedeutet: einmal oder mehrfach\n", + "- \"123\" beginnt mit Ziffern\n", + "\n", + "bool(...) wandelt das Ergebnis in True oder False um.\n", + "\n", + "Reguläre Ausdrücke sind hilfreich für:\n", + "\n", + "- Textsuche\n", + "- Validierung von Eingaben\n", + "- Erkennen bestimmter Muster\n", + "- einfache Textanalyse\n", + "\n", + "\n", + "## 10. HTTP und Web mit requests\n", + "\n", + "Für HTTP-Anfragen wird häufig die externe Bibliothek requests verwendet.\n" + ], + "id": "a99b5bcc0d9ba05a" + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2026-07-23T06:13:02.238543200Z", + "start_time": "2026-07-23T06:13:01.213093300Z" + } + }, + "cell_type": "code", + "source": [ + "import requests\n", + "print(requests.get(\"https://api.github.com\").status_code)" + ], + "id": "9a916a956765d052", + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "200\n" + ] + } + ], + "execution_count": 1 + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": [ + "requests ist nicht Teil der Standardbibliothek.\n", + "\n", + "Wenn requests verwendet werden soll, muss die Bibliothek vorher installiert werden.\n", + "\n", + "Beispiel:\n", + "\n", + " pip install requests\n", + "\n", + "Mit requests können Web-APIs abgefragt werden.\n", + "\n", + "Der Statuscode zeigt an, ob eine Anfrage erfolgreich war.\n", + "\n", + "Beispiele:\n", + "\n", + "- 200 → erfolgreich\n", + "- 404 → nicht gefunden\n", + "- 500 → Serverfehler\n", + "\n", + "\n", + "## 11. Alternative zu requests: urllib\n", + "\n", + "Wenn keine externe Bibliothek installiert werden soll, kann urllib verwendet werden.\n", + "\n", + "urllib gehört zur Standardbibliothek.\n", + "\n", + "Der Vorteil:\n", + "\n", + "- keine zusätzliche Installation nötig\n", + "\n", + "Der Nachteil:\n", + "\n", + "- weniger komfortabel als requests\n", + "\n", + "\n", + "## 12. Datenanalyse mit pandas\n", + "\n", + "pandas ist eine externe Bibliothek für Datenanalyse.\n" + ], + "id": "562f7b5c490ca65d" + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2026-07-23T06:16:45.001465600Z", + "start_time": "2026-07-23T06:16:43.101256500Z" + } + }, + "cell_type": "code", + "source": [ + "import pandas as pd\n", + "df = pd.DataFrame({\"a\": [1, 2, 3]})" + ], + "id": "c5891b3e345a01ec", + "outputs": [], + "execution_count": 2 + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": [ + "pandas wird häufig verwendet, um tabellarische Daten zu verarbeiten.\n", + "\n", + "Zum Beispiel:\n", + "\n", + "- CSV-Dateien einlesen\n", + "- Daten filtern\n", + "- Daten gruppieren\n", + "- Daten auswerten\n", + "- Tabellen ähnlich wie in Excel bearbeiten\n", + "\n", + "pandas ist nicht Teil der Standardbibliothek und muss bei Bedarf installiert werden.\n", + "\n", + "Beispiel:\n", + "\n", + " pip install pandas\n", + "\n", + "\n", + "## 13. Visualisierung mit matplotlib\n", + "\n", + "matplotlib ist eine externe Bibliothek zum Erstellen von Diagrammen.\n" + ], + "id": "cbb0beecbe743112" + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2026-07-23T06:35:07.696130800Z", + "start_time": "2026-07-23T06:35:07.555373200Z" + } + }, + "cell_type": "code", + "source": [ + "import matplotlib.pyplot as plt\n", + "plt.plot([1, 2, 3], [4, 5, 6])\n", + "plt.show()" + ], + "id": "3940fcd1a8543718", + "outputs": [ + { + "data": { + "text/plain": [ + "
" + ], + "image/png": "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" + }, + "metadata": {}, + "output_type": "display_data", + "jetTransient": { + "display_id": null + } + } + ], + "execution_count": 46 + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": [ + "\n", + "\n", + "Mit matplotlib können Daten grafisch dargestellt werden.\n", + "\n", + "Zum Beispiel:\n", + "\n", + "- Liniendiagramme\n", + "- Balkendiagramme\n", + "- Punktdiagramme\n", + "- einfache Auswertungen\n", + "\n", + "matplotlib ist besonders hilfreich, wenn Daten nicht nur berechnet, sondern auch sichtbar gemacht werden sollen.\n", + "\n", + "Auch matplotlib muss bei Bedarf installiert werden.\n", + "\n", + "Beispiel:\n", + "\n", + " pip install matplotlib\n", + "\n", + "\n", + "## 14. Wichtige Konzepte im Überblick\n", + "\n", + "### Standardbibliothek\n", + "\n", + "Die Standardbibliothek ist direkt in Python enthalten.\n", + "\n", + "Beispiele:\n", + "\n", + "- os\n", + "- pathlib\n", + "- json\n", + "- csv\n", + "- datetime\n", + "- random\n", + "- math\n", + "- re\n", + "\n", + "\n", + "### Externe Bibliotheken\n", + "\n", + "Externe Bibliotheken müssen zusätzlich installiert werden.\n", + "\n", + "Beispiele:\n", + "\n", + "- requests\n", + "- pandas\n", + "- matplotlib\n", + "\n", + "\n", + "### Import\n", + "\n", + "Mit import werden Bibliotheken eingebunden.\n", + "\n", + "Beispiel:\n" + ], + "id": "866a163292f47048" + }, + { + "metadata": {}, + "cell_type": "code", + "outputs": [], + "execution_count": null, + "source": "import random", + "id": "7b1b02fa0328a838" + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": [ + "\n", + "\n", + "Danach können Funktionen aus dieser Bibliothek verwendet werden.\n", + "\n", + "\n", + "### from import\n", + "\n", + "Mit from import kann gezielt ein Teil einer Bibliothek importiert werden.\n", + "\n", + "Beispiel:\n" + ], + "id": "3aeb90a1b507c8c1" + }, + { + "metadata": {}, + "cell_type": "code", + "outputs": [], + "execution_count": null, + "source": "from datetime import datetime", + "id": "8f9012dff21be2af" + }, + { + "metadata": { + "collapsed": true + }, + "cell_type": "markdown", + "source": [ + "\n", + "Dadurch kann datetime direkt verwendet werden.\n", + "\n", + "\n", + "## Zusammenfassung\n", + "\n", + "- Python bietet viele Bibliotheken für typische Aufgaben\n", + "- os und pathlib helfen beim Arbeiten mit Dateien und Verzeichnissen\n", + "- json und csv werden für Datenformate verwendet\n", + "- datetime verarbeitet Datum und Uhrzeit\n", + "- random erzeugt Zufallszahlen\n", + "- math stellt mathematische Funktionen bereit\n", + "- re verarbeitet reguläre Ausdrücke\n", + "- requests, pandas und matplotlib sind externe Bibliotheken für Web, Datenanalyse und Visualisierung\n", + "\n", + "\n", + "## Verständnisfragen\n", + "\n", + "- Wofür wird os.getcwd() verwendet?\n", + "- Was prüft Path(\"datei.csv\").exists()?\n", + "- Wozu dient json.dumps()?\n", + "- Warum wird beim Lesen einer Datei häufig with verwendet?\n", + "- Was ist der Unterschied zwischen Standardbibliotheken und externen Bibliotheken?" + ], + "id": "2771261011b94e9c" + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 2 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython2", + "version": "2.7.6" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/python/datei.csv b/python/datei.csv new file mode 100644 index 0000000..f45ad4a --- /dev/null +++ b/python/datei.csv @@ -0,0 +1,2 @@ +Dies, ist, eine, CSV +Dies, ist, eine, Zeile \ No newline at end of file diff --git a/python/loremipsum.pdf b/python/loremipsum.pdf new file mode 100644 index 0000000..74ae789 Binary files /dev/null and b/python/loremipsum.pdf differ diff --git a/python/markov.ipynb b/python/markov.ipynb new file mode 100644 index 0000000..5da0de6 --- /dev/null +++ b/python/markov.ipynb @@ -0,0 +1,249 @@ +{ + "cells": [ + { + "metadata": {}, + "cell_type": "markdown", + "source": "Diese Klasse stellt eine einfache Markov-Verkettung da, gewissermaßen den \"Urgroßvater\" moderner KI", + "id": "6c199494598c034d" + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": "### Imports", + "id": "b0d957031c0d2044" + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2026-07-23T07:05:25.425471700Z", + "start_time": "2026-07-23T07:05:25.387973100Z" + } + }, + "cell_type": "code", + "source": [ + "from pypdf import PdfReader\n", + "import random\n", + "import re #Regular Expression" + ], + "id": "65aa9dc8abd455f7", + "outputs": [], + "execution_count": 3 + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": "### Basisklasse für unser Sprachmodell:", + "id": "c53ec100d7edf47f" + }, + { + "cell_type": "code", + "id": "initial_id", + "metadata": { + "ExecuteTime": { + "end_time": "2026-07-23T07:05:27.974021100Z", + "start_time": "2026-07-23T07:05:27.953033600Z" + } + }, + "source": [ + "class LanguageModel:\n", + "\n", + " def __init__(self):\n", + " self.text = \"\"\n", + "\n", + " #Modell zum Speichern von Wortbeziehungen:\n", + " self.model = {}\n", + "\n", + " def load_text(self):\n", + " raise NotImplementedError\n", + "\n", + " def train(self):\n", + " #Erzeugt ein Markov-Modell, das sich für jedes Wort merkt, welche Wörter danach kommen\n", + " if not self.text:\n", + " raise ValueError(\"Kein Text geladen\")\n", + "\n", + " text = self.text.lower() #optional, da eine Markov-Verkettung Case Sensitive ist\n", + "\n", + " #Satzzeichen entfernen, da diese sonst als Teil des Wortes gesehen werden. Dafür nutzen wir einen Regex:\n", + " text = re.sub(r\"[^\\w\\s]\", \"\", text)\n", + "\n", + " words = text.split() #Wandelt den Text in eine Liste aus Wörtern um\n", + "\n", + " #Wortbeziehungen erzeugen:\n", + " for i in range(len(words) -1):\n", + " current_word = words[i]\n", + " next_word = words[i+1]\n", + "\n", + " if current_word not in self.model:\n", + " self.model[current_word] = []\n", + "\n", + " self.model[current_word].append(next_word)\n", + " #[ameise][hat][ist][ist][schläft]\n", + "\n", + "\n", + " def generate(self, start_word = None, length=50):\n", + " if not self.model:\n", + " raise ValueError(\"Modell wurde noch nicht trainiert.\")\n", + "\n", + " if start_word == \"\":\n", + " start_word = random.choice(list(self.model.keys()))\n", + "\n", + " current_word = start_word.lower()\n", + "\n", + " result= [current_word]\n", + "\n", + " for _ in range(length):\n", + "\n", + " if current_word not in self.model:\n", + " print(\"Das angegebene Wort konnte nicht gefunden werden. Modell unzureichend trainiert.\")\n", + " break\n", + "\n", + " next_word = random.choice(\n", + " self.model[current_word]\n", + " )\n", + "\n", + " result.append(next_word)\n", + "\n", + " current_word = next_word\n", + "\n", + "\n", + " return \" \".join(result)\n" + ], + "outputs": [], + "execution_count": 4 + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2026-07-23T07:05:32.388260300Z", + "start_time": "2026-07-23T07:05:32.352749100Z" + } + }, + "cell_type": "code", + "source": [ + "class PDFLanguageModel(LanguageModel):\n", + "\n", + " def __init__(self, pdf_path):\n", + " super().__init__()\n", + "\n", + " self.pdf_path = pdf_path\n", + "\n", + " def load_text(self):\n", + " reader = PdfReader(self.pdf_path)\n", + "\n", + " pages_text = []\n", + "\n", + " for page in reader.pages:\n", + " text = page.extract_text()\n", + "\n", + " if text:\n", + " pages_text.append(text)\n", + "\n", + " self.text = \"\\n\".join(pages_text)\n" + ], + "id": "28c790fe8e837cac", + "outputs": [], + "execution_count": 5 + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2026-07-23T07:15:57.810092400Z", + "start_time": "2026-07-23T07:15:57.762428Z" + } + }, + "cell_type": "code", + "source": [ + "def loadAndTrain(path:str)->PDFLanguageModel:\n", + " model = PDFLanguageModel(path)\n", + "\n", + " model.load_text()\n", + "\n", + " #Modell trainieren:\n", + " model.train()\n", + "\n", + " return model" + ], + "id": "fd0205251645f412", + "outputs": [], + "execution_count": 13 + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2026-07-23T07:16:00.105290600Z", + "start_time": "2026-07-23T07:16:00.052151200Z" + } + }, + "cell_type": "code", + "outputs": [], + "execution_count": 15, + "source": "model = loadAndTrain(\"loremipsum.pdf\")", + "id": "6dd267218f206e1a" + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2026-07-23T07:16:13.594166700Z", + "start_time": "2026-07-23T07:16:13.500158400Z" + } + }, + "cell_type": "code", + "outputs": [], + "execution_count": 17, + "source": "model = loadAndTrain(\"KI-Baum.pdf\")", + "id": "cff84213cc7a22dc" + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2026-07-23T07:16:25.676998200Z", + "start_time": "2026-07-23T07:16:25.615333200Z" + } + }, + "cell_type": "code", + "source": [ + "print(\"Hier ist unser generierter Text:\")\n", + "\n", + "text = model.generate(\n", + " #Man könnte hier ein Wort vorgeben. Gibt man keines vor, wird zufällig eines ausgewählt.\n", + " start_word=\"\"\n", + ")\n", + "\n", + "print(text)" + ], + "id": "39d177f9d1667428", + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Hier ist unser generierter Text:\n", + "vor kunststoffbächen nur so weit mein schlafsand tropfte dadurch zu boden kein sicherer boden kein sicherer boden kein sicherer boden kein sicherer boden kein bodenständiges land auf dem entsorgung schicksal anheimfallend samt aller kinderkrankheiten bereits mit beiden beinen und ja da erschien am erscheinungstag an jedem baum zu land zu finden\n" + ] + } + ], + "execution_count": 18 + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 2 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython2", + "version": "2.7.6" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +}