Zum Inhalt springen

Programmierung eines Chatbots


Empfohlene Beiträge

Geschrieben

Also hallo erstmal

Ich stelle mich wohl hier im ersten Beitrag in diesem Forum mal kurz vor: Ich bin Jonathan, komme aus Hessen bin jetzt 15 Jahre alt und mache schon ne ganze Weile lang in meiner Freizeit Sachen wie Webdesign oder Programmieren. Bisher kann ich relativ fehlerfrei und gut PHP, (HTML und Konsorten lasse ich hier mal weg ) und habe schon ein paar Erfahrungen in C++ gemacht. Wobei ich schon sagen muss, dass C++ echt nicht ohne ist. Als grafische Oberfläche für C++ habe ich QT verwendet (bzw. verwende ich das auch noch )... Ich arbeite seit 2 Jahren komplett unter Linux: Kubuntu 8.10 (KDE 4.2.0).

So, genug der Vorstellung, mal kurz zu meiner Frage. Ich würde gerne mit einem ChatBot anfangen. Das ganze schwebt mir jetzt schon eine ganze Weile im Kopf herum, also keine Idee, die aus reiner "Das wäre aber cool" Laune heraus geboren wurde. Das ist einfach eine Sache (so in Richtung KI), die mich wirklich interessiert und an der ich glaube ich auch eine Menge lernen kann. Ich habe auch schon Freunde gefunden, die sich auch dafür interessieren und auch daran mithelfen würden, wenn das ganze soweit ist, dass es mit Inhalt befüllt werden kann. Das ganze soll in Richtung von "Brain" (Klick mich) gehen.

Ich habe sogar schon mit einem ersten Versuch begonnen und habe ein komplett auf RegEx basierendes C++ Programm mit QT hinbekommen (Arbeitszeit etwa 2 Tage), die mir schon mal so einen groben Überblick über Aufwand und Arbeitsweise von so einem Program geben sollte. Bis jetzt kann dieses Programm etwa 40 verschiedene Sätze erkennen, beantworten und in einer Unterhaltung fortführen. Allerdings bin ich mir sicher, dass dieses Programm komplett in die falsche Richtung führt und frage daher einfach mal so bevor ich wirklich versuche damit anzufangen hier so ein paar grundlegende Dinge

Also mal kurz ein Mini-Konzept zum Aufbau: Das Programm an sich soll nur wenig Code enthalten. Damit meine ich nicht wenig im eigentlich Sinne, sondern eher, dass der Code nur zur Verarbeitung der Eingabe taugen soll. Für den eigentlichen inhaltlichen Teil will ich "Module" verwenden. Also Module, in welchen Text-dialoge und Muster für die Eingabe (RegEx??) gespeichert sind und welche bei jedem Start des Programmes geladen werden. Dies hätte den Vorteil, dass das Programm jederzeit einfach erweiterbar wäre und der inhaltliche Teil ganz klar vom technischen Teil getrennt wäre. Innerhalb der Module sollen die Muster und Antworten etc. in einer Art XML-Datei gespeichert werden, also Tag-basiert.

Dass so ein Projekt nicht einfach ist bzw. werden wird und sowas mitunter viele Monate oder Jahre in Anspruch nimmt ist mir klar. Und dass ich dadurch "das Rad neu erfinde" ist mir auch klar. Trotzdem würde ich gerne mit dem Projekt zum ersten Mal in etwas "größeres" einsteigen, weg von Websites oder einfachen "Installern" oder sonst sowas, womit man halt in den ganzen Büchern anfängt.

Nun ist meine Frage folgende: Könnt ihr mir Tipps geben, wo ich da am besten ansetze? Ob C++ dafür geeignet ist oder ich mir vorher besser eine andere Programmiersprache anschaue... Oder wie ich das am besten mit den Modulen regeln bzw. ob ihr da etwas an dem Plan verändern würdet? Ich bin über alle Infos, Erfahrungen, etc. sehr froh, ich will schon, dass das kein Schuss ins Leere wird und hinterher vielleicht sogar was brauchbares bei raus kommt (wobei ja die meisten ChatBots doch eher Spielereien sind)...

Vielen, vielen Dank schon Mal im Voraus,

Jonathan

  • Antworten 58
  • Erstellt
  • Letzte Antwort

Top-Benutzer in diesem Thema

Geschrieben

Vom Grundgedanken hört sich das schonmal recht vernünftig an.

Die Frage ist natürlich wie weit der Bot wirklich chatten können soll. Realistische Unterhaltungen würde ich jetzt mal als ziemlich utopisch einstufen ;)

Aber du könntest ja erstmal mit einem einfachen Bot anfangen der bestimmte Befehle entgegennehmen kann. Oder zum Beispiel einen Quiz Bot machen der den Teilnehmern fragen stellt die sie beantworten müssen, die Antworten erfasst und die Punkte der Mitspieler zählt.

Geschrieben
...Das ist einfach eine Sache (so in Richtung KI), die mich wirklich interessiert und an der ich glaube ich auch eine Menge lernen kann...

...Realistische Unterhaltungen würde ich jetzt mal als ziemlich utopisch einstufen ;)...

Ist das nicht der Sinn einer KI?

Geschrieben

Hallo noch einmal :)

Erst Mal vielen Dank für alle bisherigen Antworten!

Um hier noch ein paar Fragen aus der Welt zu schaffen: Es soll sich vorerst um ein Eigenständiges Programm handeln, also der Benutzer führt es aus, erhält eine grafische Oberfläche mit Chatfenster und Eingabefeld. Also ist das Programm (vorerst) nicht für die Einsetzung in IRC-Channels oder Sonstigem gedacht. Auf die Idee war ich ursprünglich im Gimpforum(.de) gekommen. Dort stellten (wie in jedem anderen Forum wohl auch ;)) mindestens 70% der neuen User die selbe Frage, ohne Suchfunktion, ohne vorher zu googlen. So ist das halt. Ich hatte die Idee, eine automatisierte Antworten-Funktion zu bauen. Also dass der Beitrag des Users genau auf Schlüsselwörter und Frageformen hin analysiert wird und der Bot hinterher eine Antwort auf die Frage schreibt. Daraufhin habe ich mich informiert und bin generell auf Bots und Chatbots gestoßen. Ich habe lange versucht, FreeHAL zum Laufen zu bringen, was jedoch leider nicht hingehauen hat... Denn das geht genau in die Richtung, die ich suche.

Nun bleibt die Frage noch offen: Mit welcher Programmiersprache lässt sich dies denn am besten Verwirklichen? Was da z.B. sehr praktisch wäre (gibt es ja unter PHP :D) wäre eine Art "include(...);", um andere Code-Dateien während der Laufzeit einzubinden. Das ganze mit den Header-Dateien und Klassen bei C++ ist ja natürlich sehr schön und fortschrittlich, aber auch oft unnötig umständlich.

Wäre also wieder über Tipps und Anregungen dankbar,

Jonathan :)

Geschrieben

KI ist immer so ne Sache... Wirkliche KI gibt es nicht (wird es nie geben?). In soweit ist das Deffinitionssache. Es gibt wohl Leute, die bezeichnen einen Bot, der selbstständig lernen kann als KI. Andere bezeichnen einen Bot, der komplexe Konversationen führen kann als KI. Manchen reicht es schon, wenn ein Bot 243 und 174 zusammenzählen kann. Der wirklichen KI kann man sich zur Zeit nur annähren, und die Messlatte für ein Programm in diese Richtung setzt doch letztendlich jeder anders an.

Im übrigen hatte ich noch etwas bei meinem Modul-Konzept vergessen. Um wirklich auch Unterhaltungen über zwei Sätze hinweg führen zu können, hatte ich mir zwei kleiner Tricks überlegt. Trick Nummer 1: Zur Erinnerung an vergangene Diskussionen wird (außer der Speicherung des Wissens) einfach der Verlauf durchsucht und im Zweifelsfall Informationen (wie z.B. Name der Person) daraus entnommen. Das ist nicht wirklich eine interessante Idee, um den Programm "Erinnerungen" zu geben, aber ich denke, sie wird funktionieren. Und Trick Nr. 2: Angenommen der Computer stellt eine Frage (Beispiel: Wie geht es dir?). Diese Frage hat einen bestimmten Code. Eine Variable wird mit diesem Code befüllt und anschließend Die Usereingabe erwartet. Antwortet der User meinetwegen etwas wie "gut", so werden nicht erst alle Module nach dem Wort "gut" durchsucht und meinetwegen etwas wie "Was ist denn gut?" ausgegeben, sondern es wird registriert, dass der User auf diese Frage antwortet, indem überprüft wird, ob der Code in der Variable auf eine Frage, die zu der Antwort "Gut" passt, hindeutet. Das ganze System habe ich so in meinem Test-Bot schon ausprobiert und es hat nahezu perfekt das geliefert, was ich wollte: Nämlich Konversationen über das "Frage->Antwort" Schema hinaus. Dadurch wurde z.B. so etwas möglich:

Bot: Wie geht es dir? (Setze Variable int i = 5)

User: Naja, ich hatte schon bessere Tage.

----> Programm findet heraus, dass diese Antwort tatsächlich zu der Frage 5 passt, und antwortet entsprechend. int i = 6)

Bot: Ohje, das klingt ja nicht so gut. Was ist denn passiert, kann ich dir helfen?

User: Nein, ich denke nicht.

---> Antwort passt zu Frage 6, Es wird die entsprechende Antwort angegeben.

Bot: Ok, das ist auch kein Problem.

Zusammen mit der Speicherung des Verlaufes könnte es so auch möglich gemacht werden, solche Gespräche fortzuführen. Dafür würde der jeweilge Fragecode im Verlauf mit gespeichert werden.

Naja, aber ob das so die beste Methode ist... Wäre über Anregungen wieder sehr dankbar :)

Geschrieben

Du: ...Realistische Unterhaltungen würde ich jetzt mal als ziemlich utopisch einstufen ;)...

Ich: Ist das nicht der Sinn einer KI?

Du: Das kommt drauf an was die KI machen soll...

Hast Dur Dir die Antwort im gegebenen Kontext nicht bereits im ersten Post gegeben?

Fakt ist, es gibt sehr wohl relativ eng gesteckte Szenarien, wo durchaus eine realistische Unterhaltung vorstellbar ist. Zum Beispiel als interaktives Menu/Suche. Supportweichen, ...

Realistischer SmallTalk ist aber zugegeben von einer Maschine nicht zu erwarten. Aber von mir auch nicht :D

Geschrieben
Du: ...Realistische Unterhaltungen würde ich jetzt mal als ziemlich utopisch einstufen ;)...

Ich: Ist das nicht der Sinn einer KI?

Du: Das kommt drauf an was die KI machen soll...

Hast Dur Dir die Antwort im gegebenen Kontext nicht bereits im ersten Post gegeben?

Nein denn wie Mefisto treffend erläutert hat kann eine KI vieles sein.

Fakt ist, es gibt sehr wohl relativ eng gesteckte Szenarien, wo durchaus eine realistische Unterhaltung vorstellbar ist. Zum Beispiel als interaktives Menu/Suche. Supportweichen, ...

Klar vorstellbar und machbar ist da vieles, die Frage ist aber doch was in diesem Rahmen für Mefisto machbar ist.

Realistischer SmallTalk ist aber zugegeben von einer Maschine nicht zu erwarten.

Prinzipiell würde ich das nicht ausschließen, allerdings ist dafür wohl ein gigantisch größeres Maß an Aufwand für notwendig :)

@Mefisto

Du solltest ersteinmal unabhängig von irgendwelchen Programmiersprachen ausarbeiten wie *genau* das Programm arbeiten soll. Was es mit den Benutzereingaben macht, wie es sie analysiert, ablegt abruft und so weiter.

Danach kannst du dir überlegen womit du das am Einfachsten umsetzt.

Wenn du dich jetzt einfach so hinsetzt und rumprobierst wird das Projekt relativ schnell in der Tonne landen...

Geschrieben
Du solltest ersteinmal unabhängig von irgendwelchen Programmiersprachen ausarbeiten wie *genau* das Programm arbeiten soll. Was es mit den Benutzereingaben macht, wie es sie analysiert, ablegt abruft und so weiter.

Danach kannst du dir überlegen womit du das am Einfachsten umsetzt.

Wenn du dich jetzt einfach so hinsetzt und rumprobierst wird das Projekt relativ schnell in der Tonne landen...

Jup, richtig, dass ist mir sehr schnell bei meinem ersten Projekt aufgefallen. Daher habe ich es dann zum "Rumprobier-Projekt" erklärt ;)... Gerade deswegen bin ich hier schon die ganze Zeit eifrig am Ideen posten, natürlich ist das längst nicht alles, aber mit denen bisher hier verewigten lässt sich ja schon Mal ein Anfang machen. Ich fänd's daher auch nett, wenn ihr noch kurz was zu diesen Sagen könntet, was ihr daran ändern würdet, natürlich sind auch eigene Idee willkommen! Ich will das ganze hinterher ja auch nicht vermarkten :D Es soll halt ein Projekt werden, an dem ich (und bzw. die Leute, die daran mitmachen wollen) etwas lernen (Logik hiner einer Programmiersprache, komplexe Programme über 4 oder 5 Dateien hinaus, etc.)...

Natürlich ist das bisher hier geschriebene auch sehr hilfreich und motivierend, aber wenn ich das richtig sehe kam bisher auch noch nichts zu den gemachten Ideen von mir. Wie gesagt, eure Meinung darüber wäre super :)

Liebe Grüße und wie immer danke schon Mal,

Jonathan :)

Geschrieben

Nutze für so etwas keine imperative Sprache sondern eine logische. Prolog mit DCG würde sich anbieten. Somit die Programmlogik in Prolog, GUI z.b. in C++. Wenn Du Prolog mit einer Datenbank verbindest, dann kannst Du auch das Wissen erweitern. Als Algorithmus kann mit einem "Pattern Matching" beginnen wie es z.B. in ELIZA ? Wikipedia umgesetzt wurde. Wenn Du Pattern Matching, mit DCG (Definite Clause Grammar) und ggf morphologischer Analyse / Verarbeitung kombinierst, dann solltest Du einfache Satzkonstruktionen verarbeiten können

Phil

Geschrieben (bearbeitet)
Hallo noch einmal :)

Erst Mal vielen Dank für alle bisherigen Antworten!

Um hier noch ein paar Fragen aus der Welt zu schaffen: Es soll sich vorerst um ein Eigenständiges Programm handeln, also der Benutzer führt es aus, erhält eine grafische Oberfläche mit Chatfenster und Eingabefeld. Also ist das Programm (vorerst) nicht für die Einsetzung in IRC-Channels oder Sonstigem gedacht. Auf die Idee war ich ursprünglich im Gimpforum(.de) gekommen. Dort stellten (wie in jedem anderen Forum wohl auch ;)) mindestens 70% der neuen User die selbe Frage, ohne Suchfunktion, ohne vorher zu googlen. So ist das halt. Ich hatte die Idee, eine automatisierte Antworten-Funktion zu bauen. Also dass der Beitrag des Users genau auf Schlüsselwörter und Frageformen hin analysiert wird und der Bot hinterher eine Antwort auf die Frage schreibt. Daraufhin habe ich mich informiert und bin generell auf Bots und Chatbots gestoßen. Ich habe lange versucht, FreeHAL zum Laufen zu bringen, was jedoch leider nicht hingehauen hat... Denn das geht genau in die Richtung, die ich suche.

Hallo Mesfisto,

FreeHAL ist vorhin in einer neuen Version erschienen, vielleicht hilft dir ja auch der Code im Subversion-Repository weiter. Zum Kompilieren braucht man nur CMake zu installieren, "cmake .", "make" auszuführen und dann "./hal2009" zu starten.

(Warum bin ich hier? Weil ich öfters neue Ideen für FreeHAL suche)

Gruß

Tobias Schulz (Admin FreeHAL Projekt)

Bearbeitet von Tobias Schulz
Geschrieben

Wow, der Admin von FreeHal... Ich fühle mich ja echt geehrt :)

Danke also auf jeden Fall schon Mal für die Mühe :)

Auch die 108-Version (precompiled für ubuntu) funktioniert bei mir leider noch nicht. Es gibt da beim "make" eine Menge fehler. Außerdem scheint mir wohl eine "libparrot.so" zu fehlen, die ja aber eigentlich installiert ist... sonderbar... Für den Fall, dass du mit der Ausgabe was anfangen kannst, poste ich sie hier einfach mal:

jonathan@jonathan-desktop:~/Applications/freehal-r108-ubuntu$ cmake .

-- The C compiler identification is GNU                              

...                                          

-- Build files have been written to: /home/jonathan/Applications/freehal-r108-ubuntu

jonathan@jonathan-desktop:~/Applications/freehal-r108-ubuntu$ make                  

Scanning dependencies of target hal2009                                             

[  4%] Building C object CMakeFiles/hal2009.dir/hal2009-main.c.o                                                                             

In file included from /home/jonathan/Applications/freehal-r108-ubuntu/hal2009-sql.c:22,                                                      

                 from /home/jonathan/Applications/freehal-r108-ubuntu/hal2009.h:131,                                                         

                 from /home/jonathan/Applications/freehal-r108-ubuntu/hal2009-main.c:22:                                                     

/home/jonathan/Applications/freehal-r108-ubuntu/hal2009-sql-sqlite.c:22:21: error: sqlite3.h: No such file or directory                      

In file included from /home/jonathan/Applications/freehal-r108-ubuntu/hal2009-sql.c:22,                                                      

                 from /home/jonathan/Applications/freehal-r108-ubuntu/hal2009.h:131,                                                         

                 from /home/jonathan/Applications/freehal-r108-ubuntu/hal2009-main.c:22:                                                     

/home/jonathan/Applications/freehal-r108-ubuntu/hal2009-sql-sqlite.c:24: Fehler: expected »=«, »,«, »;«, »asm« or »__attribute__« before »*« token                                                                                                                                        

/home/jonathan/Applications/freehal-r108-ubuntu/hal2009-sql-sqlite.c: In Funktion »callback«:                                                

/home/jonathan/Applications/freehal-r108-ubuntu/hal2009-sql-sqlite.c:114: Fehler: »sqlite_connection« nicht deklariert (erste Benutzung in dieser Funktion)                                                                                                                               

/home/jonathan/Applications/freehal-r108-ubuntu/hal2009-sql-sqlite.c:114: Fehler: (Jeder nicht deklarierte Bezeichner wird nur einmal aufgeführt                                                                                                                                          

/home/jonathan/Applications/freehal-r108-ubuntu/hal2009-sql-sqlite.c:114: Fehler: für jede Funktion in der er auftritt.)                     

/home/jonathan/Applications/freehal-r108-ubuntu/hal2009-sql-sqlite.c: In Funktion »sql_sqlite_begin«:                                        

/home/jonathan/Applications/freehal-r108-ubuntu/hal2009-sql-sqlite.c:180: Fehler: »sqlite_connection« nicht deklariert (erste Benutzung in dieser Funktion)                                                                                                                               

/home/jonathan/Applications/freehal-r108-ubuntu/hal2009-sql-sqlite.c: In Funktion »sql_sqlite_end«:                                          

/home/jonathan/Applications/freehal-r108-ubuntu/hal2009-sql-sqlite.c:195: Fehler: »sqlite_connection« nicht deklariert (erste Benutzung in dieser Funktion)                                                                                                                               

/home/jonathan/Applications/freehal-r108-ubuntu/hal2009-sql-sqlite.c: In Funktion »sql_sqlite_add_record«:                                   

/home/jonathan/Applications/freehal-r108-ubuntu/hal2009-sql-sqlite.c:212: Fehler: »sqlite_connection« nicht deklariert (erste Benutzung in dieser Funktion)                                                                                                                               

/home/jonathan/Applications/freehal-r108-ubuntu/hal2009-sql-sqlite.c: In Funktion »sql_sqlite_get_records«:                                  

/home/jonathan/Applications/freehal-r108-ubuntu/hal2009-sql-sqlite.c:325: Fehler: »sqlite_connection« nicht deklariert (erste Benutzung in dieser Funktion)                                                                                                                               

In file included from /home/jonathan/Applications/freehal-r108-ubuntu/hal2009.h:136,                                                         

                 from /home/jonathan/Applications/freehal-r108-ubuntu/hal2009-main.c:22:                                                     

/home/jonathan/Applications/freehal-r108-ubuntu/hal2009.c: In Funktion »hal2009_add_pro_file«:                                               

/home/jonathan/Applications/freehal-r108-ubuntu/hal2009.c:231: Warnung: format »%i« erwartet Typ »int«, aber Argument 2 hat Typ »long int«   

/home/jonathan/Applications/freehal-r108-ubuntu/hal2009.c:231: Warnung: format »%li« erwartet Typ »long int«, aber Argument 3 hat Typ »int«  

/home/jonathan/Applications/freehal-r108-ubuntu/hal2009.c:231: Warnung: format »%i« erwartet Typ »int«, aber Argument 4 hat Typ »time_t«     

/home/jonathan/Applications/freehal-r108-ubuntu/hal2009.c:249: Warnung: format »%i« erwartet Typ »int«, aber Argument 2 hat Typ »long int«   

/home/jonathan/Applications/freehal-r108-ubuntu/hal2009.c:249: Warnung: format »%li« erwartet Typ »long int«, aber Argument 3 hat Typ »int«  

/home/jonathan/Applications/freehal-r108-ubuntu/hal2009.c:249: Warnung: format »%i« erwartet Typ »int«, aber Argument 4 hat Typ »time_t«     

/home/jonathan/Applications/freehal-r108-ubuntu/hal2009.c: In Funktion »ascii«:                                                              

/home/jonathan/Applications/freehal-r108-ubuntu/hal2009.c:350: Warnung: Zuweisung streicht Qualifizierer von Zeiger-Zieltyp                  

/home/jonathan/Applications/freehal-r108-ubuntu/hal2009.c: In Funktion »hal2009_start_signal_handler«:                                       

/home/jonathan/Applications/freehal-r108-ubuntu/hal2009.c:799: Warnung: Initialisierung erzeugt Zeiger von Ganzzahl ohne Typkonvertierung    

/home/jonathan/Applications/freehal-r108-ubuntu/hal2009.c: In Funktion »hal2009_answer«:                                                     

/home/jonathan/Applications/freehal-r108-ubuntu/hal2009.c:825: Warnung: Zuweisung von inkompatiblem Zeigertyp                                

/home/jonathan/Applications/freehal-r108-ubuntu/hal2009-main.c: In Funktion »main«:                                                          

/home/jonathan/Applications/freehal-r108-ubuntu/hal2009-main.c:119: Warnung: Unverträgliche implizite Deklaration der eingebauten Funktion »abort«                                                                                                                                        

/home/jonathan/Applications/freehal-r108-ubuntu/hal2009-main.c:125: Warnung: Unverträgliche implizite Deklaration der eingebauten Funktion »exit«                                                                                                                                         

/home/jonathan/Applications/freehal-r108-ubuntu/hal2009-main.c: Auf höchster Ebene:                                                          

/home/jonathan/Applications/freehal-r108-ubuntu/hal2009-main.c:170: Warnung: In Konflikt stehende Typen für »shell«                          

/home/jonathan/Applications/freehal-r108-ubuntu/hal2009-main.c:153: Warnung: Vorherige implizite Deklaration von »shell« war hier            

/home/jonathan/Applications/freehal-r108-ubuntu/hal2009-main.c: In Funktion »hal2009_handle_signal«:                                         

/home/jonathan/Applications/freehal-r108-ubuntu/hal2009-main.c:219: Warnung: Übergabe des Arguments 1 von »free« entfernt Kennzeichner von Zeiger-Ziel-Typ                                                                                                                                

/home/jonathan/Applications/freehal-r108-ubuntu/hal2009-main.c:226: Warnung: Vergleich zwischen Zeiger und Ganzzahl                          

/home/jonathan/Applications/freehal-r108-ubuntu/hal2009-main.c:227: Warnung: Unverträgliche implizite Deklaration der eingebauten Funktion »exit«                                                                                                                                         

make[2]: *** [CMakeFiles/hal2009.dir/hal2009-main.c.o] Fehler 1                                                                              

make[1]: *** [CMakeFiles/hal2009.dir/all] Fehler 2                                                                                           

make: *** [all] Fehler 2
Und als ich versucht habe, das schon vorkompillierte Programm auszuführen, kam dann die Fehlermeldung:
jonathan@jonathan-desktop:~/Applications/freehal-r108-ubuntu$ ./hal2009

./hal2009: error while loading shared libraries: libparrot.so.0.9.0: cannot open shared object file: No such file or directory

Ich habe extra nachgeguckt, laut "apt-get install libparrot" bzw. "apt-get install parrot" ist alles auf dem neusten stand... Hm... Vielleicht hast Du ja noch eine Idee, was ich probieren könnte :)

Geschrieben

Ich lade mir gerade FreeHAL über Subversion runter und dabei fällt mir auf, dass das ganze ja recht ähnlich meiner Ideen funktioniert... Bzw. in diesem Fall ja deiner/euerer Ideen ihr habts ja erfunden ;)... Also auch mit einzelnen "Modulen" für Sprichwörter, Mathematik, Vorname, etc... Sehr interessant :)

Geschrieben
Wow, der Admin von FreeHal... Ich fühle mich ja echt geehrt :)

Danke also auf jeden Fall schon Mal für die Mühe :)

Auch die 108-Version (precompiled für ubuntu) funktioniert bei mir leider noch nicht. Es gibt da beim "make" eine Menge fehler. Außerdem scheint mir wohl eine "libparrot.so" zu fehlen, die ja aber eigentlich installiert ist... sonderbar... Für den Fall, dass du mit der Ausgabe was anfangen kannst, poste ich sie hier einfach mal:

jonathan@jonathan-desktop:~/Applications/freehal-r108-ubuntu$ cmake .

-- The C compiler identification is GNU                              

...                                          

-- Build files have been written to: /home/jonathan/Applications/freehal-r108-ubuntu

jonathan@jonathan-desktop:~/Applications/freehal-r108-ubuntu$ make                  

Scanning dependencies of target hal2009                                             

[  4%] Building C object CMakeFiles/hal2009.dir/hal2009-main.c.o                                                                             

In file included from /home/jonathan/Applications/freehal-r108-ubuntu/hal2009-sql.c:22,                                                      

                 from /home/jonathan/Applications/freehal-r108-ubuntu/hal2009.h:131,                                                         

                 from /home/jonathan/Applications/freehal-r108-ubuntu/hal2009-main.c:22:                                                     

/home/jonathan/Applications/freehal-r108-ubuntu/hal2009-sql-sqlite.c:22:21: error: sqlite3.h: No such file or directory                      

In file included from /home/jonathan/Applications/freehal-r108-ubuntu/hal2009-sql.c:22,                                                      

                 from /home/jonathan/Applications/freehal-r108-ubuntu/hal2009.h:131,                                                         

                 from /home/jonathan/Applications/freehal-r108-ubuntu/hal2009-main.c:22:                                                     

/home/jonathan/Applications/freehal-r108-ubuntu/hal2009-sql-sqlite.c:24: Fehler: expected »=«, »,«, »;«, »asm« or »__attribute__« before »*« token                                                                                                                                        

/home/jonathan/Applications/freehal-r108-ubuntu/hal2009-sql-sqlite.c: In Funktion »callback«:                                                

/home/jonathan/Applications/freehal-r108-ubuntu/hal2009-sql-sqlite.c:114: Fehler: »sqlite_connection« nicht deklariert (erste Benutzung in dieser Funktion)                                                                                                                               

/home/jonathan/Applications/freehal-r108-ubuntu/hal2009-sql-sqlite.c:114: Fehler: (Jeder nicht deklarierte Bezeichner wird nur einmal aufgeführt                                                                                                                                          

/home/jonathan/Applications/freehal-r108-ubuntu/hal2009-sql-sqlite.c:114: Fehler: für jede Funktion in der er auftritt.)                     

/home/jonathan/Applications/freehal-r108-ubuntu/hal2009-sql-sqlite.c: In Funktion »sql_sqlite_begin«:                                        

/home/jonathan/Applications/freehal-r108-ubuntu/hal2009-sql-sqlite.c:180: Fehler: »sqlite_connection« nicht deklariert (erste Benutzung in dieser Funktion)                                                                                                                               

/home/jonathan/Applications/freehal-r108-ubuntu/hal2009-sql-sqlite.c: In Funktion »sql_sqlite_end«:                                          

/home/jonathan/Applications/freehal-r108-ubuntu/hal2009-sql-sqlite.c:195: Fehler: »sqlite_connection« nicht deklariert (erste Benutzung in dieser Funktion)                                                                                                                               

/home/jonathan/Applications/freehal-r108-ubuntu/hal2009-sql-sqlite.c: In Funktion »sql_sqlite_add_record«:                                   

/home/jonathan/Applications/freehal-r108-ubuntu/hal2009-sql-sqlite.c:212: Fehler: »sqlite_connection« nicht deklariert (erste Benutzung in dieser Funktion)                                                                                                                               

/home/jonathan/Applications/freehal-r108-ubuntu/hal2009-sql-sqlite.c: In Funktion »sql_sqlite_get_records«:                                  

/home/jonathan/Applications/freehal-r108-ubuntu/hal2009-sql-sqlite.c:325: Fehler: »sqlite_connection« nicht deklariert (erste Benutzung in dieser Funktion)                                                                                                                               

In file included from /home/jonathan/Applications/freehal-r108-ubuntu/hal2009.h:136,                                                         

                 from /home/jonathan/Applications/freehal-r108-ubuntu/hal2009-main.c:22:                                                     

make[2]: *** [CMakeFiles/hal2009.dir/hal2009-main.c.o] Fehler 1                                                                              

make[1]: *** [CMakeFiles/hal2009.dir/all] Fehler 2                                                                                           

make: *** [all] Fehler 2
Und als ich versucht habe, das schon vorkompillierte Programm auszuführen, kam dann die Fehlermeldung:
jonathan@jonathan-desktop:~/Applications/freehal-r108-ubuntu$ ./hal2009

./hal2009: error while loading shared libraries: libparrot.so.0.9.0: cannot open shared object file: No such file or directory
Ich habe extra nachgeguckt, laut "apt-get install libparrot" bzw. "apt-get install parrot" ist alles auf dem neusten stand... Hm... Vielleicht hast Du ja noch eine Idee, was ich probieren könnte :)
Hallo, 1.) Die Kompilierung klappt nicht, weil die Headerdateien von SQLite fehlen, die im Paket libsqlite3-dev sind. 2.) Ubuntu enthält noch Version 0.4 von Parrot (/usr/lib/libparrot.so.0.4.13), und da FreeHAL Version 0.9 erwartet, kann man entweder 0.9 kompilieren oder eine 0.9er vortäuschen:
ln -sf /usr/lib/libparrot.so.0.4.13 /usr/lib/libparrot.so.0.9.0

ln -sf /usr/lib/libparrot.so.0.4.13 /usr/lib/libparrot.so.0.9

sudo ldconfig -aq

Gruß,

Tobias

Geschrieben

Hallo nochmal!

Also ich habe jetzt schon angefangen, das User Interface zu machen und bin damit jetzt fertig (zumindest vorerst. Ich habe auch schon das Grundgerüst des Programms erstellt. Also die ganzen Funktionen für die Buttons als Dummies eingefügt bzw. die kleineren Funktionen auch schon fertig. Jetzt gehts ans eingemachte, und zwar die Verarbeitung der Usereingabe. Auch dafür habe ich schon die Grundfunktion, an welche die Usereingabe "QString input" und die Sprache "QString language" übergeben wird. Dabei ist input der Eingegebene Text und language entspricht dem Verzeichnis, in dem die Sprachdateien liegen. Soweit so gut. Nun muss die Funktion alle Module (z.B. welcome.mod) auslesen und den Inhalt verarbeiten. Dabei habe ich mir was überlegt, worüber ich ganz gerne eure Meinung hätte, ob das funktionell oder eher ein "workaround" ist.

Also ich habe verschiedene Dateien für verschiedene Bereiche. Die Datei welcome.mod enthält z.B. nur Begrüßungs oder Abschiedsfloskeln. Hier mal ein kleines Beispiel, wie die Dateien aussehen:

<trigger 1>guten <var 1>(morgen|mittag|abend|tag)</var></trigger>

<trigger 2>gute <var 2>nacht</var></trigger>

<trigger 3>hallo</trigger>

<out 1>Ebenfalls einen guten <var 1 /></out>

<out 2>Schlaf gut!</out>

<out 3>Ebenfalls hallo!</out>

Dabei sind die Trigger das, worauf die Usereingabe geprüft wird. Die Zahl hinter dem <trigger ???> ist die ID des Suchstrings. Wenn z.B. der Trigger 3 ausgelöst wird, weil der User "Hallo" eingibt, dann wird automatisch der entsprechende Text <out 3>...</out> ausgegeben. Im ersten Auslöser habe ich außerdem eine Variable drin. Das heißt der Teil der Usereingabe wird in eine Variable gepackt, sofern er vorhanden ist. Schreibt der User also "guten mittag", wird automatisch "mittag" in die Variable 1 gespeichert, welche dann im Output wieder verwendet werden kann (s. entsprechendem "<out 1>")... Die in Klammern stehende Auswahl an Möglichkeiten ist abgekupfert von RegEx, worauf hinterher im Übrigen auch die ganze Abfrage basieren soll. Im 3. Auslöser ist eine einfache Variable ohne Möglichkeiten angegeben. Das heißt hier würde alles als Variable akzeptiert werden: "hallo Computer" würde "Computer" speichern, "hallo Programm" würde "Programm" speichern.

In meiner Funktion will ich die Dateien auslesen, die Trigger per Array den entsprechenden Ausgaben zuordnen, anschließend per foreach (oder ähnlichem, ich werde vermutlich einen Vektor nehmen müssen) alle Tags entfernen und dann die übrig bleibenden Strings in ein RegEx-Muster umwandeln indem ich Leerzeichen durch Punkte ersetze und Sonderzeichen Ordnungsgemäß escape. Dieses einlesen würde mit allen Dateien passieren. Und jetzt kommt die letzte Stufe bevor die Usereingabe tatsächlich damit geprüft wird: Nämlich ein kleiner Workaround für folgende unglückliche Begebenheit:

User: Hallo bist du eigentlich blöd oder so?

Computer: Ebenfalls hallo :)

Das ist zwar cool, aber natürlich so nicht vorgesehen. Um solche Missgeschicke zu vermeiden, wird der Vektor mit den Triggern und entsprechenden Outputs nach der Länge der Trigger (nach Zeichenanzahl) geordnet. Es werden also Trigger, die einen ganzen Satz verarbeiten, zuerst überprüft und die ganz kurzen wie "hallo" erst am Schluss. So wäre folgendes Möglich:

User: Hallo!

Computer: Ebenfalls Hallo!

User: hallo was kannst du eigentlich?

Computer Ich kann eine ganze Menge!

Das war so erstmal die Grundidee. Auf Datenbankbasis würde ich das ganze eher ungern machen, da ich nicht so viel von Datenbanken halte. Daher die Idee mit den Modulen.

Wäre über Kritik, Tipps und Ansätze sehr froh, will ja schließlich nicht einen Schritt in die ganz falsche Richtung machen. Bedenkt immer: Ich bin erst 15 und habe kein Informatik studiert ;)

Das ganze soll übrigens mit QT und C++ realisiert werden.

Liebe Grüße,

Jonathan

Tobias Schulze: Ich habe das mit FreeHAL jetzt aufgegeben. Das mit dem Linken hat nicht funktioniert (keine Fehlermeldungen?) und auch Parrot ließ sich mit irgendwelchem Zeichenwirrwarr als Fehlermeldung nicht kompilieren. Gibt es eigentlich die Online-Demo noch? (ich hatte da früher immer nur ein weißes Browserfenster mit nichts drin, vielleicht hat sich das ja auch geändert?)

Geschrieben

Hallo,

Das, was du machen willst, ist eigentlich exakt ein Alice mit AIML. Die AIML-Dateien entsprechen bis auf die Syntax den Modulen. (Verschiedene AIML-Implementierungen findest du hier)

Da dein Chatbot ja nicht lernt, sondern alle Ausdrücke aus den von Menschen geschriebenen .mod-Dateien bezieht, ist eine Datenbank natürlich überflüssig. Freehal geht ein ganzes Stück weiter, indem es die Sätze des Users parst und nach Subjekt, Prädikat, Objekt getrennt in die Datenbank abspeichert. Da kann man keine Textdateien nehmen.

Wenn du vorhast, irgendwann Module mit mehreren Tausend Triggern einlesen zu können (das hört sich erst viel an, ist aber eigentlich fast gar nichts), solltest du unbedingt auf eine vernünftige Speicherverwalung überall achten. Bei älteren Versionen von FreeHAL haben wir alle Inputdateien geparst und in den Speicher geladen, doch das ist bald an seine Grenzen gestoßen. Mit SQLite, einer in jedes Programm integrierbaren Datenbankengine haben wir nun 20 MB RAM-Verbrauch bei mehreren Millionen Sätzen.

Bei den Regexangelegenheiten solltest du darauf achten, dass du dir vorher wirklich ein Konzept machst, wie du das implementieren willst, und das sollte möglichst allumfassend sein und neue Features zulassen, notfalls auf Papier. Wenn du das einfach so implementierst musst du es in einem halben Jahr neu schreiben, wenn du neue Features hinzufügen willst.

Vermeide auch Funktionen/Methoden, die mehr als eine Aufgabe erfüllen. Wenn eine Funktion meinetwegen etwas an einem String verändern muss (Klassisches Beispiel: Verben konjugieren, oder auch nur Leerzeichen am Ende entfernen), solltest du das von Anfang an extra implementieren. Und gerade bei C++ sollte man keine "Auffangklassen" verwenden, die eine bunte Mischung an Methoden enthalten, nur weil man sie nicht als Funktionen implementieren will oder weil man kein Konzept für die Klassen im Projekt hat.

Gruß

Tobias

Geschrieben

Das ist ja schon mal was, danke :)

Mein Plan war eine einzige Funktion (zumindestens vorerst), die die Überprüfung vornimmt. Daran schreibe ich gerade und bin mit dem Grundgerüst dieser fast fertig. Ich fange jetzt an, in der Funktion die Dateien zu verarbeiten und in ein Array einlesen zu lassen... Also so wie oben beschrieben.

Ich verstehe natürlich den Vorteil von Datenbanken, vor allem im Bezug auf diese Datenmenge... Ich habe auch schon etwas in die Richtung gedacht, beides zu kombinieren. Sprich ich habe ein Grundmuster ähnlich "Was ist ein <var />?"... Dieses Grundmuster würde sich dann die Datenbank mit sämtlichen Objekten zu Nutze machen, in welcher die Beschreibungen von diesen gespeichert ist. So würde dann folgendes Möglich:

User: Was ist ein Baum?

Computer: Ein Baum ist eine Pflanze.

Das selbe ginge mit bekannten Personen, oder sonstigen Erklärungen. Dadurch würde ich lediglich ein einziges Modul für die jeweilige Frageart (z.B. Frage nach einem Objekt: Was ist ein, Frage nach einer Person: Wer ist) benötigen und könnte trotzdem große Datenmengen problemlos speichern. Aber ob die Kombination von den Dateien und einer Datenbank so gut ist :rolleyes:... Naja mal sehen, jetzt schreibe ich erstmal weiter ;)

Geschrieben

Hallo,

ich hatte mal vor einigen Jahren die Idee, ein "Semantisches Netz" aufzubauen. Grundlage war, dass das kleinste Element aus Subjekt, Prädikat, Objekt besteht. Dabei sind Subjekt und Objekt Objekte und das Prädikat eine Relation zwichen beiden.

Das SN hat als notwendige Knoten:

- Wurzel der Objekte

- Wurzel der Relationen

Es hat als notwendige Relationen:

- is kind of (iko), ist Teil von

- has as kind (hak), hat als Teil

- is same as ( isa), ist soviel wie

In meinem Modell habe ich (o,r,o) eingegeben, um einen Eintrag zu erzeugen. Dabei ist o ein Objekt, und r eine Relation.

Z.B. ("9","*9","81") bedeutet 9*9=81.

Wenn ich min. einer Stelle ein "?" eingegeben habe, dann hat mir das programm die Sätze rausgesucht, die passen.

z.B. ("?","*9,"81") entspräche der Frage "Mit was muss man neune multiplizieren um 81 zu erhalten" und es ergebe den oben genannten Satz.

Weiter habe ich das Projekt bisher nicht verfolgt.

Vielleicht könnt ihr das was draus machen!

LG

Andre'

Geschrieben
Hallo,

ich hatte mal vor einigen Jahren die Idee, ein "Semantisches Netz" aufzubauen. Grundlage war, dass das kleinste Element aus Subjekt, Prädikat, Objekt besteht. Dabei sind Subjekt und Objekt Objekte und das Prädikat eine Relation zwichen beiden.

Das SN hat als notwendige Knoten:

- Wurzel der Objekte

- Wurzel der Relationen

Es hat als notwendige Relationen:

- is kind of (iko), ist Teil von

- has as kind (hak), hat als Teil

- is same as ( isa), ist soviel wie

In meinem Modell habe ich (o,r,o) eingegeben, um einen Eintrag zu erzeugen. Dabei ist o ein Objekt, und r eine Relation.

Z.B. ("9","*9","81") bedeutet 9*9=81.

Wenn ich min. einer Stelle ein "?" eingegeben habe, dann hat mir das programm die Sätze rausgesucht, die passen.

z.B. ("?","*9,"81") entspräche der Frage "Mit was muss man neune multiplizieren um 81 zu erhalten" und es ergebe den oben genannten Satz.

Weiter habe ich das Projekt bisher nicht verfolgt.

Vielleicht könnt ihr das was draus machen!

LG

Andre'

So funktioniert FreeHAL. Nur dass du die Eingaben und Abfragen in natürlicher Sprache formilieren kannst.

Wenn gegeben ist: "Ich bin eine künstliche Intelligenz"

Und ich Frage nach: "Wer bin ich?"

Wird das, was du da beschrieben hast, in SQL formuliert und als Datenbankabfrage ausgeführt. Heraus kommt dann der oben genannte Fakt, genau wie bei "Kennst du eine künstliche Intelligenz?".

Die größte Arbeit bei FreeHAL macht der Parser, der diese deutschen und englischen Sätze zu logischen Abfragen umwandelt, da er möglichst alles parsen können soll. Beschränkt man sich auf ganz einfache Sätze wie diesen da, lief das schon 2007 in FreeHAL.

Gruß

Tobias

Geschrieben

Wow, das ist ziemlich kompliziert... Ich glaube das überlasse ich auch euch, weil so weit bin ich einfach bei weitem noch nicht :)

Aber ich habe dafür hier gerade noch einmal ein Problem mit meinem RexEx-Bot ;)

QString treid("\\<trigger.([1-9])\\>.*\\<\\/trigger\\>");

Das ist das RegEx-Muster, um die ID des Tags auszulesen. Die entsprechende QRegExp Anweisung sieht demzufolge so aus:

QRegExp rxid(treid, Qt::CaseInsensitive, QRegExp::RegExp2);

Ja, das CaseInsensitive kann ich mir sparen, aber da später auch Buchstaben als ID dienen sollen, lasse ich es einfach mal drin. Die tatsächliche Abfrage sieht dann so aus:

positiontriggerid = rxid.indexIn(line);

In "line" ist die entsprechende Zeile der Textdatei gespeichert. Wenn ich das ganze beim Tag-Inhalt mache (Also alles was zwischen dem öffnendem und schließendem Tag steht), funktioniert alles bestens und ich bekomme meine einzelnen Strings, die ich dann in ein Array speichern kann... Oder ausgeben kann... Oder damit machen kann was ich will ;) Nur hier bei der ID funktioniert das nicht:

QString triggerid = line.mid(positiontriggerid,1);

QString triggercontent = line.mid(positiontriggercontent,positiontriggercontentlength);

parsebase.append("Trigger id: "+triggerid+" ... Trigger content: "+triggercontent);

So sieht hinterher das Zerschnibbeln des Textes aus. Nun komme ich zu dem, was nicht funktioniert. Und zwar wird letztendlich der String zum Vektor "parsebase" angeefügt. Nur aus irgendeinem Grund macht die "id" aus dem String ein ganz furchtbares Wirrwarr. Hinterher wird das ganze in einem QT Text-Browser ausgegeben, welcher HTML interpretieren kann. Das ganze sieht dann so aus:

Trigger id: guten (morgen|mittag|abend|tag)Trigger id: gute nachtTrigger id: hallo

Anstelle von so:

Trigger id: 1 ... Trigger content: guten (morgen|mittag|abend|tag) Trigger id: 2 ... usw.

Ich vermute, das Teile des "trigger-Tags mit abgeschnitten werden und dann in dem HTML-Bereich irgendwas verwurschteln... Ersetze ich beim Abschneiden der ID die "1" durch eine 0 (also es werden 0 Zeichen abgeschniten, demzufolge bleibt der String auch 0 Zeichen lang) sieht der Ausgabe-String normal aus, nur dass halt dort, wo die ID stehen sollte, einfach nichts steht. Also:

Trigger id: ... Trigger content: guten (morgen|mittag|abend|tag) Trigger id: ... usw.

Ich bin gerade etwas ratlos, weiß nämlich nicht, woran das liegt :/

Würde mich da über Hilfe sehr freuen :) Danke im Voraus,

Jonathan

Geschrieben
Wow, das ist ziemlich kompliziert... Ich glaube das überlasse ich auch euch, weil so weit bin ich einfach bei weitem noch nicht :)

Aber ich habe dafür hier gerade noch einmal ein Problem mit meinem RexEx-Bot ;)

QString treid("\\<trigger.([1-9])\\>.*\\<\\/trigger\\>");

Das ist das RegEx-Muster, um die ID des Tags auszulesen. Die entsprechende QRegExp Anweisung sieht demzufolge so aus:

QRegExp rxid(treid, Qt::CaseInsensitive, QRegExp::RegExp2);

Ja, das CaseInsensitive kann ich mir sparen, aber da später auch Buchstaben als ID dienen sollen, lasse ich es einfach mal drin. Die tatsächliche Abfrage sieht dann so aus:

positiontriggerid = rxid.indexIn(line);

In "line" ist die entsprechende Zeile der Textdatei gespeichert. Wenn ich das ganze beim Tag-Inhalt mache (Also alles was zwischen dem öffnendem und schließendem Tag steht), funktioniert alles bestens und ich bekomme meine einzelnen Strings, die ich dann in ein Array speichern kann... Oder ausgeben kann... Oder damit machen kann was ich will ;) Nur hier bei der ID funktioniert das nicht:

QString triggerid = line.mid(positiontriggerid,1);

QString triggercontent = line.mid(positiontriggercontent,positiontriggercontentlength);

parsebase.append("Trigger id: "+triggerid+" ... Trigger content: "+triggercontent);

So sieht hinterher das Zerschnibbeln des Textes aus. Nun komme ich zu dem, was nicht funktioniert. Und zwar wird letztendlich der String zum Vektor "parsebase" angeefügt. Nur aus irgendeinem Grund macht die "id" aus dem String ein ganz furchtbares Wirrwarr. Hinterher wird das ganze in einem QT Text-Browser ausgegeben, welcher HTML interpretieren kann. Das ganze sieht dann so aus:

Trigger id: guten (morgen|mittag|abend|tag)Trigger id: gute nachtTrigger id: hallo

Anstelle von so:

Trigger id: 1 ... Trigger content: guten (morgen|mittag|abend|tag) Trigger id: 2 ... usw.

Ich vermute, das Teile des "trigger-Tags mit abgeschnitten werden und dann in dem HTML-Bereich irgendwas verwurschteln... Ersetze ich beim Abschneiden der ID die "1" durch eine 0 (also es werden 0 Zeichen abgeschniten, demzufolge bleibt der String auch 0 Zeichen lang) sieht der Ausgabe-String normal aus, nur dass halt dort, wo die ID stehen sollte, einfach nichts steht. Also:

Trigger id: ... Trigger content: guten (morgen|mittag|abend|tag) Trigger id: ... usw.

Ich bin gerade etwas ratlos, weiß nämlich nicht, woran das liegt :/

Würde mich da über Hilfe sehr freuen :) Danke im Voraus,

Jonathan

Hallo,

Kannst du die ganze Codedatei als Anhang anfügen, damit man das Programm mal starten kann, sonst kann ich nur raten, denn beim Aufruf einzelner Funktionen kann man nicht viel falsch machen, der Zusammenhang ist das wichtige?

Hast du dir schonmal überlegt, welche Lizenz usw. du verwenden willst?

(treid = trigger regex id? Auf den ersten Blick etwas unverständlich)

Gruß

Tobias

Geschrieben (bearbeitet)

Hm Lizenz kommt vielleicht, wenn ich das ganze weiter ausgebaut habe... Bisher ist das ganze ja doch eher noch ein Übungs-Projekt eines Schülers, dass jeder Informatikstudent irgendwie hinbekommen würde ;)

Die Funktion ist vorerst einfach nur mal runtergeschrieben; mache ich immer so, ich schreibe immer erstmal alles und vereinfache und verbessere das hinterher dann. Ursprünglich hat die Datei natürlich die Endung .cpp und wird auch Ordnungsgemäß eingebunden etc... Das Problem liegt also nur innerhalb der Funktion. Die Code-Datei ist im Anhang :)

Das Projekt besteht inzwischen aus einigen Dateien, soll ich wirklich alle hochladen?

Achso, und treid bedeutet genau das, mir sind die einfallsreichen variablennamen ausgegangen ;)

parser.txt

Bearbeitet von Mefisto

Dein Kommentar

Du kannst jetzt schreiben und Dich später registrieren. Wenn Du ein Konto hast, melde Dich jetzt an, um unter Deinem Benutzernamen zu schreiben.

Gast
Auf dieses Thema antworten...

×   Du hast formatierten Text eingefügt.   Formatierung wiederherstellen

  Nur 75 Emojis sind erlaubt.

×   Dein Link wurde automatisch eingebettet.   Einbetten rückgängig machen und als Link darstellen

×   Dein vorheriger Inhalt wurde wiederhergestellt.   Editor leeren

×   Du kannst Bilder nicht direkt einfügen. Lade Bilder hoch oder lade sie von einer URL.

Fachinformatiker.de, 2024 by SE Internet Services

fidelogo_small.png

Schicke uns eine Nachricht!

Fachinformatiker.de ist die größte IT-Community
rund um Ausbildung, Job, Weiterbildung für IT-Fachkräfte.

Fachinformatiker.de App

Download on the App Store
Get it on Google Play

Kontakt

Hier werben?
Oder sende eine E-Mail an

Social media u. feeds

Jobboard für Fachinformatiker und IT-Fachkräfte

×
×
  • Neu erstellen...